我尝试使用OpenGL和GLSL API在我的3D引擎中实现parralax映射,但显示不正确。要了解并应用这种技术,我用以下的PDF教程(16页,17和18)的启发的复杂性:Parralax映射不能正确使用OpenGL和GLSL
https://www.opengl.org/sdk/docs/tutorials/TyphoonLabs/Chapter_4.pdf
产生非常基本的parralax效果(没有任何照明效果)我需要使用2个纹理:
- 1 diffuse (color) texture (BPP: 24 -> RGB - format: JPEG)
- 1 displacement (height/grayscale) texture (BPP: 24 -> RGB - format: JPEG)
我用着名的非常有用的软件'CrazyBump'来生成我的置换贴图。此外,该软件还可以显示在我的外部3D应用程序中Parralax映射的外观。
在第一时间,下面是“CrazyBump”显示(CrazyBump利用灯光效果,但它并不重要):
正如你可以看到parralax效果正确呈现。现在这里是我场景中的渲染(使用'CrazyBump'生成的同样的位移纹理,没有亮度,我想看到的是像上面那样的假表面变形)。
正如你所看到的,显示是不一样的,当然不正确。
要尝试产生相同的效果,我在我的帖子开头讨论的PDF文件中应用该课程。
有关信息,我已经对我的引擎先前实施了'正常映射'技术(所以正切和平淡无奇的向量是正确的!)。
为了执行我的着色器程序,我需要相机在世界空间和矩阵(ModelViewProj,ModelMatrix和NormalMatrix)中的位置。
下面是客户端的C++代码,我用:
glm::mat4 modelViewMatrix = pRenderBatch->GetModelViewMatrix();
glm::mat3 normalMatrix = glm::mat3(glm::vec3(modelViewMatrix[0]),
glm::vec3(modelViewMatrix[1]), glm::vec3(modelViewMatrix[2]));
this->SetUniform("ModelViewProjMatrix", pRenderBatch->GetModelViewProjMatrix());
this->SetUniform("ModelViewMatrix", modelViewMatrix);
this->SetUniform("NormalMatrix", normalMatrix);
//Bound on channel 0
glActiveTexture(GL_TEXTURE0);
this->m_pTextureManager.PushAndBindTexture(
pMaterial->GetDiffuseTexture());
{
this->SetUniform("DiffuseSampler", 0);
}
//Bound on channel 1
glActiveTexture(GL_TEXTURE1);
this->m_pTextureManager.PushAndBindTexture(
pMaterial->GetDisplacementTexture());
{
this->SetUniform("HeightSampler", 1);
}
顶点着色器:
#version 440
/*
** Vertex attributes.
*/
layout (location = 0) in vec4 VertexPosition;
layout (location = 1) in vec2 VertexTexture;
layout (location = 2) in vec3 VertexNormal;
layout (location = 3) in vec3 VertexTangent;
layout (location = 4) in vec3 VertexBitangent;
/*
** Uniform matrices.
*/
uniform mat4 ModelViewProjMatrix;
uniform mat4 ModelViewMatrix;
uniform mat3 NormalMatrix;
//Outputs
out vec2 TexCoords;
out vec3 viewDir_TS;
/*
** Vertex shader entry point.
*/
void main(void)
{
//Texture coordinates
TexCoords = VertexTexture;
//Vertex position in world space
vec3 Position_CS = vec3(ModelViewMatrix * VertexPosition);
//Vertex normal in world space
vec3 Normal_CS = NormalMatrix * VertexNormal;
//Vertex tangent in world space
vec3 Tangent_CS = NormalMatrix * VertexTangent;
//Vertex bitangent in world space
vec3 Bitangent_CS = NormalMatrix * VertexBitangent;
//View vector in world space
vec3 viewDir_CS = -Position_CS;
//TBN matrix
mat3 TBN = mat3(
Tangent_CS.x, Bitangent_CS.x, Normal_CS.x,
Tangent_CS.y, Bitangent_CS.y, Normal_CS.y,
Tangent_CS.z, Bitangent_CS.z, Normal_CS.z);
//2 others ways to compute view vector in tangent space
//mat3 TBN = transpose(mat3(Tangent_CS, Bitangent_CS, Normal_CS));
/*viewDir_TS = vec3(
dot(viewDir_CS, Tangent_CS),
dot(viewDir_CS, Bitangent_CS),
dot(viewDir_CS, Normal_CS)
);*/
//View vector converted in tangent space (not normalized)
viewDir_TS = TBN * viewDir_CS;
gl_Position = ModelViewProjMatrix * VertexPosition;
}
最后片段着色器:
#version 440
layout (location = 0) out vec4 FragColor;
//Texture coordinates
in vec2 TexCoords;
//View (camera) vector in tangent space
in vec3 viewDir_TS;
//Diffuse texture sampler
uniform sampler2D DiffuseSampler;
//Displacement texture sampler
//(height map/grayscale map)
uniform sampler2D HeightSampler;
/*
** Fragment shader entry point
*/
void main(void)
{
//Parralax intensity {scale(s), bias(b)}
vec2 ScaleBias = vec2(0.04f, 0.02f);
//Height(h) range [0;1] (float) recovered from height map (HeightSampler)
float Height = texture2D(HeightSampler, TexCoords.st).r;
//Height scaled and biased according to the formula: hsb = h · s + b
float HSB = Height * ScaleBias.x + ScaleBias.y;
//View vector in tangent space normalized
vec3 viewDirNorm_TS = normalize(viewDir_TS);
//Computes texture offset according to the formula: Tn = To + (hsb · V{x, y})
vec2 textOffset = TexCoords + (viewDirNorm_TS.xy * HSB);
//Computes final diffuse texture color using parralax offset
FragColor = texture2D(DiffuseSampler, textOffset);
}
我试图修改的规模和偏差值没有任何成功:显示仍然不正确。我认为我的位移纹理未正确加载,但事实并非如此(有关我使用NVIDIA NSight degugger的信息)。
如果我加载我位移映射以下方式(GL_LUMINANCE):
glTexImage2D(this->m_Target, 0, GL_LUMINANCE,
this->m_PixelData.GetWidth(), this->m_PixelData.GetHeight(),
0, GL_BGR, GL_UNSIGNED_BYTE, OFFSET_BUFFER(0));
像素缓冲器开始于:
如果我加载我位移映射如下(GL_RGB):
glTexImage2D(这 - > m_Target,0,GL_RGB, 这 - > m_PixelData.GetWidth(),这 - > m_PixelData.GetHeight(), 0,GL_BGR,GL_UNSIGNED_BYTE,OFFSET_BUFFER(0));
像素缓冲区开始的:
在这两种情况下,我们有灰度像素。
所以我的问题似乎不是来自内存中加载的纹理。也许矩阵存在问题或空间问题。我真的迷失了。
有人可以帮助我吗?
非常感谢您的帮助!
单个'textOffset'方法是一个很早的方法,它可以做出非常大的近似值:偏移处的深度将是相同的。为了获得更好的效果,请在高度图中追踪(或“步骤”),直到找到交点。使用二进制搜索来改进它。然后使用交点的坐标来表示颜色。 – jozxyqk 2014-11-20 17:44:10
你想说公式Tn = To +(hsb·V {x,y})是不正确的。所以行vec2 textOffset = TexCoords +(viewDirNorm_TS.xy * HSB);是不正确的 ?这是我看到的所有教程中使用的方法,结果似乎是正确的。我不明白你的观点。 – user1364743 2014-11-20 17:51:55
我不确定该方法的具体细节,但必须是近似的。我认为这是你的问题所在。现在我看起来像'viewDir_TS'看起来可能只需要否定或者切线空间不起作用。 'FragColor = vec4(viewDir_TS,1);'会很有趣。 – jozxyqk 2014-11-20 18:07:53