I am new to 3D and DirectX - in the past I have only used abstractions for 2D drawing. Over the past month I've been studying really hard and I'm trying to modify and adapt some of the shaders as part of my personal 'study project'.
Below I have a shader, modified from one of the Microsoft samples. I set diffuse and tex0 vertex shader outputs to zero, but my model still shows the full texture and lighting as if I hadn't changed the values from the vertex buffer. Changing the position of the model works, but nothing else. Why is this?
//
// Skinned Mesh Effect file
// Copyright (c) 2000-2002 Microsoft Corporation. All rights reserved.
//
float4 lhtDir = {0.0f, 0.0f, -1.0f, 1.0f}; //light Direction
float4 lightDiffuse = {0.6f, 0.6f, 0.6f, 1.0f}; // Light Diffuse
float4 MaterialAmbient : MATERIALAMBIENT = {0.1f, 0.1f, 0.1f, 1.0f};
float4 MaterialDiffuse : MATERIALDIFFUSE = {0.8f, 0.8f, 0.8f, 1.0f};
// Matrix Pallette
static const int MAX_MATRICES = 100;
float4x3 mWorldMatrixArray[MAX_MATRICES] : WORLDMATRIXARRAY;
float4x4 mViewProj : VIEWPROJECTION;
///////////////////////////////////////////////////////
struct VS_INPUT
{
float4 Pos : POSITION;
float4 BlendWeights : BLENDWEIGHT;
float4 BlendIndices : BLENDINDICES;
float3 Normal : NORMAL;
float3 Tex0 : TEXCOORD0;
};
struct VS_OUTPUT
{
float4 Pos : POSITION;
float4 Diffuse : COLOR;
float2 Tex0 : TEXCOORD0;
};
float3 Diffuse(float3 Normal)
{
float CosTheta;
// N.L Clamped
CosTheta = max(0.0f, dot(Normal, lhtDir.xyz));
// propogate scalar result to vector
return (CosTheta);
}
VS_OUTPUT VShade(VS_INPUT i, uniform int NumBones)
{
VS_OUTPUT o;
float3 Pos = 0.0f;
float3 Normal = 0.0f;
float LastWeight = 0.0f;
// Compensate for lack of UBYTE4 on Geforce3
int4 IndexVector = D3DCOLORtoUBYTE4(i.BlendIndices);
// cast the vectors to arrays for use in the for loop below
float BlendWeightsArray[4] = (float[4])i.BlendWeights;
int IndexArray[4] = (int[4])IndexVector;
// calculate the pos/normal using the "normal" weights
// and accumulate the weights to calculate the last weight
for (int iBone = 0; iBone < NumBones-1; iBone++)
{
LastWeight = LastWeight + BlendWeightsArray[iBone];
Pos += mul(i.Pos, mWorldMatrixArray[IndexArray[iBone]]) * BlendWeightsArray[iBone];
Normal += mul(i.Normal, mWorldMatrixArray[IndexArray[iBone]]) * BlendWeightsArray[iBone];
}
LastWeight = 1.0f - LastWeight;
// Now that we have the calculated weight, add in the final influence
Pos += (mul(i.Pos, mWorldMatrixArray[IndexArray[NumBones-1]]) * LastWeight);
Normal += (mul(i.Normal, mWorldMatrixArray[IndexArray[NumBones-1]]) * LastWeight);
// transform position from world space into view and then projection space
//o.Pos = mul(float4(Pos.xyz, 1.0f), mViewProj);
o.Pos = mul(float4(Pos.xyz, 1.0f), mViewProj);
o.Diffuse.x = 0.0f;
o.Diffuse.y = 0.0f;
o.Diffuse.z = 0.0f;
o.Diffuse.w = 0.0f;
o.Tex0 = float2(0,0);
return o;
}
technique t0
{
pass p0
{
VertexShader = compile vs_3_0 VShade(4);
}
}
I am currently using the SlimDX .NET wrapper around DirectX, but the API is extremely similar:
public void Draw()
{
var device = vertexBuffer.Device;
device.Clear(ClearFlags.Target | ClearFlags.ZBuffer, Color.White, 1.0f, 0);
device.SetRenderState(RenderState.Lighting, true);
device.SetRenderState(RenderState.DitherEnable, true);
device.SetRenderState(RenderState.ZEnable, true);
device.SetRenderState(RenderState.CullMode, Cull.Counterclockwise);
device.SetRenderState(RenderState.NormalizeNormals, true);
device.SetSamplerState(0, SamplerState.MagFilter, TextureFilter.Anisotropic);
device.SetSamplerState(0, SamplerState.MinFilter, TextureFilter.Anisotropic);
device.SetTransform(TransformState.World, Matrix.Identity * Matrix.Translation(0, -50, 0));
device.SetTransform(TransformState.View, Matrix.LookAtLH(new Vector3(-200, 0, 0), Vector3.Zero, Vector3.UnitY));
device.SetTransform(TransformState.Projection, Matrix.PerspectiveFovLH((float)Math.PI / 4, (float)device.Viewport.Width / device.Viewport.Height, 10, 10000000));
var material = new Material();
material.Ambient = material.Diffuse = material.Emissive = material.Specular = new Color4(Color.White);
material.Power = 1f;
device.SetStreamSource(0, vertexBuffer, 0, vertexSize);
device.VertexDeclaration = vertexDeclaration;
device.Indices = indexBuffer;
device.Material = material;
device.SetTexture(0, texture);
var param = effect.GetParameter(null, "mWorldMatrixArray");
var boneWorldTransforms = bones.OrderedBones.OrderBy(x => x.Id).Select(x => x.CombinedTransformation).ToArray();
effect.SetValue(param, boneWorldTransforms);
effect.SetValue(effect.GetParameter(null, "mViewProj"), Matrix.Identity);// Matrix.PerspectiveFovLH((float)Math.PI / 4, (float)device.Viewport.Width / device.Viewport.Height, 10, 10000000));
effect.SetValue(effect.GetParameter(null, "MaterialDiffuse"), material.Diffuse);
effect.SetValue(effect.GetParameter(null, "MaterialAmbient"), material.Ambient);
effect.Technique = effect.GetTechnique(0);
var passes = effect.Begin(FX.DoNotSaveState);
for (var i = 0; i < passes; i++)
{
effect.BeginPass(i);
device.DrawIndexedPrimitives(PrimitiveType.TriangleList, 0, 0, skin.Vertices.Length, 0, skin.Indicies.Length / 3);
effect.EndPass();
}
effect.End();
}
Again, I set diffuse and tex0 vertex shader outputs to zero, but my model still shows the full texture and lighting as if I hadn't changed the values from the vertex buffer. Changing the position of the model works, but nothing else. Why is this?
Also, whatever I set in the bone transformation matrices doesn't seem to have an effect on my model. If I set every bone transformation to a zero matrix, the model still shows up as if nothing had happened, but changing the Pos field in shader output makes the model disappear. I don't understand why I'm getting this kind of behaviour.
Thank you!