[英]Strange OpenGL Texture Coordinates When Loading Model
我决定在我的OpenTK C#游戏中实现一个模型加载器。 它的效果很好,除了纹理坐标完全是奇异的。 我使用的代码是我在互联网上找到的OpenTK模型加载器的稍作修改的版本。 我已经尝试过在混合器中对模型进行uv解包,但结果似乎总是像被搞砸了一样。
这是我的模型在Blender中的样子:
这是我的游戏中的样子:
这是我的WavefrontModel类:
using System.Collections.Generic;
using OpenTK;
namespace GameProject.Game.Framework.ModelLoader {
public class WavefrontModel {
public List<Vector3> Vertices;
public List<Vector2> TexCoords;
public List<Vector3> Normals;
public List<Face> Faces;
public WavefrontModel( string modelPath ) {
loadModel( modelPath );
}
public WavefrontModel(
List<Vector3> points , List<Vector2> texCoords , List<Vector3> normals , List<Face> faces ) {
this.Vertices = points;
this.TexCoords = texCoords;
this.Normals = normals;
this.Faces = faces;
}
private void loadModel( string modelPath ) {
WavefrontModel model = new WavefrontModelLoader().LoadFile( modelPath );
this.Vertices = model.Vertices;
this.TexCoords = model.TexCoords;
this.Normals = model.Normals;
this.Faces = model.Faces;
}
}
public struct ModelVertex {
public int Vertex;
public int Normal;
public int TexCoord;
public ModelVertex( int v , int n , int t ) {
Vertex = v;
Normal = n;
TexCoord = t;
}
}
public struct Face {
public ModelVertex[] Points;
public Face( int i ) {
Points = new ModelVertex[ i ];
}
public Face( ModelVertex[] i ) {
Points = i;
}
}
}
这是我的WavefrontModelLoader类:
using System.Collections.Generic;
using System.IO;
using OpenTK;
namespace GameProject.Game.Framework.ModelLoader {
public class WavefrontModelLoader {
public WavefrontModel LoadStream( Stream stream ) {
StreamReader reader = new StreamReader( stream );
List<Vector3> points = new List<Vector3>();
List<Vector3> normals = new List<Vector3>();
List<Vector2> texCoords = new List<Vector2>();
List<int> indices = new List<int>();
List<Face> faces = new List<Face>();
string line;
char[] splitChars = { ' ' };
while( ( line = reader.ReadLine() ) != null ) {
line = line.Trim( splitChars );
line = line.Replace( " " , " " );
string[] parameters = line.Split( splitChars );
switch( parameters[ 0 ] ) {
case "p": // Point
break;
case "v": // Vertex
float x = float.Parse( parameters[ 1 ] );
float y = float.Parse( parameters[ 2 ] );
float z = float.Parse( parameters[ 3 ] );
points.Add( new Vector3( x , y , z ) );
break;
case "vt": // TexCoord
float u = float.Parse( parameters[ 1 ] );
float v = float.Parse( parameters[ 2 ] );
texCoords.Add( new Vector2( u , v ) );
break;
case "vn": // Normal
float nx = float.Parse( parameters[ 1 ] );
float ny = float.Parse( parameters[ 2 ] );
float nz = float.Parse( parameters[ 3 ] );
normals.Add( new Vector3( nx , ny , nz ) );
break;
case "f":
faces.Add( parseFace( parameters ) );
break;
}
}
return new WavefrontModel(points,texCoords,normals,faces);
}
public WavefrontModel LoadFile( string file ) {
using( FileStream s = File.Open( file , FileMode.Open ) ) {
WavefrontModel mesh = LoadStream( s );
s.Close();
return mesh;
}
}
private static Face parseFace( string[] indices ) {
ModelVertex[] p = new ModelVertex[ indices.Length - 1 ];
for( int i = 0; i < p.Length; i++ ) {
p[ i ] = parsePoint( indices[ i + 1 ] );
}
return new Face( p );
}
private static ModelVertex parsePoint( string s ) {
char[] splitChars = { '/' };
string[] parameters = s.Split( splitChars );
int vert = int.Parse( parameters[ 0 ] ) - 1;
int tex = int.Parse( parameters[ 1 ] ) - 1;
int norm = int.Parse( parameters[ 2 ] ) - 1;
return new ModelVertex( vert , norm , tex );
}
}
}
我的模型是这样加载的:
rockMesh = new WavefrontModel( "C:/Users/Krynn/Desktop/RockModel/untitled.obj" );
并像这样渲染:
private void DrawMesh(WavefrontModel m) {
GL.Enable( EnableCap.Texture2D );
GL.BindTexture( TextureTarget.Texture2D , rockTexture.GetID() );
GL.Begin( BeginMode.Triangles );
foreach( Face f in m.Faces ) {
foreach( ModelVertex p in f.Points ) {
Vector3 v = m.Vertices[ p.Vertex ];
Vector3 n = m.Normals[ p.Normal ];
Vector2 tc = m.TexCoords[ p.TexCoord ];
GL.Vertex3( v.X , v.Y , v.Z );
GL.Normal3( n.X , n.Y , n.Z );
GL.TexCoord2( tc.Y , tc.X );
}
}
GL.End();
}
这是Blender生成的模型,我注意到“ vt”不是1.0和0.0,这可能是问题吗?
# Blender v2.71 (sub 0) OBJ File: 'untitled.blend'
# www.blender.org
mtllib untitled.mtl
o Cube_Cube.001
v -0.872541 -0.208332 -0.514779
v -0.872541 -0.208332 -2.514779
v 1.127459 -0.208332 -2.514779
v 1.127459 -0.208332 -0.514779
v -0.872541 1.791668 -0.514779
v -0.872541 1.791668 -2.514779
v 1.127459 1.791668 -2.514779
v 1.127459 1.791668 -0.514779
vt 0.999900 0.000100
vt 0.999900 0.999900
vt 0.000100 0.999900
vt 0.000100 0.000100
vn -1.000000 0.000000 0.000000
vn 0.000000 0.000000 -1.000000
vn 1.000000 0.000000 0.000000
vn 0.000000 0.000000 1.000000
vn 0.000000 -1.000000 0.000000
vn 0.000000 1.000000 0.000000
usemtl None
s off
f 6/1/1 2/2/1 1/3/1
f 7/1/2 3/2/2 2/3/2
f 8/3/3 4/4/3 3/1/3
f 5/3/4 1/4/4 4/1/4
f 2/4/5 3/1/5 4/2/5
f 7/2/6 6/3/6 5/4/6
f 5/4/1 6/1/1 1/3/1
f 6/4/2 7/1/2 2/3/2
f 7/2/3 8/3/3 3/1/3
f 8/2/4 5/3/4 4/1/4
f 1/3/5 2/4/5 4/2/5
f 8/1/6 7/2/6 5/4/6
另外,这是我的Texture类:
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using OpenTK.Graphics.OpenGL;
using System.Drawing.Imaging;
namespace GameProject.Game.Framework {
public class Texture {
private int textureID;
public Texture( string texturePath ) {
Load( texturePath );
}
public Texture( Bitmap texture ) {
LoadInternal( texture );
}
private void LoadInternal( Bitmap bitmap ) {
GL.Enable( EnableCap.Texture2D );
GL.Hint( HintTarget.PerspectiveCorrectionHint , HintMode.Nicest );
GL.GenTextures( 1 , out textureID );
GL.BindTexture( TextureTarget.Texture2D , textureID );
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 ,
OpenTK.Graphics.OpenGL.PixelFormat.Bgra , PixelType.UnsignedByte , data.Scan0 );
bitmap.UnlockBits( data );
GL.BindTexture( TextureTarget.Texture2D , 0 );
}
public int GetID() {
return textureID;
}
private void Load( string texturePath ) {
GL.Enable( EnableCap.Texture2D );
if( System.IO.File.Exists( texturePath ) ) {
GL.Enable( EnableCap.Texture2D );
Bitmap bitmap = new Bitmap( texturePath );
GL.Hint( HintTarget.PerspectiveCorrectionHint , HintMode.Nicest );
GL.GenTextures( 1 , out textureID );
GL.BindTexture( TextureTarget.Texture2D , textureID );
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 ,
OpenTK.Graphics.OpenGL.PixelFormat.Bgra , PixelType.UnsignedByte , data.Scan0 );
bitmap.UnlockBits( data );
}
}
}
}
关卡中没有其他硬编码的几何图形存在此问题。 几何本身也是几千个体素。 除模型外的所有物体都具有正确的纹理坐标。
在旧版OpenGL中使用即时模式, glVertex*()
调用使用当时设置的其他顶点属性(例如法线,颜色)的值来发布新顶点。
在发布的代码中,调用的顺序是这样的:
GL.Vertex3( v.X , v.Y , v.Z );
GL.Normal3( n.X , n.Y , n.Z );
GL.TexCoord2( tc.Y , tc.X );
由于Vertex3
调用Vertex3
,因此它将使用最近设置的法线和纹理坐标,它们是前一个顶点的值。 然后, Normal3
和TexCoord2
调用将更改这些属性的当前值,但是新值将仅在下一个Vertex3()
调用中使用。
要为此顶点使用指定的法线和纹理坐标,必须将Vertex3()
调用保持在最后:
GL.Normal3( n.X , n.Y , n.Z );
GL.TexCoord2( tc.Y , tc.X );
GL.Vertex3( v.X , v.Y , v.Z );
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.