1
저는 쿼드를 하위 분할하고 구로 변환하여 프로그래밍 방식으로 구를 생성하려고했습니다. 텍스처 좌표와 위치가 모두 올바른 반면 최종 법선은 잘못되었습니다.생성 된 큐브 매핑 된 (사각형) 구체의 잘못된 법선
정점 당 법선을 계산하는 공식은 표준 [v1 - v2] x [v1 - v3]이 정규화 된 공식입니다. 그러나 법선을 출력하는 셰이더가 사용되면 구가 순수한 검정색으로 렌더링됩니다.
구를 생성하는 데 사용 된 코드는 구를 obj 파일로 덤프하는 방법과 함께 아래에 나와 있습니다. 올바른 법선을 만들기 위해 이것을 어떻게 수정합니까?
using System;
using System.IO;
using System.Collections.Generic;
public class QuadSphere
{
int primitiveCountSide;
VertexPositionNormalTexture[] vertices;
ushort[] indices;
public QuadSphere(int slices)
{
int planeVerts = (slices + 1) * (slices + 1);
vertices = new VertexPositionNormalTexture[planeVerts * 6];
int planeIndices = slices * slices * 6;
indices = new ushort[planeIndices * 6];
primitiveCountSide = planeIndices/3;
//Generate planes
int vertexCount = 0;
//BOTTOM
TopBottom(1, slices, vertices, vertexCount);
vertexCount += planeVerts;
//TOP
TopBottom(-1, slices, vertices, vertexCount);
vertexCount += planeVerts;
//FRONT
FrontBack(-1, slices, vertices, vertexCount);
vertexCount += planeVerts;
//BACK
FrontBack(1, slices, vertices, vertexCount);
vertexCount += planeVerts;
//LEFT
LeftRight(-1, slices, vertices, vertexCount);
vertexCount += planeVerts;
//RIGHT
LeftRight(1, slices, vertices, vertexCount);
vertexCount += planeVerts;
//Generate indices
int indexCount = 0;
int baseVert = 0;
//BOTTOM
Indices(2, 1, 0, 1, 2, 3, slices, ref indexCount, indices, baseVert);
baseVert += planeVerts;
//TOP
Indices(0, 1, 2, 3, 2, 1, slices, ref indexCount, indices, baseVert);
baseVert += planeVerts;
//FRONT
Indices(2, 1, 0, 1, 2, 3, slices, ref indexCount, indices, baseVert);
baseVert += planeVerts;
//BACK
Indices(0, 1, 2, 3, 2, 1, slices, ref indexCount, indices, baseVert);
baseVert += planeVerts;
//LEFT
Indices(2, 1, 0, 1, 2, 3, slices, ref indexCount, indices, baseVert);
baseVert += planeVerts;
//RIGHT
Indices(0, 1, 2, 3, 2, 1, slices, ref indexCount, indices, baseVert);
//Transform Cube to Sphere
for (int i = 0; i < vertices.Length; i++)
{
float x = vertices[i].Position.X;
float y = vertices[i].Position.Y;
float z = vertices[i].Position.Z;
vertices[i].Position = new Vector3(
(float)(x * Math.Sqrt(1.0 - (y * y/2.0) - (z * z/2.0) + (y * y * z * z/3.0))),
(float)(y * Math.Sqrt(1.0 - (z * z/2.0) - (x * x/2.0) + (z * z * x * x/3.0))),
(float)(z * Math.Sqrt(1.0 - (x * x/2.0) - (y * y/2.0) + (x * x * y * y/3.0)))
);
}
//Calculate Normals
CalculateNormals(vertices, indices);
}
void TopBottom(int Y, int slices, VertexPositionNormalTexture[] vertices, int vertexCount)
{
int width = slices + 1, height = slices + 1;
float advance = (2f/slices);
float tadvance = (1f/slices);
for (int z = 0; z < height; z++)
{
int basev = vertexCount + (z * width);
for (int x = 0; x < width; x++)
{
int index = basev + x;
vertices[index] = new VertexPositionNormalTexture(
new Vector3(
-1 + advance * x,
Y,
-1 + advance * z
),
Vector3.Zero,
new Vector2(
tadvance * x,
(Y == -1) ? tadvance * z : 1 - (tadvance * z)
)
);
}
}
}
void FrontBack(int Z, int slices, VertexPositionNormalTexture[] vertices, int vertexCount)
{
int width = slices + 1, height = slices + 1;
float advance = (2f/slices);
float tadvance = (1f/slices);
for (int z = 0; z < height; z++)
{
int basev = vertexCount + (z * width);
for (int x = 0; x < width; x++)
{
int index = basev + x;
vertices[index] = new VertexPositionNormalTexture(
new Vector3(
-1 + advance * x,
-1 + advance * z,
Z
),
Vector3.Zero,
new Vector2(
(Z == -1) ? 1 - (tadvance * x) : tadvance * x,
tadvance * z
)
);
}
}
}
void LeftRight(int X, int slices, VertexPositionNormalTexture[] vertices, int vertexCount)
{
int width = slices + 1, height = slices + 1;
float advance = (2f/slices);
float tadvance = (1f/slices);
for (int z = 0; z < height; z++)
{
int basev = vertexCount + (z * width);
for (int x = 0; x < width; x++)
{
int index = basev + x;
vertices[index] = new VertexPositionNormalTexture(
new Vector3(
X,
-1 + advance * x,
-1 + advance * z
),
Vector3.Zero,
new Vector2(
(X == -1) ? tadvance * z : 1 - (tadvance * z),
tadvance * x
)
);
}
}
}
void Indices(ushort t0, ushort t1, ushort t2, ushort t3, ushort t4, ushort t5, int slices, ref int i, ushort[] indices, int baseVert)
{
int width = slices + 1;
int height = slices;
ushort[] temp = new ushort[6];
for (int y = 0; y < height; y++)
{
int basev = baseVert + (y * width);
for (int x = 0; x < slices; x++)
{
//Allow defined winding order
temp[0] = (ushort)(basev + x);
temp[1] = (ushort)(basev + x + 1);
temp[2] = (ushort)(basev + width + x);
temp[3] = (ushort)(basev + width + x + 1);
indices[i++] = temp[t0];
indices[i++] = temp[t1];
indices[i++] = temp[t2];
indices[i++] = temp[t3];
indices[i++] = temp[t4];
indices[i++] = temp[t5];
}
}
}
public void Dump(string obj)
{
using (var writer = new StreamWriter(obj))
{
writer.WriteLine("#quadsphere obj");
foreach (var vert in vertices)
{
writer.WriteLine("v\t{0}\t{1}\t{2}", vert.Position.X, vert.Position.Y, vert.Position.Z);
}
writer.WriteLine();
foreach (var vert in vertices)
{
writer.WriteLine("vn\t{0}\t{1}\t{2}", vert.Normal.X, vert.Normal.Y, vert.Normal.Z);
}
writer.WriteLine();
foreach (var vert in vertices)
{
writer.WriteLine("vt\t{0}\t{1}", vert.TextureCoordinate.X, vert.TextureCoordinate.Y);
}
writer.WriteLine();
for (int i = 0; i < indices.Length/3; i++)
{
writer.WriteLine("f\t{0}/{0}/{0}\t{1}/{1}/{1}\t{2}/{2}/{2}",
1 + indices[i * 3],
1 + indices[i * 3 + 1],
1 + indices[i * 3 + 2]
);
}
}
}
void CalculateNormals(VertexPositionNormalTexture[] array, ushort[] indices)
{
for (int i = 0; i < indices.Length/3; i++)
{
var firstVec = array[indices[i * 3]].Position - array[indices[i * 3 + 1]].Position;
var secondVec = array[indices[i * 3]].Position - array[indices[i * 3 + 2]].Position;
var normal = Vector3.Cross(firstVec, secondVec);
normal.Normalize();
array[indices[i * 3]].Normal += normal;
array[indices[i * 3 + 1]].Normal += normal;
array[indices[i * 3 + 2]].Normal += normal;
}
for (int i = 0; i < array.Length; i++)
{
array[i].Normal.Normalize();
}
}
}
코드를 따르려고하지 않았지만 계산을 수행하여 구의 법선을 가져 오는 이유는 무엇입니까? 구형의 경우 법선 벡터는 위치와 동일합니다. –