Hi again, I thought I had this one but nope… so I’m updating my question with new information here.
I have a vertex declaration, looks like this
static VertexDeclaration instanceVertexDeclaration = new VertexDeclaration
(
new VertexElement(0, VertexElementFormat.Vector4, VertexElementUsage.BlendWeight, 0),
new VertexElement(sizeof(float) * 4, VertexElementFormat.Vector4, VertexElementUsage.BlendWeight, 1),
new VertexElement(sizeof(float) * 8, VertexElementFormat.Vector4, VertexElementUsage.BlendWeight, 2),
new VertexElement(sizeof(float) * 12, VertexElementFormat.Vector4, VertexElementUsage.BlendWeight, 3)
);
These four BlendWeight 0-3 are used as a Matrix…
but, what if I would like to add one more, I can’t do this…
static VertexDeclaration instanceVertexDeclaration = new VertexDeclaration
(
new VertexElement(0, VertexElementFormat.Vector4, VertexElementUsage.BlendWeight, 0),
new VertexElement(sizeof(float) * 4, VertexElementFormat.Vector4, VertexElementUsage.BlendWeight, 1),
new VertexElement(sizeof(float) * 8, VertexElementFormat.Vector4, VertexElementUsage.BlendWeight, 2),
new VertexElement(sizeof(float) * 12, VertexElementFormat.Vector4, VertexElementUsage.BlendWeight, 3),
new VertexElement(sizeof(float) * 16, VertexElementFormat.Vector4, VertexElementUsage.TextureCoordinate, 0),
new VertexElement(sizeof(float) * 20, VertexElementFormat.Vector4, VertexElementUsage.TextureCoordinate, 1),
new VertexElement(sizeof(float) * 24, VertexElementFormat.Vector4, VertexElementUsage.TextureCoordinate, 2),
new VertexElement(sizeof(float) * 28, VertexElementFormat.Vector4, VertexElementUsage.TextureCoordinate, 3)
);
And in the Shader
VertexShaderOutput HardwareInstancingVertexShader(VertexShaderInput input,
float4x4 instanceTransform : BLENDWEIGHT,
float4x4 instanceTransform2 : TEXCOORD)
{
But nothings working it’s always zero, instanceTransform is working but not the Matrice Nr 2!?
And yes I have tried to name it TEXCOORD0 but no success.
I’ve asked about this before and I thought I had it but I was wrong because I’ve noticed now that it is always zero. Isn’t this supposed to work sending two Matrices into the Shader??
I’m not using DirectX so I’m trying to find out if there’s a bug in the OpenGL part, or am
Regards, Morgan
EDIT EDIT EDIT EDIT EDIT
UPDATE UPDATE UPDATE
But still not working.
Well here’s everything
My HLSL code…
// Matrices
float4x4 World; // The world matrix, where in 3D space the object will be placed.
float4x4 View; // The camera view
float4x4 Projection; // The frustum
float xLightPower; // The power of the light
float xAmbient; // The ambient surrounding light
// For testing
float4x4 xLightsViewProjection1;// The view of the light and its frustum, already multiplic together in the app
float3 xLightPos1; // The position of the light
float4x4 xLightsViewProjection2;// The view of the light and its frustum, already multiplic together in the app
float3 xLightPos2; // The position of the light
// The texture sampler that will hold
// the information about the Texture2D
// that we send from the Application
Texture xTexture;
sampler TextureSampler = sampler_state { texture = <xTexture>; magfilter = LINEAR; minfilter = LINEAR;
mipfilter = LINEAR; AddressU = mirror; AddressV = mirror; };
// The texture of the light
// like if we want the light to cast
// an image like if it's lit through
// a churchwindow etc
Texture xLightShape;
sampler LightShapeSampler = sampler_state { texture = <xLightShape>; magfilter = LINEAR; minfilter =
LINEAR; mipfilter = LINEAR; AddressU = clamp; AddressV = clamp; };
// -------------------------------------
// Let's create the scene
// -------------------------------------
// The input object that will hold
// all the data needed.
struct VertexShaderInput
{
float4 Position : POSITION0;
float3 Normal : NORMAL0;
float2 TextureCoordinate : TEXCOORD0;
};
struct VertexShaderOutput
{
float4 Position : POSITION0; // The vertex position again
float4 Position3D : TEXCOORD2;
float4 Position2DInLight : TEXCOORD1;
float2 TextureCoordinate : TEXCOORD0;
float3 Normal : TEXCOORD3;
};
struct SScenePixelToFrame
{
float4 Color : COLOR0;
};
// Hardware instancing reads the per-instance world transform from a secondary vertex stream.
VertexShaderOutput HardwareInstancingVertexShader(VertexShaderInput input,
float4x4 instanceTransform : TEXCOORD0, float4x4 lightMatrices : TEXCOORD4)
{
VertexShaderOutput output = (VertexShaderOutput)0;
// To the world we go!
instanceTransform = mul(World, transpose(instanceTransform));
// Apply the objects translation in the world
// to the input.Position that contain the
// X and Y values of the screen coordinate of the current pixel
float4 worldPosition = mul(input.Position, instanceTransform);
// Apply the camera view to it
float4 viewPosition = mul(worldPosition, View);
// And the projection frustum to become the camera screen position
output.Position = mul(viewPosition, Projection);
// And do the same for the light screen pixels
output.Position2DInLight = mul(worldPosition, lightMatrices);
// Calculate the objects in the world vertex normals
output.Normal = normalize(mul(input.Normal, (float3x3)instanceTransform));
// The objects 3D positions is stored
output.Position3D = worldPosition;
// Copy across the input texture coordinate.
output.TextureCoordinate = input.TextureCoordinate;
return output;
}
float DotProduct(float3 lightPos, float3 pos3D, float3 normal)
{
float3 lightDir = normalize(pos3D - lightPos);
return dot(-lightDir, normal);
}
SScenePixelToFrame PixelShaderFunction(VertexShaderOutput input) : COLOR0
{
// Create the output object that will hold the data
SScenePixelToFrame Output = (SScenePixelToFrame)0;
// Texture coordinates have to be between the [0, 1] region,
// so we need a simple remap of point (-1,-1) which has
// to become (0,0), while point (1,1) has to stay (1,1)
float2 ProjectedTexCoords;
ProjectedTexCoords[0] = input.Position2DInLight.x / input.Position2DInLight.w / 2.0f + 0.5f;
ProjectedTexCoords[1] = -input.Position2DInLight.y / input.Position2DInLight.w / 2.0f + 0.5f;
float diffuseLightingFactor = 0;
if ((saturate(ProjectedTexCoords).x == ProjectedTexCoords.x) && (saturate(ProjectedTexCoords).y == ProjectedTexCoords.y))
{
float realDistance = input.Position2DInLight.z / input.Position2DInLight.w;
if ((realDistance - 1.0f / 100.0f) <= 0.99f)
{
diffuseLightingFactor = DotProduct(xLightPos1, input.Position3D, input.Normal);
diffuseLightingFactor = saturate(diffuseLightingFactor);
diffuseLightingFactor *= xLightPower;
// The light texture that will be projected onto the objects
float lightTextureFactor = tex2D(LightShapeSampler, ProjectedTexCoords).r;
diffuseLightingFactor *= lightTextureFactor;
}
}
// Apply the objects textures
// and add the lightning color and ambient power to the pixel
float4 baseColor = tex2D(TextureSampler, input.TextureCoordinate);
Output.Color = baseColor * (diffuseLightingFactor + xAmbient);
return Output;
}
// Hardware instancing technique.
technique HardwareInstancing
{
pass Pass1
{
VertexShader = compile vs_3_0 HardwareInstancingVertexShader();
PixelShader = compile ps_3_0 PixelShaderFunction();
}
}
The Custom Vertex thingy..
public struct CustomVertex1 : IVertexType
{
Matrix instanceTransform;
Matrix lightMatrices;
// To store instance transform matrices in a vertex buffer, we use this custom
// vertex type which encodes 4x4 matrices as a set of four Vector4 values.
static VertexDeclaration instanceVertexDeclaration = new VertexDeclaration
(
new VertexElement(0, VertexElementFormat.Vector4, VertexElementUsage.TextureCoordinate, 0),
new VertexElement(sizeof(float) * 4, VertexElementFormat.Vector4, VertexElementUsage.TextureCoordinate, 1),
new VertexElement(sizeof(float) * 8, VertexElementFormat.Vector4, VertexElementUsage.TextureCoordinate, 2),
new VertexElement(sizeof(float) * 12, VertexElementFormat.Vector4, VertexElementUsage.TextureCoordinate, 3),
new VertexElement(sizeof(float) * 16, VertexElementFormat.Vector4, VertexElementUsage.TextureCoordinate, 4),
new VertexElement(sizeof(float) * 20, VertexElementFormat.Vector4, VertexElementUsage.TextureCoordinate, 5),
new VertexElement(sizeof(float) * 24, VertexElementFormat.Vector4, VertexElementUsage.TextureCoordinate, 6),
new VertexElement(sizeof(float) * 28, VertexElementFormat.Vector4, VertexElementUsage.TextureCoordinate, 7)
);
public CustomVertex1(Matrix instanceTransform, Matrix lightMatrices)
{
this.lightMatrices = lightMatrices;
this.instanceTransform = instanceTransform;
}
//Public methods for accessing the components of the custom vertex.
public Matrix InstaceTransform
{
get { return this.instanceTransform; }
set { this.instanceTransform = value; }
}
public Matrix LightMatrices
{
get { return this.lightMatrices; }
set { this.lightMatrices = value; }
}
VertexDeclaration IVertexType.VertexDeclaration
{
get { return instanceVertexDeclaration; }
}
}
And the code for drawing my little entities on screen
public void drawEntitiesHarware(GraphicsDevice gD, string technique, Vector3 worldCalibrationPoint, Matrix viewMatrix, Matrix projectionMatrix,
Matrix lightsViewProjectionMatrix, Vector3 lightSourcePosition, Texture2D lightTexture,
float ambientLightPower, float lightSourcePower)
{
// Gather instance transform matrices into a single array.
if (null == this.mCV || this.mCV.Length != this.mEntities.Count)
Array.Resize(ref this.mCV, this.mEntities.Count);
if (this.mEntitiesAreDirty)
{
for (int i = 0; i < this.mEntities.Count; i++)
{
this.mCV[i].InstaceTransform = Matrix.CreateScale(this.mEntities[i].getScale()) * this.mEntities[i].entityTranslationMatrix * (Matrix.CreateTranslation(worldCalibrationPoint + this.mEntities[i].planetsLocalWorldPosition));
this.mCV[i].LightMatrices = lightsViewProjectionMatrix;
}
this.mEntitiesAreDirty = false;
}
if (this.mCV.Length == 0)
return;
// If we have more instances than room in our vertex buffer, grow it to the neccessary size.
if ((this.mInstanceVertexBuffer == null) ||
(this.mCV.Length > this.mInstanceVertexBuffer.VertexCount))
{
if (this.mInstanceVertexBuffer != null)
this.mInstanceVertexBuffer.Dispose();
this.mInstanceVertexBuffer = new DynamicVertexBuffer(gD, typeof(CustomVertex1),
this.mCV.Length, BufferUsage.WriteOnly);
}
// Transfer the latest instance transform matrices into the instanceVertexBuffer.
this.mInstanceVertexBuffer.SetData<CustomVertex1>(this.mCV);
int tt = 0;
foreach (ModelMesh mesh in this.mModel.Meshes)
{
foreach (ModelMeshPart meshPart in mesh.MeshParts)
{
// Tell the GPU to read from both the model vertex buffer plus our instanceVertexBuffer.
gD.SetVertexBuffers(
new VertexBufferBinding(meshPart.VertexBuffer, meshPart.VertexOffset, 0),
new VertexBufferBinding(this.mInstanceVertexBuffer, 0, 1)
);
gD.Indices = meshPart.IndexBuffer;
// Set up the instance rendering effect.
Effect effect = meshPart.Effect;
Matrix worldMatrix = this.mModelTransforms[mesh.ParentBone.Index];
effect.CurrentTechnique = effect.Techniques[technique];
effect.Parameters["World"].SetValue(worldMatrix);
effect.Parameters["View"].SetValue(viewMatrix);
effect.Parameters["Projection"].SetValue(projectionMatrix);
effect.Parameters["xTexture"].SetValue(this.mModelTextures[tt++]);
effect.Parameters["xLightPos1"].SetValue(lightSourcePosition);
effect.Parameters["xLightPower"].SetValue(lightSourcePower);
effect.Parameters["xLightShape"].SetValue(lightTexture);
effect.Parameters["xAmbient"].SetValue(ambientLightPower);
// Draw all the instance copies in a single call.
foreach (EffectPass pass in effect.CurrentTechnique.Passes)
{
pass.Apply();
gD.DrawInstancedPrimitives(PrimitiveType.TriangleList, 0,
meshPart.StartIndex,
meshPart.PrimitiveCount, this.mCV.Length);
}
}
}
}
And in the Draw() function I call
.drawEntitiesHarware(GraphicsDevice, technique, worldCalibrationPoint, viewMatrix, projectionMatrix, lightsViewProjectionMatrix, lightPosTemp, lamppostTextures, ambientPower, lightPower);
If I add the lightsViewProjectionMatrix as a Parameter to the Shader and change this row in the Shader…
output.Position2DInLight = mul(worldPosition, lightMatrices);
To…
output.Position2DInLight = mul(worldPosition, xLightsViewProjection1);
Then everything is looking good with a working frustum, but as long as I’m using my lightMatrices the light’s frustum Matrix is gone.
EDIT: And I’ve changed the BLENDWEIGHT to TEXCOORD instead, even though it was working from the beginning.
And here’s the GLSL code generated for the Vertex Shader…
#ifdef GL_ES
precision highp float;
precision mediump int;
#endif
uniform vec4 vs_uniforms_vec4[12];
uniform vec4 posFixup;
vec4 vs_r0;
vec4 vs_r1;
vec4 vs_r2;
#define vs_c0 vs_uniforms_vec4[0]
#define vs_c1 vs_uniforms_vec4[1]
#define vs_c2 vs_uniforms_vec4[2]
#define vs_c3 vs_uniforms_vec4[3]
#define vs_c4 vs_uniforms_vec4[4]
#define vs_c5 vs_uniforms_vec4[5]
#define vs_c6 vs_uniforms_vec4[6]
#define vs_c7 vs_uniforms_vec4[7]
#define vs_c8 vs_uniforms_vec4[8]
#define vs_c9 vs_uniforms_vec4[9]
#define vs_c10 vs_uniforms_vec4[10]
#define vs_c11 vs_uniforms_vec4[11]
#define vs_o0 gl_Position
attribute vec4 vs_v1;
varying vec4 vTexCoord2;
#define vs_o1 vTexCoord2
attribute vec4 vs_v2;
varying vec4 vTexCoord1;
#define vs_o2 vTexCoord1
attribute vec4 vs_v3;
varying vec4 vTexCoord0;
#define vs_o3 vTexCoord0
attribute vec4 vs_v4;
varying vec4 vTexCoord3;
#define vs_o4 vTexCoord3
attribute vec4 vs_v5;
attribute vec4 vs_v6;
attribute vec4 vs_v7;
attribute vec4 vs_v8;
attribute vec4 vs_v9;
attribute vec4 vs_v10;
void main()
{
vs_r0 = vs_c1 * vs_v1.wwww;
vs_r0 = (vs_c0 * vs_v10.wwww) + vs_r0;
vs_r0 = (vs_c2 * vs_v2.wwww) + vs_r0;
vs_r0 = (vs_c3 * vs_v3.wwww) + vs_r0;
vs_r0.w = dot(vs_v8, vs_r0);
vs_r1 = vs_c1 * vs_v1.xxxx;
vs_r1 = (vs_c0 * vs_v10.xxxx) + vs_r1;
vs_r1 = (vs_c2 * vs_v2.xxxx) + vs_r1;
vs_r1 = (vs_c3 * vs_v3.xxxx) + vs_r1;
vs_r0.x = dot(vs_v8, vs_r1);
vs_r1.x = dot(vs_v9.xyz, vs_r1.xyz);
vs_r2 = vs_c1 * vs_v1.yyyy;
vs_r2 = (vs_c0 * vs_v10.yyyy) + vs_r2;
vs_r2 = (vs_c2 * vs_v2.yyyy) + vs_r2;
vs_r2 = (vs_c3 * vs_v3.yyyy) + vs_r2;
vs_r0.y = dot(vs_v8, vs_r2);
vs_r1.y = dot(vs_v9.xyz, vs_r2.xyz);
vs_r2 = vs_c1 * vs_v1.zzzz;
vs_r2 = (vs_c0 * vs_v10.zzzz) + vs_r2;
vs_r2 = (vs_c2 * vs_v2.zzzz) + vs_r2;
vs_r2 = (vs_c3 * vs_v3.zzzz) + vs_r2;
vs_r0.z = dot(vs_v8, vs_r2);
vs_r1.z = dot(vs_v9.xyz, vs_r2.xyz);
vs_r2.x = dot(vs_r0, vs_c4);
vs_r2.y = dot(vs_r0, vs_c5);
vs_r2.z = dot(vs_r0, vs_c6);
vs_r2.w = dot(vs_r0, vs_c7);
vs_o0.x = dot(vs_r2, vs_c8);
vs_o0.y = dot(vs_r2, vs_c9);
vs_o0.z = dot(vs_r2, vs_c10);
vs_o0.w = dot(vs_r2, vs_c11);
vs_o2.x = dot(vs_r0, vs_v4);
vs_o2.y = dot(vs_r0, vs_v5);
vs_o2.z = dot(vs_r0, vs_v6);
vs_o2.w = dot(vs_r0, vs_v7);
vs_o1 = vs_r0;
vs_r0.x = dot(vs_r1.xyz, vs_r1.xyz);
vs_r0.x = inversesqrt(vs_r0.x);
vs_o4.xyz = vs_r0.xxx * vs_r1.xyz;
vs_o3.xy = vs_v10.xy;
gl_Position.y = gl_Position.y * posFixup.y;
gl_Position.xy += posFixup.zw * gl_Position.ww;
gl_Position.z = gl_Position.z * 2.0 - gl_Position.w;
}
And the Pixel Shader…
#ifdef GL_ES
precision mediump float;
precision mediump int;
#endif
uniform vec4 ps_uniforms_vec4[3];
const vec4 ps_c3 = vec4(0.5, -0.01, 0.99, 0.0);
const vec4 ps_c4 = vec4(-1.0, -0.0, 0.0, 0.0);
vec4 ps_r0;
vec4 ps_r1;
vec4 ps_r2;
#define ps_c0 ps_uniforms_vec4[0]
#define ps_c1 ps_uniforms_vec4[1]
#define ps_c2 ps_uniforms_vec4[2]
uniform sampler2D ps_s0;
uniform sampler2D ps_s1;
varying vec4 vTexCoord2;
#define ps_v0 vTexCoord2
#define ps_oC0 gl_FragColor
varying vec4 vTexCoord1;
#define ps_v1 vTexCoord1
varying vec4 vTexCoord0;
#define ps_v2 vTexCoord0
varying vec4 vTexCoord3;
#define ps_v3 vTexCoord3
void main()
{
ps_r0.xyz = -ps_c0.xyz + ps_v0.xyz;
ps_r1.xyz = normalize(ps_r0.xyz);
ps_r0.x = clamp(dot(-ps_r1.xyz, ps_v3.xyz), 0.0, 1.0);
ps_r0.x = ps_r0.x * ps_c1.x;
ps_r0.y = 1.0 / ps_v1.w;
ps_r0.z = ps_r0.y * ps_v1.x;
ps_r1.x = (ps_r0.z * ps_c3.x) + ps_c3.x;
ps_r0.z = ps_r0.y * -ps_v1.y;
ps_r0.y = (ps_v1.z * ps_r0.y) + ps_c3.y;
ps_r0.y = -ps_r0.y + ps_c3.z;
ps_r1.y = (ps_r0.z * ps_c3.x) + ps_c3.x;
ps_r2 = texture2D(ps_s1, ps_r1.xy);
ps_r0.x = ps_r0.x * ps_r2.x;
ps_r0.x = ((ps_r0.y >= 0.0) ? ps_r0.x : ps_c3.w);
ps_r0.yz = clamp(ps_r1.xy, vec2(0.0), vec2(1.0));
ps_r0.yz = -ps_r1.xy + ps_r0.yz;
ps_r0.z = ((-abs(ps_r0.z) >= 0.0) ? ps_c4.x : ps_c4.y);
ps_r0.y = ((-abs(ps_r0.y) >= 0.0) ? ps_r0.z : ps_c3.w);
ps_r0.x = ((ps_r0.y >= 0.0) ? ps_c3.w : ps_r0.x);
ps_r0.x = ps_r0.x + ps_c2.x;
ps_r1 = texture2D(ps_s0, ps_v2.xy);
ps_oC0 = ps_r0.xxxx * ps_r1;
}