2015-11-02 31 views
0

我正在創建一個模型導入器,它將.obj的轉換爲我自己的專有格式,將用於我創建的遊戲。我的模型解析器似乎一開始就工作得很好,從像塞爾達傳說這樣的各種遊戲中加載小模型,但無論如何,都無法正確紋理先進的模型,比如來自無主之地的Claptrap。下面是一些屏幕爭奪向你展示我的意思:在OpenGL/OpenTK中不一致的模型紋理

型號裝載機用塞爾達模式工作: enter image description here

再有就是譁衆取寵沒有被正確紋理: enter image description here

儘管它在Blender中質感很好: enter image description here

我不明白這一點,也不知道錯誤來自哪裏。這裏是我的WavefrontParser的代碼,這可能會產生一些不可預見的錯誤較大的模型,我不知道的:

using System; 
using System.Collections.Generic; 
using System.IO; 
using OpenTK; 
using StardustModeling.Modeling.DataTypes; 

namespace StardustModeling.Modeling.Parsers 
{ 
    /// <summary> 
    /// 
    /// Stardust Engine 
    /// 
    /// A simple, lightweight WavefrontModel Parser. This 
    /// class serves as the basis for the Stardust Model 
    /// conversion wizard. All Stardust Models(.sdm) start 
    /// out as .obj files; this class is how we load them 
    /// before the conversion to .sdm begins. 
    /// 
    /// Original Author: Gordon Kyle Wallace, "Krythic" 
    /// 
    /// </summary> 
    public static class WavefrontModelParser 
    { 
     /// <summary> 
     /// Parses a Wavefront .obj file. The given 
     /// file must be triangulated and have normals 
     /// included during exportation from Blender. 
     /// </summary> 
     /// <param name="path">The path of the .obj on disk</param> 
     /// <returns>A WavefrontModel Instance</returns> 
     public static WavefrontModel Parse(string path) 
     { 
      WavefrontModel model = new WavefrontModel(); 
      VertexIndex[] verticesIndex; 
      string[] wavefrontFileData = File.ReadAllLines(path); 
      int loopLength = wavefrontFileData.Length; // Squeeze out every last drop! 
      for(int lines = 0; lines < loopLength; lines++) 
      { 
       string[] lineTokens = wavefrontFileData[ lines ].Split(' '); 
       switch(lineTokens[ 0 ]) 
       { 
        case "v": // Vector 
         float x = Single.Parse(lineTokens[ 1 ]); 
         float y = Single.Parse(lineTokens[ 2 ]); 
         float z = Single.Parse(lineTokens[ 3 ]); 
         model.Vertices.Add(new Vector3(x , y , z)); 
         break; 
        case "vt": // Texture Coordinate 
         float u = Single.Parse(lineTokens[ 1 ]); 
         float v = Single.Parse(lineTokens[ 2 ]); 
         model.TexCoords.Add(new Vector2(u , v)); 
         break; 
        case "vn": // Normal 
         float normalX = Single.Parse(lineTokens[ 1 ]); 
         float normalY = Single.Parse(lineTokens[ 2 ]); 
         float normalZ = Single.Parse(lineTokens[ 3 ]); 
         model.Normals.Add(new Vector3(normalX , normalY , normalZ)); 
         break; 
        case "f": 
         verticesIndex = new VertexIndex[ 3 ]; 
         for(int i = 0; i < 3; i++) 
         { 
          string[] parameters = lineTokens[ i + 1 ].Split('/'); 
          int vertice = Int32.Parse(parameters[ 0 ]) - 1; 
          int texture = Int32.Parse(parameters[ 1 ]) - 1; 
          int normal = Int32.Parse(parameters[ 2 ]) - 1; 
          verticesIndex[ i ] = new VertexIndex(vertice , normal , texture); 
         } 
         model.Faces.Add(new Face(verticesIndex)); 
         break; 
       } 
      } 
      return model; 
     } 
    } 
} 

我WavefrontModel類:

using System.Collections.Generic; 
using OpenTK; 
using StardustModeling.Modeling.Parsers; 

namespace StardustModeling.Modeling.DataTypes 
{ 
    public class WavefrontModel 
    { 
     public List<Vector3> Vertices; 
     public List<Vector2> TexCoords; 
     public List<Vector3> Normals; 
     public List<Face> Faces; 
     public string ModelSource; 

     public int TotalTriangles 
     { 
      get 
      { 
       return this.Vertices.Count/3; 
      } 
     } 

     public WavefrontModel() 
     { 
      this.Vertices = new List<Vector3>(); 
      this.TexCoords = new List<Vector2>(); 
      this.Normals = new List<Vector3>(); 
      this.Faces = new List<Face>(); 
     } 

     public WavefrontModel(int buffer) 
     { 
      this.Vertices = new List<Vector3>(buffer); 
      this.TexCoords = new List<Vector2>(buffer); 
      this.Normals = new List<Vector3>(buffer); 
      this.Faces = new List<Face>(buffer); 
     } 

     public WavefrontModel(string modelPath, bool loadImmediately) 
     { 
      this.ModelSource = modelPath; 
      if (loadImmediately) 
      { 
       Load(); 
      } 
     } 

     private void Load() 
     { 
      WavefrontModel model = WavefrontModelParser.Parse(ModelSource); 
      this.Vertices = model.Vertices; 
      this.TexCoords = model.TexCoords; 
      this.Normals = model.Normals; 
      this.Faces = model.Faces; 
     } 
    } 

} 

我的材料類,這也可能產生一個錯誤:

using System.Drawing; 
using System.Drawing.Imaging; 
using OpenTK.Graphics.OpenGL; 
using PixelFormat = OpenTK.Graphics.OpenGL.PixelFormat; 

namespace StardustFramework.Framework.OpenGL.Texturing 
{ 
    public enum MaterialType 
    { 
     /// <summary> 
     /// Represents a Diffuse Texture 
     /// </summary> 
     Diffuse, 
     /// <summary> 
     /// Represents a Normal Texture 
     /// </summary> 
     Normal 
    } 

    public class Material 
    { 
     /// <summary> 
     /// The name of the Material 
     /// </summary> 
     public string Name; 
     /// <summary> 
     /// The Diffuse Texture 
     /// </summary> 
     public int Diffuse; 
     /// <summary> 
     /// The Normal Texture 
     /// </summary> 
     public int NormalMap; 
     /// <summary> 
     /// The Ambient Color for the Material 
     /// </summary> 
     public Color AmbientColor; 

     public Material(string materialName) 
     { 
      this.Name = materialName; 
      this.AmbientColor = Color.White; 
      this.Diffuse = 0; 
      this.NormalMap = 0; 
     } 

     /// <summary> 
     /// Loads a Bitmap as a Diffuse texture. 
     /// </summary> 
     /// <param name="bitmap">The bitmap.</param> 
     public void LoadDiffuse(Bitmap bitmap) 
     { 
      GL.Enable(EnableCap.Texture2D); 
      //GL.Hint(HintTarget.PerspectiveCorrectionHint , HintMode.Nicest); 
      GL.GenTextures(1 , out Diffuse); 
      GL.BindTexture(TextureTarget.Texture2D , Diffuse); 
      GL.TexParameter(TextureTarget.Texture2D , TextureParameterName.TextureMinFilter , (int)TextureMinFilter.Nearest); 
      GL.TexParameter(TextureTarget.Texture2D , TextureParameterName.TextureMagFilter , (int)TextureMagFilter.Nearest); 
      BitmapData data = bitmap.LockBits(new Rectangle(0 , 0 , bitmap.Width , bitmap.Height) , 
       ImageLockMode.ReadOnly , System.Drawing.Imaging.PixelFormat.Format32bppArgb); 
      GL.TexImage2D(TextureTarget.Texture2D , 0 , PixelInternalFormat.Rgba , data.Width , data.Height , 0 , 
       PixelFormat.Bgra , PixelType.UnsignedByte , data.Scan0); 
      bitmap.UnlockBits(data); 
      GL.BindTexture(TextureTarget.Texture2D , 0); 
     } 
    } 
} 

我真的很喜歡它,如果有人能幫我發現這個bug;我開始把我的頭髮撕掉(我不必從頭開始,哈哈)。

編輯:

我忘了提到我如何渲染這個。我使用OpenTK/OpenGL,並通過即時模式繪製(用於初始應用程序測試)。

private void DrawMesh(WavefrontModel m) 
     { 

      GL.Enable(EnableCap.Texture2D); 
      GL.Color3(_modelMaterial.AmbientColor); 
      if(_modelMaterial.Diffuse > 0) 
      { 
       GL.BindTexture(TextureTarget.Texture2D , _modelMaterial.Diffuse); 
      } 
      GL.Begin(PrimitiveType.Triangles); 
      for(int i = 0; i < m.Faces.Count; i++) 
      { 
       for(int index = 0; index < m.Faces[ i ].Indices.Length; index++) 
       { 
        Vector3 v = m.Vertices[ m.Faces[ i ].Indices[ index ].Vector ]; 
        Vector3 n = m.Normals[ m.Faces[ i ].Indices[ index ].Normal ]; 
        Vector2 tc = m.TexCoords[ m.Faces[ i ].Indices[ index ].TextureCoordinateIndex ]; 
        GL.Normal3(n.X , n.Y , n.Z); 
        GL.TexCoord2(tc.X , tc.Y); 
        GL.Vertex3(v.X , v.Y , v.Z); 
       } 
      } 
      GL.End(); 
     } 
+0

我剛放下牀,開始打瞌睡,當一個可能的解決方案打我。我認爲問題在於Floats的解析。我可能會在將字符串轉換爲浮點數的時候出現一些降級(當float更抽象時,比如使用高級uv建模)。我明天會做一些調試。不過,這可能與其他東西完全不相關。 – Krythic

+0

downvote的理由?如有必要,我可以提供更多代碼。僅僅因爲一個問題很複雜,並不值得降低價值。 – Krythic

回答

0

經過許多折磨我的頭髮痛苦的小時,我終於意識到我的問題。我沒有想到的,現在對我來說似乎很愚蠢,那就是我試圖在OpenGL環境中紋理爲DirectX製作的模型。爲什麼這很重要?那麼,在OpenGL中,紋理原點是左下角0,0。在DirectX中,它是左上角。所以通過簡單地在gimp中垂直翻轉紋理,我就可以使用它了。

enter image description here

很高興知道有沒有錯,我的型號裝載機,我只是沒有想到我所用的模型的目標平臺/ API。

+0

最終結果是相同的,但我認爲這更多的是如何在OBJ文件中指定紋理座標的問題。至少在我看到的文件中,您需要翻轉紋理座標的y分量以便與OpenGL一起使用。無需更改文件或紋理,只需在讀入文件時翻轉紋理座標即可。 –

+0

@ReetoKoradi如果你有時間,你認爲你可以看看這個新的相關問題嗎?它涉及Blender如何顯然檢測何時翻轉紋理座標(如您所提及的)以及何時忽略這樣做。兩個.obj模型(無論OpenGL或DirectX目標平臺)在Blender中正確渲染。我很好奇它是如何做到這一點的。也許你知道答案。乾杯。 =)http://blender.stackexchange.com/questions/40958/how-does-blender-autodetect-texture-culture?noredirect=1#comment68019_40958 – Krythic