2015-11-02 88 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