GPU-skinned tangent-space effects for non-instanced units, plus a bit of cleanup.

This was SVN commit r12795.
This commit is contained in:
myconid 2012-10-29 13:20:21 +00:00
parent ae4b3cc9b6
commit 367c67d6ad
14 changed files with 205 additions and 180 deletions

View File

@ -73,9 +73,12 @@ renderpath = default
; Prefer GLSL shaders over ARB shaders (not recommended). REQUIRES gentangents=true.
preferglsl = false
; Generate tangents for normal and parallax mapping. REQUIRES preferglsl=true. Incompatible with gpuskinning.
; Generate tangents for normal and parallax mapping. REQUIRES preferglsl=true.
gentangents = false
; Experimental probably-non-working GPU skinning support; requires preferglsl; use at own risk
gpuskinning = false
; Use smooth LOS interpolation; REQUIRES preferglsl=true.
smoothlos = false
@ -96,9 +99,6 @@ materialmgr.PARALLAX_VHQ_DIST.max = 0
; Replace alpha-blending with alpha-testing, for performance experiments
forcealphatest = false
; Experimental probably-non-working GPU skinning support; requires preferglsl; use at own risk
gpuskinning = false
; Opt-in online user reporting system
userreport.url = "http://feedback.wildfiregames.com/report/upload/v1/"

View File

@ -38,7 +38,7 @@ varying vec4 v_lighting;
varying vec2 v_tex;
varying vec2 v_los;
#if USE_INSTANCING && USE_AO
#if (USE_INSTANCING || USE_GPU_SKINNING) && USE_AO
varying vec2 v_tex2;
#endif
@ -53,14 +53,14 @@ varying vec2 v_los;
#if USE_SPECULAR || USE_NORMAL_MAP || USE_SPECULAR_MAP || USE_PARALLAX_MAP
varying vec4 v_normal;
#if USE_INSTANCING && (USE_NORMAL_MAP || USE_PARALLAX_MAP)
#if (USE_INSTANCING || USE_GPU_SKINNING) && (USE_NORMAL_MAP || USE_PARALLAX_MAP)
varying vec4 v_tangent;
//varying vec3 v_bitangent;
#endif
#if USE_SPECULAR || USE_SPECULAR_MAP
varying vec3 v_half;
#endif
#if USE_INSTANCING && USE_PARALLAX_MAP
#if (USE_INSTANCING || USE_GPU_SKINNING) && USE_PARALLAX_MAP
varying vec3 v_eyeVec;
#endif
#endif
@ -112,12 +112,12 @@ void main()
{
vec2 coord = v_tex;
#if USE_PARALLAX_MAP || USE_NORMAL_MAP
#if (USE_INSTANCING || USE_GPU_SKINNING) && (USE_PARALLAX_MAP || USE_NORMAL_MAP)
vec3 bitangent = vec3(v_normal.w, v_tangent.w, v_lighting.w);
mat3 tbn = mat3(v_tangent.xyz, bitangent, v_normal.xyz);
#endif
#if USE_PARALLAX_MAP
#if (USE_INSTANCING || USE_GPU_SKINNING) && USE_PARALLAX_MAP
{
float h = texture2D(normTex, coord).a;
@ -222,7 +222,7 @@ void main()
vec3 normal = v_normal.xyz;
#endif
#if USE_INSTANCING && USE_NORMAL_MAP
#if (USE_INSTANCING || USE_GPU_SKINNING) && USE_NORMAL_MAP
vec3 ntex = texture2D(normTex, coord).rgb * 2.0 - 1.0;
ntex.y = -ntex.y;
normal = normalize(tbn * ntex);
@ -251,7 +251,7 @@ void main()
vec3 color = (texdiffuse * sundiffuse + specular.rgb) * get_shadow();
vec3 ambColor = texdiffuse * ambient;
#if USE_INSTANCING && USE_AO
#if (USE_INSTANCING || USE_GPU_SKINNING) && USE_AO
vec3 ao = texture2D(aoTex, v_tex2).rrr;
ao = mix(vec3(1.0), ao * 2.0, effectSettings.w);
ambColor *= ao;

View File

@ -30,27 +30,27 @@ varying vec2 v_los;
varying vec4 v_shadow;
#endif
#if USE_INSTANCING && USE_AO
#if (USE_INSTANCING || USE_GPU_SKINNING) && USE_AO
varying vec2 v_tex2;
#endif
#if USE_SPECULAR || USE_NORMAL_MAP || USE_SPECULAR_MAP || USE_PARALLAX_MAP
varying vec4 v_normal;
#if USE_INSTANCING && (USE_NORMAL_MAP || USE_PARALLAX_MAP)
#if (USE_INSTANCING || USE_GPU_SKINNING) && (USE_NORMAL_MAP || USE_PARALLAX_MAP)
varying vec4 v_tangent;
//varying vec3 v_bitangent;
#endif
#if USE_SPECULAR || USE_SPECULAR_MAP
varying vec3 v_half;
#endif
#if USE_INSTANCING && USE_PARALLAX_MAP
#if (USE_INSTANCING || USE_GPU_SKINNING) && USE_PARALLAX_MAP
varying vec3 v_eyeVec;
#endif
#endif
attribute vec3 a_vertex;
attribute vec3 a_normal;
#if USE_INSTANCING
#if (USE_INSTANCING || USE_GPU_SKINNING)
attribute vec4 a_tangent;
#endif
attribute vec2 a_uv0;
@ -86,9 +86,13 @@ void main()
}
}
vec4 position = instancingTransform * vec4(p, 1.0);
vec3 normal = mat3(instancingTransform) * normalize(n);
mat3 normalMatrix = mat3(instancingTransform[0].xyz, instancingTransform[1].xyz, instancingTransform[2].xyz);
vec3 normal = normalMatrix * normalize(n);
#if (USE_NORMAL_MAP || USE_PARALLAX_MAP)
vec3 tangent = normalMatrix * a_tangent.xyz;
#endif
#else
#if USE_INSTANCING
#if (USE_INSTANCING)
vec4 position = instancingTransform * vec4(a_vertex, 1.0);
mat3 normalMatrix = mat3(instancingTransform[0].xyz, instancingTransform[1].xyz, instancingTransform[2].xyz);
vec3 normal = normalMatrix * a_normal;
@ -140,7 +144,7 @@ void main()
#if USE_SPECULAR || USE_NORMAL_MAP || USE_SPECULAR_MAP || USE_PARALLAX_MAP
v_normal.xyz = normal;
#if USE_INSTANCING && (USE_NORMAL_MAP || USE_PARALLAX_MAP)
#if (USE_INSTANCING || USE_GPU_SKINNING) && (USE_NORMAL_MAP || USE_PARALLAX_MAP)
v_tangent.xyz = tangent;
vec3 bitangent = cross(v_normal.xyz, v_tangent.xyz) * a_tangent.w;
v_normal.w = bitangent.x;
@ -154,7 +158,7 @@ void main()
vec3 sunVec = -sunDir;
v_half = normalize(sunVec + normalize(eyeVec));
#endif
#if USE_INSTANCING && USE_PARALLAX_MAP
#if (USE_INSTANCING || USE_GPU_SKINNING) && USE_PARALLAX_MAP
v_eyeVec = eyeVec;
#endif
#endif
@ -164,7 +168,7 @@ void main()
v_tex = a_uv0;
#if USE_INSTANCING && USE_AO
#if (USE_INSTANCING || USE_GPU_SKINNING) && USE_AO
v_tex2 = a_uv1;
#endif

View File

@ -12,7 +12,7 @@
<attrib name="a_uv1" semantics="gl_MultiTexCoord1" if="USE_AO"/>
<attrib name="a_skinJoints" semantics="CustomAttribute0" if="USE_GPU_SKINNING"/>
<attrib name="a_skinWeights" semantics="CustomAttribute1" if="USE_GPU_SKINNING"/>
<attrib name="a_tangent" semantics="CustomAttribute2" if="USE_INSTANCING"/>
<attrib name="a_tangent" semantics="CustomAttribute2" if="USE_INSTANCING || USE_GPU_SKINNING"/>
</vertex>
<fragment file="glsl/model_common.fs"/>

View File

@ -31,13 +31,14 @@
#include "graphics/LightEnv.h"
#include "graphics/Model.h"
#include "graphics/ModelDef.h"
#include "graphics/weldmesh.h"
#include "renderer/InstancingModelRenderer.h"
#include "renderer/Renderer.h"
#include "renderer/RenderModifiers.h"
#include "renderer/VertexArray.h"
#include "third_party/mikktspace/weldmesh.h"
///////////////////////////////////////////////////////////////////////////////////////////////
// InstancingModelRenderer implementation
@ -85,6 +86,17 @@ IModelDef::IModelDef(const CModelDefPtr& mdef, bool gpuSkinning, bool calculateT
m_Array.AddAttribute(&m_UVs[i]);
}
if (gpuSkinning)
{
m_BlendJoints.type = GL_UNSIGNED_BYTE;
m_BlendJoints.elems = 4;
m_Array.AddAttribute(&m_BlendJoints);
m_BlendWeights.type = GL_UNSIGNED_BYTE;
m_BlendWeights.elems = 4;
m_Array.AddAttribute(&m_BlendWeights);
}
if (calculateTangents)
{
// Generate tangents for the geometry:-
@ -93,8 +105,12 @@ IModelDef::IModelDef(const CModelDefPtr& mdef, bool gpuSkinning, bool calculateT
m_Tangent.elems = 4;
m_Array.AddAttribute(&m_Tangent);
// floats per vertex; position + normal + tangent + UV*sets
// floats per vertex; position + normal + tangent + UV*sets [+ GPUskinning]
int numVertexAttrs = 3 + 3 + 4 + 2 * mdef->GetNumUVsPerVertex();
if (gpuSkinning)
{
numVertexAttrs += 8;
}
// the tangent generation can increase the number of vertices temporarily
// so reserve a bit more memory to avoid reallocations in GenTangents (in most cases)
@ -102,7 +118,7 @@ IModelDef::IModelDef(const CModelDefPtr& mdef, bool gpuSkinning, bool calculateT
newVertices.reserve(numVertexAttrs * numVertices * 2);
// Generate the tangents
ModelRenderer::GenTangents(mdef, newVertices);
ModelRenderer::GenTangents(mdef, newVertices, gpuSkinning);
// how many vertices do we have after generating tangents?
int newNumVert = newVertices.size() / numVertexAttrs;
@ -123,23 +139,44 @@ IModelDef::IModelDef(const CModelDefPtr& mdef, bool gpuSkinning, bool calculateT
VertexArrayIterator<CVector3D> Normal = m_Normal.GetIterator<CVector3D>();
VertexArrayIterator<CVector4D> Tangent = m_Tangent.GetIterator<CVector4D>();
VertexArrayIterator<u8[4]> BlendJoints;
VertexArrayIterator<u8[4]> BlendWeights;
if (gpuSkinning)
{
BlendJoints = m_BlendJoints.GetIterator<u8[4]>();
BlendWeights = m_BlendWeights.GetIterator<u8[4]>();
}
// copy everything into the vertex array
for (int i = 0; i < numVertices2; i++)
{
int q = numVertexAttrs * i;
Position[i] = CVector3D(vertexDataOut[q + 0], vertexDataOut[q + 1], vertexDataOut[q + 2]);
q += 3;
Normal[i] = CVector3D(vertexDataOut[q + 3], vertexDataOut[q + 4], vertexDataOut[q + 5]);
Normal[i] = CVector3D(vertexDataOut[q + 0], vertexDataOut[q + 1], vertexDataOut[q + 2]);
q += 3;
Tangent[i] = CVector4D(vertexDataOut[q + 6], vertexDataOut[q + 7], vertexDataOut[q + 8],
vertexDataOut[q + 9]);
Tangent[i] = CVector4D(vertexDataOut[q + 0], vertexDataOut[q + 1], vertexDataOut[q + 2],
vertexDataOut[q + 3]);
q += 4;
if (gpuSkinning)
{
for (size_t j = 0; j < 4; ++j)
{
BlendJoints[i][j] = (u8)vertexDataOut[q + 0 + 2 * j];
BlendWeights[i][j] = (u8)vertexDataOut[q + 1 + 2 * j];
}
q += 8;
}
for (size_t j = 0; j < mdef->GetNumUVsPerVertex(); j++)
{
VertexArrayIterator<float[2]> UVit = m_UVs[j].GetIterator<float[2]>();
UVit[i][0] = vertexDataOut[q + 10 + 2 * j];
UVit[i][1] = vertexDataOut[q + 11 + 2 * j];
UVit[i][0] = vertexDataOut[q + 0 + 2 * j];
UVit[i][1] = vertexDataOut[q + 1 + 2 * j];
}
}
@ -169,17 +206,6 @@ IModelDef::IModelDef(const CModelDefPtr& mdef, bool gpuSkinning, bool calculateT
{
// Upload model without calculating tangents:-
if (gpuSkinning)
{
m_BlendJoints.type = GL_UNSIGNED_BYTE;
m_BlendJoints.elems = 4;
m_Array.AddAttribute(&m_BlendJoints);
m_BlendWeights.type = GL_UNSIGNED_BYTE;
m_BlendWeights.elems = 4;
m_Array.AddAttribute(&m_BlendWeights);
}
m_Array.SetNumVertices(numVertices);
m_Array.Layout();

View File

@ -25,40 +25,42 @@
#include "graphics/ModelDef.h"
#include "graphics/ShaderManager.h"
#include "graphics/TextureManager.h"
#include "graphics/mikktspace.h"
#include "renderer/MikktspaceWrap.h"
#include "third_party/mikktspace/mikktspace.h"
MikkTSpace::MikkTSpace(const CModelDefPtr& m, std::vector<float>& v) : model(m), newVertices(v)
MikkTSpace::MikkTSpace(const CModelDefPtr& m, std::vector<float>& v, bool gpuSkinning) : m_Model(m),
m_NewVertices(v), m_GpuSkinning(gpuSkinning)
{
// ensure that newVertices is empty
newVertices.clear();
// ensure that m_NewVertices is empty
m_NewVertices.clear();
// set up SMikkTSpaceInterface struct
interface.m_getNumFaces = getNumFaces;
interface.m_getNumVerticesOfFace = getNumVerticesOfFace;
interface.m_getPosition = getPosition;
interface.m_getNormal = getNormal;
interface.m_getTexCoord = getTexCoord;
interface.m_setTSpaceBasic = NULL;
interface.m_setTSpace = setTSpace;
m_Interface.m_getNumFaces = getNumFaces;
m_Interface.m_getNumVerticesOfFace = getNumVerticesOfFace;
m_Interface.m_getPosition = getPosition;
m_Interface.m_getNormal = getNormal;
m_Interface.m_getTexCoord = getTexCoord;
m_Interface.m_setTSpaceBasic = NULL;
m_Interface.m_setTSpace = setTSpace;
// set up SMikkTSpaceContext struct
context.m_pInterface = &interface;
context.m_pUserData = (void*)this;
m_Context.m_pInterface = &m_Interface;
m_Context.m_pUserData = (void*)this;
}
void MikkTSpace::generate()
{
genTangSpaceDefault(&context);
genTangSpaceDefault(&m_Context);
}
int MikkTSpace::getNumFaces(const SMikkTSpaceContext *pContext)
{
return ((MikkTSpace*)pContext->m_pUserData)->model->GetNumFaces();
return ((MikkTSpace*)pContext->m_pUserData)->m_Model->GetNumFaces();
}
@ -71,9 +73,9 @@ int MikkTSpace::getNumVerticesOfFace(const SMikkTSpaceContext* UNUSED(pContext),
void MikkTSpace::getPosition(const SMikkTSpaceContext *pContext,
float fvPosOut[], const int iFace, const int iVert)
{
SModelFace &face = ((MikkTSpace*)pContext->m_pUserData)->model->GetFaces()[iFace];
SModelFace &face = ((MikkTSpace*)pContext->m_pUserData)->m_Model->GetFaces()[iFace];
long i = face.m_Verts[iVert];
const CVector3D &p = ((MikkTSpace*)pContext->m_pUserData)->model->GetVertices()[i].m_Coords;
const CVector3D &p = ((MikkTSpace*)pContext->m_pUserData)->m_Model->GetVertices()[i].m_Coords;
fvPosOut[0] = p.X;
fvPosOut[1] = p.Y;
@ -84,9 +86,9 @@ void MikkTSpace::getPosition(const SMikkTSpaceContext *pContext,
void MikkTSpace::getNormal(const SMikkTSpaceContext *pContext,
float fvNormOut[], const int iFace, const int iVert)
{
SModelFace &face = ((MikkTSpace*)pContext->m_pUserData)->model->GetFaces()[iFace];
SModelFace &face = ((MikkTSpace*)pContext->m_pUserData)->m_Model->GetFaces()[iFace];
long i = face.m_Verts[iVert];
const CVector3D &n = ((MikkTSpace*)pContext->m_pUserData)->model->GetVertices()[i].m_Norm;
const CVector3D &n = ((MikkTSpace*)pContext->m_pUserData)->m_Model->GetVertices()[i].m_Norm;
fvNormOut[0] = n.X;
fvNormOut[1] = n.Y;
@ -97,9 +99,9 @@ void MikkTSpace::getNormal(const SMikkTSpaceContext *pContext,
void MikkTSpace::getTexCoord(const SMikkTSpaceContext *pContext,
float fvTexcOut[], const int iFace, const int iVert)
{
SModelFace &face = ((MikkTSpace*)pContext->m_pUserData)->model->GetFaces()[iFace];
SModelFace &face = ((MikkTSpace*)pContext->m_pUserData)->m_Model->GetFaces()[iFace];
long i = face.m_Verts[iVert];
SModelVertex &v = ((MikkTSpace*)pContext->m_pUserData)->model->GetVertices()[i];
SModelVertex &v = ((MikkTSpace*)pContext->m_pUserData)->m_Model->GetVertices()[i];
// the tangents are calculated according to the 'default' UV set
fvTexcOut[0] = v.m_UVs[0];
@ -111,33 +113,42 @@ void MikkTSpace::setTSpace(const SMikkTSpaceContext * pContext, const float fvTa
const float UNUSED(fvBiTangent)[], const float UNUSED(fMagS), const float UNUSED(fMagT),
const tbool bIsOrientationPreserving, const int iFace, const int iVert)
{
SModelFace &face = ((MikkTSpace*)pContext->m_pUserData)->model->GetFaces()[iFace];
SModelFace &face = ((MikkTSpace*)pContext->m_pUserData)->m_Model->GetFaces()[iFace];
long i = face.m_Verts[iVert];
SModelVertex* vertices = ((MikkTSpace*)pContext->m_pUserData)->model->GetVertices();
size_t numUVsPerVertex = ((MikkTSpace*)pContext->m_pUserData)->model->GetNumUVsPerVertex();
std::vector<float>& newVertices = ((MikkTSpace*)pContext->m_pUserData)->newVertices;
SModelVertex* vertices = ((MikkTSpace*)pContext->m_pUserData)->m_Model->GetVertices();
size_t numUVsPerVertex = ((MikkTSpace*)pContext->m_pUserData)->m_Model->GetNumUVsPerVertex();
std::vector<float>& m_NewVertices = ((MikkTSpace*)pContext->m_pUserData)->m_NewVertices;
const CVector3D &p = vertices[i].m_Coords;
const CVector3D &n = vertices[i].m_Norm;
newVertices.push_back(p.X);
newVertices.push_back(p.Y);
newVertices.push_back(p.Z);
m_NewVertices.push_back(p.X);
m_NewVertices.push_back(p.Y);
m_NewVertices.push_back(p.Z);
newVertices.push_back(n.X);
newVertices.push_back(n.Y);
newVertices.push_back(n.Z);
m_NewVertices.push_back(n.X);
m_NewVertices.push_back(n.Y);
m_NewVertices.push_back(n.Z);
newVertices.push_back(fvTangent[0]);
newVertices.push_back(fvTangent[1]);
newVertices.push_back(fvTangent[2]);
newVertices.push_back(bIsOrientationPreserving > 0.5 ? 1.0f : (-1.0f));
m_NewVertices.push_back(fvTangent[0]);
m_NewVertices.push_back(fvTangent[1]);
m_NewVertices.push_back(fvTangent[2]);
m_NewVertices.push_back(bIsOrientationPreserving > 0.5 ? 1.0f : (-1.0f));
if (((MikkTSpace*)pContext->m_pUserData)->m_GpuSkinning)
{
for (size_t j = 0; j < 4; ++j)
{
m_NewVertices.push_back(vertices[i].m_Blend.m_Bone[j]);
m_NewVertices.push_back(255.f * vertices[i].m_Blend.m_Weight[j]);
}
}
for (size_t UVset = 0; UVset < numUVsPerVertex; ++UVset)
{
newVertices.push_back(vertices[i].m_UVs[UVset * 2]);
newVertices.push_back(1.0 - vertices[i].m_UVs[UVset * 2 + 1]);
m_NewVertices.push_back(vertices[i].m_UVs[UVset * 2]);
m_NewVertices.push_back(1.0 - vertices[i].m_UVs[UVset * 2 + 1]);
}
}

View File

@ -19,7 +19,7 @@
#define INCLUDED_MIKKWRAP
#include "graphics/mikktspace.h"
#include "third_party/mikktspace/mikktspace.h"
// Disable useless MSVC warning
#if MSC_VERSION
@ -31,18 +31,19 @@ class MikkTSpace
public:
MikkTSpace(const CModelDefPtr& m, std::vector<float>& v);
MikkTSpace(const CModelDefPtr& m, std::vector<float>& v, bool gpuSkinning);
void generate();
private:
SMikkTSpaceInterface interface;
SMikkTSpaceContext context;
SMikkTSpaceInterface m_Interface;
SMikkTSpaceContext m_Context;
const CModelDefPtr& model;
const CModelDefPtr& m_Model;
std::vector<float>& newVertices;
std::vector<float>& m_NewVertices;
bool m_GpuSkinning;
// Returns the number of faces (triangles/quads) on the mesh to be processed.
@ -66,20 +67,6 @@ private:
float fvTexcOut[], const int iFace, const int iVert);
// either (or both) of the two setTSpace callbacks can be set.
// The call-back m_setTSpaceBasic() is sufficient for basic normal mapping.
// This function is used to return the tangent and fSign to the application.
// fvTangent is a unit length vector.
// For normal maps it is sufficient to use the following simplified version of the bitangent which is generated at pixel/vertex level.
// bitangent = fSign * cross(vN, tangent);
// Note that the results are returned unindexed. It is possible to generate a new index list
// But averaging/overwriting tangent spaces by using an already existing index list WILL produce INCRORRECT results.
// DO NOT! use an already existing index list.
//void setTSpaceBasic(const MikkTSpace *parent, const SMikkTSpaceContext *pContext,
// const float fvTangent[], const float fSign, const int iFace, const int iVert);
// This function is used to return tangent space results to the application.
// fvTangent and fvBiTangent are unit length vectors and fMagS and fMagT are their
// true magnitudes which can be used for relief mapping effects.
@ -88,9 +75,6 @@ private:
// For normal maps it is sufficient to use the following simplified version of the bitangent which is generated at pixel/vertex level.
// fSign = bIsOrientationPreserving ? 1.0f : (-1.0f);
// bitangent = fSign * cross(vN, tangent);
// Note that the results are returned unindexed. It is possible to generate a new index list
// But averaging/overwriting tangent spaces by using an already existing index list WILL produce INCRORRECT results.
// DO NOT! use an already existing index list.
static void setTSpace(const SMikkTSpaceContext * pContext, const float fvTangent[],
const float fvBiTangent[], const float fMagS, const float fMagT,
const tbool bIsOrientationPreserving, const int iFace, const int iVert);

View File

@ -149,9 +149,9 @@ void ModelRenderer::BuildColor4ub(
}
void ModelRenderer::GenTangents(const CModelDefPtr& mdef, std::vector<float>& newVertices)
void ModelRenderer::GenTangents(const CModelDefPtr& mdef, std::vector<float>& newVertices, bool gpuSkinning)
{
MikkTSpace ms(mdef, newVertices);
MikkTSpace ms(mdef, newVertices, gpuSkinning);
ms.generate();
}

View File

@ -262,7 +262,7 @@ public:
* @param newVertices An out vector of the unindexed vertices with tangents added.
* The new vertices cannot be used with existing face index and must be welded/reindexed.
*/
static void GenTangents(const CModelDefPtr& mdef, std::vector<float>& newVertices);
static void GenTangents(const CModelDefPtr& mdef, std::vector<float>& newVertices, bool gpuSkinning);
};

View File

@ -584,7 +584,7 @@ void CRenderer::ReloadShaders()
if (GetRenderPath() == RP_SHADER && m_Options.m_GPUSkinning) // TODO: should check caps and GLSL etc too
{
m->Model.VertexGPUSkinningShader = ModelVertexRendererPtr(new InstancingModelRenderer(true, false));
m->Model.VertexGPUSkinningShader = ModelVertexRendererPtr(new InstancingModelRenderer(true, m_Options.m_GenTangents));
m->Model.NormalSkinned = ModelRendererPtr(new ShaderModelRenderer(m->Model.VertexGPUSkinningShader));
m->Model.TranspSkinned = ModelRendererPtr(new ShaderModelRenderer(m->Model.VertexGPUSkinningShader));
}