0

This is probably some newbie question, but I'm trying to render an fbx model with its colors (Materials).

The thing is, when I've tried using a BasicEffect, it all went well and the colors where rendered fine - but now I am writing a custom HLSL effect file, and whenever I try to render the model with it, it says that the model does not have colors:

The current vertex declaration does not include all the elements required by the current vertex shader. Color0 is missing.

It probably is some stupid semantic mistake (or something like that), since I'm not very experienced with working with HLSL. Anyway, here is the code (originally taken from a Riemers tutorial):

float4x4 xWorldViewProjection;

float4x4 xWorld;
float3 xLightPos;
float xLightPower;
float xAmbient;

struct VertexToPixel
{
    float4 Position     : POSITION;    
    float3 Normal        : TEXCOORD0;
    float3 Position3D    : TEXCOORD1;
    float4 Color        : COLOR0;
};

struct PixelToFrame
{
    float4 Color        : COLOR0;
};

float DotProduct(float3 lightPos, float3 pos3D, float3 normal)
{
    float3 lightDir = normalize(pos3D - lightPos);
        return dot(-lightDir, normal);    
}

VertexToPixel SimplestVertexShader( float4 inPos : POSITION0, float3 inNormal: NORMAL0, float4 inColor : COLOR0)
{
    VertexToPixel Output = (VertexToPixel)0;

    Output.Position =mul(inPos, xWorldViewProjection);
    Output.Normal = normalize(mul(inNormal, (float3x3)xWorld));    
    Output.Position3D = mul(inPos, xWorld);
    Output.Color = inColor;

    return Output;
}

PixelToFrame OurFirstPixelShader(VertexToPixel PSIn)
{
    PixelToFrame Output = (PixelToFrame)0;    

    float diffuseLightingFactor = DotProduct(xLightPos, PSIn.Position3D, PSIn.Normal);
    diffuseLightingFactor = saturate(diffuseLightingFactor);
    diffuseLightingFactor *= xLightPower;

    Output.Color = PSIn.Color* (diffuseLightingFactor + xAmbient);

    return Output;
}

technique Simplest
{
    pass Pass0
    {
        VertexShader = compile vs_3_0 SimplestVertexShader();
        PixelShader = compile ps_3_0 OurFirstPixelShader();
    }
}

and the XNA code used:

(after loading:)

    foreach (ModelMesh mesh in MainRoom.Meshes)
        foreach (ModelMeshPart meshPart in mesh.MeshParts)
            meshPart.Effect = roomEffect.Clone();

...

private void DrawModel(Model model, Matrix world)
{
    Matrix[] bones = new Matrix[model.Bones.Count];
    model.CopyAbsoluteBoneTransformsTo(bones);


    foreach (ModelMesh mesh in model.Meshes)
    {
        foreach (Effect currentEffect in mesh.Effects)
        {
            Matrix worldMatrix = bones[mesh.ParentBone.Index] * world;

            roomEffect.CurrentTechnique = roomEffect.Techniques["Simplest"];
            currentEffect.Parameters["xWorldViewProjection"].SetValue(worldMatrix * camera.view * camera.projection);
            currentEffect.Parameters["xWorld"].SetValue(worldMatrix);
            currentEffect.Parameters["xLightPos"].SetValue(lightPos);
            currentEffect.Parameters["xLightPower"].SetValue(lightPower);
            currentEffect.Parameters["xAmbient"].SetValue(ambientPower);
        }
        mesh.Draw();
    }
}
Noam Gal
  • 1,114
  • 2
  • 11
  • 20
  • 1
    A quick glance suggests that it's not a problem with your HLSL, but with your mesh not specifying colour data. Do you get the same error if you use `BasicEffect` with `VertexColorEnabled = true`? This enables the version of the basic-effect shader that uses `COLOR0`. So try that to verify whether it's a problem with your model. – Andrew Russell Aug 16 '13 at 12:03
  • @AndrewRussell Yes, that's it. Enabling _VertexColor_ does preduce the same error. This though rises a different question, since using BasicEffect without VertexColor does render the original colors, how could I also do so? (I suppose I should use something else instead of Color0) – Noam Gal Aug 16 '13 at 14:07

1 Answers1

2

Happily enough, After reading both @AndrewRussell 's comment and @Cole Campbell 's answer, I have finally managed to sort out the problem (and a few other bugs my code had).

The final (working) code is now:

float4x4 xWorldViewProjection;

float4x4 xWorld;
float3 xLightPos;
float xLightPower;
float xAmbient;
float3 DiffuseColor;

struct VertexToPixel
{
    float4 Position      : POSITION;    
    float3 Normal        : TEXCOORD0;
    float3 Position3d    : TEXCOORD1;

};

struct PixelToFrame
{
    float4 Color        : COLOR0;
};

float DotProduct(float3 lightPos, float3 pos3D, float3 normal)
{
    float3 lightDir = normalize(pos3D - lightPos);
        return dot(-lightDir, normal);    
}

VertexToPixel SimplestVertexShader(float4 inPosition : POSITION, float3 inNormal : TEXCOORD0)
{
    VertexToPixel Output = (VertexToPixel)0;

    Output.Position = mul(inPosition, xWorldViewProjection);
    Output.Normal = normalize(mul(inNormal, (float3x3)xWorld));    
    Output.Position3d = mul(inPosition, xWorld);

    return Output;
}

PixelToFrame OurFirstPixelShader(VertexToPixel PSIn)
{
    PixelToFrame Output = (PixelToFrame)0;    

    float diffuseLightingFactor = DotProduct(xLightPos, PSIn.Position3d, PSIn.Normal);
    diffuseLightingFactor = saturate(diffuseLightingFactor);
    diffuseLightingFactor *= xLightPower;

    Output.Color = float4(DiffuseColor, 1) * (diffuseLightingFactor + xAmbient);

    return Output;
}

technique Simplest
{
    pass Pass0
    {
        VertexShader = compile vs_3_0 SimplestVertexShader();
        PixelShader = compile ps_3_0 OurFirstPixelShader();
    }
}

...

List<Vector3> OriginalDiffuseColors = new List<Vector3>();

...

protected override void LoadContent()
{
    ...

    foreach (ModelMesh mesh in MainRoom.Meshes)
    {
         foreach (BasicEffect effect in mesh.Effects)
             OriginalDiffuseColors.Add(effect.DiffuseColor);
         foreach (ModelMeshPart meshPart in mesh.MeshParts)
             meshPart.Effect = roomEffect.Clone();
    }
}

...

private void DrawModel(Model model, Matrix world)
{
    Matrix[] bones = new Matrix[model.Bones.Count];
    model.CopyAbsoluteBoneTransformsTo(bones);

    roomEffect.CurrentTechnique = roomEffect.Techniques["Simplest"];

    int count = 0;
    foreach (ModelMesh mesh in model.Meshes)
    {
        foreach (Effect currentEffect in mesh.Effects)
        {
            Matrix worldMatrix = bones[mesh.ParentBone.Index] * world;
            currentEffect.Parameters["xWorldViewProjection"].SetValue(worldMatrix * camera.view * camera.projection);
            currentEffect.Parameters["xWorld"].SetValue(worldMatrix);
            currentEffect.Parameters["xLightPos"].SetValue(lightPos);
            currentEffect.Parameters["xLightPower"].SetValue(lightPower);
            currentEffect.Parameters["xAmbient"].SetValue(ambientPower);
            currentEffect.Parameters["DiffuseColor"].SetValue(OriginalDiffuseColors[count++]);
        }
        mesh.Draw();
    }
}

Thanks for all the help. =]

Community
  • 1
  • 1
Noam Gal
  • 1,114
  • 2
  • 11
  • 20