1
0
forked from 0ad/0ad

Transform normals using the original bone matrix instead of the inverse of the

transpose. This assumes orthogonal transformations (which we have
exclusively,
as far as I can tell), but is significantly faster, because calculating
the
inverse is slow.

This was SVN commit r3041.
This commit is contained in:
prefect 2005-10-28 19:25:47 +00:00
parent b5c489e1d5
commit b10534d224
5 changed files with 76 additions and 18 deletions

View File

@ -27,8 +27,8 @@
// Constructor
CModel::CModel()
: m_Parent(0), m_Flags(0), m_Anim(0), m_AnimTime(0),
m_BoneMatrices(0), m_InvBoneMatrices(0),
m_PositionValid(false), m_ShadingColor(1,1,1,1)
m_BoneMatrices(0), m_InvTranspBoneMatrices(0),
m_PositionValid(false), m_InvTranspValid(false), m_ShadingColor(1,1,1,1)
{
}
@ -61,7 +61,7 @@ CModel::~CModel()
void CModel::ReleaseData()
{
delete[] m_BoneMatrices;
delete[] m_InvBoneMatrices;
delete[] m_InvTranspBoneMatrices;
for (size_t i=0;i<m_Props.size();i++) {
delete m_Props[i].m_Model;
}
@ -86,7 +86,7 @@ bool CModel::InitModel(CModelDefPtr modeldef)
if (numBones != 0) {
// allocate matrices for bone transformations
m_BoneMatrices=new CMatrix3D[numBones];
m_InvBoneMatrices=new CMatrix3D[numBones];
m_InvTranspBoneMatrices=new CMatrix3D[numBones];
// store default pose until animation assigned
CBoneState* defpose=modeldef->GetBones();
for (uint i=0;i<numBones;i++) {
@ -94,7 +94,7 @@ bool CModel::InitModel(CModelDefPtr modeldef)
m.SetIdentity();
m.Rotate(defpose[i].m_Rotation);
m.Translate(defpose[i].m_Translation);
m.GetInverse(m_InvBoneMatrices[i]);
m_InvTranspValid = false;
}
}
@ -315,11 +315,11 @@ void CModel::ValidatePosition()
const CMatrix3D& transform=GetTransform();
for (size_t i=0;i<m_pModelDef->GetNumBones();i++) {
m_BoneMatrices[i].Concatenate(transform);
m_BoneMatrices[i].GetInverse(m_InvBoneMatrices[i]);
}
}
m_PositionValid = true;
m_InvTranspValid = false;
// re-position and validate all props
for (size_t j = 0; j < m_Props.size(); ++j)
@ -338,6 +338,24 @@ void CModel::ValidatePosition()
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////
// CalcInvTranspBoneMatrices
void CModel::CalcInvTranspBoneMatrices()
{
debug_assert(m_BoneMatrices);
PROFILE( "invert transpose bone matrices" );
CMatrix3D tmp;
for(size_t i = 0; i < m_pModelDef->GetNumBones(); ++i)
{
m_BoneMatrices[i].GetInverse(tmp);
tmp.GetTranspose(m_InvTranspBoneMatrices[i]);
}
m_InvTranspValid = true;
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////
// SetAnimation: set the given animation as the current animation on this model;
// return false on error, else true

View File

@ -105,10 +105,12 @@ public:
debug_assert(m_PositionValid);
return m_BoneMatrices;
}
// return the models inverted bone matrices
const CMatrix3D* GetInvBoneMatrices() {
// return the models inverted transposed bone matrices for normal transformation
const CMatrix3D* GetInvTranspBoneMatrices() {
debug_assert(m_PositionValid);
return m_InvBoneMatrices;
if (!m_InvTranspValid)
CalcInvTranspBoneMatrices();
return m_InvTranspBoneMatrices;
}
// load raw animation frame animation from given file, and build a
@ -142,6 +144,12 @@ private:
*/
void InvalidatePosition();
/**
* CalcInvTranspBoneMatrices: Calc inverse transpose bone matrices
* from bone matrices.
*/
void CalcInvTranspBoneMatrices();
/**
* m_Parent: If non-null, m_Parent points to the model that we
* are attached to.
@ -170,8 +178,8 @@ private:
float m_AnimTime;
// current state of all bones on this model; null if associated modeldef isn't skeletal
CMatrix3D* m_BoneMatrices;
// inverse of the above world space transform of the above matrices
CMatrix3D* m_InvBoneMatrices;
// inverse of the transpose of the above matrices
CMatrix3D* m_InvTranspBoneMatrices;
// list of current props on model
std::vector<Prop> m_Props;
@ -181,6 +189,12 @@ private:
*/
bool m_PositionValid;
/**
* m_InvTranspValid: true if m_InvTranspBoneMatrices match the current
* m_BoneMatrices
*/
bool m_InvTranspValid;
// modulating color
CColor m_ShadingColor;
};

View File

@ -52,7 +52,7 @@ static void SkinPoint(const SModelVertex& vertex,const CMatrix3D* matrices,CVect
/////////////////////////////////////////////////////////////////////////////////////////////////////////////
// SkinPoint: skin the vertex normal using it's blend data and given bone matrices
static void SkinNormal(const SModelVertex& vertex,const CMatrix3D* invmatrices,CVector3D& result)
static void SkinNormal(const SModelVertex& vertex, const CMatrix3D* invtranspmatrices, CVector3D& result)
{
CVector3D tmp;
const SVertexBlend& blend=vertex.m_Blend;
@ -60,13 +60,13 @@ static void SkinNormal(const SModelVertex& vertex,const CMatrix3D* invmatrices,C
// must have at least one valid bone if we're using SkinNormal
debug_assert(blend.m_Bone[0]!=0xff);
const CMatrix3D& m=invmatrices[blend.m_Bone[0]];
m.RotateTransposed(vertex.m_Norm,result);
const CMatrix3D& m = invtranspmatrices[blend.m_Bone[0]];
m.Rotate(vertex.m_Norm, result);
result*=blend.m_Weight[0];
for (u32 i=1; i<SVertexBlend::SIZE && vertex.m_Blend.m_Bone[i]!=0xff; i++) {
const CMatrix3D& m=invmatrices[blend.m_Bone[i]];
m.RotateTransposed(vertex.m_Norm,tmp);
const CMatrix3D& m = invtranspmatrices[blend.m_Bone[i]];
m.Rotate(vertex.m_Norm,tmp);
result+=tmp*blend.m_Weight[i];
}
}
@ -89,11 +89,27 @@ void ModelRenderer::BuildPositionAndNormals(
{
// boned model - calculate skinned vertex positions/normals
PROFILE( "skinning bones" );
const CMatrix3D* invbonematrices = model->GetInvBoneMatrices();
const CMatrix3D* invtranspbonematrices;
// Analytic geometry tells us that normal vectors need to be
// multiplied by the inverse of the transpose. However, calculating
// the inverse is slow, and analytic geometry also tells us that
// for orthogonal matrices, the inverse is equal to the transpose,
// so the inverse of the transpose is, in fact, the original matrix.
//
// The "fast normals" code assumes that bone transformation contain
// no "weird" transformations like shears or non-uniform scaling
// (actually, the entire code assumes no scaling) and thus gets
// around the slow calculation of the inverse.
if (g_Renderer.m_FastNormals)
invtranspbonematrices = bonematrices;
else
invtranspbonematrices = model->GetInvTranspBoneMatrices();
for (size_t j=0; j<numVertices; j++)
{
SkinPoint(vertices[j],bonematrices,Position[j]);
SkinNormal(vertices[j],invbonematrices,Normal[j]);
SkinNormal(vertices[j],invtranspbonematrices,Normal[j]);
}
}
else

View File

@ -68,6 +68,7 @@ CRenderer::CRenderer()
m_ShadowMap=0;
m_SortAllTransparent = false;
m_FastNormals = true;
m_VertexShader = 0;
@ -1594,6 +1595,7 @@ void CRenderer::ScriptingInit()
AddProperty(L"fastPlayerColor", &CRenderer::JSI_GetFastPlayerColor, &CRenderer::JSI_SetFastPlayerColor);
AddProperty(L"renderpath", &CRenderer::JSI_GetRenderPath, &CRenderer::JSI_SetRenderPath);
AddProperty(L"sortAllTransparent", &CRenderer::m_SortAllTransparent);
AddProperty(L"fastNormals", &CRenderer::m_FastNormals);
CJSObject<CRenderer>::ScriptingInit("Renderer");
}

View File

@ -396,6 +396,14 @@ protected:
* batching renderer when possible.
*/
bool m_SortAllTransparent;
/**
* m_FastNormals: Use faster normal transformation in the
* software transform by multiplying with the bone matrix itself
* instead of the transpose of the inverse.
*/
bool m_FastNormals;
// State used by LoadWaterTextures with progressive loading
uint cur_loading_water_tex;