如何在创建阴影体积时在GLSL中转换背面顶点

3

我正在使用OpenGL编写一款游戏,尝试实现阴影体。

我希望通过顶点着色器在GPU上构建模型的阴影体。为此,我使用VBO表示模型,其中:

  • 重复每个三角形的三个唯一顶点
  • 每个顶点都有其三角形的法线
    • 出于某些原因,我实际上已经按照上述两个点进行操作,所以我不太担心顶点重复问题
  • 添加退化三角形以在“常规”三角形之间的边缘内形成四边形

使用这种模型格式,在顶点着色器中,我能够找到面向光线背面的三角形的顶点,并将它们移回来形成阴影体。

我需要解决的最后一个问题是应该对背面顶点应用什么样的变换。

我能够检测出一个顶点是否面向光线背面,但我不确定应该对它应用什么样的变换。以下是我的顶点着色器:

uniform vec3 lightDir; // Parallel light.
                       // On the CPU this is represented in world
                       // space.  After setting the camera with
                       // gluLookAt, the light vector is multiplied by
                       // the inverse of the modelview matrix to get
                       // it into eye space (I think that's what I'm
                       // working in :P ) before getting passed to
                       // this shader.

void main()
{
    vec3 eyeNormal = normalize(gl_NormalMatrix * gl_Normal);
    vec3 realLightDir = normalize(lightDir);

    float dotprod = dot(eyeNormal, realLightDir);

    if (dotprod <= 0.0)
    {
        // Facing away from the light
        // Need to translate the vertex along the light vector to
        // stretch the model into a shadow volume

        //---------------------------------//
        // This is where I'm getting stuck //
        //---------------------------------//
        // All I know is that I'll probably turn realLightDir into a
        // vec4

        gl_Position = ???;
    }
    else
    {
        gl_Position = ftransform();
    }
}

我尝试简单地将gl_position设置为ftransform() - (vec4(realLightDir, 1.0) * someConstant),但这会导致某种深度测试错误(当我用颜色渲染体积时,一些面似乎在其他面后面可见),并且someConstant似乎不影响背面的延伸距离。
更新 - 1月22日
只是想澄清一下关于我可能处于什么空间的问题。我必须说,跟踪我所处的空间是我着色器头痛的最大原因。
在渲染场景时,我首先使用gluLookAt设置相机。相机可以固定或移动;这应该没有关系。然后,我使用像glTranslated这样的平移函数来定位我的模型。
在程序中(即在CPU上),我用世界坐标系(三个浮点数)表示光向量。在开发过程中,我发现要将此光向量放入我的着色器的正确空间中,我必须在设置相机之后,在定位模型之前,将其乘以当前模型视图矩阵的逆矩阵。因此,我的程序代码如下:
- 定位相机(gluLookAt) - 取出光向量,它在世界空间中,并将其乘以当前模型视图矩阵的逆矩阵,并将其传递给着色器。 - 定位模型 - 绘制模型
这样清楚些吗?

“深度测试错误”是因为您在没有使用Z缓冲的情况下渲染未排序的多边形批次吗?您能提供一张截图吗? - Justicle
我已经开启了深度测试。很难描述,我需要在阴影体着色器中应用浅色调颜色(我没有传入颜色数据),以使其明显。基本上,似乎我看到了我不应该看到的多边形。我会添加一个屏幕截图作为对Bahbar答案的回应。 - user256282
1个回答

1

ftransform的结果在剪辑空间中。因此,这不是您想要应用realLightDir的空间。我不确定您的光源在哪个空间(您的评论让我感到困惑),但可以确定的是,您希望添加处于同一空间的向量。

在CPU上,它以世界空间表示。在使用gluLookAt设置相机之后,将光矢量乘以模型视图矩阵的逆矩阵,使其进入眼睛空间(我认为我正在使用的是这个:P),然后传递给此着色器。

将向量乘以mv矩阵的逆矩阵会将向量从视图空间带到模型空间。因此,您说您的光矢量(在世界空间中)应用了一个执行视图->模型的变换。这对我来说没有多少意义。

我们有4个空间:

  • 模型空间:定义gl_Vertex的空间。
  • 世界空间:GL通常不关心的一个空间,用于定位模型的任意空间。这通常是3D引擎工作的空间(它映射到我们对世界坐标的一般理解)。
  • 视图空间:对应于观察者的参考系。0,0,0是观察者所在的位置,朝向Z轴负方向。通过将gl_Vertex乘以模型视图矩阵获得。
  • 裁剪空间:矩阵投影带给我们的神奇空间。ftransform的结果就在这个空间内(gl_ModelViewProjectionMatrix * gl_Vertex也在这个空间内)。

你能澄清一下你的光线方向究竟是在哪个空间中吗?

然而,你需要做的是使光线向量加法在模型、世界或视图空间中进行:将操作中的所有部分放置在同一空间中。例如,对于模型空间,只需在CPU上计算模型空间中的光线方向,然后执行以下操作:

vec3 vertexTemp = gl_Vertex + lightDirInModelSpace * someConst

然后你可以将新的顶点位置带到剪辑空间中,方法是

gl_Position = gl_ModelViewProjectionMatrix * vertexTemp

最后一点,不要尝试在剪裁空间中应用向量加法。通常情况下,它不会做你认为它应该做的事情,因为在那一点上,你必然涉及到具有非均匀w值的齐次坐标

我更新了我的问题,试图解释我的光源、着色器等在哪个空间中。我认为我的光矢量是在模型空间中的。至少,点积测试给出了我认为是正确的结果。我尝试遵循您的建议,并像这样设置背面顶点的位置:“gl_ModelViewProjectionMatrix * (gl_Vertex - vec4(lightDir, 0.0));” 然而,挤出似乎跟随模型的旋转,并且仍然存在一些故障多边形,如http://yfrog.com/b6ship1px所示(与http://yfrog.com/3orealship1px的实际模型相比)。 - user256282
嗯,听起来好像你没有在模型空间中放置光线方向。 - Bahbar

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接