Part of the Khronos Group
OpenGL.org

The Industry's Foundation for High Performance Graphics

from games to virtual reality, mobile phones to supercomputers

Page 2 of 3 FirstFirst 123 LastLast
Results 11 to 20 of 23

Thread: Ray intersection with GLSL

  1. #11
    Junior Member Newbie
    Join Date
    Dec 2017
    Posts
    28
    Hi GClements,

    thank you so much. I have followed your suggestion and moved the reflection computation to fragment, as well as I converted the position and normal in the world space as inputs.

    Since I've tried to simulate the first reflections by rasterization and second ones by ray-tracing, so I need some data in eye space for the first process. In this case, can I avoid the camera position?

    Follows my current code. Could you have a look again, please?

    Vertex:

    Code :
    #version 130
     
    uniform mat4 osg_ViewMatrixInverse;
     
    out vec3 positionEyeSpace;
    out vec3 normalEyeSpace;
    out vec3 positionWorldSpace;
    out vec3 normalWorldSpace;
     
    void main() {
        gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;
     
        // eye space
        positionEyeSpace = vec3(gl_ModelViewMatrix * gl_Vertex);
        normalEyeSpace = gl_NormalMatrix * gl_Normal;
     
        // world space
        mat4 modelWorld = osg_ViewMatrixInverse * gl_ModelViewMatrix;
        positionWorldSpace = vec3(modelWorld * gl_Vertex);
        normalWorldSpace = mat3(modelWorld) * gl_Normal;
     
        // Texture for normal mapping (irregularities surfaces)
        gl_TexCoord[0] = gl_TextureMatrix[0] * gl_MultiTexCoord0;
    }

    Fragment:

    Code :
    #version 130
     
    in vec3 positionEyeSpace;
    in vec3 normalEyeSpace;
    in vec3 positionWorldSpace;
    in vec3 normalWorldSpace;
     
    uniform float farPlane;
     
    // ray definition
    struct Ray {
        vec3 origin;        // starting point
        vec3 direction;     // ray direction
    };
     
     
    // primary reflections: rasterization
    vec4 primaryReflections() {
        vec3 nNormalEyeSpace = normalize(normalEyeSpace);
     
        // Depth calculation
        vec3 nPositionEyeSpace = normalize(-positionEyeSpace);
        float linearDepth = length(positionEyeSpace);
     
        // Normalize depth using range value (farPlane)
        linearDepth = linearDepth / farPlane;
        gl_FragDepth = linearDepth;
     
        // presents the normal and depth data as matrix
        vec4 output = vec4(0, 0, 0, 1);
        if (linearDepth <= 1) {
            output.y = linearDepth;
            output.z = abs(dot(nPositionEyeSpace, nNormalEyeSpace));
        }
     
        return output;
    }
     
    // secondary reflections: ray-triangle intersection
    vec4 secondaryReflections(vec4 firstR) {
        // calculate the reflection direction for an incident vector
        vec3 nNormalWorldSpace = normalize(normalWorldSpace);
        vec3 reflectedDir = reflect(positionWorldSpace, nNormalWorldSpace);
     
        Ray ray;
        ray.origin = positionWorld;
        ray.direction = reflectedDir;
     
        // TODO: perform the ray-triangle intersection
        vec4 output = vec4(0,0,0,1);
     
        return output;
    }
     
    void main() {
        // output: primary reflections by rasterization
        vec4 firstR = primaryReflections();
        vec4 secndR = secondaryReflections(firstR);
     
        // gl_FragData[0] = firstR;
        gl_FragData[0] = secndR;
    }
    Last edited by romulogcerqueira; 08-07-2018 at 05:29 PM.

  2. #12
    Senior Member OpenGL Guru
    Join Date
    Jun 2013
    Posts
    2,954
    Quote Originally Posted by romulogcerqueira View Post
    Fragment:
    Code :
        float linearDepth = length(positionEyeSpace);
    This is the distance from the viewpoint, which isn't the same thing as depth.

    Quote Originally Posted by romulogcerqueira View Post
    Code :
        // Normalize depth using range value (farPlane)
        linearDepth = linearDepth / farPlane;
        gl_FragDepth = linearDepth;
    Why are you writing out linear depth (or distance)? Writing to gl_FragCoord can be relatively expensive, as it disables early depth tests.

    Quote Originally Posted by romulogcerqueira View Post
    Code :
            output.z = abs(dot(nPositionEyeSpace, nNormalEyeSpace));
    Note that using world-space vectors would compute the same value (but note that nPositionEyeSpace is actually a direction rather than a position, so you'd need to subtract from the view position rather than simply negating; but that's a trivial operation).

    Quote Originally Posted by romulogcerqueira View Post
    Code :
    // secondary reflections: ray-triangle intersection
    vec4 secondaryReflections(vec4 firstR) {
        // calculate the reflection direction for an incident vector
        vec3 nNormalWorldSpace = normalize(normalWorldSpace);
        vec3 reflectedDir = reflect(positionWorldSpace, nNormalWorldSpace);
    The incident vector should be cameraPos-positionWorldSpace. In eye space, the camera position is (0,0,0), so the calculation simplifies to -positionEyeSpace. But that doesn't apply to world space.

    In short, if you don't need the eye-space position or normal, you shouldn't calculate them. The more outputs the vertex shader has, the fewer vertices will fit in the cache. Fixed-function lighting uses eye space instead of world space, but raytracing is (presumably) going to need to use world-space rays for the intersection calculations (either that, or you'd need to transform your scene description into eye space each frame). If possible, you should only use world space

  3. #13
    Junior Member Newbie
    Join Date
    Dec 2017
    Posts
    28
    Hi GClement,

    thanks for your kindly explanation and support. I followed your tips and now all calculations are done on world-space.

    My current question: can I associate incident vector to Ray.origin?

    Thanks in advance.

    Vertex:
    Code :
    #version 130
     
    uniform mat4 osg_ViewMatrixInverse;
     
    out vec3 posWorldSpace;
    out vec3 normalWorldSpace;
    out vec3 cameraPos;
     
    void main() {
        gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;
     
        // position/normal in world space
        mat4 modelWorld = osg_ViewMatrixInverse * gl_ModelViewMatrix;
        posWorldSpace = vec3(modelWorld * gl_Vertex);
        normalWorldSpace = mat3(modelWorld) * gl_Normal;
     
        // incident vector
        cameraPos = osg_ViewMatrixInverse[3].xyz;
     
        // Texture for normal mapping (irregularities surfaces)
        gl_TexCoord[0] = gl_TextureMatrix[0] * gl_MultiTexCoord0;
    }

    Fragment:
    Code :
    #version 130
     
    in vec3 posWorldSpace;
    in vec3 normalWorldSpace;
    in vec3 cameraPos;
     
    uniform float farPlane;
     
    // ray definition
    struct Ray {
        vec3 origin;        // starting point
        vec3 direction;     // ray direction
    };
     
    // primary reflections: rasterization
    vec4 primaryReflections() {
        vec3 nPosWorldSpace = normalize(cameraPos - posWorldSpace);
        vec3 nNormalWorldSpace = normalize(normalWorldSpace);
     
        // Distance calculation
        float viewDistance = length(cameraPos - posWorldSpace);
     
        // Normalize distance using range value (farPlane)
        float nViewDistance = viewDistance / farPlane;
     
        // presents the normal and depth data as matrix
        vec4 output = vec4(0, 0, 0, 1);
        if (nViewDistance <= 1) {
            output.y = nViewDistance;
            output.z = abs(dot(nPosWorldSpace, nNormalWorldSpace));
        }
     
        return output;
    }
     
    // secondary reflections: ray-triangle intersection
    vec4 secondaryReflections(vec4 firstR) {
     
        // calculate the reflection direction for an incident vector
        vec3 incidentVec = cameraPos - posWorldSpace;
        vec3 nNormalWorldSpace = normalize(normalWorldSpace);
        vec3 reflectedDir = reflect(incidentVec, nNormalWorldSpace);
     
        // setup ray
        Ray ray;
        ray.origin = incidentVec;
        ray.direction = reflectedDir;
     
        // TODO: perform ray-triangle intersection
        vec4 output = vec4(0,0,0,1);
        return output;
    }
     
    void main() {
        // output: primary reflections by rasterization
        vec4 firstR = primaryReflections();
     
        // output: secondary reflections by ray-tracing
        vec4 secndR = secondaryReflections(firstR);
     
        // gl_FragData[0] = firstR;
        gl_FragData[0] = secndR;
    }

  4. #14
    Senior Member OpenGL Guru
    Join Date
    Jun 2013
    Posts
    2,954
    Quote Originally Posted by romulogcerqueira View Post
    My current question: can I associate incident vector to Ray.origin?
    The first ray has origin cameraPos, direction posWorldSpace-cameraPos. The second ray has origin posWorldSpace, direction reflect(posWorldSpace-cameraPos, normalWorldSpace).

    The "eye" vector used for lighting calculations is the negation of the incident vector, but it's probably cheaper to negate the result of the dot product rather than the vector: dot(-a,b)=-dot(a,b).

  5. #15
    Junior Member Newbie
    Join Date
    Dec 2017
    Posts
    28
    Thanks, GClement.

    The reflect requires the normalized normal vector, right? i.e. reflect(posWorldSpace - cameraPos, normalize(normalWorldSpace));

  6. #16
    Senior Member OpenGL Guru
    Join Date
    Jun 2013
    Posts
    2,954
    Quote Originally Posted by romulogcerqueira View Post
    The reflect requires the normalized normal vector, right?
    Yes.

    Although if you aren't going to be normalising for other reasons, it might be more efficient to use e.g.
    Code :
    vec3 reflect1(vec3 I, vec3 N)
    {
        return I - (2.0 * dot(N, I) / dot(N,N)) * N;
    }
    which doesn't require N to be normalised.

  7. #17
    Junior Member Newbie
    Join Date
    Dec 2017
    Posts
    28
    Thanks again, GClement. I will do some tests and update you here.

  8. #18
    Junior Member Newbie
    Join Date
    Dec 2017
    Posts
    28
    Hi GClement,

    I have gotten some progress with my challenge. At this moment, I am trying to get secondary reflection with ray-tracing without success - I didn't get any intersection. Could you kindly have a look in my current fragment shader?

    Given:
    • Use the primary reflections (with rasterization) as input of secondary reflections (with ray tracing);
    • Triangles data (vertices, centroid and normal in world coordinates) are sorted as level order k-d tree and sent to shader as texture;
    • The nearest function calculates the closest triangle to the current ray, performing a nearest neighbor search;
    • Use of Möller–Trumbore ray-triangle intersection algorithm;


    Thanks in advance.

    Code :
    #version 130
     
    in vec3 worldPos;
    in vec3 worldNormal;
    in vec3 cameraPos;
     
    uniform float farPlane;
    uniform sampler2D trianglesTex;         // all triangles/meshes collected from the simulated scene
    uniform vec2 trianglesTexSize;          // texture size of triangles
     
    // ray definition
    struct Ray {
        vec3 origin, direction;
    };
     
    // triangle definition
    struct Triangle {
        vec3 v0;        // vertex A
        vec3 v1;        // vertex B
        vec3 v2;        // vertex C
        vec3 center;    // centroid
        vec3 normal;    // normal
    };
     
    ...
     
    float getTexData(int i, int j) {
        return texelFetch(trianglesTex, ivec2(i,j), 0).r;
    }
     
    Triangle getTriangleData(int idx) {
        Triangle triangle;
        triangle.v0     = vec3(getTexData(idx,0), getTexData(idx,1), getTexData(idx,2));
        triangle.v1     = vec3(getTexData(idx,3), getTexData(idx,4), getTexData(idx,5));
        triangle.v2     = vec3(getTexData(idx,6), getTexData(idx,7), getTexData(idx,8));
        triangle.center = vec3(getTexData(idx,9), getTexData(idx,10), getTexData(idx,11));
        triangle.normal = vec3(getTexData(idx,12), getTexData(idx,13), getTexData(idx,14));
        return triangle;
    }
     
    // Calculate the distance between two points
    float dist(vec3 a, vec3 b) {
        vec3 c = a - b;
        return (c.x * c.x +
                c.y * c.y +
                c.z * c.z);
    }
     
    // Calculate the closest triangle to the ray
    Triangle nearest(vec3 nd) {
     
        Queue queue = createQueue();
        enqueue(queue, 0);
        int i = 0;
     
        bool first = true;
        Triangle best;
        float best_dist;
     
        while (!isEmpty(queue)) {
            int idx = dequeue(queue);
     
            if (idx > (trianglesTexSize.x - 1))
                continue;
     
            Triangle root = getTriangleData(idx);
            float d = dist(root.center, nd);
            float dx = 0;
            switch (i) {
                case 0: dx = root.center.x - nd.x; break;
                case 1: dx = root.center.y - nd.y; break;
                case 2: dx = root.center.z - nd.z; break;
            }
     
            if (first || d < best_dist) {
                best_dist = d;
                best = root;
                first = false;
            }
     
            // If chance of exact match is high
            if (best_dist == 0)
                return best;
     
            i = (i + 1) % 3;
     
            int idx_left  = 2 * idx + 1;
            int idx_right = 2 * idx + 2;
            if (dx > 0)
                enqueue(queue, idx_left);
            else
                enqueue(queue, idx_right);
        }
        return best;
    }
     
    // Möller–Trumbore ray-triangle intersection algorithm
    // source: [url]http://bit.ly/2MxnPMG[/url]
    bool rayIntersectsTriangle(Ray ray, Triangle triangle)
    {
        float EPSILON = 0.0000001;
     
        vec3 edge1, edge2, h, s, q;
        float a, f, u, v;
        edge1 = triangle.v1 - triangle.v0;
        edge2 = triangle.v2 - triangle.v0;
     
        h = cross(ray.direction, edge2);
        a = dot(edge1, h);
        if (a > -EPSILON && a < EPSILON)
            return false;
     
        f = 1 / a;
        s = ray.origin - triangle.v0;
        u = f * dot(s, h);
        if (u < 0.0 || u > 1.0)
            return false;
     
        q = cross(s, edge1);
        v = f * dot(ray.direction, q);
        if (v < 0.0 || (u + v) > 1.0)
            return false;
     
        // At this stage we can compute t to find out where the intersection point is on the line.
        float t = f * dot(edge2, q);
        if (t <= EPSILON)   // this means that there is a line intersection but not a ray intersection.
            return false;
     
        return true;        // ray intersection
    }
     
     
    // ============================================================================================================================
     
    // primary reflections: rasterization
    vec4 primaryReflections() {
        vec3 worldIncident = cameraPos - worldPos;
        vec3 nWorldPos = normalize(worldIncident);
        vec3 nWorldNormal = normalize(worldNormal);
     
        // Distance calculation
        float viewDistance = length(worldIncident);
     
        // Normalize distance using range value (farPlane)
        float nViewDistance = viewDistance / farPlane;
     
        // presents the normal and depth data as matrix
        vec4 output = vec4(0, 0, 0, 1);
        if (nViewDistance <= 1) {
            output.y = nViewDistance;
            output.z = abs(dot(nWorldPos, nWorldNormal));
        }
     
        return output;
    }
     
    // ============================================================================================================================
     
    // secondary reflections: ray-triangle intersection
    vec4 secondaryReflections(vec4 firstR) {
     
        // calculate the reflection direction for an incident vector
        vec3 worldIncident = cameraPos - worldPos;
        vec3 nWorldNormal = normalize(worldNormal);
        vec3 reflectedDir = reflect(-worldIncident, nWorldNormal);
     
        // set current ray
        Ray ray = Ray(worldPos, reflectedDir);
     
        // perform ray-triangle intersection only for pixels with valid normal values
        vec4 output = vec4(0,0,0,1);
        if (firstR.z > 0) {
            // find the closest triangle to the origin point
            Triangle triangle = nearest(ray.origin);
     
            // ray-triangle intersection
            bool intersected = rayIntersectsTriangle(ray, triangle);
            if (intersected) {
                output = vec4(1,1,1,1);
            }
       }
     
        return output;
    }
     
    // ============================================================================================================================
     
    void main() {
        // output: primary reflections by rasterization
        vec4 firstR = primaryReflections();
     
        // output: secondary reflections by ray-tracing
        vec4 secndR = secondaryReflections(firstR);
     
        // gl_FragData[0] = firstR;
        gl_FragData[0] = secndR;
    }
    0

  9. #19
    Senior Member OpenGL Guru
    Join Date
    Jun 2013
    Posts
    2,954
    Quote Originally Posted by romulogcerqueira View Post
    I have gotten some progress with my challenge. At this moment, I am trying to get secondary reflection with ray-tracing without success - I didn't get any intersection. Could you kindly have a look in my current fragment shader?
    The first thing I'd do is write out some information regarding the triangle which nearest() finds, and check whether it makes sense.

  10. #20
    Junior Member Newbie
    Join Date
    Dec 2017
    Posts
    28
    Hi GClements,

    I have good news: I can advance a lot with my adventure with ray tracing! Thanks for all your help!

    After I updated my shader code to work in world space coordinates, I faced with some problems with my normal mapping process. Once normal maps are built in tangent space, interpolating the vertex normal and a RGB texture, we need to create a TBN matrix to convert between these two spaces (tangent and world space). I believe my problem is due to work with tangent space.

    1) In the vertex shader, I calculate the TBN matrix as follows:

    Code :
        vec3 N = worldNormal;
        vec3 T = mat3(modelWorld) * gl_MultiTexCoord0.xyz;
        vec3 B = cross(N, T);
        TBN = transpose(mat3(T, B, N));

    and I got the following sonar image result. Please look the normal mapping is applied on the center of sonar image, however the corners are black.

    Click image for larger version. 

Name:	sonar_multibeam-run.rb_016.jpg 
Views:	9 
Size:	14.2 KB 
ID:	2843

    2) If I remove the tranpose operation on TBN matrix, I got the following result, with corners filled and the center of sonar image in black:

    Code :
        TBN = mat3(T, B, N);
    Click image for larger version. 

Name:	sonar_multibeam-run.rb_017.jpg 
Views:	5 
Size:	12.3 KB 
ID:	2844

    If I just modify the bitangent vector by sum of cross(N,T) and cross(T,N), I got a weird result.

    Code :
        vec3 B = cross(N, T) + cross(T, N);
        TBN = transpose(mat3(T, B, N));

    Click image for larger version. 

Name:	sonar_multibeam-run.rb_018.jpg 
Views:	3 
Size:	13.0 KB 
ID:	2845

    Do you have any tip how can I solve this problem?

    Thanks in advance,

Tags for this Thread

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •