简体   繁体   English

OpenGL / OpenTK中的模型纹理不一致

[英]Inconsistent Model Texturing In OpenGL/OpenTK

I am creating a Model Importer which converts .obj's to my own proprietary format, that will be used for the game I am creating. 我正在创建一个模型导入器,它将.obj转换为我自己的专有格式,该格式将用于我正在创建的游戏。 My model parser appeared to work just fine at first, loading small models from various games like Legend of Zelda, but for whatever reason, fails at correctly texturing advanced models, like Claptrap from Borderlands. 我的模型解析器一开始似乎运行良好,可以从《塞尔达传说》等各种游戏中加载小型模型,但是由于某种原因,无法正确地对高级模型(例如《无主之地》的Claptrap)进行纹理化。 Here are some screen grabs to show you what I mean: 以下是一些屏幕截图,向您展示了我的意思:

The model loader working with a zelda model: 模型加载器与zelda模型一起使用: 在此处输入图片说明

And then there is Claptrap NOT being textured correctly: 然后是Claptrap没有正确构造纹理: 在此处输入图片说明

Despite the fact that it is textured just fine in Blender: 尽管事实上它在Blender中纹理还不错: 在此处输入图片说明

I don't understand this, nor do I know where the error is coming from. 我不明白这一点,也不知道错误是从哪里来的。 Here is the code for my WavefrontParser, which may yield some unforeseen bug for larger models that I am not aware of: 这是我的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;
        }
    }
}

My WavefrontModel class: 我的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;
        }
    }

}

And my Material class, which may also yield a mistake: 还有我的Material类,这也可能会产生一个错误:

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 );
        }
    }
}

I would really like it if someone could help me spot this bug; 如果有人可以帮助我发现此错误,我真的很喜欢。 I am starting to tear my hair out(which I don't have to begin with, lol). 我开始扯掉我的头发(我不必一开始,哈哈)。

EDIT: 编辑:

I forgot to mention how I am rendering this. 我忘了提到我是如何渲染的。 I use OpenTK/OpenGL, and draw via immediate mode(for initial application testing). 我使用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();
        }

After many excruciating hours of tearing my hair out, I finally realized my problem. 经过数小时的辛苦工作,我终于意识到了自己的问题。 What I did not think about, and it seems dumb to me now, was that I was trying to texture a model crafted for DirectX within an OpenGL environment. 我没有想到的,现在看来对我来说是愚蠢的,因为我试图在OpenGL环境中构造为DirectX设计的模型。 Why does this matter? 为什么这么重要? Well, in OpenGL the texture origin is bottom-left hand corner 0,0. 好吧,在OpenGL中,纹理原点是左下角0,0。 In DirectX it's top-left hand corner. 在DirectX中,它是左上角。 So by simply flipping the texture vertically in gimp I got it to work. 因此,只需简单地在gimp中垂直翻转纹理,即可使其正常工作。

在此处输入图片说明

It's nice to know that there was nothing wrong with my Model Loader, I just wasn't thinking about the targeted platform/api of the models I was using. 很高兴知道我的Model Loader没问题,我只是没有考虑我正在使用的模型的目标平台/ api。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM