GLSL中简单光线跟踪器的反射问题

时间:2017-03-09 20:49:31

标签: glsl raytracing

我正在GLSL 4.0中编写一个简单的光线跟踪器,我在使用正确的着色(phong)进行基本反射方面遇到了一些麻烦。我正在使用渲染到纹理着色器(屏幕对齐四边形)编写我的场景由6个球体和一个平面组成,如下面的代码所述。我使用Intersection结构来跟踪交叉点和光线的Ray结构。由于GLSL 4.0不允许递归,我迭代地投射二次光线(通过每次迭代改变每条光线的方向和原点)。

#version 400

in vec3 dir;
out vec4 outcolour;

uniform mat4 mMatrix;
uniform mat4 mvMatrix;
uniform mat4 mvMatrixScene;
uniform mat4 pMatrix;
uniform mat3 normalMatrix; //mv matrix without translation

uniform vec3 light = vec3(6,4,3);
uniform vec4 ambient = vec4(0.0,0.0,0.0,1.0);
uniform vec4 diffuse = vec4(1.0,0.1,0.0,1.0);
uniform vec4 specular = vec4(1.0,1.0,1.0,1.0);
uniform float ambientCoefficent = 1.0;
uniform float diffuseCoefficent = 1.0;
uniform float specularCoefficent = 1.0;

const float PI = 3.14159265358979;
const int raytraceDepth = 2;
const int numSpheres = 6;

//example data structures
struct Ray
{
    vec3 origin;
    vec3 dir;
};

struct Sphere
{
    vec3 centre;
    float radius;
    vec3 colour;
};

struct Plane
{
    vec3 point;
    vec3 normal;
    vec3 colour;
};

struct Intersection
{
    float t; //closest hit
    vec3 point; // hit point
    vec3 normal; // normal
    int hit; //did it hit?
    vec3 colour; // colour accumulation, can be also implemented in struct Ray
};

void sphere_intersect(Sphere sph, Ray ray, inout Intersection intersect) {
    vec3 dp = ray.origin - sph.centre;
    vec3 d = ray.dir;
    float r = sph.radius;

    // Does the sphere intersect?
    float x = pow(dot(d,dp),2.0) - pow(length(dp),2.0) + pow(r,2.0);
    intersect.hit = 0;

    if (x >= 0) {
        float u1 = dot(-d,dp) + sqrt(x);
        float u2 = dot(-d,dp) - sqrt(x);
        float u = min(u1,u2);
        if (u < intersect.t) {
            intersect.t = u;
            intersect.colour = sph.colour;
            intersect.point = ray.origin + intersect.t*d;
            intersect.hit = 1;
            intersect.normal = (intersect.point - sph.centre) / sph.radius;
        }
    }
}

void plane_intersect(Plane pl, Ray ray, inout Intersection intersect)
{
    float x = dot(ray.dir,pl.normal);
    // Assuming no paralel rays otherwise divide by 0 error
    float h = dot(pl.point - ray.origin,pl.normal)/x;
    intersect.hit = 0;
    //intersect.colour = vec3(0.0,0.0,0.0);
    intersect.point = vec3(0.0,0.0,0.0);
    if (h >=0 ) {
    float u = -dot((ray.origin - pl.point),pl.normal)/x;
        if (u < intersect.t) {
        intersect.t = u;
        intersect.point = ray.origin + u*ray.dir;
        intersect.normal = pl.normal;
        intersect.hit = 1;

        // Normal used is y so used x and z for checkerboard pattern
            if (int((floor(intersect.point.x) + floor(intersect.point.z)))%2 == 1) {
                intersect.colour = pl.colour;
            } else {
                intersect.colour = vec3(0.0,0.0,0.0);
            }
        }
    }
}

Sphere sphere[numSpheres];
Plane plane;

vec4 local_shading_term(vec3 light, Intersection intersection) {
    float q = 10;
    float d = length(light - intersection.point);
    float s = 10;

    vec3 n = normalize(intersection.normal);
    vec3 l = normalize(light - intersection.point);
    vec3 r = normalize(-reflect(l,n));
    vec3 v = -normalize(intersection.point);
    vec4 diff = diffuse * diffuseCoefficent * vec4(max(dot(n,l),0));
    vec4 spec = specular * specularCoefficent * vec4(pow(max(dot(v,r),0), q));
    return (diff + spec) * 250 / (4 * PI * (d + s));
}

void Intersect(Ray ray, inout Intersection intersection)
{
    vec3 colour = vec3(0.0,0.0,0.0);
    int sphere_hits = 0;

    // Sphere intersection
    for (int i=0; i<numSpheres; i++) {
        sphere_intersect(sphere[i],ray,intersection);
        sphere_hits += intersection.hit;
    }

    if (sphere_hits > 0) {
    colour = intersection.colour + vec3(local_shading_term(light,intersection));
    }

    // Plane intersection
    plane_intersect(plane,ray,intersection);

    if (sphere_hits == 0 ) {
        colour = intersection.colour;
    }
    intersection.colour = colour;
}

void main()
{
    //White
    sphere[0].centre = vec3(-2.0, 1.5, -3.5);
    sphere[0].radius = 1.5;
    sphere[0].colour = vec3(0.8,0.8,0.8);

    //Green
    sphere[1].centre = vec3(-0.5, 0.0, -2.0);
    sphere[1].radius = 0.6;
    sphere[1].colour = vec3(0.3,0.8,0.3);

    //Blue
    sphere[2].centre = vec3(1.0, 0.7, -2.2);
    sphere[2].radius = 0.8;
    sphere[2].colour = vec3(0.3,0.8,0.8);

    //Yellow
    sphere[3].centre = vec3(0.7, -0.3, -1.2);
    sphere[3].radius = 0.2;
    sphere[3].colour = vec3(0.8,0.8,0.3);

    //Red
    sphere[4].centre = vec3(-0.7, -0.3, -1.2);
    sphere[4].radius = 0.2;
    sphere[4].colour = vec3(0.8,0.3,0.3);

    //Purple
    sphere[5].centre = vec3(0.2, -0.2, -1.2);
    sphere[5].radius = 0.3;
    sphere[5].colour = vec3(0.8,0.3,0.8);

    plane.point = vec3(0,-0.5, 0);
    plane.normal = vec3(0, 1.0, 0);
    plane.colour = vec3(1, 1, 1);

    vec4 colour = vec4(0,0,0,1);

    Ray ray;
    ray.origin = vec3(0.0,0.0,0.0);
    ray.dir = normalize(dir);

    Intersection intersection;
    for (int i=0; i<raytraceDepth; i++) {
        intersection.t = 999999999;
        Intersect(ray,intersection);
        ray.origin = intersection.point;
        ray.dir = reflect(ray.dir,intersection.normal);
    }
    colour = vec4(intersection.colour,0.0);
    outcolour = colour;
}

我已经调试了几天我的代码,但我似乎无法实现我的目标,最好用下图来描述:

enter image description here

除了阴影和精度问题,我试图实现上述目标,但现在它看起来像这样:

enter image description here

raytraceDepth = 1

enter image description here raytraceDepth = 2

如您所见,平面上方的背景中存在随机垃圾(可能是由于我未正确设置颜色值所致,因此它使用GPU内存中的任何内容)。当我加载着色器时,有时会出现噪音,有时它不是,当我拍摄这些截图时,恰好就在那里。当intersection.point中的plane_intersect设置为vec3(0.0,0.0,0.0)时,球体会产生奇怪的镜像效果。如果我将它移除,我不再看到效果了,但是更大的球体内的实际球体,这就是我保留它的原因。

我的想法是,我将光线与场景中的所有物体相交。交集结构作为inout参数传递给函数Intersect(),该函数测试与光线的交叉点。它使用最近的可见交叉点的值填充结构。因此t表示用于确定发生交叉的光线上的点的值,即ray = ray_origin + t*ray_direction

我不确定为什么我无法获得正确的反射效果。任何人都可以看到我的代码有任何问题?

0 个答案:

没有答案