我正在创建一个模型导入器,它将.obj转换为我自己的专有格式,将用于我正在创建的游戏。我的模型解析器最初看起来工作得很好,加载来自塞尔达传说等各种游戏的小型模型,但无论出于何种原因,都无法正确地纹理化高级模型,如来自Borderlands的Claptrap。以下是一些屏幕抓取来向您展示我的意思:
我不明白这一点,也不知道错误的来源。这是我的WavefrontParser的代码,它可能会产生一些我不知道的大型模型的无法预料的错误:
process.stdin
我的WavefrontModel类:
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;
}
}
}
我的Material类,也可能会出错:
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;
}
}
}
如果有人能帮助我发现这个错误,我真的很喜欢它;我开始把头发撕掉了(我不必从头开始,哈哈)。
编辑:
我忘了提到我是如何渲染这个的。我使用OpenTK / OpenGL,并通过立即模式绘制(用于初始应用程序测试)。
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 );
}
}
}