Hardware instancing retrieve color from Model

Hello I’m using hardware instancing and extracting a models vertices, normal, textureCoordinate and color. When I render the model using its Texture and textureCoordinate with HLSL the model looks fine. But when I render the model only by its Color it comes up all broken and wrong.

  • The left model is correct this is the same 3d model but is loaded as a single 3d model without hardware instancing. This is how the colors should look I used blender to manually set these colors.
  • The right model is using hardware instancing, the shape looks correct but the colors are wrong.

This is how I initialize the custom vertex decleration:

public struct VertexPositionNormalTextureColor
{
    public Vector3 Position;
    public Vector3 Normal;
    public Vector2 TextureCoordinate;
    public Vector4 Color;

    public VertexPositionNormalTextureColor(Vector3 _Position, Vector3 _Normal, Vector2 _TextureCoordinate, Vector4 _Color)
    {
        Position = _Position;
        Normal = _Normal;
        TextureCoordinate = _TextureCoordinate;
        Color = _Color;
    }

    static public VertexDeclaration VertexDeclaration { get { return MyVertexDeclaration; } }

    static readonly VertexDeclaration MyVertexDeclaration = new VertexDeclaration(new VertexElement[]
    {
        new VertexElement( 0, VertexElementFormat.Vector3, VertexElementUsage.Position, 0 ),
        new VertexElement(sizeof(float) * 3, VertexElementFormat.Vector3, VertexElementUsage.Normal, 0 ),
        new VertexElement(sizeof(float) * 6, VertexElementFormat.Vector2, VertexElementUsage.TextureCoordinate, 0 ),
        new VertexElement(sizeof(float) * 8, VertexElementFormat.Vector4, VertexElementUsage.Color, 0 )
    });
}

This is how I gather the models vertices, normal, textureCoordinate and color:

List<Vector3> vertices = new List<Vector3>();
List<Vector3> normal = new List<Vector3>();
List<Vector2> texCoord = new List<Vector2>();
List<Vector4> color = new List<Vector4>();

bones = new Matrix[myModel.Bones.Count];

myModel.CopyAbsoluteBoneTransformsTo(bones);
foreach (ModelMesh mm in myModel.Meshes)
{
    foreach (ModelMeshPart mmp in mm.MeshParts)
    {
        VertexPositionNormalTextureColor[] vertexData = new 
        VertexPositionNormalTextureColor[mmp.NumVertices];

        mmp.VertexBuffer.GetData(mmp.VertexOffset * mmp.VertexBuffer.VertexDeclaration.VertexStride, 
        vertexData, 0, mmp.NumVertices, mmp.VertexBuffer.VertexDeclaration.VertexStride);
        for (int i = 0; i != vertexData.Length; i++)
        {
             vertices.Add(vertexData[i].Position);
             normal.Add(vertexData[i].Normal);
             texCoord.Add(vertexData[i].TextureCoordinate);
             color.Add(vertexData[i].Color);
        }
    }    
}

This is how I set the models vertices, normal, textureCoordinate, color to the vertex buffer:

jvertices = new List<VertexPositionNormalTextureColor>(vertices.Count);
for(int i = 0; i < vertices.Count(); i++)
{
    jvertices.Add(new VertexPositionNormalTextureColor(vertices[i], normal[i], texCoord[i], color[i]));
}

geometryBuffer = new VertexBuffer(device, VertexPositionNormalTextureColor.VertexDeclaration, vertices.Count(), BufferUsage.WriteOnly);
geometryBuffer.SetData(jvertices.ToArray());

The code for the HLSL is as below:

struct VertexShaderInput
{
    float3 inPositionOS : SV_Position;
    float3 NormalOS : NORMAL0;
    float2 inTexCoords : TEXCOORD0;
    float4 inColor : COLOR0;
};

struct VertexShaderOutput
{
    float4 PositionCS : SV_Position;     //clip space
    float4 PositionWS : POSITIONWS;      //world space
    float3 NormalWS : NORMAL0;
    float2 inTexCoords : TEXCOORD0;
    float4 inColor : COLOR0;
};

VertexShaderOutput InstancingVS(VertexShaderInput input, float4x4 instanceTransform : TEXCOORD2)
{
    VertexShaderOutput output;

    float4x4 instance = transpose(instanceTransform);

    output.PositionWS = mul(float4(input.inPositionOS.xyz, 1.0f), instance);
    output.PositionCS = mul(output.PositionWS, ViewProjection);
    output.NormalWS = normalize(mul(input.NormalOS, (float3x3)instance));
    output.inTexCoords = input.inTexCoords;
    output.inColor = input.inColor;

    return output;
}

float4 InstancingPS(VertexShaderOutput input) : COLOR0
{
    float4 color = input.inColor;

    if (color.a < 0.75f) { clip(-1); return color; }
    else color.a = 1;

    return color;
}

If anyone notices any issue that might be the reason why Color wont work on HLSL but a texture works perfectly fine.

I changed the order of the variables in the struct setting the vertex declaration. It turns out it changed the result I looked into what mmp.VertexBuffer.GetData() actually had stored from the model and for some reason it doesn’t have Color.

static readonly VertexDeclaration MyVertexDeclaration = new VertexDeclaration(new VertexElement[]
{
    new VertexElement(0, VertexElementFormat.Vector3, VertexElementUsage.Position, 0 ),
    new VertexElement(12, VertexElementFormat.Vector3, VertexElementUsage.Normal, 0 ),
    new VertexElement(24, VertexElementFormat.Vector2, VertexElementUsage.TextureCoordinate, 0 ),
    new VertexElement(32, VertexElementFormat.Vector3, VertexElementUsage.Tangent, 0 ),
    new VertexElement(44, VertexElementFormat.Vector3, VertexElementUsage.Binormal, 0 )
});

I followed the offset and order for these variables in the vertex declaration struct and it seems to be working. How do I make mmp.VertexBuffer.GetData() also gather the Color from the model, Thankyou.

It looks like your model just doesn’t have vertex colors at all. How did you create and export it? If you export to a readable format, you could check directly if vertex colors are exported.

1 Like