I got quite a small problem about OpenGl, Directx11 shaders. To begin with, few weeks ago I just created skinned animating. However now I got one problem, because models without skinning are scaled by 0 and that's means they are not shown in screen. In order to avoid this I need to create somekind of protection and I have two ways (atleast I think there's two ways).
1. Use simple if, but I think its slow, stupid and I never saw in anybodies shader if function in bones.
2. Create shader for every model with defined options #if. But I think this way is very unpractical. By the way I saw Heroes of Newerth using #if for bones, but does't means they create for every mesh in scene new shader program?
////////////////////////////////////////////////////////////////////////////////
// Filename: texture.vs
////////////////////////////////////////////////////////////////////////////////
/////////////
// GLOBALS //
/////////////
cbuffer MatrixBuffer
{
matrix worldMatrix;
matrix viewMatrix;
matrix projectionMatrix;
matrix boneMatrix[100];
};
cbuffer CameraBuffer
{
float3 cameraPosition;
float padding;
};
//////////////
// TYPEDEFS //
//////////////
struct VertexInputType
{
float4 position : POSITION;
float2 tex : TEXCOORD;
float3 normal : NORMAL;
float3 tangent : TANGENT;
float3 binormal : BINORMAL;
int4 boneId : BONEID;
float4 boneWeight : BONEWEIGHT;
};
struct PixelInputType
{
float4 position : SV_POSITION;
float2 tex : TEXCOORD;
float3 normal : NORMAL;
float3 tangent : TANGENT;
float3 binormal : BINORMAL;
int4 boneId : BONEID;
float4 boneWeight : BONEWEIGHT;
float3 viewDirection : TEXCOORD2;
};
////////////////////////////////////////////////////////////////////////////////
// Vertex Shader
////////////////////////////////////////////////////////////////////////////////
PixelInputType LightVertexShader(VertexInputType input)
{
PixelInputType output;
float4 worldPosition;
input.position.w = 1.0f;
//#if (ZERO == 1)
//if (input.boneWeight[0] + input.boneWeight[1] + input.boneWeight[2] + input.boneWeight[0] != 0)
//{
matrix boneTransformation = boneMatrix[input.boneId[0]] * input.boneWeight[0];
boneTransformation += boneMatrix[input.boneId[1]] * input.boneWeight[1];
boneTransformation += boneMatrix[input.boneId[2]] * input.boneWeight[2];
boneTransformation += boneMatrix[input.boneId[3]] * input.boneWeight[3];
input.position = mul(input.position, boneTransformation);
input.normal = mul(input.normal, boneTransformation);
//}
//endif
//#endif
output.position = mul(input.position, worldMatrix);
output.position = mul(output.position, viewMatrix);
output.position = mul(output.position, projectionMatrix);
// Store the input color for the pixel shader to use.
output.tex = input.tex;
output.normal = mul(input.normal, (float3x3)worldMatrix);
output.normal = normalize(output.normal);
output.tangent = mul(input.tangent, (float3x3)worldMatrix);
output.tangent = normalize(output.tangent);
output.binormal = mul(input.binormal, (float3x3)worldMatrix);
output.binormal = normalize(output.binormal);
worldPosition = mul(input.position, worldMatrix);
output.viewDirection = normalize(cameraPosition.xyz - worldPosition.xyz);
return output;
}
// Filename: texture.vs
////////////////////////////////////////////////////////////////////////////////
/////////////
// GLOBALS //
/////////////
cbuffer MatrixBuffer
{
matrix worldMatrix;
matrix viewMatrix;
matrix projectionMatrix;
matrix boneMatrix[100];
};
cbuffer CameraBuffer
{
float3 cameraPosition;
float padding;
};
//////////////
// TYPEDEFS //
//////////////
struct VertexInputType
{
float4 position : POSITION;
float2 tex : TEXCOORD;
float3 normal : NORMAL;
float3 tangent : TANGENT;
float3 binormal : BINORMAL;
int4 boneId : BONEID;
float4 boneWeight : BONEWEIGHT;
};
struct PixelInputType
{
float4 position : SV_POSITION;
float2 tex : TEXCOORD;
float3 normal : NORMAL;
float3 tangent : TANGENT;
float3 binormal : BINORMAL;
int4 boneId : BONEID;
float4 boneWeight : BONEWEIGHT;
float3 viewDirection : TEXCOORD2;
};
////////////////////////////////////////////////////////////////////////////////
// Vertex Shader
////////////////////////////////////////////////////////////////////////////////
PixelInputType LightVertexShader(VertexInputType input)
{
PixelInputType output;
float4 worldPosition;
input.position.w = 1.0f;
//#if (ZERO == 1)
//if (input.boneWeight[0] + input.boneWeight[1] + input.boneWeight[2] + input.boneWeight[0] != 0)
//{
matrix boneTransformation = boneMatrix[input.boneId[0]] * input.boneWeight[0];
boneTransformation += boneMatrix[input.boneId[1]] * input.boneWeight[1];
boneTransformation += boneMatrix[input.boneId[2]] * input.boneWeight[2];
boneTransformation += boneMatrix[input.boneId[3]] * input.boneWeight[3];
input.position = mul(input.position, boneTransformation);
input.normal = mul(input.normal, boneTransformation);
//}
//endif
//#endif
output.position = mul(input.position, worldMatrix);
output.position = mul(output.position, viewMatrix);
output.position = mul(output.position, projectionMatrix);
// Store the input color for the pixel shader to use.
output.tex = input.tex;
output.normal = mul(input.normal, (float3x3)worldMatrix);
output.normal = normalize(output.normal);
output.tangent = mul(input.tangent, (float3x3)worldMatrix);
output.tangent = normalize(output.tangent);
output.binormal = mul(input.binormal, (float3x3)worldMatrix);
output.binormal = normalize(output.binormal);
worldPosition = mul(input.position, worldMatrix);
output.viewDirection = normalize(cameraPosition.xyz - worldPosition.xyz);
return output;
}
1. Use simple if, but I think its slow, stupid and I never saw in anybodies shader if function in bones.
2. Create shader for every model with defined options #if. But I think this way is very unpractical. By the way I saw Heroes of Newerth using #if for bones, but does't means they create for every mesh in scene new shader program?
// (C)2009 S2 Games
// mesh_color.vsh
//
// Default mesh vertex shader
//=============================================================================
//=============================================================================
// Uniform variables
//=============================================================================
uniform mat4 mWorldViewProj;
uniform mat4 mWorldView;
uniform mat4 mWorldViewOffset; // World * View Offset
uniform mat3 mWorldRotate; // World rotation for normals
uniform vec4 vColor;
uniform vec3 vSunPositionWorld;
uniform vec3 vAmbient;
uniform vec3 vSunColor;
uniform float fFogStart;
uniform float fFogEnd;
uniform float fFogScale;
uniform float fFogDensity;
uniform vec3 vFog;
#if (SHADOWS == 1)
uniform mat4 mLightWorldViewProjTex; // Light's World * View * Projection * Tex
#endif
#if (NUM_BONES > 0)
#ifdef NON_SQUARE_MATRIX
uniform mat3x4 vBones[NUM_BONES];
#else
uniform vec4 vBones3[NUM_BONES * 3];
#endif
#endif
#ifdef CLOUDS
uniform mat4 mCloudProj;
#endif
#if (FOG_OF_WAR == 1)
uniform mat4 mFowProj;
#endif
//=============================================================================
// Varying variables
//=============================================================================
varying vec4 v_vColor;
#if (LIGHTING_QUALITY == 0)
varying vec3 v_vNormal;
varying vec3 v_vTangent;
varying vec3 v_vBinormal;
#elif (LIGHTING_QUALITY == 1)
varying vec3 v_vHalfAngle;
#ifdef GROUND_AMBIENT
varying vec4 v_vSunLight;
#else
varying vec3 v_vSunLight;
#endif
#elif (LIGHTING_QUALITY == 2)
#ifdef GROUND_AMBIENT
varying vec4 v_vDiffLight;
#else
varying vec3 v_vDiffLight;
#endif
#endif
#if (LIGHTING_QUALITY == 0 || FALLOFF_QUALITY == 0)
varying vec3 v_vPositionOffset;
#endif
#if (SHADOWS == 1)
varying vec4 v_vTexcoordLight;
#endif
#ifdef CLOUDS
varying vec2 v_vClouds;
#endif
#if ((FOG_QUALITY == 1 && FOG_TYPE != 0) || (FALLOFF_QUALITY == 1 && (FOG_TYPE != 0 || SHADOWS == 1)) || FOG_OF_WAR == 1)
varying vec4 v_vData0;
#endif
//=============================================================================
// Vertex attributes
//=============================================================================
attribute vec4 a_vPosition;
attribute vec3 a_vNormal;
attribute vec4 a_vTexCoord0;
attribute vec4 a_vTangent;
#if (NUM_BONES > 0)
attribute vec4 a_vBoneIndex;
attribute vec4 a_vBoneWeight;
#endif
//=============================================================================
// Vertex Shader
//=============================================================================
void main()
{
#if ((FOG_QUALITY == 1 && FOG_TYPE != 0) || (FALLOFF_QUALITY == 1 && (FOG_TYPE != 0 || SHADOWS == 1)) || FOG_OF_WAR == 1)
v_vData0 = vec4(0.0, 0.0, 0.0, 0.0);
#endif
vec3 vInNormal = (a_vNormal / 255.0) * 2.0 - 1.0;
vec4 vInTangent = (a_vTangent / 255.0) * 2.0 - 1.0;
#if (NUM_BONES > 0)
vec4 vPosition;
vec3 vNormal;
vec3 vTangent;
//
// GPU Skinning
// Blend bone matrix transforms for this bone
//
vec4 vBlendIndex = a_vBoneIndex;
vec4 vBoneWeight = a_vBoneWeight;
#ifdef NON_SQUARE_MATRIX
mat3x4 mBlend = mat3x4(0.0);
for (int i = 0; i < NUM_BONE_WEIGHTS; ++i)
mBlend += vBones[int(vBlendIndex)] * vBoneWeight;
#else
mat4 mBlend = mat4(0.0);
mBlend[3][3] = 1.0;
for (int i = 0; i < NUM_BONE_WEIGHTS; ++i)
{
mBlend[0] += vBones3[int(vBlendIndex) * 3 + 0] * vBoneWeight;
mBlend[1] += vBones3[int(vBlendIndex) * 3 + 1] * vBoneWeight;
mBlend[2] += vBones3[int(vBlendIndex) * 3 + 2] * vBoneWeight;
}
#endif
vPosition = vec4((a_vPosition * mBlend).xyz, 1.0);
vNormal = normalize((vec4(vInNormal, 0.0) * mBlend).xyz);
vTangent = normalize((vec4(vInTangent.xyz, 0.0) * mBlend).xyz);
#else
vec4 vPosition = a_vPosition;
vec3 vNormal = vInNormal;
vec3 vTangent = vInTangent.xyz;
#endif
vec3 vPositionOffset = (mWorldViewOffset * vPosition).xyz;
gl_Position = mWorldViewProj * vPosition;
#if (WATER_QUALITY == 0)
gl_ClipVertex = mWorldView * vPosition;
#else
#ifdef REFLECTIONS
gl_ClipVertex = mWorldView * vPosition;
#endif
#endif
gl_TexCoord[0] = a_vTexCoord0;
v_vColor = vColor;
#if (LIGHTING_QUALITY == 0)
v_vNormal = mWorldRotate * vNormal;
v_vTangent = mWorldRotate * vTangent;
v_vBinormal = cross(v_vTangent, v_vNormal) * vInTangent.w;
#elif (LIGHTING_QUALITY == 1)
vec3 vCamDirection = -normalize(vPositionOffset);
vec3 vLight = vSunPositionWorld;
vec3 vWVNormal = mWorldRotate * vNormal;
vec3 vWVTangent = mWorldRotate * vTangent;
vec3 vWVBinormal = cross(vWVTangent, vWVNormal) * vInTangent.w;
mat3 mRotate = mat3(vWVTangent, vWVBinormal, vWVNormal);
v_vSunLight.xyz = vLight * mRotate;
#ifdef GROUND_AMBIENT
v_vSunLight.w = dot(vWVNormal, vec3(0.0, 0.0, 1.0)) * 0.375 + 0.625;
#endif
v_vHalfAngle = normalize(vLight + vCamDirection) * mRotate;
#elif (LIGHTING_QUALITY == 2)
vec3 vLight = vSunPositionWorld;
vec3 vWVNormal = mWorldRotate * vNormal;
float fDiffuse = max(dot(vWVNormal, vLight), 0.0);
v_vDiffLight.xyz = vSunColor * fDiffuse;
#ifdef GROUND_AMBIENT
v_vDiffLight.w = dot(vWVNormal, vec3(0.0, 0.0, 1.0)) * 0.375 + 0.625;
#endif
#endif
#if (LIGHTING_QUALITY == 0 || FALLOFF_QUALITY == 0)
v_vPositionOffset = vPositionOffset;
#endif
#if (SHADOWS == 1)
v_vTexcoordLight = mLightWorldViewProjTex * vPosition;
#endif
#ifdef CLOUDS
v_vClouds = (mCloudProj * vPosition).xy;
#endif
#if (FALLOFF_QUALITY == 1 && (FOG_TYPE != 0 || SHADOWS == 1))
v_vData0.z = length(vPositionOffset);
#endif
#if (FOG_QUALITY == 1 && FOG_TYPE != 0)
#if (FOG_TYPE == 0)
// FOG_NONE
v_vData0.w = 0.0;
#elif (FOG_TYPE == 1)
// FOG_LINEAR
v_vData0.w = clamp(length(vPositionOffset) * vFog.x + vFog.y, 0.0, 1.0) * vFog.z;
#elif (FOG_TYPE == 2)
// FOG_EXP2
v_vData0.w = 1.0 - exp2(-length(vPositionOffset) * fFogDensity);
#elif (FOG_TYPE == 3)
// FOG_EXP
v_vData0.w = 1.0 - exp(-length(vPositionOffset) * fFogDensity);
#elif (FOG_TYPE == 4)
// FOG_HERMITE
v_vData0.w = smoothstep(fFogStart, fFogEnd, length(vPositionOffset)) * fFogScale;
#endif
#endif
#if (FOG_OF_WAR == 1)
v_vData0.xy = (mFowProj * vPosition).xy;
#endif
}
// mesh_color.vsh
//
// Default mesh vertex shader
//=============================================================================
//=============================================================================
// Uniform variables
//=============================================================================
uniform mat4 mWorldViewProj;
uniform mat4 mWorldView;
uniform mat4 mWorldViewOffset; // World * View Offset
uniform mat3 mWorldRotate; // World rotation for normals
uniform vec4 vColor;
uniform vec3 vSunPositionWorld;
uniform vec3 vAmbient;
uniform vec3 vSunColor;
uniform float fFogStart;
uniform float fFogEnd;
uniform float fFogScale;
uniform float fFogDensity;
uniform vec3 vFog;
#if (SHADOWS == 1)
uniform mat4 mLightWorldViewProjTex; // Light's World * View * Projection * Tex
#endif
#if (NUM_BONES > 0)
#ifdef NON_SQUARE_MATRIX
uniform mat3x4 vBones[NUM_BONES];
#else
uniform vec4 vBones3[NUM_BONES * 3];
#endif
#endif
#ifdef CLOUDS
uniform mat4 mCloudProj;
#endif
#if (FOG_OF_WAR == 1)
uniform mat4 mFowProj;
#endif
//=============================================================================
// Varying variables
//=============================================================================
varying vec4 v_vColor;
#if (LIGHTING_QUALITY == 0)
varying vec3 v_vNormal;
varying vec3 v_vTangent;
varying vec3 v_vBinormal;
#elif (LIGHTING_QUALITY == 1)
varying vec3 v_vHalfAngle;
#ifdef GROUND_AMBIENT
varying vec4 v_vSunLight;
#else
varying vec3 v_vSunLight;
#endif
#elif (LIGHTING_QUALITY == 2)
#ifdef GROUND_AMBIENT
varying vec4 v_vDiffLight;
#else
varying vec3 v_vDiffLight;
#endif
#endif
#if (LIGHTING_QUALITY == 0 || FALLOFF_QUALITY == 0)
varying vec3 v_vPositionOffset;
#endif
#if (SHADOWS == 1)
varying vec4 v_vTexcoordLight;
#endif
#ifdef CLOUDS
varying vec2 v_vClouds;
#endif
#if ((FOG_QUALITY == 1 && FOG_TYPE != 0) || (FALLOFF_QUALITY == 1 && (FOG_TYPE != 0 || SHADOWS == 1)) || FOG_OF_WAR == 1)
varying vec4 v_vData0;
#endif
//=============================================================================
// Vertex attributes
//=============================================================================
attribute vec4 a_vPosition;
attribute vec3 a_vNormal;
attribute vec4 a_vTexCoord0;
attribute vec4 a_vTangent;
#if (NUM_BONES > 0)
attribute vec4 a_vBoneIndex;
attribute vec4 a_vBoneWeight;
#endif
//=============================================================================
// Vertex Shader
//=============================================================================
void main()
{
#if ((FOG_QUALITY == 1 && FOG_TYPE != 0) || (FALLOFF_QUALITY == 1 && (FOG_TYPE != 0 || SHADOWS == 1)) || FOG_OF_WAR == 1)
v_vData0 = vec4(0.0, 0.0, 0.0, 0.0);
#endif
vec3 vInNormal = (a_vNormal / 255.0) * 2.0 - 1.0;
vec4 vInTangent = (a_vTangent / 255.0) * 2.0 - 1.0;
#if (NUM_BONES > 0)
vec4 vPosition;
vec3 vNormal;
vec3 vTangent;
//
// GPU Skinning
// Blend bone matrix transforms for this bone
//
vec4 vBlendIndex = a_vBoneIndex;
vec4 vBoneWeight = a_vBoneWeight;
#ifdef NON_SQUARE_MATRIX
mat3x4 mBlend = mat3x4(0.0);
for (int i = 0; i < NUM_BONE_WEIGHTS; ++i)
mBlend += vBones[int(vBlendIndex)] * vBoneWeight;
#else
mat4 mBlend = mat4(0.0);
mBlend[3][3] = 1.0;
for (int i = 0; i < NUM_BONE_WEIGHTS; ++i)
{
mBlend[0] += vBones3[int(vBlendIndex) * 3 + 0] * vBoneWeight;
mBlend[1] += vBones3[int(vBlendIndex) * 3 + 1] * vBoneWeight;
mBlend[2] += vBones3[int(vBlendIndex) * 3 + 2] * vBoneWeight;
}
#endif
vPosition = vec4((a_vPosition * mBlend).xyz, 1.0);
vNormal = normalize((vec4(vInNormal, 0.0) * mBlend).xyz);
vTangent = normalize((vec4(vInTangent.xyz, 0.0) * mBlend).xyz);
#else
vec4 vPosition = a_vPosition;
vec3 vNormal = vInNormal;
vec3 vTangent = vInTangent.xyz;
#endif
vec3 vPositionOffset = (mWorldViewOffset * vPosition).xyz;
gl_Position = mWorldViewProj * vPosition;
#if (WATER_QUALITY == 0)
gl_ClipVertex = mWorldView * vPosition;
#else
#ifdef REFLECTIONS
gl_ClipVertex = mWorldView * vPosition;
#endif
#endif
gl_TexCoord[0] = a_vTexCoord0;
v_vColor = vColor;
#if (LIGHTING_QUALITY == 0)
v_vNormal = mWorldRotate * vNormal;
v_vTangent = mWorldRotate * vTangent;
v_vBinormal = cross(v_vTangent, v_vNormal) * vInTangent.w;
#elif (LIGHTING_QUALITY == 1)
vec3 vCamDirection = -normalize(vPositionOffset);
vec3 vLight = vSunPositionWorld;
vec3 vWVNormal = mWorldRotate * vNormal;
vec3 vWVTangent = mWorldRotate * vTangent;
vec3 vWVBinormal = cross(vWVTangent, vWVNormal) * vInTangent.w;
mat3 mRotate = mat3(vWVTangent, vWVBinormal, vWVNormal);
v_vSunLight.xyz = vLight * mRotate;
#ifdef GROUND_AMBIENT
v_vSunLight.w = dot(vWVNormal, vec3(0.0, 0.0, 1.0)) * 0.375 + 0.625;
#endif
v_vHalfAngle = normalize(vLight + vCamDirection) * mRotate;
#elif (LIGHTING_QUALITY == 2)
vec3 vLight = vSunPositionWorld;
vec3 vWVNormal = mWorldRotate * vNormal;
float fDiffuse = max(dot(vWVNormal, vLight), 0.0);
v_vDiffLight.xyz = vSunColor * fDiffuse;
#ifdef GROUND_AMBIENT
v_vDiffLight.w = dot(vWVNormal, vec3(0.0, 0.0, 1.0)) * 0.375 + 0.625;
#endif
#endif
#if (LIGHTING_QUALITY == 0 || FALLOFF_QUALITY == 0)
v_vPositionOffset = vPositionOffset;
#endif
#if (SHADOWS == 1)
v_vTexcoordLight = mLightWorldViewProjTex * vPosition;
#endif
#ifdef CLOUDS
v_vClouds = (mCloudProj * vPosition).xy;
#endif
#if (FALLOFF_QUALITY == 1 && (FOG_TYPE != 0 || SHADOWS == 1))
v_vData0.z = length(vPositionOffset);
#endif
#if (FOG_QUALITY == 1 && FOG_TYPE != 0)
#if (FOG_TYPE == 0)
// FOG_NONE
v_vData0.w = 0.0;
#elif (FOG_TYPE == 1)
// FOG_LINEAR
v_vData0.w = clamp(length(vPositionOffset) * vFog.x + vFog.y, 0.0, 1.0) * vFog.z;
#elif (FOG_TYPE == 2)
// FOG_EXP2
v_vData0.w = 1.0 - exp2(-length(vPositionOffset) * fFogDensity);
#elif (FOG_TYPE == 3)
// FOG_EXP
v_vData0.w = 1.0 - exp(-length(vPositionOffset) * fFogDensity);
#elif (FOG_TYPE == 4)
// FOG_HERMITE
v_vData0.w = smoothstep(fFogStart, fFogEnd, length(vPositionOffset)) * fFogScale;
#endif
#endif
#if (FOG_OF_WAR == 1)
v_vData0.xy = (mFowProj * vPosition).xy;
#endif
}