2016-07-09 3 views
1

私は球をプログラム分割して、それを球に変換して球を生成しようとしていました。テクスチャ座標と位置の両方が正しいが、最後の法線は間違っている。生成されたCube-mapped(Quad)Sphereの不正確な法線

頂点当りの法線を計算するために使用される式は、標準化された[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; 
} 
関連する問題