编辑:您可能想从“编辑 3”开始,因为我已经解决了很多问题
这是我应用于 icosphere 的普通立方体贴图的屏幕截图:
我的立方体贴图 icosphere 的切线是使用以下代码生成的。m_indices
中的一个std::vector
索引进入 中std::vector
的顶点m_vertices
。
std::vector<glm::vec3> storedTan(m_vertices.size(),glm::vec3(0,0,0));
// tangents
for(int i = 0; i < m_indices.size(); i+=3)
{
int i1 = m_indices[i];
int i2 = m_indices[i+1];
int i3 = m_indices[i+2];
VertexData v1 = m_vertices[i1];
VertexData v2 = m_vertices[i2];
VertexData v3 = m_vertices[i3];
glm::vec3 p1 = glm::vec3(v1.position[0],v1.position[1],v1.position[2]);
glm::vec3 p2 = glm::vec3(v2.position[0],v2.position[1],v2.position[2]);
glm::vec3 p3 = glm::vec3(v3.position[0],v3.position[1],v3.position[2]);
glm::vec3 t1 = glm::vec3(v1.tcoords[0],v1.tcoords[1],v1.tcoords[2]);
glm::vec3 t2 = glm::vec3(v2.tcoords[0],v2.tcoords[1],v2.tcoords[2]);
glm::vec3 t3 = glm::vec3(v3.tcoords[0],v3.tcoords[1],v3.tcoords[2]);
std::function<glm::vec2(glm::vec3)> get_uv = [=](glm::vec3 STR)
{
float sc, tc, ma;
float x = std::abs(STR.x);
float y = std::abs(STR.y);
float z = std::abs(STR.z);
if(x > y && x > z)
{
if(STR.x > 0)
{
sc = -STR.z;
tc = -STR.y;
ma = STR.x;
}
else
{
sc = STR.z;
tc = -STR.t;
ma = STR.x;
}
}
else if(y > z)
{
if(STR.y > 0)
{
sc = STR.x;
tc = STR.z;
ma = STR.y;
}
else
{
sc = STR.x;
tc = -STR.z;
ma = STR.y;
}
}
else
{
if(STR.z > 0)
{
sc = STR.x;
tc = -STR.y;
ma = STR.z;
}
else
{
sc = -STR.x;
tc = -STR.y;
ma = STR.z;
}
}
return glm::vec2((sc/std::abs(ma) + 1.0) / 2.0,(tc/std::abs(ma) + 1.0) / 2.0);
};
glm::vec2 uv1 = get_uv(t1);
glm::vec2 uv2 = get_uv(t2);
glm::vec2 uv3 = get_uv(t3);
glm::vec3 edge1 = p2 - p1;
glm::vec3 edge2 = p3 - p1;
glm::vec2 tedge1 = uv2 - uv1;
glm::vec2 tedge2 = uv3 - uv1;
float r = 1.0f / (tedge1.x * tedge2.y - tedge2.x - tedge1.y);
glm::vec3 sdir((tedge2.y * edge1.x - tedge1.y * edge2.x) * r,
(tedge2.y * edge1.y - tedge1.y * edge2.y) * r,
(tedge2.y * edge1.z - tedge1.y * edge2.z) * r);
glm::vec3 tdir((tedge1.x * edge2.x - tedge2.x * edge1.x) * r,
(tedge1.x * edge2.y - tedge2.x * edge1.y) * r,
(tedge1.x * edge2.z - tedge2.x * edge1.z) * r);
m_vertices[i1].tangent[0] += sdir.x;
m_vertices[i1].tangent[1] += sdir.y;
m_vertices[i1].tangent[2] += sdir.z;
m_vertices[i2].tangent[0] += sdir.x;
m_vertices[i2].tangent[1] += sdir.y;
m_vertices[i2].tangent[2] += sdir.z;
m_vertices[i3].tangent[0] += sdir.x;
m_vertices[i3].tangent[1] += sdir.y;
m_vertices[i3].tangent[2] += sdir.z;
storedTan[i1] += sdir;
storedTan[i2] += sdir;
storedTan[i3] += sdir;
}
for(int i = 0; i < m_vertices.size(); ++i)
{
glm::vec3 n = glm::vec3(m_vertices[i].normal[0],m_vertices[i].normal[1],m_vertices[i].normal[2]);
glm::vec3 t = glm::vec3(m_vertices[i].tangent[0],m_vertices[i].tangent[1],m_vertices[i].tangent[2]);
glm::vec3 newT = glm::normalize(t - n * glm::dot(n,t));
m_vertices[i].tangent[0] = newT.x;
m_vertices[i].tangent[1] = newT.y;
m_vertices[i].tangent[2] = newT.z;
m_vertices[i].tangent[3] = (glm::dot(glm::cross(n,t), storedTan[i]) < 0.0f) ? -1.0f : 1.0f;
}
我的 VertexData 看起来像这样 BTW:
struct VertexData
{
GLfloat position[4];
GLfloat normal[3];
GLfloat tcoords[3];
GLfloat tangent[4];
};
我知道 currenttcoords
和很好position
(normal
否则你不会看到上面的屏幕截图)。
然后我的顶点着色器看起来像这样:
#version 400
layout (location = 0) in vec4 in_position;
layout (location = 1) in vec3 in_normal;
layout (location = 2) in vec3 in_UV;
layout (location = 3) in vec4 in_tangent;
struct PointLight
{
bool active;
vec3 position;
vec3 ambient;
vec3 diffuse;
vec3 specular;
float constant;
float linear;
float quadratic;
};
uniform mat4 model;
uniform mat4 view;
uniform mat4 projection;
uniform mat4 lightMVP;
uniform PointLight uLight;
smooth out vec3 ex_UV;
out vec3 ex_normal;
out vec3 ex_positionCameraSpace;
out vec3 ex_originalPosition;
out vec3 ex_positionWorldSpace;
out vec4 ex_positionLightSpace;
out vec3 ex_tangent;
out vec3 ex_binormal;
out PointLight ex_light;
void main()
{
gl_Position = projection * view * model * in_position;
ex_UV = in_UV;
ex_normal = mat3(transpose(inverse(view * model))) * in_normal;
ex_positionCameraSpace = vec3(view * model * in_position);
ex_originalPosition = vec3(in_position.xyz);
ex_positionWorldSpace = vec3(model*in_position);
ex_positionLightSpace = lightMVP * model * in_position;
ex_tangent = mat3(transpose(inverse(view * model))) * in_tangent.xyz;
ex_binormal = cross(ex_normal,ex_tangent);
// provide the fragment shader with a light in view space rather than world space
PointLight p = uLight;
p.position = vec3(view * vec4(p.position,1.0));
ex_light = p;
}
最后我的片段着色器看起来像这样:
#version 400
layout (location = 0) out vec4 color;
struct Material
{
bool useMaps;
samplerCube diffuse;
samplerCube specular;
samplerCube normal;
float shininess;
vec4 color1;
vec4 color2;
};
struct PointLight
{
bool active;
vec3 position;
vec3 ambient;
vec3 diffuse;
vec3 specular;
float constant;
float linear;
float quadratic;
};
uniform Material uMaterial;
smooth in vec3 ex_UV;
in vec3 ex_normal;
in vec3 ex_positionCameraSpace;
in vec3 ex_originalPosition;
in vec3 ex_positionWorldSpace;
in vec4 ex_positionLightSpace;
in vec3 ex_tangent;
in vec3 ex_binormal;
in PointLight ex_light;
/* ******************
Provides a better lookup into a cubemap
******************* */
vec3 fix_cube_lookup(vec3 v, float cube_size)
{
float M = max(max(abs(v.x), abs(v.y)), abs(v.z));
float scale = (cube_size - 1) / cube_size;
if (abs(v.x) != M)
v.x *= scale;
if (abs(v.y) != M)
v.y *= scale;
if (abs(v.z) != M)
v.z *= scale;
return v;
}
/* *********************
Calculates the color when using a point light. Uses shadow map
********************* */
vec3 CalcPointLight(PointLight light, Material mat, vec3 normal, vec3 fragPos, vec3 originalPos, vec3 viewDir)
{
// replace the normal with lookup normal. This is now in tangent space
vec3 textureLookup = fix_cube_lookup(normalize(ex_originalPosition),textureSize(mat.normal,0).x);
normal = texture(mat.normal,textureLookup).rgb;
// the direction the light is in in the light position - fragpos
// light dir and view dir are now in tangent space
vec3 lightDir = transpose(mat3(ex_tangent,ex_binormal,ex_normal)) * normalize(fragPos - light.position);
viewDir = transpose(mat3(ex_tangent,ex_binormal,ex_normal)) * viewDir;
// get the diffuse color
textureLookup = fix_cube_lookup(normalize(ex_originalPosition),textureSize(mat.diffuse,0).x);
vec3 diffuseMat = vec3(0.0);
if(mat.useMaps)
diffuseMat = texture(mat.diffuse,textureLookup).rgb;
else
diffuseMat = mat.color1.rgb;
// get the specular color
textureLookup = fix_cube_lookup(normalize(ex_originalPosition),textureSize(mat.specular,0).x);
vec3 specularMat = vec3(0.0);
if(mat.useMaps)
specularMat = texture(mat.specular,textureLookup).rgb;
else
specularMat = mat.color2.rgb;
// the ambient color is the amount of normal ambient light hitting the diffuse texture
vec3 ambientColor = light.ambient * diffuseMat;
// Diffuse shading
float diffuseFactor = dot(normal, -lightDir);
vec3 diffuseColor = vec3(0,0,0);
vec3 specularColor = vec3(0,0,0);
if(diffuseFactor > 0)
diffuseColor = light.diffuse * diffuseFactor * diffuseMat;
// Specular shading
vec3 reflectDir = normalize(reflect(lightDir, normal));
float specularFactor = pow(dot(viewDir,reflectDir), mat.shininess);
if(specularFactor > 0 && diffuseFactor > 0)
specularColor = light.specular * specularFactor * specularMat;
float lightDistance = length(fragPos - light.position);
float attenuation = light.constant + light.linear * lightDistance + light.quadratic * lightDistance * lightDistance;
return ambientColor + (diffuseColor + specularColor) / attenuation;
}
void main(void)
{
vec3 norm = normalize(ex_normal);
vec3 viewDir = normalize(-ex_positionCameraSpace);
vec3 result = CalcPointLight(ex_light,uMaterial,norm,ex_positionCameraSpace, ex_positionWorldSpace,viewDir);
color = vec4(result,1.0);
}
据我所知:
- 我的切线计算正确。
- 我的法线贴图对我来说就像一张法线贴图。
- 我正在将光线和视图方向更改为切线空间以匹配我的法线贴图。
结果什么都没有。即没有任何东西被绘制到屏幕上。根本不是纯色。所以就像后面的一切都是没有遮挡的。
如果我将查找丢弃到我的法线贴图中,而只使用切线矩阵光并查看,我会得到以下信息:
这上面有一个后处理镜头光晕,它产生了那些有趣的点点滴滴。我认为重要的是来自法线似乎有些准确的表面的压倒性眩光。
如果我只是通过切线矩阵变换光线,我会得到:
所有这些结合起来告诉我我不知道我哪里出错了。
我有一种暗示,这是我的切线一代,因为其他作品似乎遵循我读过的每个教程似乎都在说的话。切线是在考虑立方体贴图的 icosphere 的情况下生成的。因此,要从立方体贴图通常的 3D 坐标中确定<S,T>
2D<U,V>
坐标,我:
- 用最大值确定我所在的脸
- 使用https://www.opengl.org/registry/specs/ARB/texture_cube_map.txt中的代码来确定 S、T 坐标
这是我正在谈论的https://www.opengl.org/registry/specs/ARB/texture_cube_map.txt的摘录。
major axis
direction target sc tc ma
---------- ------------------------------- --- --- ---
+rx TEXTURE_CUBE_MAP_POSITIVE_X_ARB -rz -ry rx
-rx TEXTURE_CUBE_MAP_NEGATIVE_X_ARB +rz -ry rx
+ry TEXTURE_CUBE_MAP_POSITIVE_Y_ARB +rx +rz ry
-ry TEXTURE_CUBE_MAP_NEGATIVE_Y_ARB +rx -rz ry
+rz TEXTURE_CUBE_MAP_POSITIVE_Z_ARB +rx -ry rz
-rz TEXTURE_CUBE_MAP_NEGATIVE_Z_ARB -rx -ry rz
Using the sc, tc, and ma determined by the major axis direction as
specified in the table above, an updated (s,t) is calculated as
follows
s = ( sc/|ma| + 1 ) / 2
t = ( tc/|ma| + 1 ) / 2
This new (s,t) is used to find a texture value in the determined
face's 2D texture image using the rules given in sections 3.8.5
and 3.8.6." ...
编辑 我不知道为什么我以前没有,但我已经在几何着色器中输出了法线、切线和双切线,以查看它们面对的方式。我使用了本教程。
黄色是面法线,绿色是顶点法线。我不确定为什么顶点法线看起来是错误的,它们不会影响任何其他照明,所以它可能只是我的几何着色器中的一个错误。
切线是红色的,副法线是蓝色的。这些看起来(很难说)它们是相互垂直的,这是正确的,但除了它们没有指向统一的方向。这就是我以前的斑驳模式。
我不知道如何解决这个问题。
编辑 2 我已经解决了显示法线等问题。现在已修复。
结果,我添加了一些阴影使其更清晰,每种颜色都是不同的立方体面。
我改变的另一件事是查找我的法线贴图。我忘记将范围调整回 -1 到 1(从 0 到 1)。
normal = texture(mat.normal,textureLookup).rgb * 2.0 - 1.0;
这不能解决我的问题。
令人困惑的部分是,当我尝试使用纹理中的法线时,我没有得到任何渲染。深度缓冲区中没有任何内容。我已经检查并再次检查了纹理是否可以从着色器访问(因此原始屏幕截图显示了应用于球体的纹理)。
因为即使我的切线和副法线都指向各个方向;我仍然希望展示一些东西,即使它是错误的。但即使是环境颜色也没有通过。(即使我独自一人也会发生这种情况。如果我只是忽略顶点法线并查找纹理。我会失去环境颜色)lightDir
......viewdir
编辑 3:最后一个问题
通常情况下,部分问题与您认为错误的地方无关。我的问题是我用不同的纹理覆盖了我的法线贴图的绑定。
所以,有了它,我现在可以看到我的颜色通过了。用我漂亮的性感凹凸贴图。
但是,现在立方体贴图的接缝处出现了问题。我不确定是因为计算了切线还是因为我的法线贴图的生成方式。我的法线贴图是从每个面的高度图独立生成的。
这可以解释我认为的一些接缝影响,我将对其进行修改以对这些边缘上的相邻面进行采样,看看会发生什么。
我仍然认为正在生成的切线也会对这些接缝产生不利影响。我的想法是,它们将在接缝处指向相反的方向。
截屏:
编辑 4 从 EDIT1 开始测试时,我为我的 icosphere 使用了一个非常低的多边形网格。所以我有最小的细分。
我想看看我的不太完美的法线贴图球体看起来有很多多边形。这立即暴露了这个问题:
如果不清楚,从左边跑来写的是我的老朋友,接缝,但在接缝下面,看起来像是三角形边缘。
所以在上述所有之后,我想我又回到了我原来的不正确切线问题。
仍在寻求任何正在阅读本文的人的帮助。
编辑 4 嗯,这很快。这个网站http://www.geeks3d.com/20130122/normal-mapping-without-precomputed-tangent-space-vectors/给了我另一种创建切线的方法。虽然代码看起来有点类似于我在 CPU 上所做的,但它并没有导致那些随机定向的切线从 EDIT 3 中产生这些边缘。
我现在非常接近。我仍然有接缝,这种生成切线的另一种方法似乎增加了它们的“接缝度”
编辑 5 我现在尝试修改我的法线贴图生成。之前的代码是这样的:
for(int i = 0; i < 6; ++i)
{
float scale = 15.0;
std::deque<glm::vec4> normalMap(textureSize*textureSize);
for(int x = 0; x < textureSize; ++x)
{
for(int y = 0; y < textureSize; ++y)
{
// center point
int i11 = utils::math::get_1d_array_index_from_2d(x,y,textureSize);
float v11 = cubeFacesHeight[i][i11].r;
// to the left
int i01 = utils::math::get_1d_array_index_from_2d(std::max(x-1,0),y,textureSize);
float v01 = cubeFacesHeight[i][i01].r;
// to the right
int i21 = utils::math::get_1d_array_index_from_2d(std::min(x+1,textureSize-1),y,textureSize);
float v21 = cubeFacesHeight[i][i21].r;
// to the top
int i10 = utils::math::get_1d_array_index_from_2d(x,std::max(y-1,0),textureSize);
float v10 = cubeFacesHeight[i][i10].r;
// and now the bottom
int i12 = utils::math::get_1d_array_index_from_2d(x,std::min(y+1,textureSize-1),textureSize);
float v12 = cubeFacesHeight[i][i12].r;
glm::vec3 S = glm::vec3(1, 0, scale * v21 - scale * v01);
glm::vec3 T = glm::vec3(0, 1, scale * v12 - scale * v10);
glm::vec3 N = (glm::vec3(-S.z,-T.z,1) / std::sqrt(S.z*S.z + T.z*T.z + 1));
N.x = (N.x+1.0)/2.0;
N.y = (N.y+1.0)/2.0;
N.z = (N.z+1.0)/2.0;
normalMap[utils::math::get_1d_array_index_from_2d(x,y,textureSize)] = glm::vec4(N.x,N.y,N.z,v11);
}
}
for(int x = 0; x < textureSize; ++x)
{
for(int y = 0; y < textureSize; ++y)
{
cubeFacesHeight[i][utils::math::get_1d_array_index_from_2d(x,y,textureSize)] = normalMap[utils::math::get_1d_array_index_from_2d(x,y,textureSize)];
}
}
}
cubeFacesHeight
是s 中std::array
的一个。或者,我的立方体贴图的六个面。脸上的颜色是灰度的,我不使用花车的原因并不重要。6
std::deque
glm::vec4
我现在将其更改为以下内容,警告,这既丑陋又长。
for(int i = 0; i < 6; ++i)
{
// 0 is negative X
// 1 is positive X
// 2 is negative Y
// 3 is positive Y
// 4 is negative Z
// 5 is positive Z
// +X: right -Z (left), left +Z (right), top -Y (right), bottom +Y (right)
// -X: right +Z (left), left -Z (right), top -Y (left), bottom +Y (left)
// -Z: right -X (left), left +X (right), top -Y (bottom), bottom +Y (top)
// +Z: right +X (left), left -X (right), top -Y (top), bottom +Y (bottom)
// -Y: right +X (top), left -X (top), top +Z (top), bottom -Z (top)
// +Y: right +X (bottom), left -X (bottom), top -Z (bottom), bottom +Z (bottom)
//+Z is towards, -Z is distance
const int NEGATIVE_X = 0;
const int NEGATIVE_Y = 2;
const int NEGATIVE_Z = 4;
const int POSITIVE_X = 1;
const int POSITIVE_Y = 3;
const int POSITIVE_Z = 5;
float scale = 15.0;
std::deque<glm::vec4> normalMap(textureSize*textureSize);
for(int x = 0; x < textureSize; ++x)
{
for(int y = 0; y < textureSize; ++y)
{
// center point
int i11 = utils::math::get_1d_array_index_from_2d(x,y,textureSize);
float v11 = cubeFacesHeight[i][i11].r;
// to the left
int i01 = utils::math::get_1d_array_index_from_2d(std::max(x-1,0),y,textureSize);
float v01 = cubeFacesHeight[i][i01].r;
if(x-1 < 0)
{
if(i == NEGATIVE_X)
{
i01 = utils::math::get_1d_array_index_from_2d(textureSize-1,y,textureSize);
v01 = cubeFacesHeight[NEGATIVE_Z][i01].r;
}
else if(i == POSITIVE_X)
{
i01 = utils::math::get_1d_array_index_from_2d(textureSize-1,y,textureSize);
v01 = cubeFacesHeight[POSITIVE_Z][i01].r;
}
else if(i == NEGATIVE_Z)
{
i01 = utils::math::get_1d_array_index_from_2d(textureSize-1,y,textureSize);
v01 = cubeFacesHeight[POSITIVE_X][i01].r;
}
else if(i == POSITIVE_Z)
{
i01 = utils::math::get_1d_array_index_from_2d(textureSize-1,y,textureSize);
v01 = cubeFacesHeight[NEGATIVE_X][i01].r;
}
else if(i == NEGATIVE_Y)
{
i01 = utils::math::get_1d_array_index_from_2d(y,0,textureSize);
v01 = cubeFacesHeight[NEGATIVE_X][i01].r;
}
else if(i == POSITIVE_Y)
{
i01 = utils::math::get_1d_array_index_from_2d(y,textureSize-1,textureSize);
v01 = cubeFacesHeight[NEGATIVE_X][i01].r;
}
}
// to the right
int i21 = utils::math::get_1d_array_index_from_2d(std::min(x+1,textureSize-1),y,textureSize);
float v21 = cubeFacesHeight[i][i21].r;
if(x+1 > textureSize-1)
{
if(i == NEGATIVE_X)
{
i01 = utils::math::get_1d_array_index_from_2d(0,y,textureSize);
v01 = cubeFacesHeight[POSITIVE_Z][i01].r;
}
else if(i == POSITIVE_X)
{
i01 = utils::math::get_1d_array_index_from_2d(0,y,textureSize);
v01 = cubeFacesHeight[NEGATIVE_Z][i01].r;
}
else if(i == NEGATIVE_Z)
{
i01 = utils::math::get_1d_array_index_from_2d(0,y,textureSize);
v01 = cubeFacesHeight[NEGATIVE_X][i01].r;
}
else if(i == POSITIVE_Z)
{
i01 = utils::math::get_1d_array_index_from_2d(0,y,textureSize);
v01 = cubeFacesHeight[POSITIVE_X][i01].r;
}
else if(i == NEGATIVE_Y)
{
i01 = utils::math::get_1d_array_index_from_2d(y,0,textureSize);
v01 = cubeFacesHeight[POSITIVE_X][i01].r;
}
else if(i == POSITIVE_Y)
{
i01 = utils::math::get_1d_array_index_from_2d(y,textureSize-1,textureSize);
v01 = cubeFacesHeight[POSITIVE_X][i01].r;
}
}
// to the top
int i10 = utils::math::get_1d_array_index_from_2d(x,std::max(y-1,0),textureSize);
float v10 = cubeFacesHeight[i][i10].r;
if(y-1 < 0)
{
if(i == NEGATIVE_X)
{
i01 = utils::math::get_1d_array_index_from_2d(0,x,textureSize);
v01 = cubeFacesHeight[NEGATIVE_Y][i01].r;
}
else if(i == POSITIVE_X)
{
i01 = utils::math::get_1d_array_index_from_2d(textureSize-1,x,textureSize);
v01 = cubeFacesHeight[NEGATIVE_Y][i01].r;
}
else if(i == NEGATIVE_Z)
{
i01 = utils::math::get_1d_array_index_from_2d(x,textureSize-1,textureSize);
v01 = cubeFacesHeight[NEGATIVE_Y][i01].r;
}
else if(i == POSITIVE_Z)
{
i01 = utils::math::get_1d_array_index_from_2d(x,0,textureSize);
v01 = cubeFacesHeight[NEGATIVE_Y][i01].r;
}
else if(i == NEGATIVE_Y)
{
i01 = utils::math::get_1d_array_index_from_2d(x,0,textureSize);
v01 = cubeFacesHeight[POSITIVE_Z][i01].r;
}
else if(i == POSITIVE_Y)
{
i01 = utils::math::get_1d_array_index_from_2d(x,textureSize-1,textureSize);
v01 = cubeFacesHeight[NEGATIVE_Z][i01].r;
}
}
// and now the bottom
int i12 = utils::math::get_1d_array_index_from_2d(x,std::min(y+1,textureSize-1),textureSize);
float v12 = cubeFacesHeight[i][i12].r;
if(y+1 > textureSize-1)
{
if(i == NEGATIVE_X)
{
i01 = utils::math::get_1d_array_index_from_2d(0,x,textureSize);
v01 = cubeFacesHeight[POSITIVE_Y][i01].r;
}
else if(i == POSITIVE_X)
{
i01 = utils::math::get_1d_array_index_from_2d(textureSize-1,x,textureSize);
v01 = cubeFacesHeight[POSITIVE_Y][i01].r;
}
else if(i == NEGATIVE_Z)
{
i01 = utils::math::get_1d_array_index_from_2d(x,0,textureSize);
v01 = cubeFacesHeight[POSITIVE_Y][i01].r;
}
else if(i == POSITIVE_Z)
{
i01 = utils::math::get_1d_array_index_from_2d(x,textureSize-1,textureSize);
v01 = cubeFacesHeight[POSITIVE_Y][i01].r;
}
else if(i == NEGATIVE_Y)
{
i01 = utils::math::get_1d_array_index_from_2d(x,0,textureSize);
v01 = cubeFacesHeight[NEGATIVE_Z][i01].r;
}
else if(i == POSITIVE_Y)
{
i01 = utils::math::get_1d_array_index_from_2d(x,textureSize-1,textureSize);
v01 = cubeFacesHeight[POSITIVE_Z][i01].r;
}
}
glm::vec3 S = glm::vec3(1, 0, scale * v21 - scale * v01);
glm::vec3 T = glm::vec3(0, 1, scale * v12 - scale * v10);
glm::vec3 N = (glm::vec3(-S.z,-T.z,1) / std::sqrt(S.z*S.z + T.z*T.z + 1));
N.x = (N.x+1.0)/2.0;
N.y = (N.y+1.0)/2.0;
N.z = (N.z+1.0)/2.0;
normalMap[utils::math::get_1d_array_index_from_2d(x,y,textureSize)] = glm::vec4(N.x,N.y,N.z,v11);
}
}
for(int x = 0; x < textureSize; ++x)
{
for(int y = 0; y < textureSize; ++y)
{
cubeFacesHeight[i][utils::math::get_1d_array_index_from_2d(x,y,textureSize)] = normalMap[utils::math::get_1d_array_index_from_2d(x,y,textureSize)];
}
}
}
所以我现在有点“流血”到相邻的立方体表面,以在生成法线贴图的同时对那里的高度进行采样。这实际上增加了接缝的外观。
但这种方式提出了它自己的问题。例如……“到底为什么影响会增加?” 你可以看到它现在是一种斜角效果。
所以,我很确定当“流血”到下一个时,我已经正确地匹配了我的立方体面。这让我回到了不正确的切线。
即使我完全混合了立方体面,它也不会产生斜角效果,它会是完全参差不齐的东西。例如,即使在完全平坦的部分上,即将法线贴图生成渗入下一张面,效果为零,我仍然看到一个巨大的斜面。
这让我觉得如果切线之前是正确的,那么法线贴图会“匹配”切线方向吗?我不知道。
快速编辑 我注意到我在原始地图生成期间有效地对我的面部边缘进行了两次采样。如果我删除这个双重采样并且只使用 0 作为附加值,我最终会看到同样的大接缝。我不确定这意味着什么...
另一个快速编辑
这张图片显示了我认为很有说服力的东西。
我可以在这里看到两个不同的面孔“指向”相反的方向。这是我的片段切线生成。
所以我回到我的切线是一个问题。