Sign in to follow this  

Mesh single subset

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

If you intended to correct an error in the post then please contact us.

Recommended Posts

Maybe,

LPDIRECT3DINDEXBUFFER9 ib;
LPDIRECT3DVERTEXBUFFER9 vb;
mesh->GetIndexBuffer(&ib);
mesh->GetVertexBuffer(&vb);


and see this topic: Click

[Edited by - gymisi on December 20, 2005 2:13:05 AM]

Share this post


Link to post
Share on other sites
Before you can get an index buffer and vertex buffer for each subset you will need to know what a subset is. A subset is the division of a mesh into a set of data for each material used.
From the SDK Documentation
"It is divided into a subset for each material that was loaded for the mesh"
You could probably poke around in the mesh data for the information you are looking for and extracting the vertex and index data per subset. I am sure there are easier ways to do this but you'll have to wait for someone with more experience in the field to reply.

I hope this helps.
Take care.

Share this post


Link to post
Share on other sites
I don't have any experience with this myself, but a quick look at the docs reveals the ID3DXBaseMesh::GetAttributeTable method. This method gives you an array of D3DXATTRIBUTERANGE structs from which you can retrieve the vertex and face information you need to get the data out of the mesh buffers.

Share this post


Link to post
Share on other sites
A combination of what Armadon and remigius said is the only way I know of doing what you want.

You'll have to query the attribute table to get the details for the specific subset, then lock the vertex/index buffer and extract the data as indicated by the values you got from the attribute table.

If you want a VB/IB rather than just a list of vertices and indices then you'll have to create them and copy the data yourself.

hth
Jack

Share this post


Link to post
Share on other sites
Below an example of a code on C#:



Mesh Mesh00 = null; // Mesh Object
Material[] meshMaterials; // Material for each subset
Texture[] meshTextures; // Texture for each subset
IndexBuffer[] meshIndBuffs; // Index buffers for each subset
ExtendedMaterial[] materials = null; // Array of the expanded materials received from a x-file

// Load Mesh from a file
Mesh00 = Mesh.FromFile(@"Persons\aamSens00.X", MeshFlags.SystemMemory, ADevice, out materials);

// Allocate memory under materials
meshTextures = new Texture[ materials.Length ];
// Allocate memory under structures
meshMaterials = new Material[ materials.Length ];
// Allocate memory under IndexBuffers
meshIndBuffs = new IndexBuffer[ materials.Length ];

// For each subset
for( int i = 0; i < materials.Length; i++ )
{
// Write in a array a materials from the expanded materials
meshMaterials[i] = materials[i].Material3D;
// Write in a array an ambient colors for a materials
meshMaterials[i].Ambient = meshMaterials[i].Diffuse;
// If the subset has the texture
if (materials[i].TextureFilename != null)
// Load the texture
meshTextures[i] = TextureLoader.FromFile(ADevice, @"Persons\" + materials[i].TextureFilename);
else
meshTextures[i] = null;
// Write in a array the IndexBuffer
meshIndBuffs[i] = Mesh.ConvertMeshSubsetToSingleStrip(Mesh00, i, MeshFlags.SystemMemory, out NumIndices);
...
}




Call function ConvertMeshSubsetToSingleStrip for Mesh gives out error message InvalidCallException if mesh consist of several subsets and does not give out it, if mesh consist of one subset. I.e. the question is reduced to use of functions ConvertMeshSubsetToSingleStrip and ConvertMeshSubsetToStrips.
Whether there is other alternative, as in Managed DirectX for .Net 2.0 couple " ConvertMeshSubsetToSingleStrip/ToStrips - removed " as Tom Miller (<http://www.thezbuffer.com/articles/294.aspx>) informs us.

[Edited by - Maxim Skachkov on December 22, 2005 5:17:54 PM]

Share this post


Link to post
Share on other sites
Argh, couldn't you have posted that method earlier? :)

Below is my aproach, untested and made utterly redundant due to these methods in the MDX 1.1 API. Maybe it's still useful for creating a similar method for MDX 2.0, so here it is:

[source lang=c#]

private IndexBuffer[] indexBuffers;
private VertexBuffer[] vertexBuffers;

private void CreateSubsetBuffers(Mesh mesh)
{
// generate adjecency for optimization
int[] adj = new int[mesh.NumberFaces * 3];
mesh.GenerateAdjacency(0, adj);

// optimize as recommended by the docs
Mesh optimizedMesh = mesh.Optimize( MeshFlags.OptimizeAttributeSort, adj );

// get attribute ranges and init buffer arrays
AttributeRange[] ranges = optimizedMesh.GetAttributeTable();
indexBuffers = new IndexBuffer[ ranges.Length ];
vertexBuffers = new VertexBuffer[ ranges.Length ];

for(int i = 0; i < ranges.Length; i++)
{
// we'll use the ID as the array index, just to make sure
int id = ranges[i].AttributeId;

int vStart = ranges[i].VertexStart;
int vCount = ranges[i].VertexCount;

int fStart = ranges[i].FaceStart;
int fCount = ranges[i].FaceCount;

// convert face info to indices for use later
int iStart = 3 * fStart;
int iCount = 3 * fCount;

// create vertex buffer
int vertexSize = mesh.NumberBytesPerVertex;
vertexBuffers[ id ] = new VertexBuffer( mesh.Device, vCount * vertexSize, 0, mesh.VertexFormat, Pool.Default );

// get graphics streams
using (GraphicsStream meshStream = mesh.VertexBuffer.Lock( vStart * vertexSize, vCount * vertexSize, LockFlags.ReadOnly ) )
{
using (GraphicsStream subsetStream = vertexBuffers[ id ].Lock( 0, vCount * vertexSize, LockFlags.None ))
{
// create io buffer
byte[] buffer = new byte[vertexSize];

for (int v = 0; v < vCount; v++)
{
meshStream.Read( buffer, v * vertexSize, vertexSize );
subsetStream.Write( buffer, v * vertexSize, vertexSize );
}

subsetStream.Flush();
}
}

// size in bytes, 2 for shorts, 4 for ints (16/32 bit)
int indexSize = 2;
indexBuffers[ id ] = new IndexBuffer( mesh.Device, iCount * indexSize, 0, Pool.Default, indexSize == 2);

// get graphics streams
using (GraphicsStream meshStream = mesh.IndexBuffer.Lock( iStart * indexSize, iCount * indexSize, LockFlags.ReadOnly ))
{
using (GraphicsStream subsetStream = indexBuffers[ id ].Lock( 0, iCount * indexSize, LockFlags.None ))
{
// create io buffer
byte[] buffer = new byte[indexSize];

for (int j = 0; j < iCount; j++)
{
meshStream.Read( buffer, j * indexSize, indexSize );
subsetStream.Write( buffer, j * indexSize, indexSize );
}

subsetStream.Flush();
}
}
}
}



Share this post


Link to post
Share on other sites
byte[] buffer = new byte[vertexSize];
for (int v = 0; v < vCount; v++)
{
meshStream.Read( buffer, v * vertexSize, vertexSize );
subsetStream.Write( buffer, v * vertexSize, vertexSize );
}


gives an error about the array???
I can not find why?

Share this post


Link to post
Share on other sites
Quote:
Original post by Armadon
Before you can get an index buffer and vertex buffer for each subset you will need to know what a subset is. A subset is the division of a mesh into a set of data for each material used.
From the SDK Documentation
"It is divided into a subset for each material that was loaded for the mesh"
You could probably poke around in the mesh data for the information you are looking for and extracting the vertex and index data per subset. I am sure there are easier ways to do this but you'll have to wait for someone with more experience in the field to reply.

I hope this helps.
Take care.


Pieter!
One week ago I completely saw your site and blog, downloaded tutorials. Today I registered on this site and it was a surprise for me to meet you there and that you answered my question.
Example Normal Mapping was useful to us. As to this example - in Render Monkey 1.6 is shader, allows you to create normal maps effect from texture.

Share this post


Link to post
Share on other sites
Quote:
Original post by Maxim Skachkov
remigius!

Thanks for the first post - it was a key ! And for example. Now I use MDX 1.1 API.


Good to see it helped. Would you mind posting some code? I went to investigate this further for TheMaskedFace, but I can't get it to work properly for myself :)

Basically I've split up the mesh into vertex and index buffers, but I'm rather confused about the large amount of vertices that seem to be assigned for each attribute range. So, if you could clear things up in turn, that'd be great!

Share this post


Link to post
Share on other sites
Quote:
Original post by remigius

Would you mind posting some code? I went to investigate this further for TheMaskedFace, but I can't get it to work properly for myself :)



My code (unit):


using System;
using Microsoft.DirectX;
using Microsoft.DirectX.Direct3D;
using Microsoft.Samples.DirectX.UtilityToolkit;

namespace Main
{
/// <summary>
/// Summary description for Gynecology.
/// </summary>
public class Andrology
{
VertexBuffer MeshVB = null;
IndexBuffer MeshIB = null;
Mesh Mesh00 = null;
Mesh Mesh01 = null;
Mesh Mesh02 = null;
VertexBuffer VB00 = null;
VertexBuffer VB01 = null;
VertexBuffer VB02 = null;
IndexBuffer IB = null;

Effect effect = null;

EffectHandle WorldViewProjHandle = null; // Effect Handle for the 'world view Proj' matrix
EffectHandle WorldHandle = null; // Effect Handle for the 'world view Proj' matrix
EffectHandle WeightHandle = null;
EffectHandle LightPosHandle = null;
// EffectHandle TextureHandle = null;

int VerticesNum;
int FacesNum;

Texture MeshTexture = null;

VertexDeclaration VertDecl = null;

Material[] meshMaterials;
Texture[] meshTextures;
IndexBuffer[] meshIndBuffs;
AttributeRange[] attributeTable;

double KickFreq;
double Phase;
double BlendWeight;

Vector4 Weight;

public Andrology()
{

}

void Load (Device ADevice)
{
Mesh MeshTemp = null;
int NumIndices;
int[] adjacency;

MeshTexture = TextureLoader.FromFile(ADevice, @"Persons\Gynecology.bmp");

ExtendedMaterial[] materials = null;
Mesh00 = Mesh.FromFile(@"Persons\kadr00.X", MeshFlags.Managed, ADevice, out materials);

MeshTemp = Mesh00.Clone( Mesh00.Options.Value, VertexFormats.Position | VertexFormats.Normal | VertexFormats.Texture1, ADevice );
MeshTemp.ComputeNormals();
Mesh00.Dispose();
Mesh00 = MeshTemp;

adjacency = new int[3 * Mesh00.NumberFaces];
Mesh00.GenerateAdjacency( 0.01f, adjacency );
Mesh00.OptimizeInPlace( MeshFlags.OptimizeAttributeSort, adjacency );

attributeTable = Mesh00.GetAttributeTable();

meshTextures = new Texture[ materials.Length ];
meshMaterials = new Material[ materials.Length ];
meshIndBuffs = new IndexBuffer[ materials.Length ];
//meshEffect = new Effect[materials.Length];
for( int i = 0; i < materials.Length; i++ )
{
meshMaterials[i] = materials[i].Material3D;
meshMaterials[i].Ambient = meshMaterials[i].Diffuse;
if (materials[i].TextureFilename != null)
meshTextures[i] = TextureLoader.FromFile(ADevice, @"Persons\" + materials[i].TextureFilename);
else
meshTextures[i] = null;
}

Mesh01 = Mesh.FromFile(@"Persons\kadr01.X", MeshFlags.Managed, ADevice, out materials);

MeshTemp = Mesh01.Clone( Mesh00.Options.Value, VertexFormats.Position | VertexFormats.Normal | VertexFormats.Texture1, ADevice );
MeshTemp.ComputeNormals();
Mesh01.Dispose();
Mesh01 = MeshTemp;

adjacency = new int[3 * Mesh01.NumberFaces];
Mesh01.GenerateAdjacency( 0.01f, adjacency );
Mesh01.OptimizeInPlace( MeshFlags.OptimizeAttributeSort, adjacency );


Mesh02 = Mesh.FromFile(@"Persons\kadr02.X", MeshFlags.Managed, ADevice, out materials);

MeshTemp = Mesh02.Clone( Mesh00.Options.Value, VertexFormats.Position | VertexFormats.Normal | VertexFormats.Texture1, ADevice );
MeshTemp.ComputeNormals();
Mesh02.Dispose();
Mesh02 = MeshTemp;

adjacency = new int[3 * Mesh02.NumberFaces];
Mesh02.GenerateAdjacency( 0.01f, adjacency );
Mesh02.OptimizeInPlace( MeshFlags.OptimizeAttributeSort, adjacency );

VerticesNum = Mesh00.NumberVertices;
FacesNum = Mesh00.NumberFaces;

VB00 = new VertexBuffer(typeof(CustomVertex.PositionNormalTextured), VerticesNum, ADevice,
Usage.WriteOnly, CustomVertex.PositionNormalTextured.Format, Pool.Managed);
VB01 = new VertexBuffer(typeof(CustomVertex.PositionNormalTextured), VerticesNum, ADevice,
Usage.WriteOnly, CustomVertex.PositionNormalTextured.Format, Pool.Managed);
VB02 = new VertexBuffer(typeof(CustomVertex.PositionNormalTextured), VerticesNum, ADevice,
Usage.WriteOnly, CustomVertex.PositionNormalTextured.Format, Pool.Managed);

IB = new IndexBuffer(typeof(ushort), FacesNum * 3, ADevice, Usage.WriteOnly, Pool.Default);


CustomVertex.PositionNormalTextured[] Buff = null;
CustomVertex.PositionNormalTextured[] BuffNew = null;

// Copy vertices for mesh 00
Buff = (CustomVertex.PositionNormalTextured[])Mesh00.LockVertexBuffer(typeof(CustomVertex.PositionNormalTextured), LockFlags.None, VerticesNum);
BuffNew = (CustomVertex.PositionNormalTextured[])VB00.Lock(0,0);
Array.Copy(Buff, BuffNew, Buff.Length );
VB00.Unlock();
Mesh00.UnlockVertexBuffer();

// Copy vertices for mesh 01
Buff = (CustomVertex.PositionNormalTextured[])Mesh01.LockVertexBuffer(typeof(CustomVertex.PositionNormalTextured), LockFlags.None, VerticesNum);
BuffNew = (CustomVertex.PositionNormalTextured[])VB01.Lock(0,0);
Array.Copy(Buff, BuffNew, Buff.Length );
VB01.Unlock();
Mesh01.UnlockVertexBuffer();

// Copy vertices for mesh 03
Buff = (CustomVertex.PositionNormalTextured[])Mesh02.LockVertexBuffer(typeof(CustomVertex.PositionNormalTextured), LockFlags.None, VerticesNum);
BuffNew = (CustomVertex.PositionNormalTextured[])VB02.Lock(0,0);
Array.Copy(Buff, BuffNew, Buff.Length );
VB02.Unlock();
Mesh02.UnlockVertexBuffer();


ushort[] ib;

// Copy indices for the dolphin mesh
ib = (ushort[])Mesh00.LockIndexBuffer(typeof(ushort), LockFlags.None, FacesNum * 3);
IB.SetData(ib, 0, LockFlags.None);
Mesh00.UnlockIndexBuffer();

// Create vertex shader for the
// Create the vertex element array.
VertexElement[] elements = new VertexElement[]
{
// First stream is first mesh
new VertexElement(0, 0, DeclarationType.Float3, DeclarationMethod.Default, DeclarationUsage.Position, 0),
new VertexElement(0, 12, DeclarationType.Float3, DeclarationMethod.Default, DeclarationUsage.Normal, 0),
new VertexElement(0, 24, DeclarationType.Float2, DeclarationMethod.Default, DeclarationUsage.TextureCoordinate, 0),
// Second stream is second mesh
new VertexElement(1, 0, DeclarationType.Float3, DeclarationMethod.Default, DeclarationUsage.Position, 1),
new VertexElement(1, 12, DeclarationType.Float3, DeclarationMethod.Default, DeclarationUsage.Normal, 1),
new VertexElement(1, 24, DeclarationType.Float2, DeclarationMethod.Default, DeclarationUsage.TextureCoordinate, 1),
// Third stream is third mesh
new VertexElement(2, 0, DeclarationType.Float3, DeclarationMethod.Default, DeclarationUsage.Position, 2),
new VertexElement(2, 12, DeclarationType.Float3, DeclarationMethod.Default, DeclarationUsage.Normal, 2),
new VertexElement(2, 24, DeclarationType.Float2, DeclarationMethod.Default, DeclarationUsage.TextureCoordinate, 2),
VertexElement.VertexDeclarationEnd
};

// Use the vertex element array to create a vertex declaration.
VertDecl = new VertexDeclaration(ADevice, elements);

string errorMessage;
effect = Effect.FromFile(ADevice, @"Shaders\Tween.fx", null, ShaderFlags.Debug, null, out errorMessage);

if ( errorMessage != null ) return;

WorldViewProjHandle = effect.GetParameter(null, "WorldViewProj");
WorldHandle = effect.GetParameter(null, "World");
LightPosHandle = effect.GetParameter(null, "LightPos");
WeightHandle = effect.GetParameter(null, "Weight");
// TextureHandle = effect.GetParameter(null, "Texture");
}


public override bool SetPositionNext(double ATime, Way.DrawFlags Flag)
{
KickFreq = 2*ATime;
Phase = ATime/3;
BlendWeight = Math.Sin(KickFreq);

double Weight1;
double Weight2;
double Weight3;

if( BlendWeight > 0.0f )
{
Weight1 = Math.Abs(BlendWeight);
Weight2 = 1.0f - Math.Abs(BlendWeight);
Weight3 = 0.0f;
}
else
{
Weight1 = 0.0f;
Weight2 = 1.0f - Math.Abs(BlendWeight);
Weight3 = Math.Abs(BlendWeight);
}

Weight = new Vector4((float)Weight1, (float)Weight2, (float)Weight3, 0);



return true;
}

public override void Draw(Way.DrawFlags Flag, Device ADevice, ModelViewerCamera ACamera, ref Vector3 AShift, Matrix ARotate)
{
if (Mesh00 == null) Load(ADevice);

// ADevice.Transform.World = ACamera.WorldMatrix * Matrix.Translation(AShift) * Matrix.RotationZ((float)Math.PI);

Vector4 Diffuse = new Vector4 (0.9f, 0.9f, 0.9f, 0.9f);
Vector4 Ambient = new Vector4 (0.1f, 0.1f, 0.1f, 0.1f);
Vector4 Fog = new Vector4 (0.5f, 50.0f, 1.0f/(50.0f - 1.0f), 0.0f);
Vector4 Light = new Vector4 (0.0f, 0.0f, -100.0f, 0.0f );

// Setup vertex shader constants
effect.SetValue(WorldViewProjHandle, ACamera.WorldMatrix * Matrix.Translation(AShift) * ACamera.ViewMatrix * ACamera.ProjectionMatrix);
effect.SetValue(WorldHandle, ACamera.WorldMatrix * Matrix.Translation(AShift));
effect.SetValue(WeightHandle, Weight);
effect.SetValue(LightPosHandle, Light);
// effect.SetValue(TextureHandle, meshTextures[0]);

ADevice.VertexDeclaration = VertDecl;
ADevice.SetStreamSource(0, VB00, 0);
ADevice.SetStreamSource(1, VB01, 0);
ADevice.SetStreamSource(2, VB02, 0);
ADevice.Indices = IB;

effect.Technique = "Tweenly";
// effect.Begin(0);
// effect.BeginPass(0);

// ADevice.SetTexture( 0, meshTextures[8] );
// ADevice.DrawIndexedPrimitives(PrimitiveType.TriangleList, 0, 0, VerticesNum, ADevice.RenderState.ZBufferEnable = true;
for (int i = 0; i < meshMaterials.Length; i++)
{
// Set the material and texture for this subset.
ADevice.Material = meshMaterials[i];
ADevice.SetTexture( 0, meshTextures[i] );

// Draw the mesh subset.
// ADevice.DrawPrimitives(PrimitiveType.TriangleList, attributeTable[i].VertexStart,
attributeTable[i].VertexCount);
ADevice.DrawIndexedPrimitives(PrimitiveType.TriangleList, 0, 0, attributeTable[i].VertexCount, attributeTable[i].FaceStart * 3, attributeTable[i].FaceCount);

// Mesh01.DrawSubset(i);
}
// effect.EndPass();
// effect.End();

}
}
}









I need separate Indexbuffer for everyone subset in mesh for SHADER tweening animation. The current vertex is calculated by approximation of three vertices (like dolphin sample). But together with shader my code uncorrectly displays object - the triangles are disappeared, code for effect commented



effect.Begin(0);
effect.BeginPass(0);
...
effect.EndPass();
effect.End();










And with one IB for mesh the program with shader works correctly (below code is also commented):



ADevice. SetTexture (0, meshTextures [8]);
ADevice. DrawIndexedPrimitives (PrimitiveType. TriangleList, 0, 0, VerticesNum, 0, FacesNum);








It is not acceptable for me, since we need to texture everyone subset in mesh using shader.


Where are the triangles disappeared?

[Edited by - Maxim Skachkov on December 26, 2005 12:58:09 PM]

Share this post


Link to post
Share on other sites
Thanks for posting your code, I think I've found out where I got it wrong. As for your problem, you could try turning off backface culling (device.RenderState.CullMode = Cull.None) to see if that helps. Might be worth a shot.

Share this post


Link to post
Share on other sites

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

If you intended to correct an error in the post then please contact us.

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this