[XNA] Adding texture coordinate offsets to instanced models.

Started by
2 comments, last by unbird 13 years, 4 months ago
Hallo,
Im trying to add some more data to my vertex data structure. Im trying to add a vector2 for each instance of a model, but I cant get it to work and was wondering if anyone could give me a nudge in the right direction. The objects render, but the data in textcoord5 is random.
Thanks

The initialize stage, where I create the extra vertex element to pass to the shader
// Create the extra dataVertexElement[] extraElements = new VertexElement[5];   // 4 * vector4 (matrix) + 2 * float (vector2)for (int i = 0; i < extraElements.Length-1; i++){    short matrixOffset = (short)(sizeof(float) * 4 * i);    extraElements = new VertexElement(1, matrixOffset, VertexElementFormat.Vector4, VertexElementMethod.Default,                                    VertexElementUsage.TextureCoordinate, (byte)(i+1));}short extraOffset = (short)(sizeof(float) * 4 * 4);extraElements[4] = new VertexElement(2, extraOffset, VertexElementFormat.Vector2, VertexElementMethod.Default,                                    VertexElementUsage.TextureCoordinate, 5);// Put it in thereVertexElement[] oldVertexDeclaration = m_vertexDeclaration.GetVertexElements();VertexElement[] elements = new VertexElement[oldVertexDeclaration.Length + extraElements.Length];oldVertexDeclaration.CopyTo(elements, 0);extraElements.CopyTo(elements, oldVertexDeclaration.Length);// Repalce the vertex declarationm_vertexDeclaration.Dispose();m_vertexDeclaration = new VertexDeclaration(device, elements);



The render stage, currently the data it passes is not very usefull, its only for testing.
public void Draw(GraphicsDevice device, Effect effect, Matrix[] instanceTransforms){    // Temp!    Vector2[] otherData = new Vector2[instanceTransforms.Length];    for (int i = 0; i < instanceTransforms.Length; i++)    {        float t = (float)i / (float)instanceTransforms.Length;        otherData = new Vector2(t, 0);    }    device.VertexDeclaration = m_vertexDeclaration;    device.Vertices[0].SetSource(m_vertexBuffer, 0, m_vertexStride);    device.Indices = m_indexBuffer;    effect.Begin();    foreach (EffectPass pass in effect.CurrentTechnique.Passes)    {        pass.Begin();        // make sure there is enough space in out buffer to pass the instance data, recalculate it if needed.        // not the best way of doing it, but I think it should be fine        int matrixDataSize = sizeof(float) * 16 * instanceTransforms.Length;        int extraDataSize =  sizeof(float) * 2 * otherData.Length;        // Matrix data        if ((m_instanceMatrixStream == null) || (m_instanceMatrixStream.SizeInBytes < matrixDataSize))        {            if (m_instanceMatrixStream != null)                m_instanceMatrixStream.Dispose();            m_instanceMatrixStream = new DynamicVertexBuffer(device, matrixDataSize, BufferUsage.WriteOnly);        }        m_instanceMatrixStream.SetData(instanceTransforms, 0, instanceTransforms.Length, SetDataOptions.Discard);        // Extra data        if ((m_instanceExtraDataStream == null) || (m_instanceExtraDataStream.SizeInBytes < extraDataSize))        {            if (m_instanceExtraDataStream != null)                m_instanceExtraDataStream.Dispose();            m_instanceExtraDataStream = new DynamicVertexBuffer(device, extraDataSize, BufferUsage.WriteOnly);        }        m_instanceExtraDataStream.SetData(otherData, 0, otherData.Length, SetDataOptions.Discard);        // Set the current draw process to use the data        VertexStreamCollection vertices = device.Vertices;        vertices[0].SetFrequencyOfIndexData(instanceTransforms.Length);        vertices[1].SetSource(m_instanceMatrixStream, 0, sizeof(float) * 16);        vertices[1].SetFrequencyOfInstanceData(1);        vertices[2].SetSource(m_instanceExtraDataStream, 0, sizeof(float) * 2);        vertices[2].SetFrequencyOfInstanceData(1);        // Draw the model        device.DrawIndexedPrimitives(PrimitiveType.TriangleList, 0, 0, m_vertexCount, 0, m_indexCount / 3);        // Reset the streams to make sure they are not used later        vertices[0].SetSource(null, 0, 0);        vertices[1].SetSource(null, 0, 0);        vertices[2].SetSource(null, 0, 0);        pass.End();    }    effect.End();}


The vertex shader
VertexShaderOutput InstancingVertexShader(VertexShaderInput input, float4x4 instanceTransform : TEXCOORD1, float2 extraData : TEXCOORD5){    return VertexShader(input, transpose(instanceTransform), extraData);}
Advertisement
I think your offset for the vertex element in stream 2 is wrong (extraOffset). You don't continue from the offset from "previous" streams, but start anew from 0 - like you did for stream 1. Try setting it to 0.
Thats it! Cant belive i didnt think of trying that. Thanks!
Glad I could help.

It's easy to do something wrong when setting up a vertex declaration by hand, especially when using multiple streams. I found this quite handy, but one adjustment I made is let it return the vertex element arrays instead of a vertex declaration. So I could later combine them into one like you did.

Consider using structs for more complex vertices (e.g. your matrix) then you can at least check the offsets and strides with Marshal.OffsetOf and Marshal.SizeOf.

This topic is closed to new replies.

Advertisement