2016-07-09 4 views
1

저는 쿼드를 하위 분할하고 구로 변환하여 프로그래밍 방식으로 구를 생성하려고했습니다. 텍스처 좌표와 위치가 모두 올바른 반면 최종 법선은 잘못되었습니다.생성 된 큐브 매핑 된 (사각형) 구체의 잘못된 법선

정점 당 법선을 계산하는 공식은 표준 [v1 - v2] x [v1 - v3]이 정규화 된 공식입니다. 그러나 법선을 출력하는 셰이더가 사용되면 구가 순수한 검정색으로 렌더링됩니다. Black sphere with bad normals

구를 생성하는 데 사용 된 코드는 구를 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(); 
     } 
    } 
} 
+2

코드를 따르려고하지 않았지만 계산을 수행하여 구의 법선을 가져 오는 이유는 무엇입니까? 구형의 경우 법선 벡터는 위치와 동일합니다. –

답변

1

@Reto Koradi에 따르면, 구형의 법선은 위치와 같습니다. 따라서 CalculateNormals 메서드를 다음과 같이 단순화 할 수 있습니다. 개별 삼각형에 대한 계산이 필요하지 않습니다.

void CalculateNormals(VertexPositionNormalTexture[] vertices) 
{ 
    for(int i = 0; i < vertices.Length; i++) 
     vertices[i].Normal = vertices[i].Position; 
}