From ede71ea791321d852f6e5b42a2883c1663cb7e71 Mon Sep 17 00:00:00 2001 From: Ykkrosh Date: Fri, 24 Sep 2010 16:54:20 +0000 Subject: [PATCH] Inline common vector/matrix operations, for performance. Remove some redundant vector methods. Compute skinning for positions and normals simultaneously. (These changes reduce skinning cost by >50%.) This was SVN commit r8170. --- source/graphics/ModelDef.cpp | 42 +++++++++++++++- source/graphics/ModelDef.h | 16 +++++- source/maths/Matrix3D.cpp | 33 +----------- source/maths/Matrix3D.h | 44 ++++++++++++---- source/maths/Plane.cpp | 1 - source/maths/Quaternion.cpp | 15 +++--- source/maths/Vector3D.cpp | 74 +-------------------------- source/maths/Vector3D.h | 83 ++++++++++++++++++++----------- source/renderer/ModelRenderer.cpp | 7 +-- 9 files changed, 157 insertions(+), 158 deletions(-) diff --git a/source/graphics/ModelDef.cpp b/source/graphics/ModelDef.cpp index 7b593b4e8a..f4a582224d 100644 --- a/source/graphics/ModelDef.cpp +++ b/source/graphics/ModelDef.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2009 Wildfire Games. +/* Copyright (C) 2010 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -89,6 +89,46 @@ CVector3D CModelDef::SkinNormal(const SModelVertex& vtx, return result; } +void CModelDef::SkinPointsAndNormals( + size_t numVertices, + const VertexArrayIterator& Position, + const VertexArrayIterator& Normal, + const SModelVertex* vertices, + const CMatrix3D newPoseMatrices[], + const CMatrix3D inverseBindMatrices[]) +{ + for (size_t j = 0; j < numVertices; ++j) + { + const SModelVertex vtx = vertices[j]; + + CVector3D pos(0, 0, 0); + CVector3D normal(0, 0, 0); + + for (int i = 0; i < SVertexBlend::SIZE && vtx.m_Blend.m_Bone[i] != 0xff; ++i) + { + CVector3D posBindSpace = inverseBindMatrices[vtx.m_Blend.m_Bone[i]].Transform(vtx.m_Coords); + CVector3D normBindSpace = inverseBindMatrices[vtx.m_Blend.m_Bone[i]].Rotate(vtx.m_Norm); + + CVector3D posWorldSpace = newPoseMatrices[vtx.m_Blend.m_Bone[i]].Transform(posBindSpace); + CVector3D normWorldSpace = newPoseMatrices[vtx.m_Blend.m_Bone[i]].Rotate(normBindSpace); + + pos += posWorldSpace * vtx.m_Blend.m_Weight[i]; + normal += normWorldSpace * vtx.m_Blend.m_Weight[i]; + } + + // If there was more than one influence, the result is probably not going + // to be of unit length (since it's a weighted sum of several independent + // unit vectors), so we need to normalise it. + // (It's fairly common to only have one influence, so it seems sensible to + // optimise that case a bit.) + if (vtx.m_Blend.m_Bone[1] != 0xff) // if more than one influence + normal.Normalize(); + + Position[j] = pos; + Normal[j] = normal; + } +} + // CModelDef Constructor CModelDef::CModelDef() : m_NumVertices(0), m_pVertices(0), m_NumFaces(0), m_pFaces(0), m_NumBones(0), m_Bones(0), diff --git a/source/graphics/ModelDef.h b/source/graphics/ModelDef.h index 55bab679c5..14af5effdc 100644 --- a/source/graphics/ModelDef.h +++ b/source/graphics/ModelDef.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2009 Wildfire Games. +/* Copyright (C) 2010 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -26,6 +26,7 @@ #include "maths/Vector3D.h" #include "maths/Quaternion.h" #include "lib/file/vfs/vfs_path.h" +#include "renderer/VertexArray.h" #include class CBoneState; @@ -158,6 +159,19 @@ public: static CVector3D SkinNormal(const SModelVertex& vtx, const CMatrix3D newPoseMatrices[], const CMatrix3D inverseBindMatrices[]); + /** + * Transform vertices' positions and normals. + * (This is equivalent to looping over SkinPoint and SkinNormal, + * but slightly more efficient.) + */ + static void SkinPointsAndNormals( + size_t numVertices, + const VertexArrayIterator& Position, + const VertexArrayIterator& Normal, + const SModelVertex* vertices, + const CMatrix3D newPoseMatrices[], + const CMatrix3D inverseBindMatrices[]); + /** * Register renderer private data. Use the key to * distinguish between private data used by different render paths. diff --git a/source/maths/Matrix3D.cpp b/source/maths/Matrix3D.cpp index 7f9bff35f2..a60411c2f2 100644 --- a/source/maths/Matrix3D.cpp +++ b/source/maths/Matrix3D.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2009 Wildfire Games. +/* Copyright (C) 2010 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -340,22 +340,6 @@ CVector3D CMatrix3D::GetIn () const return Temp; } - -//Transform a vector by this matrix -CVector3D CMatrix3D::Transform (const CVector3D &vector) const -{ - CVector3D result; - Transform(vector,result); - return result; -} - -void CMatrix3D::Transform(const CVector3D& vector,CVector3D& result) const -{ - result.X = _11*vector.X + _12*vector.Y + _13*vector.Z + _14; - result.Y = _21*vector.X + _22*vector.Y + _23*vector.Z + _24; - result.Z = _31*vector.X + _32*vector.Y + _33*vector.Z + _34; -} - //Transform a vector by this matrix CVector4D CMatrix3D::Transform(const CVector4D &vector) const { @@ -372,21 +356,6 @@ void CMatrix3D::Transform(const CVector4D& vector,CVector4D& result) const result[3] = _41*vector[0] + _42*vector[1] + _43*vector[2] + _44*vector[3]; } -//Only rotate (not translate) a vector by this matrix -CVector3D CMatrix3D::Rotate(const CVector3D& vector) const -{ - CVector3D result; - Rotate(vector,result); - return result; -} - -void CMatrix3D::Rotate(const CVector3D& vector,CVector3D& result) const -{ - result.X = _11*vector.X + _12*vector.Y + _13*vector.Z; - result.Y = _21*vector.X + _22*vector.Y + _23*vector.Z; - result.Z = _31*vector.X + _32*vector.Y + _33*vector.Z; -} - /////////////////////////////////////////////////////////////////////////////// // RotateTransposed: rotate a vector by the transpose of this matrix CVector3D CMatrix3D::RotateTransposed(const CVector3D& vector) const diff --git a/source/maths/Matrix3D.h b/source/maths/Matrix3D.h index 4193d35701..2388b6a9fc 100644 --- a/source/maths/Matrix3D.h +++ b/source/maths/Matrix3D.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2009 Wildfire Games. +/* Copyright (C) 2010 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -23,7 +23,8 @@ #ifndef INCLUDED_MATRIX3D #define INCLUDED_MATRIX3D -class CVector3D; +#include "maths/Vector3D.h" + class CVector4D; class CQuaternion; @@ -137,14 +138,39 @@ public: CQuaternion GetRotation() const; // transform a 3D vector by this matrix - void Transform(const CVector3D &vector,CVector3D& result) const; - CVector3D Transform(const CVector3D &vector) const; - // transform a 4D vector by this matrix - void Transform(const CVector4D &vector,CVector4D& result) const; - CVector4D Transform(const CVector4D &vector) const; + CVector3D Transform (const CVector3D &vector) const + { + CVector3D result; + Transform(vector, result); + return result; + } + + void Transform(const CVector3D& vector, CVector3D& result) const + { + result.X = _11*vector.X + _12*vector.Y + _13*vector.Z + _14; + result.Y = _21*vector.X + _22*vector.Y + _23*vector.Z + _24; + result.Z = _31*vector.X + _32*vector.Y + _33*vector.Z + _34; + } + // rotate a vector by this matrix - void Rotate(const CVector3D& vector,CVector3D& result) const; - CVector3D Rotate(const CVector3D& vector) const; + CVector3D Rotate(const CVector3D& vector) const + { + CVector3D result; + Rotate(vector, result); + return result; + } + + void Rotate(const CVector3D& vector, CVector3D& result) const + { + result.X = _11*vector.X + _12*vector.Y + _13*vector.Z; + result.Y = _21*vector.X + _22*vector.Y + _23*vector.Z; + result.Z = _31*vector.X + _32*vector.Y + _33*vector.Z; + } + + // transform a 4D vector by this matrix + void Transform(const CVector4D& vector,CVector4D& result) const; + CVector4D Transform(const CVector4D& vector) const; + // rotate a vector by the transpose of this matrix void RotateTransposed(const CVector3D& vector,CVector3D& result) const; CVector3D RotateTransposed(const CVector3D& vector) const; diff --git a/source/maths/Plane.cpp b/source/maths/Plane.cpp index cddb3f680c..d780fcec78 100644 --- a/source/maths/Plane.cpp +++ b/source/maths/Plane.cpp @@ -29,7 +29,6 @@ CPlane::CPlane () { - m_Norm.Clear (); m_Dist = 0.0f; } diff --git a/source/maths/Quaternion.cpp b/source/maths/Quaternion.cpp index 78abb8b43c..59d0e5a92e 100644 --- a/source/maths/Quaternion.cpp +++ b/source/maths/Quaternion.cpp @@ -23,14 +23,13 @@ const float EPSILON=0.0001f; -CQuaternion::CQuaternion() +CQuaternion::CQuaternion() : + m_W(1) { - m_V.Clear(); - m_W = 1; } -CQuaternion::CQuaternion(float x, float y, float z, float w) -: m_V(x, y, z), m_W(w) +CQuaternion::CQuaternion(float x, float y, float z, float w) : + m_V(x, y, z), m_W(w) { } @@ -109,13 +108,13 @@ void CQuaternion::FromEulerAngles (float x, float y, float z) sp = sinf(y * 0.5f); sy = sinf(z * 0.5f); - QRoll.m_V.Set (sr,0,0); + QRoll.m_V = CVector3D(sr, 0, 0); QRoll.m_W = cr; - QPitch.m_V.Set (0,sp,0); + QPitch.m_V = CVector3D(0, sp, 0); QPitch.m_W = cp; - QYaw.m_V.Set (0,0,sy); + QYaw.m_V = CVector3D(0, 0, sy); QYaw.m_W = cy; (*this) = QYaw * QPitch * QRoll; diff --git a/source/maths/Vector3D.cpp b/source/maths/Vector3D.cpp index 48f26446df..04ed878195 100644 --- a/source/maths/Vector3D.cpp +++ b/source/maths/Vector3D.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2009 Wildfire Games. +/* Copyright (C) 2010 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -45,77 +45,6 @@ int CVector3D::operator ! () const return 1; } -bool CVector3D::operator== (const CVector3D &vector) const -{ - return (X == vector.X && Y == vector.Y && Z == vector.Z); -} - -//vector addition -CVector3D CVector3D::operator + (const CVector3D &vector) const -{ - return CVector3D(X+vector.X, Y+vector.Y, Z+vector.Z); -} - -//vector addition/assignment -CVector3D &CVector3D::operator += (const CVector3D &vector) -{ - X += vector.X; - Y += vector.Y; - Z += vector.Z; - - return *this; -} - -//vector subtraction -CVector3D CVector3D::operator - (const CVector3D &vector) const -{ - return CVector3D(X-vector.X, Y-vector.Y, Z-vector.Z); -} - -//vector negation -CVector3D CVector3D::operator-() const -{ - return CVector3D(-X, -Y, -Z); -} -//vector subtrcation/assignment -CVector3D &CVector3D::operator -= (const CVector3D &vector) -{ - X -= vector.X; - Y -= vector.Y; - Z -= vector.Z; - - return *this; -} - -//scalar multiplication -CVector3D CVector3D::operator * (float value) const -{ - return CVector3D(X*value, Y*value, Z*value); -} - -//scalar multiplication/assignment -CVector3D& CVector3D::operator *= (float value) -{ - X *= value; - Y *= value; - Z *= value; - - return *this; -} - -void CVector3D::Set (float x, float y, float z) -{ - X = x; - Y = y; - Z = z; -} - -void CVector3D::Clear () -{ - X = Y = Z = 0.0f; -} - -//Dot product float CVector3D::Dot (const CVector3D &vector) const { return ( X * vector.X + @@ -123,7 +52,6 @@ float CVector3D::Dot (const CVector3D &vector) const Z * vector.Z ); } -//Cross product CVector3D CVector3D::Cross (const CVector3D &vector) const { CVector3D Temp; diff --git a/source/maths/Vector3D.h b/source/maths/Vector3D.h index 73abd8c811..05994c90ff 100644 --- a/source/maths/Vector3D.h +++ b/source/maths/Vector3D.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2009 Wildfire Games. +/* Copyright (C) 2010 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -31,47 +31,74 @@ class CVector3D float X, Y, Z; public: - CVector3D () : X(0.0f), Y(0.0f), Z(0.0f) {} - CVector3D (float x, float y, float z) : X(x), Y(y), Z(z) {} - CVector3D (const CFixedVector3D& v); + CVector3D() : X(0.0f), Y(0.0f), Z(0.0f) {} + CVector3D(float x, float y, float z) : X(x), Y(y), Z(z) {} + CVector3D(const CFixedVector3D& v); int operator!() const; float& operator[](int index) { return *((&X)+index); } const float& operator[](int index) const { return *((&X)+index); } - //vector equality (testing float equality, so please be careful if necessary) - bool operator== (const CVector3D &vector) const; - bool operator!= (const CVector3D &vector) const { return !operator==(vector); } + // vector equality (testing float equality, so please be careful if necessary) + bool operator==(const CVector3D &vector) const + { + return (X == vector.X && Y == vector.Y && Z == vector.Z); + } - //vector addition - CVector3D operator + (const CVector3D &vector) const ; - //vector addition/assignment - CVector3D &operator += (const CVector3D &vector); + bool operator!=(const CVector3D& vector) const + { + return !operator==(vector); + } - //vector subtraction - CVector3D operator - (const CVector3D &vector) const ; - //vector subtraction/assignment - CVector3D &operator -= (const CVector3D &vector); - - //scalar multiplication - CVector3D operator * (float value) const ; - //scalar multiplication/assignment - CVector3D& operator *= (float value); + CVector3D operator+(const CVector3D& vector) const + { + return CVector3D(X + vector.X, Y + vector.Y, Z + vector.Z); + } - // negation - CVector3D operator-() const; + CVector3D& operator+=(const CVector3D& vector) + { + X += vector.X; + Y += vector.Y; + Z += vector.Z; + return *this; + } + + CVector3D operator-(const CVector3D& vector) const + { + return CVector3D(X - vector.X, Y - vector.Y, Z - vector.Z); + } + + CVector3D& operator-=(const CVector3D& vector) + { + X -= vector.X; + Y -= vector.Y; + Z -= vector.Z; + return *this; + } + + CVector3D operator*(float value) const + { + return CVector3D(X * value, Y * value, Z * value); + } + + CVector3D& operator*=(float value) + { + X *= value; + Y *= value; + Z *= value; + return *this; + } + + CVector3D operator-() const + { + return CVector3D(-X, -Y, -Z); + } public: - void Set (float x, float y, float z); - void Clear (); - - //Dot product float Dot (const CVector3D &vector) const; - //Cross product CVector3D Cross (const CVector3D &vector) const; - //Returns length of the vector float Length () const; float LengthSquared () const; void Normalize (); diff --git a/source/renderer/ModelRenderer.cpp b/source/renderer/ModelRenderer.cpp index dce9b14b69..3668d3351d 100644 --- a/source/renderer/ModelRenderer.cpp +++ b/source/renderer/ModelRenderer.cpp @@ -86,11 +86,8 @@ void ModelRenderer::BuildPositionAndNormals( return; } - for (size_t j=0; jGetAnimatedBoneMatrices(), model->GetInverseBindBoneMatrices()); - Normal[j] = CModelDef::SkinNormal(vertices[j], model->GetAnimatedBoneMatrices(), model->GetInverseBindBoneMatrices()); - } + CModelDef::SkinPointsAndNormals(numVertices, Position, Normal, vertices, model->GetAnimatedBoneMatrices(), model->GetInverseBindBoneMatrices()); + } else {