diff --git a/binaries/data/config/default.cfg b/binaries/data/config/default.cfg index d18a3d026b..97cd451d24 100644 --- a/binaries/data/config/default.cfg +++ b/binaries/data/config/default.cfg @@ -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/" diff --git a/binaries/data/mods/public/shaders/glsl/model_common.fs b/binaries/data/mods/public/shaders/glsl/model_common.fs index d6bb9dd0a4..5ffe2a254c 100644 --- a/binaries/data/mods/public/shaders/glsl/model_common.fs +++ b/binaries/data/mods/public/shaders/glsl/model_common.fs @@ -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; diff --git a/binaries/data/mods/public/shaders/glsl/model_common.vs b/binaries/data/mods/public/shaders/glsl/model_common.vs index f5cd2af6ee..1d4a324d22 100644 --- a/binaries/data/mods/public/shaders/glsl/model_common.vs +++ b/binaries/data/mods/public/shaders/glsl/model_common.vs @@ -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 diff --git a/binaries/data/mods/public/shaders/glsl/model_common.xml b/binaries/data/mods/public/shaders/glsl/model_common.xml index 8b7c47ef7c..0eb6fef37c 100644 --- a/binaries/data/mods/public/shaders/glsl/model_common.xml +++ b/binaries/data/mods/public/shaders/glsl/model_common.xml @@ -12,7 +12,7 @@ - + diff --git a/source/renderer/InstancingModelRenderer.cpp b/source/renderer/InstancingModelRenderer.cpp index d7c37faf3b..06e4b670eb 100644 --- a/source/renderer/InstancingModelRenderer.cpp +++ b/source/renderer/InstancingModelRenderer.cpp @@ -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 Normal = m_Normal.GetIterator(); VertexArrayIterator Tangent = m_Tangent.GetIterator(); + VertexArrayIterator BlendJoints; + VertexArrayIterator BlendWeights; + if (gpuSkinning) + { + BlendJoints = m_BlendJoints.GetIterator(); + BlendWeights = m_BlendWeights.GetIterator(); + } + // 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 UVit = m_UVs[j].GetIterator(); - 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(); diff --git a/source/renderer/MikktspaceWrap.cpp b/source/renderer/MikktspaceWrap.cpp index 8499050f9b..eb10368b6c 100644 --- a/source/renderer/MikktspaceWrap.cpp +++ b/source/renderer/MikktspaceWrap.cpp @@ -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& v) : model(m), newVertices(v) + +MikkTSpace::MikkTSpace(const CModelDefPtr& m, std::vector& 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& 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& 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]); } } diff --git a/source/renderer/MikktspaceWrap.h b/source/renderer/MikktspaceWrap.h index fc8e96a953..afcb59faa3 100644 --- a/source/renderer/MikktspaceWrap.h +++ b/source/renderer/MikktspaceWrap.h @@ -1,102 +1,86 @@ -/* Copyright (C) 2012 Wildfire Games. - * This file is part of 0 A.D. - * - * 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 - * the Free Software Foundation, either version 2 of the License, or - * (at your option) any later version. - * - * 0 A.D. is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with 0 A.D. If not, see . - */ - -#ifndef INCLUDED_MIKKWRAP -#define INCLUDED_MIKKWRAP - - -#include "graphics/mikktspace.h" - -// Disable useless MSVC warning +/* Copyright (C) 2012 Wildfire Games. + * This file is part of 0 A.D. + * + * 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 + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * 0 A.D. is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with 0 A.D. If not, see . + */ + +#ifndef INCLUDED_MIKKWRAP +#define INCLUDED_MIKKWRAP + + +#include "third_party/mikktspace/mikktspace.h" + +// Disable useless MSVC warning #if MSC_VERSION # pragma warning(disable:4512) // "assignment operator could not be generated" -#endif - -class MikkTSpace -{ - -public: - - MikkTSpace(const CModelDefPtr& m, std::vector& v); - - void generate(); - -private: - - SMikkTSpaceInterface interface; - SMikkTSpaceContext context; - - const CModelDefPtr& model; - - std::vector& newVertices; - - - // 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} - 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. - 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 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 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. - // 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 + +class MikkTSpace +{ + +public: + + MikkTSpace(const CModelDefPtr& m, std::vector& v, bool gpuSkinning); + + void generate(); + +private: + + SMikkTSpaceInterface m_Interface; + SMikkTSpaceContext m_Context; + + const CModelDefPtr& m_Model; + + std::vector& 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 vertices on face number 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. + 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 getTexCoord(const SMikkTSpaceContext *pContext, + float fvTexcOut[], 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); + 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 \ No newline at end of file diff --git a/source/renderer/ModelRenderer.cpp b/source/renderer/ModelRenderer.cpp index f57cf9d305..8741e1eb44 100644 --- a/source/renderer/ModelRenderer.cpp +++ b/source/renderer/ModelRenderer.cpp @@ -149,9 +149,9 @@ void ModelRenderer::BuildColor4ub( } -void ModelRenderer::GenTangents(const CModelDefPtr& mdef, std::vector& newVertices) +void ModelRenderer::GenTangents(const CModelDefPtr& mdef, std::vector& newVertices, bool gpuSkinning) { - MikkTSpace ms(mdef, newVertices); + MikkTSpace ms(mdef, newVertices, gpuSkinning); ms.generate(); } diff --git a/source/renderer/ModelRenderer.h b/source/renderer/ModelRenderer.h index dde9a359d2..3aed661515 100644 --- a/source/renderer/ModelRenderer.h +++ b/source/renderer/ModelRenderer.h @@ -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& newVertices); + static void GenTangents(const CModelDefPtr& mdef, std::vector& newVertices, bool gpuSkinning); }; diff --git a/source/renderer/Renderer.cpp b/source/renderer/Renderer.cpp index dc487fe3e9..daa9f66a01 100644 --- a/source/renderer/Renderer.cpp +++ b/source/renderer/Renderer.cpp @@ -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)); } diff --git a/source/graphics/mikktspace.cpp b/source/third_party/mikktspace/mikktspace.cpp similarity index 100% rename from source/graphics/mikktspace.cpp rename to source/third_party/mikktspace/mikktspace.cpp diff --git a/source/graphics/mikktspace.h b/source/third_party/mikktspace/mikktspace.h similarity index 100% rename from source/graphics/mikktspace.h rename to source/third_party/mikktspace/mikktspace.h diff --git a/source/graphics/weldmesh.cpp b/source/third_party/mikktspace/weldmesh.cpp similarity index 100% rename from source/graphics/weldmesh.cpp rename to source/third_party/mikktspace/weldmesh.cpp diff --git a/source/graphics/weldmesh.h b/source/third_party/mikktspace/weldmesh.h similarity index 100% rename from source/graphics/weldmesh.h rename to source/third_party/mikktspace/weldmesh.h