Vertex colors are not displayed with custom shader

I have a fbx model that I want to render, but the Vertex Colors do not work. It was created in Blender 2.77a and then exported to fbx.
When I try to render the model with my custom effect like this:

            foreach (ModelMesh mesh in model.Meshes)
                foreach (ModelMeshPart part in mesh.MeshParts)
                {
                    part.Effect = effect;
                }

            foreach (ModelMesh mesh in model.Meshes)
                {
                    foreach (Effect e in mesh.Effects)
                    {
                        e.Parameters["World"].SetValue(world);
                        e.Parameters["View"].SetValue(cam.View);
                        e.Parameters["Projection"].SetValue(cam.Projection);
    
                        e.Parameters["AmbientColor"].SetValue(Color.White.ToVector3());
                        e.Parameters["AmbientIntensity"].SetValue(0.3f);

                        e.Parameters["DiffuseColor"].SetValue(Color.White.ToVector3());
                        e.Parameters["DiffuseIntensity"].SetValue(0.5f);
                        e.Parameters["DiffuseDirection"].SetValue(new Vector3(1.0f, 0.8f, 0.3f));                    
                    }
                    mesh.Draw();
                }

the model appears just black (since I multiply by the vertex color in my shader).
However, if I render it like this (with BasicEffect):

            foreach(ModelMesh mesh in model.Meshes)
                foreach(BasicEffect e in mesh.Effects)
                {
                    e.EnableDefaultLighting();
                }

            model.Draw(world, cam.View, cam.Projection);

everything works just fine. Also using the first variant with BasicEffect instead of my own effect works.
So it is not my fbx file that is faulty (trying it with the default Blender cube also did not work).
This is my Shader code:

// Matrix
float4x4 World;
float4x4 View;
float4x4 Projection;

// Light
float4 AmbientColor;
float AmbientIntensity;

float3 DiffuseDirection;
float4 DiffuseColor;
float DiffuseIntensity;


// The input for the VertexShader
struct VertexShaderInput
{
	float4 Position : POSITION;
	float4 Color : COLOR0;
	float3 Normal : NORMAL0;
	float2 TexCoord : TEXCOORD0;
};

// The output from the vertex shader
struct VertexShaderOutput
{
	float4 Position : POSITION;
	float3 Normal : TEXCOORD0;
	float4 Color : COLOR0;
	float2 TexCoord : TEXCOORD1;
};

// The VertexShader.
VertexShaderOutput VertexShaderFunction(VertexShaderInput input)
{
	VertexShaderOutput output;

 	float4 worldPosition = mul(input.Position, World);
	float4 viewPosition = mul(worldPosition, View);
	output.Position = mul(viewPosition, Projection);
	float3 normal = normalize(mul(input.Normal, World));
	output.Normal = normal;
	output.Color = input.Color;
	output.TexCoord = input.TexCoord;
 
	return output;
}

// The Pixel Shader
float4 PixelShaderFunction(VertexShaderOutput input) : COLOR0
{
	float4 norm = float4(input.Normal, 1.0);
	float diffuse = saturate(dot(-DiffuseDirection, norm));
 
	return float4(AmbientColor.rgb*AmbientIntensity + DiffuseIntensity*DiffuseColor.rgb*diffuse, 1) * input.Color;
}

//the Techinique
technique Technique1
{
	pass Pass1
	{
		VertexShader = compile vs_3_0 VertexShaderFunction();
		PixelShader = compile ps_3_0 PixelShaderFunction();
	}
}

I really do not know what the problem is. It could have to do with VertexDeclarations.
Just for clarity: If I am not multiplying by color in the shader i get the lighting, but without colors.
With Google I found this question that is similar to mine. The question was also posted on Stackexchange, but the solution he found is not really good. There has to be something better that is not a “hack”.

So my final question is: How do I get vertex colors right with custom shaders?

Thanks in advance

Hello i have the same problem 3 days ago…

here the solution :
http://xboxforums.create.msdn.com/forums/p/83988/506445.aspx#506445

:slightly_smiling:

Thank you for your reply. This works great and solves the problem for now.
But it is much like the solution from the old discussions I found on Stackexchange. Now I am curious about how BasicEffect gets the vertex color. Since I am setting BasicEffect as the default one in the Content Pipeline, I think it is given the colors during the processing of the fbx file. Could a custom Content Processor do the trick for me? (Maybe I could also set my effect as default one?)
Custom Content Importers/Processors are one of the topics I know nearly nothing about right now…
Could someone maybe point me in the right direction where to start and tell me whether my Idea is correct?

If you go with basic effect, it would be easier to cast the effect to BasicEffect so you can use the simplified API to configure the effect. The effect is pretty complicated and the wrapper class makes it a lot easier. You should be drawing with another technique to get the rendering with lights right (BasicEffect_PixelLighting should work). If you check out the source, you’ll see the technique is changed if the EnabledLighting flag is set. If you want the vertex colors to be taken into account, there’s a flag for that too, it’s VertexColorEnabled and if it’s set to true the effect will use yet another technique. I really recommend using the BasicEffect class to handle this :slight_smile:

Setting your own effect with a custom processor is pretty doable. You’ll need the latest development version, since this was recently fixed. Easiest way to do this is:

  1. Create a new project with the ContentPipelineExtension template.
  2. Delete the Importer, we just need the processor.
  3. The processor should extend ModelProcessor,
  4. Optionally override Process to save a reference to the content identity so you can give a relative path of the effect, rather than having to give an absolute path (this should make sense after you see the code sample below).
  5. Override ConvertMaterial and set the effect of the material to your own custom effect. The Effect property of the material is an ExternalReference, which means it points to some other content. If you did 4 you can supply the content identity of your model to the constructor of the ExternalReference so it sets the path relative to that of your model.

The result should look something like this.

using Microsoft.Xna.Framework.Content.Pipeline;
using Microsoft.Xna.Framework.Content.Pipeline.Graphics;
using Microsoft.Xna.Framework.Content.Pipeline.Processors;

namespace CustomEffectModelProcessor
{
    [ContentProcessor(DisplayName = "CustomEffectModelProcessor")]
    public class CustomEffectModelProcessor : ModelProcessor
    {
        private ContentIdentity _identity;

        public override ModelContent Process(NodeContent input, ContentProcessorContext context)
        {
            _identity = input.Identity;
            return base.Process(input, context);
        }

        protected override MaterialContent ConvertMaterial(MaterialContent material, ContentProcessorContext context)
        {
            EffectMaterialContent myMaterial = new EffectMaterialContent();
            myMaterial.Effect = new ExternalReference<EffectContent>("MyEffect.fx", _identity);

            // set some default parameters for your effect here

            return base.ConvertMaterial(myMaterial, context);
        }
    }
}
1 Like

Thank you for the great answer.
(and sorry for the late reply)
However I think I will wait for the latest development branch to be marked as stable because I do not want to break anything else in my code (or is it save to use?).
For now I decided to use the method that was suggested by Payet_Romain.

In the source code you provided, in ConvertMaterial(), how do i set my default parameters? I only have access to myMaterial.Effect which is an ExternalReference. I cant figure out how to set custom effect parameters at this point.

Develop is fine to use most of the time, and since it’s been a while since 3.5 there’s been a bunch of fixes.

Add them to the OpaqueData dictionary (EffectmaterialContent inherits from ContentItem) and they will be set later on :slight_smile:

Thank you I will certainly give it a shot :slightly_smiling:

1 Like