# Configuring projection matrix and getting textures to show up...

This topic is 2589 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

## Recommended Posts

[color="#4A4A4A"]I'm new to 3D-rendering and have finally figured out how to render meshes, but I cannot for the life of me figure out how to render the meshes upright! Right now they are rendered sideways. I also can't figure out how to get textures to show up, even though I've called mSimpleEffect.EnableDefaultLighting();
Any help is greatly appreciated!

[color="#4a4a4a"]
 using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Text; using System.Windows.Forms; using XNA = Microsoft.Xna.Framework; using Microsoft.Xna.Framework; using Microsoft.Xna.Framework.Graphics; namespace XNAWinForms { /// <summary> /// Windows form that inherits from XNAWinForms and adds the rendering of a simple rotating triangle /// /// Author: Iñaki Ayucar (http://graphicdna.blogspot.com) /// Date: 14/11/2007 /// /// This software is distributed "for free" for any non-commercial usage. The software is provided “as-is.” /// You bear the risk of using it. The contributors give no express warranties, guarantees or conditions. /// </summary> public partial class Form1 : XNAWinForm { private Mesh m_CurrentMesh; private Texture2D m_Tex; bool m_LoadComplete = false; private float mRotation = 0f; private Matrix mViewMat, mWorldMat, mProjectionMat; private BasicEffect mSimpleEffect; VertexPositionColor[] triVerts = new VertexPositionColor[] { new VertexPositionColor(Vector3.Zero*2, Microsoft.Xna.Framework.Graphics.Color.Blue), new VertexPositionColor(Vector3.Right*2, Microsoft.Xna.Framework.Graphics.Color.Green), new VertexPositionColor(Vector3.Up*2, Microsoft.Xna.Framework.Graphics.Color.Red)}; private VertexPositionNormalTexture[] m_NormVerticies; /// <summary> /// /// </summary> public Form1() { InitializeComponent(); this.DeviceResetting += new XNAWinForm.EmptyEventHandler(mWinForm_DeviceResetting); this.DeviceReset += new XNAWinForm.GraphicsDeviceDelegate(mWinForm_DeviceReset); this.OnFrameRender += new XNAWinForm.GraphicsDeviceDelegate(mWinForm_OnFrameRender); this.OnFrameMove += new GraphicsDeviceDelegate(Form1_OnFrameMove); mViewMat = mWorldMat = mProjectionMat = Matrix.Identity; } /// <summary> /// /// </summary> /// <param name="pDevice"></param> void Form1_OnFrameMove(Microsoft.Xna.Framework.Graphics.GraphicsDevice pDevice) { mRotation += 0.05f; this.mWorldMat = Matrix.CreateRotationY(mRotation); } /// <summary> /// /// </summary> /// <param name="pDevice"></param> void mWinForm_OnFrameRender(GraphicsDevice pDevice) { // Configure effect mSimpleEffect.World = this.mWorldMat; mSimpleEffect.View = this.mViewMat; mSimpleEffect.Projection = this.mProjectionMat; mSimpleEffect.DiffuseColor = XNA.Graphics.Color.DarkRed.ToVector3(); if (m_Tex != null) { mSimpleEffect.Texture = m_Tex; mSimpleEffect.TextureEnabled = true; mSimpleEffect.EnableDefaultLighting(); } mSimpleEffect.CommitChanges(); // Draw mSimpleEffect.Begin(); mSimpleEffect.Techniques[0].Passes[0].Begin(); /*pDevice.DrawUserPrimitives<VertexPositionColor>(PrimitiveType.TriangleList, triVerts, 0, 1);*/ if (m_NormVerticies != null) { if (m_LoadComplete) { foreach (Face Fce in m_CurrentMesh.Faces) { VertexPositionNormalTexture[] Vertex = new VertexPositionNormalTexture[3]; Vertex[0] = m_NormVerticies[Fce.AVertexIndex]; Vertex[1] = m_NormVerticies[Fce.BVertexIndex]; Vertex[2] = m_NormVerticies[Fce.CVertexIndex]; pDevice.DrawUserPrimitives<VertexPositionNormalTexture>(PrimitiveType.TriangleList, Vertex, 0, 1); } } } mSimpleEffect.Techniques[0].Passes[0].End(); mSimpleEffect.End(); } /// <summary> /// /// </summary> /// <param name="pDevice"></param> void mWinForm_DeviceReset(GraphicsDevice pDevice) { // Re-Create effect mSimpleEffect = new BasicEffect(pDevice, null); // Configure device pDevice.VertexDeclaration = new VertexDeclaration(pDevice, VertexPositionColor.VertexElements); pDevice.RenderState.CullMode = CullMode.None; // Create camera and projection matrix mWorldMat = Matrix.Identity; mViewMat = Matrix.CreateLookAt(Vector3.Backward * 10,Vector3.Zero, Vector3.Up); mProjectionMat = Matrix.CreatePerspectiveFieldOfView(MathHelper.Pi / 4.0f, (float)pDevice.PresentationParameters.BackBufferWidth / (float)pDevice.PresentationParameters.BackBufferHeight, 1.0f, 100.0f); } /// <summary> /// /// </summary> void mWinForm_DeviceResetting() { // Dispose all if (mSimpleEffect != null) mSimpleEffect.Dispose(); } private void openToolStripMenuItem_Click(object sender, EventArgs e) { OpenFileDialog OpenFDiag = new OpenFileDialog(); OpenFDiag.Filter = "Mesh file|*.mesh"; OpenFDiag.Title = "Select a mesh to open..."; if (OpenFDiag.ShowDialog() == DialogResult.OK) { m_CurrentMesh = new Mesh(OpenFDiag.FileName); m_NormVerticies = new VertexPositionNormalTexture[m_CurrentMesh.VertexCount]; for (int i = 0; i < m_CurrentMesh.VertexCount; i++) { m_NormVerticies = new VertexPositionNormalTexture(); m_NormVerticies.Position.X = m_CurrentMesh.VertexData[i, 0]; m_NormVerticies.Position.Y = m_CurrentMesh.VertexData[i, 1]; m_NormVerticies.Position.Z = m_CurrentMesh.VertexData[i, 2]; m_NormVerticies.Normal.X = m_CurrentMesh.VertexData[i, 3]; m_NormVerticies.Normal.Y = m_CurrentMesh.VertexData[i, 4]; m_NormVerticies.Normal.Z = m_CurrentMesh.VertexData[i, 5]; //Not really sure why this is important, but I think it has something to do //with being able to see the texture. m_NormVerticies.Normal.Normalize(); } for (int i = 0; i < m_CurrentMesh.TexVertexCount; i++) { m_NormVerticies.TextureCoordinate.X = m_CurrentMesh.TextureVertData[i, 0]; m_NormVerticies.TextureCoordinate.X = m_CurrentMesh.TextureVertData[i, 1]; } string TextureName = OpenFDiag.FileName.Replace("meshes", "textures").Replace("mesh", "jpg"). Replace("fah", "").Replace("fa", "falgt").Replace("-head-head", ""); m_Tex = Texture2D.FromFile(this.Device, TextureName); m_LoadComplete = true; } } private void exitToolStripMenuItem_Click(object sender, EventArgs e) { Application.Exit(); } } }
[font="courier new"] [/font]
[font="courier new"] [/font]
The above code is based on an example I found showing how to use XNA in Windows Forms. If anyone has a better example, feel free to show it. The main thing is that it would be neat to get textures to work and to be able to rotate the mesh correctly.

##### Share on other sites
Ok so I looked over the code again and realized I had made a mistake:

 for (int i = 0; i < m_CurrentMesh.TexVertexCount; i++) { m_NormVerticies.TextureCoordinate.X = m_CurrentMesh.TextureVertData[i, 1]; m_NormVerticies.TextureCoordinate.X = m_CurrentMesh.TextureVertData[i, 2]; }

I changed it to:

 for (int i = 0; i < m_CurrentMesh.TexVertexCount; i++) { m_NormVerticies.TextureCoordinate.X = m_CurrentMesh.TextureVertData[i, 1]; m_NormVerticies.TextureCoordinate.Y = m_CurrentMesh.TextureVertData[i, 2]; }

Then I added three lines in the main drawing loop:

 if (m_NormVerticies != null) { if (m_LoadComplete) { foreach (Face Fce in m_CurrentMesh.Faces) { VertexPositionNormalTexture[] Vertex = new VertexPositionNormalTexture[3]; Vertex[0] = m_NormVerticies[Fce.AVertexIndex]; Vertex[1] = m_NormVerticies[Fce.BVertexIndex]; Vertex[2] = m_NormVerticies[Fce.CVertexIndex]; Vertex[0].TextureCoordinate = m_NormVerticies[Fce.AVertexIndex].TextureCoordinate; Vertex[1].TextureCoordinate = m_NormVerticies[Fce.BVertexIndex].TextureCoordinate; Vertex[2].TextureCoordinate = m_NormVerticies[Fce.CVertexIndex].TextureCoordinate; pDevice.DrawUserPrimitives<VertexPositionNormalTexture>(PrimitiveType.TriangleList, Vertex, 0, 1); } } }

##### Share on other sites
You're setting the wrong vertex declaration, one that does not have a texcoord. Not sure if that's your only problem, cause normally a shader expecting texcoords should fail if they're not provided, but probably XNA captures that.

Additional note: Is there a reason you draw each triangle individually ? This is quite slow. At least batch them into the same draw call.

And: Are you familiar with PIX, the DirectX debugging tool ? It's very useful to track down such bugs.

##### Share on other sites
VertexPositionNormalTexture has a texture coordinate!

##### Share on other sites
Your vertex struct, yes, but I meant this:

 pDevice.VertexDeclaration = new VertexDeclaration(pDevice, VertexPositionColor.VertexElements); 
From the DX 9 API side, the declaration is the key, how you define your vertex struct is just for your convenience. Not sure how XNA handles all that exactly, namely if the DrawUserPrimitives has some automatic in this regard. Its documentation let me suspect you have to set the declaration manually, though.

If your declaration is wrong, you get artifacts, mostly. From your description that's the (only?) thing I could spot in your code. I could be wrong, sure, or there could be more problems, but try:

 pDevice.VertexDeclaration = new VertexDeclaration(pDevice, VertexPositionNormalTexture.VertexElements); 
and make sure it gets called (with a breakpoint), or even better set it before you begin your effect.

Edit: Sorry, totally missed your "upright" problem. Don't change the projection, but the view: Change the last parameter of CreateLookAt, cameraUpVector. This is the "up" of your scene/mesh. Or alternatively give your world matrix a fixed 90-degree rotation.

##### Share on other sites
Thanks, I managed to get textures to show up now, although they look a bit weird.
There's probably something wrong with my rendering.

And as for changing the view, it worked!

I changed the last parameter to Vector3.Right, and then I changed

this.mWorldMat = Matrix.CreateRotationY(mRotation);

to:

this.mWorldMat = Matrix.CreateRotationX(mRotation);

##### Share on other sites
Can someone please explain to me what a vertex-blend is? I've figured that it isn't like alpha blending, but I haven't been able to find any reliable information on what it is and how to do it!
Right now I'm trying to figure out how to render body meshes correctly. Each mesh contains a number of indexes of verticies to be blended. I've figured out how to do transformations, I'm doing them as such:

 //The file selected was most likely a body-mesh, so apply the adult skeleton to it. if (Pair.Value.Contains("bodies")) { foreach (Bone Bne in m_Skeleton.Bones) { foreach (BoneBinding Bnd in m_CurrentMesh.BoneBindings) { if (Bne.ID == Bnd.BoneIndex) { VertexPositionNormalTexture[] VerticiesToBeTransformed = new VertexPositionNormalTexture[Bnd.VertexCount]; int Counter = 0; for (int i = Bnd.FirstVertex; i < Bnd.VertexCount; i++) { VerticiesToBeTransformed[Counter] = m_NormVerticies; Vector3 TransformedVector = Vector3.Transform( VerticiesToBeTransformed[Counter].Position, new Quaternion(Bne.Quaternions[0], Bne.Quaternions[1], Bne.Quaternions[2], Bne.Quaternions[3])); m_NormVerticies.Position = TransformedVector; Counter++; } } } } }

I still need to apply the blending operation(s) though!

If anyone's wondering, here's the code for loading a mesh (which also shows how the blend data is loaded):

using System; using System.Collections.Generic; using System.Text; using System.IO; using System.Windows.Forms; namespace XNAWinForms { public struct Face { public int AVertexIndex, BVertexIndex, CVertexIndex; } public struct BoneBinding { public int BoneIndex, FirstVertex, VertexCount, FirstBlendedVert, BlendedVertexCount; } public struct BlendData { public int WeightFixed, OtherVertexIndex; } class Mesh { private static int m_Version = 0; private int m_BoneCount = 0; private List<string> m_BoneNames = new List<string>(); private int m_FaceCount = 0; private Face[] m_Faces; private int m_BndCount = 0; //private int[,] m_BoneBindings; private List<BoneBinding> m_BoneBindings = new List<BoneBinding>(); private int m_NumTexVerticies = 0; private Single[,] m_TexVerticies; private int m_BlendCount = 0; //private int[,] m_BlendData; private List<BlendData> m_BlendData = new List<BlendData>(); private int m_VertexCount = 0; private Single[,] m_VertexData; public int TexVertexCount { get { return m_NumTexVerticies; } } /// <summary> /// Number of verticies in this mesh. /// </summary> public int VertexCount { get { return m_VertexCount; } } public Single[,] VertexData { get { return m_VertexData; } } public Single[,] TextureVertData { get { return m_TexVerticies; } } /// <summary> /// Number of faces in this mesh. /// </summary> public int FaceCount { get { return m_FaceCount; } } /// <summary> /// The faces of this mesh. /// </summary> public Face[] Faces { get { return m_Faces; } } /// <summary> /// The bonebindings associated with this mesh. /// </summary> public List<BoneBinding> BoneBindings { get { return m_BoneBindings; } } public Mesh(string Path) { BinaryReader Reader = new BinaryReader(File.Open(Path, FileMode.Open)); m_Version = Endian.SwapInt32(Reader.ReadInt32()); m_BoneCount = Endian.SwapInt32(Reader.ReadInt32()); for (int i = 0; i < m_BoneCount; i++) { byte StrLen = Reader.ReadByte(); string BoneName = Encoding.ASCII.GetString(Reader.ReadBytes(StrLen)); m_BoneNames.Add(BoneName); } m_FaceCount = Endian.SwapInt32(Reader.ReadInt32()); m_Faces = new Face[m_FaceCount]; for (int i = 0; i < m_FaceCount; i++) { m_Faces.AVertexIndex = Endian.SwapInt32(Reader.ReadInt32()); m_Faces.BVertexIndex = Endian.SwapInt32(Reader.ReadInt32()); m_Faces.CVertexIndex = Endian.SwapInt32(Reader.ReadInt32()); } m_BndCount = Endian.SwapInt32(Reader.ReadInt32()); /*m_BoneBindings = new int[m_BndCount, 5]; for (int i = 0; i < m_BndCount; i++) for (int j = 0; j < 5; j++) m_BoneBindings[i, j] = Endian.SwapInt32(Reader.ReadInt32());*/ for (int i = 0; i < m_BndCount; i++) { BoneBinding Binding = new BoneBinding(); Binding.BoneIndex = Endian.SwapInt32(Reader.ReadInt32()); Binding.FirstVertex = Endian.SwapInt32(Reader.ReadInt32()); Binding.VertexCount = Endian.SwapInt32(Reader.ReadInt32()); Binding.FirstBlendedVert = Endian.SwapInt32(Reader.ReadInt32()); Binding.BlendedVertexCount = Endian.SwapInt32(Reader.ReadInt32()); m_BoneBindings.Add(Binding); } m_NumTexVerticies = Endian.SwapInt32(Reader.ReadInt32()); m_TexVerticies = new Single[m_NumTexVerticies, 3]; switch (m_Version) { case 0: for (int i = 0; i < m_NumTexVerticies; i++) { //These coordinates aren't reversed, and the Endian class //doesn't support swapping Single values, so do it manually... m_TexVerticies[i, 0] = i; byte[] XOffset = Reader.ReadBytes(4); byte[] YOffset = Reader.ReadBytes(4); Array.Reverse(XOffset); Array.Reverse(YOffset); m_TexVerticies[i, 1] = BitConverter.ToSingle(XOffset, 0); m_TexVerticies[i, 2] = BitConverter.ToSingle(YOffset, 0); } break; default: for (int i = 0; i < m_NumTexVerticies; i++) { m_TexVerticies[i, 0] = i; m_TexVerticies[i, 1] = Reader.ReadSingle(); //X offset m_TexVerticies[i, 2] = Reader.ReadSingle(); //Y offset } break; } m_BlendCount = Endian.SwapInt32(Reader.ReadInt32()); /*m_BlendData = new int[m_BlendCount, 2]; for (int i = 0; i < m_BlendCount; i++) { m_BlendData[i, 1] = Endian.SwapInt32(Reader.ReadInt32()); m_BlendData[i, 0] = Endian.SwapInt32(Reader.ReadInt32()); }*/ for (int i = 0; i < m_BlendCount; i++) { BlendData Blend = new BlendData(); Blend.WeightFixed = Endian.SwapInt32(Reader.ReadInt32()); Blend.OtherVertexIndex = Endian.SwapInt32(Reader.ReadInt32()); m_BlendData.Add(Blend); } m_VertexCount = Endian.SwapInt32(Reader.ReadInt32()); m_VertexData = new Single[m_VertexCount, 7]; switch (m_Version) { case 0: for (int i = 0; i < m_VertexCount; i++) { m_VertexData[i, 0] = i; for (int j = 0; j < 6; j++) m_VertexData[i, j] = Reader.ReadSingle(); } break; default: for (int i = 0; i < m_VertexCount; i++) { m_VertexData[i, 0] = i; //These coordinates are apparently reversed, but since the file is Big-Endian, //and the default is reading Little-Endian, there should be no need to convert... for (int j = 0; j < 6; j++) m_VertexData[i, j] = Reader.ReadSingle(); } break; } } public Mesh(byte[] FileData) { MemoryStream MemStream = new MemoryStream(FileData); BinaryReader Reader = new BinaryReader(MemStream); m_Version = Endian.SwapInt32(Reader.ReadInt32()); m_BoneCount = Endian.SwapInt32(Reader.ReadInt32()); for (int i = 0; i < m_BoneCount; i++) { byte StrLen = Reader.ReadByte(); string BoneName = Encoding.ASCII.GetString(Reader.ReadBytes(StrLen)); m_BoneNames.Add(BoneName); } m_FaceCount = Endian.SwapInt32(Reader.ReadInt32()); m_Faces = new Face[m_FaceCount]; for (int i = 0; i < m_FaceCount; i++) { m_Faces.AVertexIndex = Endian.SwapInt32(Reader.ReadInt32()); m_Faces.BVertexIndex = Endian.SwapInt32(Reader.ReadInt32()); m_Faces.CVertexIndex = Endian.SwapInt32(Reader.ReadInt32()); } m_BndCount = Endian.SwapInt32(Reader.ReadInt32()); /*m_BoneBindings = new int[m_BndCount, 5]; for (int i = 0; i < m_BndCount; i++) for (int j = 0; j < 5; j++) m_BoneBindings[i, j] = Endian.SwapInt32(Reader.ReadInt32());*/ for (int i = 0; i < m_BndCount; i++) { BoneBinding Binding = new BoneBinding(); Binding.BoneIndex = Endian.SwapInt32(Reader.ReadInt32()); Binding.FirstVertex = Endian.SwapInt32(Reader.ReadInt32()); Binding.VertexCount = Endian.SwapInt32(Reader.ReadInt32()); Binding.FirstBlendedVert = Endian.SwapInt32(Reader.ReadInt32()); Binding.BlendedVertexCount = Endian.SwapInt32(Reader.ReadInt32()); m_BoneBindings.Add(Binding); } m_NumTexVerticies = Endian.SwapInt32(Reader.ReadInt32()); m_TexVerticies = new Single[m_NumTexVerticies, 3]; switch (m_Version) { case 0: for (int i = 0; i < m_NumTexVerticies; i++) { //These coordinates aren't reversed, and the Endian class //doesn't support swapping Single values, so do it manually... m_TexVerticies[i, 0] = i; byte[] XOffset = Reader.ReadBytes(4); byte[] YOffset = Reader.ReadBytes(4); Array.Reverse(XOffset); Array.Reverse(YOffset); m_TexVerticies[i, 1] = BitConverter.ToSingle(XOffset, 0); m_TexVerticies[i, 2] = BitConverter.ToSingle(YOffset, 0); } break; default: for (int i = 0; i < m_NumTexVerticies; i++) { m_TexVerticies[i, 0] = i; m_TexVerticies[i, 1] = Reader.ReadSingle(); //X offset m_TexVerticies[i, 2] = Reader.ReadSingle(); //Y offset } break; } m_BlendCount = Endian.SwapInt32(Reader.ReadInt32()); /*m_BlendData = new int[m_BlendCount, 2]; for (int i = 0; i < m_BlendCount; i++) { m_BlendData[i, 1] = Endian.SwapInt32(Reader.ReadInt32()); m_BlendData[i, 0] = Endian.SwapInt32(Reader.ReadInt32()); }*/ for (int i = 0; i < m_BlendCount; i++) { BlendData Blend = new BlendData(); Blend.WeightFixed = Endian.SwapInt32(Reader.ReadInt32()); Blend.OtherVertexIndex = Endian.SwapInt32(Reader.ReadInt32()); m_BlendData.Add(Blend); } m_VertexCount = Endian.SwapInt32(Reader.ReadInt32()); m_VertexData = new Single[m_VertexCount, 7]; switch (m_Version) { case 0: for (int i = 0; i < m_VertexCount; i++) { m_VertexData[i, 0] = i; for (int j = 0; j < 6; j++) m_VertexData[i, j] = Reader.ReadSingle(); } break; default: for (int i = 0; i < m_VertexCount; i++) { m_VertexData[i, 0] = i; //These coordinates are apparently reversed, but since the file is Big-Endian, //and the default is reading Little-Endian, there should be no need to convert... for (int j = 0; j < 6; j++) m_VertexData[i, j] = Reader.ReadSingle(); } break; } } } } 

1. 1
2. 2
Rutin
16
3. 3
4. 4
5. 5

• 26
• 11
• 9
• 9
• 11
• ### Forum Statistics

• Total Topics
633702
• Total Posts
3013452
×