edit: вы можете начать с "Edit 3", потому что я решил многое из этого
Вот скриншот моей обычной кубической карты, примененной к икосфере:
Касательные для моей икосферы с кубической картой генерируются с помощью следующего кода. 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];
};
Я знаю, что текущие tcoords
, 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);
}
Насколько я могу судить:
- Мои касательные рассчитываются правильно.
- Моя карта нормалей для меня выглядит как карта нормалей.
- Я меняю направление света и обзора на касательное пространство, чтобы оно соответствовало моей карте нормалей.
Результат - ничего. Т.е. на экран ничего не рисуется. Совсем не сплошной цвет. Как будто все позади нарисовано без окклюзии.
Если я откажусь от поиска в моей карте нормалей и вместо этого просто использую свет и вид касательной матрицы, я получу следующее:
На нем есть блики объектива после обработки, которые создают эти забавные кусочки и качки. Что важно, я думаю, так это подавляющее сияние от поверхности, где нормали кажутся довольно точными.
Если я просто трансформирую свет по касательной матрице, я получу следующее:
Все это в совокупности говорит мне, что я понятия не имею, в чем я ошибаюсь.
У меня есть подозрение, что это мое касательное поколение, потому что другие части, кажется, следуют тому, что, по-видимому, говорится в каждом учебнике, который я прочитал. Касательные генерируются с учетом кубической икосферы. Итак, чтобы определить <S,T>
или <U,V>
2D-координаты из обычных 3D-координат кубической карты, я:
- Используйте наибольшее значение, чтобы определить лицо, на котором я нахожусь
- Используйте код из 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 и ниже я использовал очень-очень низкополигональную сетку для своей икосферы. Так что у меня было минимальное количество подразделений.
Я хотел посмотреть, как будет выглядеть моя не совсем идеальная сфера нормалей с множеством полигонов. Это сразу выявило эту проблему:
В случае, если неясно, бегущий слева, чтобы писать, - это мой старый друг, шов, но под ним, кажется, есть края треугольника.
Итак, после всего вышесказанного, я думаю, что вернулся к своей первоначальной проблеме неправильных касательных.
Все еще ищу помощи у тех, кто это читает.
РЕДАКТИРОВАТЬ 4. Это было быстро. Этот сайт находится здесь http://www.geeks3d.com/20130122/normal-mapping-without-precomputed-tangent-space-vectors/ дал мне другой способ создания касательных. Хотя код кажется чем-то похожим на то, что я делал на ЦП, он не привел к тем случайно ориентированным касательным, которые создавали эти ребра из 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
- это 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 для дополнительной, я в конечном итоге увижу те же самые большие швы. Я не уверен, что это значит ...
Еще одно быстрое редактирование. Это изображение показывает кое-что, что, на мой взгляд, очень красноречиво.
Здесь я вижу, что два разных лица «указывают» в противоположных направлениях. Это с моей касательной генерацией фрагмента.
Так что я вернулся к тому, что касалось моих проблем.