gpt4 book ai didi

c# - 加载模型时出现奇怪的 OpenGL 纹理坐标

转载 作者:太空宇宙 更新时间:2023-11-03 21:28:01 28 4
gpt4 key购买 nike

我决定在我的 OpenTK C# 游戏中实现一个模型加载器;除了纹理坐标完全奇怪之外,它渲染得很好。我使用的代码是我在 Internet 上找到的 OpenTK 模型加载器的略微修改版本。我曾尝试在 blender 中对我的模型进行紫外线展开,但结果似乎总是一团糟。

这是我的模型在 Blender 中的样子:

enter image description here

这是它在我的游戏中的样子:

enter image description here

这是我的 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

此外,这是我的纹理类:

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 调用先进行,它将使用最近设置的法线和纹理坐标,它们是前一个顶点的值。 Normal3TexCoord2 调用将更改这些属性的当前值,但新值将仅用于下一个 Vertex3()打电话。

要为这个 顶点使用指定的法线和纹理坐标,Vertex3() 调用需要放在最后:

GL.Normal3( n.X , n.Y , n.Z );
GL.TexCoord2( tc.Y , tc.X );
GL.Vertex3( v.X , v.Y , v.Z );

关于c# - 加载模型时出现奇怪的 OpenGL 纹理坐标,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25836774/

28 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com