Sign in to follow this  
Bosduif

XNA weird HLSL problem

Recommended Posts

Hi, I just implemented support for animation in my shader. It works perfectly as you see it below, at least for the Normal technique. But at least it compiles when used in XNA. However, the value ShellOffset is a parameter I have to set from within my draw code. If you look at the first line of the pixelshader for the Fur technique, I define ShellOffset. With that line there, my fur won't render correctly because it always uses 0 rather than the value I passed in my draw method. So when I remove that line, I get an error as soon as my code tries to draw anything that uses this shader, even if it doesn't use that pixelshader. The error is: 'Both a valid vertex shader and pixel shader (or valid effect) must be set on the device before draw operations may be performed' I really don't get this, I have a version of this fur shader without the matBones support for animation but it's exactly the same except for that and that compiles just fine. I'm getting desperate here as I can't for the life of me see what I'm doing wrong. Does any of you? Thanks in advance.
float4x4 World;
float4x4 View;
float4x4 Projection;

float3 Light1Direction = normalize(float3(1, 0.5, -2));
float3 Light1Color = float3(0.9, 0.8, 0.7);

float ShellOffset = 0.0f;
float3 Light2Direction = normalize(float3(-1, -1, 1));
float3 Light2Color = float3(0.1, 0.3, 0.8);

float3 AmbientColor = 0.2;

float3 CameraPos;
float Shine = 128.0f;

float4x3 matBones[80];


texture Texture;
texture SpecularTexture;

// Is texturing enabled?
bool TextureEnabled = true;

sampler Sampler = sampler_state
{
    Texture = (Texture);

    MinFilter = Linear;
    MagFilter = Linear;
    MipFilter = Linear;
};

sampler SpecularSampler = sampler_state 
{
	Texture = (SpecularTexture);
	MinFilter = linear;
	MagFilter = linear;
	MipFilter = linear;
};

struct VertexShaderInput
{
    float4 Position : POSITION0;
    float3 Normal : NORMAL0;
    float2 TexCoord : TEXCOORD0;
	float4 boneIndex	: BLENDINDICES0;
    float4 boneWeight	: BLENDWEIGHT0;

};

struct VertexShaderOutput
{
    float4 Position : POSITION0;
    float2 TexCoord : TEXCOORD0;
    float3 Normal : TEXCOORD1;
    float3 WorldPos : TEXCOORD2;
};

texture Fur;

sampler FurSampler = sampler_state
{
    Texture = (Fur);

    MinFilter = Linear;
    MagFilter = Linear;
    MipFilter = Linear;
    AddressW = CLAMP;
    AddressU = Mirror;
    AddressV = Mirror;
};

VertexShaderOutput VertexShaderFunction(VertexShaderInput input)
{
    VertexShaderOutput output;

	// Calculate the final bone transformation matrix
    float4x3 matSmoothSkin = 0;
    matSmoothSkin += matBones[input.boneIndex.x] * input.boneWeight.x;
    matSmoothSkin += matBones[input.boneIndex.y] * input.boneWeight.y;
    matSmoothSkin += matBones[input.boneIndex.z] * input.boneWeight.z;
    matSmoothSkin += matBones[input.boneIndex.w] * input.boneWeight.w;
    
    // Combine skin and world transformations
    float4x4 matSmoothSkinWorld = 0;
    matSmoothSkinWorld[0] = float4(matSmoothSkin[0], 0);
    matSmoothSkinWorld[1] = float4(matSmoothSkin[1], 0);
    matSmoothSkinWorld[2] = float4(matSmoothSkin[2], 0);
    matSmoothSkinWorld[3] = float4(matSmoothSkin[3], 1);
    matSmoothSkinWorld = mul(matSmoothSkinWorld, World);
	
	float4 worldPosition = mul(input.Position, matSmoothSkinWorld);
	float3 normal = normalize(mul(input.Normal, matSmoothSkinWorld));
	
    output.TexCoord = input.TexCoord; 
    output.Normal = normal;   
    output.WorldPos = worldPosition;
    
    float4 viewPosition = mul(worldPosition, View);
    output.Position = mul(viewPosition, Projection);


    return output;
}

VertexShaderOutput VertexShaderFurFunction(VertexShaderInput input)
{
    VertexShaderOutput output;

	// Calculate the final bone transformation matrix
    float4x3 matSmoothSkin = 0;
    matSmoothSkin += matBones[input.boneIndex.x] * input.boneWeight.x;
    matSmoothSkin += matBones[input.boneIndex.y] * input.boneWeight.y;
    matSmoothSkin += matBones[input.boneIndex.z] * input.boneWeight.z;
    matSmoothSkin += matBones[input.boneIndex.w] * input.boneWeight.w;
    
    // Combine skin and world transformations
    float4x4 matSmoothSkinWorld = 0;
    matSmoothSkinWorld[0] = float4(matSmoothSkin[0], 0);
    matSmoothSkinWorld[1] = float4(matSmoothSkin[1], 0);
    matSmoothSkinWorld[2] = float4(matSmoothSkin[2], 0);
    matSmoothSkinWorld[3] = float4(matSmoothSkin[3], 1);
    matSmoothSkinWorld = mul(matSmoothSkinWorld, World);
	
	float4 worldPosition = mul(input.Position, matSmoothSkinWorld);
	float3 normal = normalize(mul(input.Normal, matSmoothSkinWorld));
	
	
	// offset shells
    worldPosition += 1 * ShellOffset * float4(normal, 0);
	
    output.TexCoord = input.TexCoord; 
    output.Normal = normal;   
    output.WorldPos = worldPosition;
    
    float4 viewPosition = mul(worldPosition, View);
    output.Position = mul(viewPosition, Projection);


    return output;
}

// PIXELSHADER FUR ( ERROR!!! )
float4 PixelShaderFurFunction(VertexShaderOutput input) : COLOR0
{
    // If I remove this first line, I get the error.
    float ShellOffset = 0;


    float4 color = tex2D(Sampler, input.TexCoord);
	
    float4 shell = tex3D(FurSampler, float3(5 * input.TexCoord, ShellOffset));

    float3 light1 = max(dot(input.Normal, -Light1Direction), 0) * Light1Color;
    float3 light2 = max(dot(input.Normal, -Light2Direction), 0) * Light2Color;

    float3 lighting = light1 + light2 + AmbientColor;
    
	float3 view = normalize(CameraPos.xyz - input.WorldPos.xyz);
	float3 reflection = normalize(2 * light1 * input.Normal + Light1Direction);
	float4 specular = pow(saturate(dot(reflection, view)), 8); 
    
	// light the texture
	// use less light on the lower shells, faking self shadowing
    color.rgb *= (0.3 * ShellOffset + 0.7) * lighting;
        
    // Some trickery to use texture alpha to determine the amount of fur
    // We'll also modulate the specular with the color a, to make the fur
    // a lot less shiny, but still allow for very shiny things like the eyes
    shell.a = color.a < 1 ? 0 : shell.a; // hide fur where texture alpha < 1, cheap hack    
    specular *= 0.1 + 0.9 * (1 - color.a); // lower specular intensity for the fur, use full for other parts
    specular *= 1 - shell.a; // this add a bit of 'noise' to the specular, so the fur looks less smooth. Another cheap hack
    specular *= 1 - ShellOffset; // use specular on lower shells only, giving the fure more depth without making it shiny
    color.a = 1; // we output the color for the 1st pass, for which we'll need it fully opaque
	
    
    // Add the specular to the color for a bright white highlight (should really modulate with light color)
    color.rgb += specular;
        
    // use the computed color for the shell, we'll only reuse the alpha from fur volume
    shell.rgb = color.rgb;  
    
    
    // for the 1st 'pass', we'll render the basic model without any fur alpha
    if (ShellOffset < 0.01)
    {		
		return color;
    }
    else
    {
		return shell;
	}
}

// NORMAL
float4 PixelShaderFunction(VertexShaderOutput input) : COLOR0
{

	float4 color = tex2D(Sampler, input.TexCoord);

    float3 light1 = max(dot(input.Normal, -Light1Direction), 0) * Light1Color;
    float3 light2 = max(dot(input.Normal, -Light2Direction), 0) * Light2Color;

    float3 lighting = light1 + light2 + AmbientColor;
    
	float3 view = normalize(CameraPos.xyz - input.WorldPos.xyz);
	float3 reflection = normalize(2 * light1 * input.Normal + Light1Direction);
	float4 specular = pow(saturate(dot(reflection, view)), 8); 
    
	// light the texture
	// use less light on the lower shells, faking self shadowing
	color.rgb *= lighting;
    //color.rgb *= (0.3 * ShellOffset + 0.7) * lighting;
        

    // Add the specular to the color for a bright white highlight (should really modulate with light color)
    color.rgb += specular/4;
       
	   
	return color;
}

// SPECULAR
float4 PixelShaderSpecularFunction(VertexShaderOutput input) : COLOR0
{
	float4 color = tex2D(Sampler, input.TexCoord);
	float3 specularfactor = tex2D(SpecularSampler, input.TexCoord).xyz;
	

    float3 light1 = max(dot(input.Normal, -Light1Direction), 0) * Light1Color;
    float3 light2 = max(dot(input.Normal, -Light2Direction), 0) * Light2Color;

    float3 lighting = light1 + light2 + AmbientColor;
    
	float3 view = normalize(CameraPos.xyz - input.WorldPos.xyz);
	float3 reflection = normalize(2 * light1 * input.Normal + Light1Direction);
	float3 specular = pow(saturate(dot(reflection, view)), Shine) * specularfactor;
    
	
	
	// light the texture
	// use less light on the lower shells, faking self shadowing
	color.rgb *= lighting;
    //color.rgb *= (0.3 * ShellOffset + 0.7) * lighting;
        

    // Add the specular to the color for a bright white highlight (should really modulate with light color)
    color.rgb += specular;
   
	return color;
}

technique Normal
{
    pass Pass1
    {
        VertexShader = compile vs_2_0 VertexShaderFunction();
        PixelShader = compile ps_2_0 PixelShaderFunction();
    }
}

technique Fur
{
	pass Pass1
	{
        VertexShader = compile vs_2_0 VertexShaderFunction();
        PixelShader = compile ps_2_0 PixelShaderFurFunction();
	}
}

technique Specular
{
	pass Pass1
	{
        VertexShader = compile vs_2_0 VertexShaderFunction();
        PixelShader = compile ps_2_0 PixelShaderSpecularFunction();
	}
}
These are the methods I use to draw my model

Share this post


Link to post
Share on other sites
Appearantly it's not an error in the shader but it uses more variables than shadermodel 2.0 can handle.

Removing some/switching to 3.0 fixed my problem.

Share this post


Link to post
Share on other sites

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