首页 > 解决方案 > 如何使用模型视图投影矩阵计算光线行进的光线原点和方向?

问题描述

我正在尝试在 GLSL 片段着色器中渲染 raymarched 场景。我能够在不使用 MVP 矩阵时成功绘制场景,而只是从指定的摄像机位置沿用固定视图渲染的方向场景行进光线,但是当我尝试更改代码以使用模型视图投影矩阵时(到请允许我使用合适的相机在场景中移动)我只是得到一个黑屏。我正在按照使用模型的说明,从这里查看带有光线行进的投影矩阵

不使用模型视图投影时我的顶点着色器

#version 330 core
layout (location = 0) in vec2 position;


void main() {
    gl_Position = vec4(position, 0.0, 1.0);
}

不使用模型视图投影时我的片段着色器

#version 330 core
#define MAX_VOXELS 128
#define MAX_STEPS 100
#define MAX_DIST 100.
#define SURF_DIST .001

uniform float iTime;
uniform vec2 iResolution;

uniform vec3 camPosition;
uniform vec3 camDirection;

uniform vec3 voxelPositions[MAX_VOXELS];
uniform float voxelSizes[MAX_VOXELS];
uniform int voxelCount;
out vec4 fragColor;

float sdBoundingBox( vec3 p, vec3 b, float e )
{
    p = abs(p  )-b;
    vec3 q = abs(p+e)-e;

    return min(min(
    length(max(vec3(p.x,q.y,q.z),0.0))+min(max(p.x,max(q.y,q.z)),0.0),
    length(max(vec3(q.x,p.y,q.z),0.0))+min(max(q.x,max(p.y,q.z)),0.0)),
    length(max(vec3(q.x,q.y,p.z),0.0))+min(max(q.x,max(q.y,p.z)),0.0));
}

float GetDist(vec3 point) {
    float planeDist = point.y;
    float d = 10000.0;
    for(int i = 0; i < voxelCount; i++)
    {
        vec3 voxelSize = vec3(voxelSizes[i],voxelSizes[i],voxelSizes[i]);
        float vox = sdBoundingBox(point-voxelPositions[i], voxelSize, 0.015);
        d = min(d, vox);
    }

    return d;
}

float RayMarch(vec3 rayOrigin, vec3 rayDir) {
    float dO=0.;

    for(int i=0; i<MAX_STEPS; i++) {
        vec3 p = rayOrigin + rayDir*dO;
        float dS = GetDist(p);
        dO += dS;
        if(dO>MAX_DIST || dS<SURF_DIST) break;
    }

    return dO;
}

vec3 GetNormal(vec3 p) {
    float d = GetDist(p);
    vec2 e = vec2(.001, 0);

    vec3 n = d - vec3(
    GetDist(p-e.xyy),
    GetDist(p-e.yxy),
    GetDist(p-e.yyx));

    return normalize(n);
}


float GetLight(vec3 p) {
    vec3 lightPos = vec3(0, 5, 0);
    lightPos.xz += vec2(sin(iTime), cos(iTime))*2.;
    vec3 l = normalize(lightPos-p);
    vec3 n = GetNormal(p);

    float dif = clamp(dot(n, l), 0., 1.);
    float d = RayMarch(p+n*SURF_DIST*2., l);
    if(d<length(lightPos-p)) dif *= .1;

    return dif;
}

void main()
{
    vec2 uv = (gl_FragCoord.xy-.5*iResolution.xy)/iResolution.y;
    vec3 col = vec3(0);
    vec3 rayOrigin = camPosition;
    vec3 rayDir = normalize(vec3(uv.x, uv.y, 1));
    float d = RayMarch(rayOrigin, rayDir);
    vec3 p = rayOrigin + rayDir * d;

    float dif = GetLight(p);
    col = vec3(dif);
    col = pow(col, vec3(.4545));    // gamma correction

    fragColor = vec4(col,1.0);
}

但是,当我尝试使用模型视图投影矩阵来转换场景时,我得到的只是一个空白屏幕。

这是我将矩阵传递给着色器的方法:

...
glm::mat4 mvp = camera.GetProjMatrix(width, height) * camera.GetViewMatrix() * octree.getTransform();
auto inverseMatrix = glm::inverse(mvp);
raymarchShader.setMat4("mvp", mvp);
raymarchShader.setMat4("inverseMatrix", inverseMatrix);

我的模型视图投影矩阵顶点着色器

#version 330 core
layout (location = 0) in vec2 position;

out vec4 near_4;
out vec4 far_4;

uniform mat4 mvp;
uniform mat4 inverseMatrix;

void main() {
    gl_Position = mvp * vec4(position, 0.0, 1.0);
    vec2 pos = gl_Position.xy/gl_Position.w;

    near_4 = inverseMatrix * (vec4(pos, -1.0, 1.0));
    far_4  = inverseMatrix * (vec4(pos, 1.0, 1.0));

}

这是更新的片段着色器

...
in vec4 near_4;    //for computing rays in fragment shader
in vec4 far_4;
...
void main()
{
    vec2 uv = (gl_FragCoord.xy-.5*iResolution.xy)/iResolution.y;

    vec3 col = vec3(0);
    vec3 rayOrigin = near_4.xyz/near_4.w;
    vec3 far3 = far_4.xyz/far_4.w;
    vec3 rayDir = far3- rayOrigin;
    rayDir = normalize(rayDir);

    float d = RayMarch(rayOrigin, rayDir);

    vec3 p = rayOrigin + rayDir * d;

    float dif = GetLight(p);
    col = vec3(dif);
    col = pow(col, vec3(.4545));    // gamma correction

    fragColor = vec4(col,1.0);
}

这是最终结果我到底做错了什么?如何使用模型视图投影矩阵计算光线行进的光线原点和方向?

标签: openglglslfragment-shaderraymarching

解决方案


推荐阅读