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. ; Prefer GLSL shaders over ARB shaders (not recommended). REQUIRES gentangents=true.
preferglsl = false 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 gentangents = false
; Experimental probably-non-working GPU skinning support; requires preferglsl; use at own risk
gpuskinning = false
; Use smooth LOS interpolation; REQUIRES preferglsl=true. ; Use smooth LOS interpolation; REQUIRES preferglsl=true.
smoothlos = false smoothlos = false
@ -96,9 +99,6 @@ materialmgr.PARALLAX_VHQ_DIST.max = 0
; Replace alpha-blending with alpha-testing, for performance experiments ; Replace alpha-blending with alpha-testing, for performance experiments
forcealphatest = false forcealphatest = false
; Experimental probably-non-working GPU skinning support; requires preferglsl; use at own risk
gpuskinning = false
; Opt-in online user reporting system ; Opt-in online user reporting system
userreport.url = "http://feedback.wildfiregames.com/report/upload/v1/" 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_tex;
varying vec2 v_los; varying vec2 v_los;
#if USE_INSTANCING && USE_AO #if (USE_INSTANCING || USE_GPU_SKINNING) && USE_AO
varying vec2 v_tex2; varying vec2 v_tex2;
#endif #endif
@ -53,14 +53,14 @@ varying vec2 v_los;
#if USE_SPECULAR || USE_NORMAL_MAP || USE_SPECULAR_MAP || USE_PARALLAX_MAP #if USE_SPECULAR || USE_NORMAL_MAP || USE_SPECULAR_MAP || USE_PARALLAX_MAP
varying vec4 v_normal; 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 vec4 v_tangent;
//varying vec3 v_bitangent; //varying vec3 v_bitangent;
#endif #endif
#if USE_SPECULAR || USE_SPECULAR_MAP #if USE_SPECULAR || USE_SPECULAR_MAP
varying vec3 v_half; varying vec3 v_half;
#endif #endif
#if USE_INSTANCING && USE_PARALLAX_MAP #if (USE_INSTANCING || USE_GPU_SKINNING) && USE_PARALLAX_MAP
varying vec3 v_eyeVec; varying vec3 v_eyeVec;
#endif #endif
#endif #endif
@ -112,12 +112,12 @@ void main()
{ {
vec2 coord = v_tex; 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); vec3 bitangent = vec3(v_normal.w, v_tangent.w, v_lighting.w);
mat3 tbn = mat3(v_tangent.xyz, bitangent, v_normal.xyz); mat3 tbn = mat3(v_tangent.xyz, bitangent, v_normal.xyz);
#endif #endif
#if USE_PARALLAX_MAP #if (USE_INSTANCING || USE_GPU_SKINNING) && USE_PARALLAX_MAP
{ {
float h = texture2D(normTex, coord).a; float h = texture2D(normTex, coord).a;
@ -222,7 +222,7 @@ void main()
vec3 normal = v_normal.xyz; vec3 normal = v_normal.xyz;
#endif #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; vec3 ntex = texture2D(normTex, coord).rgb * 2.0 - 1.0;
ntex.y = -ntex.y; ntex.y = -ntex.y;
normal = normalize(tbn * ntex); normal = normalize(tbn * ntex);
@ -251,7 +251,7 @@ void main()
vec3 color = (texdiffuse * sundiffuse + specular.rgb) * get_shadow(); vec3 color = (texdiffuse * sundiffuse + specular.rgb) * get_shadow();
vec3 ambColor = texdiffuse * ambient; vec3 ambColor = texdiffuse * ambient;
#if USE_INSTANCING && USE_AO #if (USE_INSTANCING || USE_GPU_SKINNING) && USE_AO
vec3 ao = texture2D(aoTex, v_tex2).rrr; vec3 ao = texture2D(aoTex, v_tex2).rrr;
ao = mix(vec3(1.0), ao * 2.0, effectSettings.w); ao = mix(vec3(1.0), ao * 2.0, effectSettings.w);
ambColor *= ao; ambColor *= ao;

View File

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

View File

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

View File

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

View File

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

View File

@ -1,102 +1,86 @@
/* Copyright (C) 2012 Wildfire Games. /* Copyright (C) 2012 Wildfire Games.
* This file is part of 0 A.D. * This file is part of 0 A.D.
* *
* 0 A.D. is free software: you can redistribute it and/or modify * 0 A.D. is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 2 of the License, or * the Free Software Foundation, either version 2 of the License, or
* (at your option) any later version. * (at your option) any later version.
* *
* 0 A.D. is distributed in the hope that it will be useful, * 0 A.D. is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of * but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details. * GNU General Public License for more details.
* *
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU General Public License
* along with 0 A.D. If not, see <http://www.gnu.org/licenses/>. * along with 0 A.D. If not, see <http://www.gnu.org/licenses/>.
*/ */
#ifndef INCLUDED_MIKKWRAP #ifndef INCLUDED_MIKKWRAP
#define INCLUDED_MIKKWRAP #define INCLUDED_MIKKWRAP
#include "graphics/mikktspace.h" #include "third_party/mikktspace/mikktspace.h"
// Disable useless MSVC warning // Disable useless MSVC warning
#if MSC_VERSION #if MSC_VERSION
# pragma warning(disable:4512) // "assignment operator could not be generated" # pragma warning(disable:4512) // "assignment operator could not be generated"
#endif #endif
class MikkTSpace class MikkTSpace
{ {
public: public:
MikkTSpace(const CModelDefPtr& m, std::vector<float>& v); MikkTSpace(const CModelDefPtr& m, std::vector<float>& v, bool gpuSkinning);
void generate(); void generate();
private: private:
SMikkTSpaceInterface interface; SMikkTSpaceInterface m_Interface;
SMikkTSpaceContext context; 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.
static int getNumFaces(const SMikkTSpaceContext *pContext); // Returns the number of faces (triangles/quads) on the mesh to be processed.
static int getNumFaces(const SMikkTSpaceContext *pContext);
// Returns the number of vertices on face number iFace
// iFace is a number in the range {0, 1, ..., getNumFaces()-1} // Returns the number of vertices on face number iFace
static int getNumVerticesOfFace(const SMikkTSpaceContext *pContext, const int iFace); // iFace is a number in the range {0, 1, ..., getNumFaces()-1}
static int getNumVerticesOfFace(const SMikkTSpaceContext *pContext, const int iFace);
// returns the position/normal/texcoord of the referenced face of vertex number iVert.
// iVert is in the range {0,1,2} for triangles and {0,1,2,3} for quads. // returns the position/normal/texcoord of the referenced face of vertex number iVert.
static void getPosition(const SMikkTSpaceContext *pContext, // iVert is in the range {0,1,2} for triangles and {0,1,2,3} for quads.
float fvPosOut[], const int iFace, const int iVert); static void getPosition(const SMikkTSpaceContext *pContext,
float fvPosOut[], const int iFace, const int iVert);
static void getNormal(const SMikkTSpaceContext *pContext,
float fvNormOut[], const int iFace, const int iVert); static void getNormal(const SMikkTSpaceContext *pContext,
float fvNormOut[], const int iFace, const int iVert);
static void getTexCoord(const SMikkTSpaceContext *pContext,
float fvTexcOut[], const int iFace, const int iVert); static void getTexCoord(const SMikkTSpaceContext *pContext,
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 tangent space results to the application.
// fvTangent and fvBiTangent are unit length vectors and fMagS and fMagT are their
// This function is used to return the tangent and fSign to the application. // true magnitudes which can be used for relief mapping effects.
// fvTangent is a unit length vector. // fvBiTangent is the "real" bitangent and thus may not be perpendicular to fvTangent.
// For normal maps it is sufficient to use the following simplified version of the bitangent which is generated at pixel/vertex level. // However, both are perpendicular to the vertex normal.
// bitangent = fSign * cross(vN, tangent); // For normal maps it is sufficient to use the following simplified version of the bitangent which is generated at pixel/vertex level.
// Note that the results are returned unindexed. It is possible to generate a new index list // fSign = bIsOrientationPreserving ? 1.0f : (-1.0f);
// But averaging/overwriting tangent spaces by using an already existing index list WILL produce INCRORRECT results. // bitangent = fSign * cross(vN, tangent);
// DO NOT! use an already existing index list. static void setTSpace(const SMikkTSpaceContext * pContext, const float fvTangent[],
//void setTSpaceBasic(const MikkTSpace *parent, const SMikkTSpaceContext *pContext, const float fvBiTangent[], const float fMagS, const float fMagT,
// const float fvTangent[], const float fSign, const int iFace, const int iVert); const tbool bIsOrientationPreserving, 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.
// fvBiTangent is the "real" bitangent and thus may not be perpendicular to fvTangent.
// However, both are perpendicular to the vertex normal.
// 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);
};
#endif // INCLUDED_MIKKWRAP #endif // INCLUDED_MIKKWRAP

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(); ms.generate();
} }

View File

@ -262,7 +262,7 @@ public:
* @param newVertices An out vector of the unindexed vertices with tangents added. * @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. * 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 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.NormalSkinned = ModelRendererPtr(new ShaderModelRenderer(m->Model.VertexGPUSkinningShader));
m->Model.TranspSkinned = ModelRendererPtr(new ShaderModelRenderer(m->Model.VertexGPUSkinningShader)); m->Model.TranspSkinned = ModelRendererPtr(new ShaderModelRenderer(m->Model.VertexGPUSkinningShader));
} }