我已经从灯光的角度成功地将场景渲染到了深度立方体贴图上,但是我不太了解如何将其实际投影到场景上。

以下是当前情况的简短片段:http://youtu.be/54WXDWxqmXw

我在这里找到了一个实现示例:

http://www.opengl.org/discussion_boards/showthread.php/174093-GLSL-cube-shadows-projecting?p=1219162&viewfull=1#post1219162

这似乎很容易理解,所以我认为这是一个很好的起点,但是我在使用矩阵时遇到了一些困难(如上面的视频所示)。

我的顶点着色器:

#version 330 core
layout(std140) uniform ViewProjection
{
    mat4 V;
    mat4 P;
};

layout(location = 0) in vec3 vertexPosition;
layout(location = 1) in vec2 vertexUV;

out vec2 UV;
out vec4 posCs;

uniform mat4 M;
uniform mat4 lightView;

void main()
{
    mat4 MVP = P *V *M;
    gl_Position = MVP *vec4(vertexPosition,1);

    UV = vertexUV;
    posCs = V *M *vec4(vertexPosition,1);
}


片段着色器:

#version 330 core

in vec2 UV;
in vec4 posCs;

out vec4 color;

// Diffuse texture
uniform sampler2D renderTexture;

uniform samplerCubeShadow shadowCubeMap;

uniform mat4 lightView;
uniform mat4 lightProjection;
uniform mat4 camViewInv;

void main()
{
    color = texture2D(renderTexture,UV).rgba;

    mat4 lView = mat4(1); // The light is currently at the world origin, so we'll skip the transformation for now (The less potential error sources the better)
    vec4 posLs = lView *camViewInv *posCs;
    vec4 posAbs = abs(posLs);
    float fs_z = -max(posAbs.x,max(posAbs.y,posAbs.z));
    vec4 clip = lightProjection *vec4(0.0,0.0,fs_z,1.0);
    float depth = (clip.z /clip.w) *0.5 +0.5;
    vec4 r = shadowCube(shadowCubeMap,vec4(posLs.xyz,depth));
    color *= r;
}


(我只发布了相关部分)

lightProjection与我用于将场景渲染到立方体贴图中的投影矩阵相同。

我对“ camViewInv”并不完全确定,从上面链接的示例中我得出以下结论:

glm::mat4 camViewInv(
    camView[0][0],camView[1][0],camView[2][0],0.0f,
    camView[0][1],camView[1][1],camView[2][1],0.0f,
    camView[0][2],camView[1][2],camView[2][2],0.0f,
    camPos[0],camPos[1],camPos[2],1.0f
);


camView是相机的视图矩阵,并且camPos相机的世界空间位置。

我认为,其他所有内容都应不言自明。

我看不到着色器有任何问题,但我可以肯定,场景已正确渲染到立方体贴图(如上面的视频所示)。也许有人比我更精通此事。

//更新:

有关阴影立方体贴图的创建/用法的一些其他信息:

创建立方体贴图纹理:

unsigned int frameBuffer;
glGenFramebuffers(1,&frameBuffer);
glBindFramebuffer(GL_FRAMEBUFFER,frameBuffer);

unsigned int texture;
glGenTextures(1,&texture);
glBindTexture(GL_TEXTURE_CUBE_MAP,texture);

glTexParameteri(GL_TEXTURE_CUBE_MAP,GL_TEXTURE_COMPARE_FUNC,GL_LEQUAL);
glTexParameteri(GL_TEXTURE_CUBE_MAP,GL_TEXTURE_MAG_FILTER,GL_NEAREST);
glTexParameteri(GL_TEXTURE_CUBE_MAP,GL_TEXTURE_MIN_FILTER,GL_NEAREST);
glTexParameteri(GL_TEXTURE_CUBE_MAP,GL_TEXTURE_WRAP_R,GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_CUBE_MAP,GL_TEXTURE_WRAP_S,GL_CLAMP_TO_BORDER);
glTexParameteri(GL_TEXTURE_CUBE_MAP,GL_TEXTURE_WRAP_T,GL_CLAMP_TO_BORDER);
glTexParameteri(GL_TEXTURE_CUBE_MAP,GL_TEXTURE_COMPARE_MODE,GL_COMPARE_R_TO_TEXTURE);

for(int i=0;i<6;i++)
{
    glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X +i,0,GL_DEPTH_COMPONENT,size,size,0,GL_DEPTH_COMPONENT,GL_FLOAT,0);
    glFramebufferTexture2D(GL_FRAMEBUFFER,GL_DEPTH_ATTACHMENT,GL_TEXTURE_CUBE_MAP_POSITIVE_X +i,texture,0);
    glDrawBuffer(GL_NONE);
}


光的矩阵:

glm::perspective<float>(90.f,1.f,2.f,m_distance); // Projection Matrix

// View Matrices
glm::vec3 pos = GetPosition(); // Light worldspace position
glm::lookAt(pos,pos +glm::vec3(1,0,0),glm::vec3(0,1,0));
glm::lookAt(pos,pos +glm::vec3(-1,0,0),glm::vec3(0,1,0));
glm::lookAt(pos,pos +glm::vec3(0,1,0),glm::vec3(0,0,-1))
glm::lookAt(pos,pos +glm::vec3(0,-1,0),glm::vec3(0,0,1))
glm::lookAt(pos,pos +glm::vec3(0,0,1),glm::vec3(0,1,0))
glm::lookAt(pos,pos +glm::vec3(0,0,-1),glm::vec3(0,1,0))


顶点着色器:

#version 330 core

layout(location = 0) in vec4 vertexPosition;

uniform mat4 shadowMVP;

void main()
{
    gl_Position = shadowMVP *vertexPosition;
}


片段着色器:

#version 330 core

layout(location = 0) out float fragmentDepth;

void main()
{
    fragmentdepth = gl_FragCoord.z;
}

最佳答案

我建议在世界空间中执行此操作,通常在世界空间中定义灯光位置,如果保持这种方式,它将减少工作量。我删除了一堆在世界空间中不需要的制服。



以vtx计算照明方向和深度。着色器:

#version 330 core
layout(std140) uniform ViewProjection
{
    mat4 V;
    mat4 P;
};

layout(location = 0) in vec4 vertexPosition; // W is automatically assigned 1, if missing.
layout(location = 1) in vec2 vertexUV;

out vec2 UV;
out vec4 lightDirDepth; // Direction = xyz, Depth = w

uniform mat4 M;

uniform vec3 lightPos;     // World Space Light Pos
uniform vec2 shadowZRange; // Near / Far clip plane distances for shadow's camera

float vecToDepth (vec3 Vec)
{
  vec3  AbsVec     = abs (Vec);
  float LocalZcomp = max (AbsVec.x, max (AbsVec.y, AbsVec.z));

  const float n = shadowZRange [0]; // Near plane when the shadow map was built
  const float f = shadowZRange [1]; // Far plane when the shadow map was built

  float NormZComp = (f+n) / (f-n) - (2.0*f*n)/(f-n)/LocalZcomp;
  return (NormZComp + 1.0) * 0.5;
}

void main()
{
    mat4 MVP = P *V *M;
    gl_Position = MVP *vertexPosition;

    UV    = vertexUV;

    vec3  lightDir   = lightPos - (M *vertexPosition).xyz;
    float lightDepth = vecToDepth (lightDir);

    lightDirDepth = vec4 (lightDir, lightDepth);
}


修改后的片段着色器(使用光照方向采样立方体贴图,并针对深度进行测试):

#version 330 core

in vec2 UV;
in vec4 lightDirDepth;  // Direction = xyz, Depth = w

out vec4 color;

// Diffuse texture
uniform sampler2D         renderTexture;
uniform samplerCubeShadow shadowCubeMap;

void main()
{
    const float bias = 0.0001; // Prevent shadow acne

    color   = texture (renderTexture,UV).rgba;
    float r = texture (shadowCubeMap, vec4 (lightDirDepth.xyz, lightDirDepth.w + bias));

    color *= r;
}


我增加了两套新制服:


lightPos-灯光的世界空间位置
shadowZRange-构建阴影立方体贴图时打包在vec2中的近平面和远平面的值


让我知道您是否需要我解释什么,或者这没有产生有意义的结果。

09-25 18:51