Я получаю странные артефакты, когда рисую свой сгенерированный объект множеством полигонов. Если я, например, использую меньше полигонов, все в порядке. Если я использую слишком много полигонов, вы все равно можете видеть эти артефакты, но они слишком малы, чтобы обращать на них внимание. Я не могу использовать слишком много полигонов, как на третьем изображении, и не могу найти причину такого странного поведения. Мой вершинный шейдер:
attribute vec3 a_position;
attribute vec3 a_normal;
attribute vec2 a_texCoord0;
uniform mat4 model;
uniform mat4 view;
uniform mat4 projection;
varying vec3 fragPos;
varying vec3 normal;
varying vec2 texcoord0;
void main()
{
gl_Position = projection * view * model * vec4(a_position, 1.0);
fragPos = vec3(model * vec4(a_position, 1.0));
normal = a_normal;
texcoord0 = a_texCoord0;
}
Код моего фрагментного шейдера:
#ifdef GL_ES
precision mediump float;
#endif
varying vec3 normal;
varying vec2 texcoord0;
varying vec3 fragPos;
uniform vec3 lightPos;
uniform vec3 lightColor;
void main()
{
vec3 color = vec3(1.0, 0, 0);
// Ambient
float ambientStrength = 0.1;
vec3 ambient = ambientStrength * lightColor;
// Diffuse
vec3 norm = normalize(normal);
vec3 lightDir = normalize(lightPos - fragPos);
float diff = max(dot(norm, lightDir), 0.0);
vec3 diffuse = diff * lightColor;
vec3 result = (ambient + diffuse) * color;
gl_FragColor = vec4(result, 1.0);
}
Вот часть, как я вычисляю нормали:
public class MeshData {
private final static int COMPONENTS_NUM = 8;
public Vector2[] uv = new Vector2[0];
private Vector3[] vertices = new Vector3[0];
public short[] triangles = new short[0];
public Normal[] normals;
public void recalculateNormals(){
for(int i = 0; i < triangles.length; i+=3){
computeFaceNormal(triangles[i], triangles[i + 1], triangles[i + 2]);
}
}
public static class Normal{
private Vector3 normal = new Vector3();
public Vector3 getUnitNormal() {
return normal.cpy().nor();
}
public void addNormal(float x, float y, float z){
normal.add(x, y, z);
}
}
private void computeFaceNormal(int i1, int i2, int i3) {
Vector3 vertex1 = vertices[i1];
Vector3 vertex2 = vertices[i2];
Vector3 vertex3 = vertices[i3];
//normal
float EPSILON = 0.000001f;
// default return value (0, 0, 0)
float normalX = 0, normalY = 0, normalZ = 0;
// find 2 edge vectors: v1-v2, v1-v3
float ex1 = vertex2.x - vertex1.x;
float ey1 = vertex2.y - vertex1.y;
float ez1 = vertex2.z - vertex1.z;
float ex2 = vertex3.x - vertex1.x;
float ey2 = vertex3.y - vertex1.y;
float ez2 = vertex3.z - vertex1.z;
// cross product: e1 x e2
float nx, ny, nz;
nx = ey1 * ez2 - ez1 * ey2;
ny = ez1 * ex2 - ex1 * ez2;
nz = ex1 * ey2 - ey1 * ex2;
// normalize only if the length is > 0
float length = (float) Math.sqrt(nx * nx + ny * ny + nz * nz);
if (length > EPSILON) {
// normalize
float lengthInv = 1.0f / length;
normalX = nx * lengthInv;
normalY = ny * lengthInv;
normalZ = nz * lengthInv;
}
normals[i1].addNormal(normalX, normalY, normalZ);
normals[i2].addNormal(normalX, normalY, normalZ);
normals[i3].addNormal(normalX, normalY, normalZ);
}
}
Я использую класс Normal длясглаживать нормали. Таким образом, если несколько полигонов используют одну вершину, нормали этих полигонов будут суммироваться и затем нормализованы для этой вершины.