超级简单的光线追踪

Super simple ray tracing

我正在努力了解使用 GLSL 的简单光线追踪技术。 我参考了 Inigo Quilez 的教程,[link] http://www.iquilezles.org/blog/?p=1521

我的代码编译正确,没有错误,但没有产生预期的球体输出。输出图像全黑。我似乎不知道如何解决这个问题。

#ifdef GL_ES
precision highp float;
#endif

uniform vec3 unResolution;
uniform float time;
uniform sampler2D tex0;
uniform sampler2D tex1;
uniform sampler2D fft;
uniform vec4 unPar;
uniform vec4 unPos;
uniform vec4 unBeatBassFFT;

float iSphere( in vec3 ro, in vec3 rd, in vec4 sph )
{
    // sphere centered at origin
    // |ro|^2 + t^2 + 2<ro,rd>t - r^2 = 0
    vec3 oc = ro - sph.xyz;
    float b = 2.0*dot( oc,rd );
    float c = 2.0*dot( oc,oc );
    float h = b*b - sph.w*sph.w;
    if ( h<0.0 ) return -1.0;
    float t = (-b - sqrt(h))/2.0;
    return t; 
}
vec3 nSphere( in vec3 pos, in vec4 sph )
{
    return (pos-sph.xyz)/sph.w;
}

float iPlane( in vec3 ro, in vec3 rd )
{
    return -ro.y/rd.y;
}

vec3 nPlane( in vec3 pos ) 
{
    return vec3(0.0,1.0,0.0);
}

vec4 sph1 = vec4( 0.0, 1.0, 0.0, 1.0 );
float intersect( in vec3 ro, in vec3 rd, out float resT )
{
    resT = 1000.0;
    float id = -1.0;
    float tsph = iSphere( ro, rd, sph1 );
    float tpla = iPlane( ro, rd );
    if ( tsph>0.0 )
    {
        id = 1.0;
        resT = tsph;
    }
    if (tpla>0.0 && tpla<resT)
    {
        id = 2.0;
        resT = tpla;
    }
    return id;
}

void main(void) 
{
    vec3 light = normalize( vec3( 0.57703 ));
    vec2 uv = (gl_FragCoord.xy/unResolution.xy)*vec2(1.78,1.0);

    //sph1.x = 0.5*cos(time);
    //sph1.z = 0.5*sin(time);

    vec3 ro = vec3( 0.0, 0.5, 3.0 );
    vec3 rd = normalize( vec3( (-1.0+2.0+uv)*vec2(1.78,1.0), 1.0 ) );

    float t;
    float id = intersect( ro, rd, t );

    vec3 col = vec3(0.0);
    if( id>0.5 && id<1.5 )
    {
        vec3 pos = ro + t*rd; 
        vec3 nor = nSphere( pos, sph1 );
        float dif = clamp(dot( nor, light ), 0.0, 1.0);
        float ao = 0.5 + 0.5*nor.y;
    float amb = 0.5 + 0.5*nor.y;
        col = vec3( 0.9, 0.8, 0.6 )*dif+amb*vec3(0.5,0.6,0.7);
    }
    else if( id>1.5 )
    {
        vec3 pos = ro + t*rd;
        vec3 nor = nPlane( pos );
        float dif = clamp( dot(nor, light), 0.0, 1.0 );
        float amb = smoothstep( 0.0, 2.0*sph1.w, length(pos.xz-sph1.xz) );
        col = vec3(amb*0.7);
        //col = vec3( 1.0, 0.0, 0.0 )*dif + amb*vec3(0.5,0.6,0.7);
    }
    col = sqrt(col);

    gl_FragColor = vec4(col,1.0);
}

编辑:以下是根据@LJᛃ 的回答更新的代码。 为通过搜索引擎找到此 post 的用户添加。

我还没有完善球体的阴影,但这里有一段代码供大家使用!

#ifdef GL_ES
precision highp float;
#endif

uniform vec2 resolution;
#define unResolution resolution
uniform float time;
uniform sampler2D tex0;
uniform sampler2D tex1;
uniform sampler2D fft;
uniform vec4 unPar;
uniform vec4 unPos;
uniform vec4 unBeatBassFFT;

float iSphere( in vec3 ro, in vec3 rd, in vec4 sph )
{
    // sphere centered at origin
    // |ro|^2 + t^2 + 2<ro,rd>t - r^2 = 0
    vec3 oc = ro - sph.xyz;
    float b = 2.0*dot( oc,rd );
    float c = 2.0*dot( oc,oc );
    float h = b*b - sph.w*sph.w;
    if ( h<0.0 ) return -1.0;
    float t = (-b - sqrt(h))/2.0;
    return t; 
}
vec3 nSphere( in vec3 pos, in vec4 sph )
{
    return (pos-sph.xyz)/sph.w;
}

float iPlane( in vec3 ro, in vec3 rd )
{
    return -ro.y/rd.y;
}

vec3 nPlane( in vec3 pos ) 
{
    return vec3(0.0,1.0,0.0);
}

vec4 sph1 = vec4( 0.0, 1.0, 0.0, 1.0 );
float intersect( in vec3 ro, in vec3 rd, out float resT )
{
    resT = 1000.0;
    float id = -1.0;
    float tsph = iSphere( ro, rd, sph1 );
    float tpla = iPlane( ro, rd );
    if ( tsph>0.0 )
    {
        id = 1.0;
        resT = tsph;
    }
    if (tpla>0.0 && tpla<resT)
    {
        id = 2.0;
        resT = tpla;
    }
    return id;
}

void main(void) 
{
    vec3 light = normalize( vec3( 0.57703 ));
    vec2 uv = (gl_FragCoord.xy/unResolution.xy);
    vec2 p = uv * 2.0 - 1.0;
    p.x*=unResolution.x/unResolution.y;

    //sph1.x = 0.5*cos(time);
    //sph1.z = 0.5*sin(time);

    vec3 ro = vec3( 0.0, 1.0, -1.0 );
    vec3 rd = normalize( vec3(p,0.2) );

    float t;
    float id = intersect( ro, rd, t );

    vec3 col = vec3(0.0);
    if( id>0.5 && id<1.5 )
    {
        vec3 pos = ro + t*rd; 
        vec3 nor = nSphere( pos, sph1 );
        float dif = clamp(dot( nor, light ), 0.0, 1.0);
        float ao = 0.1 + 0.5*nor.y;
        float amb = 0.5 + 0.5*nor.y;
        col = vec3( 1.0, 0.0, 0.0 )*dif + amb*vec3(0.5,0.6,0.7);
    }
    else if( id>1.5 )
    {
        vec3 pos = ro + t*rd;
        vec3 nor = nPlane( pos );
        float dif = clamp( dot(nor, light), 0.5, 1.0 );
        float amb = smoothstep( 0.5, 2.0*sph1.w, length(pos.xz-sph1.xz) );
        col = vec3(amb*0.9);
        //col = vec3( 1.0, 0.0, 0.0 )*dif + amb*vec3(0.5,0.6,0.7);
    }
    col = sqrt(col);

    gl_FragColor = vec4(col,1.0);
}

所以我将其移植到 GLSLSandbox.com,我将 unResolution 制服替换为一个 glsl 沙箱提供的制服:

uniform vec2 resolution;
#define unResolution resolution

然后我查看了您对光线来源和方向的基本设置。你试图在 uv 中考虑纵横比的方式是错误的,你想先计算居中坐标,然后应用纵横比变换:

vec2 uv = gl_FragCoord.xy/unResolution.xy;
// p is 0 at the center of the screen, x=-1 on the left, +1 on the right etc.
vec2 p = uv * 2.0 - 1.0;
// account for aspect ratio
p.x*=unResolution.x/unResolution.y;

// substitute uv with p in the following code

此时我看到了我认为是你的地平面的东西,屏幕在灰白色和黑色之间水平分割,所以我稍微调整了一下你的光线原点和方向:

vec3 ro = vec3( 0.0, 1., -1. );
vec3 rd = normalize( vec3( p, .25 ) )

瞧,我们有一个球体:

投影仍然有点奇怪,移动光线原点并不像我期望的那样,但我会把它留给你:)