|
@@ -22,6 +22,7 @@
|
|
|
//
|
|
//
|
|
|
|
|
|
|
|
#include "Precompiled.h"
|
|
#include "Precompiled.h"
|
|
|
|
|
+#include "AnimatedModel.h"
|
|
|
#include "Batch.h"
|
|
#include "Batch.h"
|
|
|
#include "Camera.h"
|
|
#include "Camera.h"
|
|
|
#include "Context.h"
|
|
#include "Context.h"
|
|
@@ -35,13 +36,14 @@
|
|
|
#include "ResourceCache.h"
|
|
#include "ResourceCache.h"
|
|
|
#include "Scene.h"
|
|
#include "Scene.h"
|
|
|
#include "SceneEvents.h"
|
|
#include "SceneEvents.h"
|
|
|
-#include "StaticModel.h"
|
|
|
|
|
#include "VertexBuffer.h"
|
|
#include "VertexBuffer.h"
|
|
|
|
|
|
|
|
#include "DebugNew.h"
|
|
#include "DebugNew.h"
|
|
|
|
|
|
|
|
static const Vector3 DOT_SCALE(1 / 3.0f, 1 / 3.0f, 1 / 3.0f);
|
|
static const Vector3 DOT_SCALE(1 / 3.0f, 1 / 3.0f, 1 / 3.0f);
|
|
|
-static const unsigned DEFAULT_MAX_VERTICES = 1024;
|
|
|
|
|
|
|
+static const unsigned DEFAULT_MAX_VERTICES = 512;
|
|
|
|
|
+static const unsigned UNSKINNED_ELEMENT_MASK = MASK_POSITION | MASK_NORMAL | MASK_TEXCOORD1 | MASK_TANGENT;
|
|
|
|
|
+static const unsigned SKINNED_ELEMENT_MASK = MASK_POSITION | MASK_NORMAL | MASK_TEXCOORD1 | MASK_TANGENT | MASK_BLENDWEIGHTS | MASK_BLENDINDICES;
|
|
|
|
|
|
|
|
void Decal::CalculateBoundingBox()
|
|
void Decal::CalculateBoundingBox()
|
|
|
{
|
|
{
|
|
@@ -58,14 +60,14 @@ DecalSet::DecalSet(Context* context) :
|
|
|
vertexBuffer_(new VertexBuffer(context_)),
|
|
vertexBuffer_(new VertexBuffer(context_)),
|
|
|
numVertices_(0),
|
|
numVertices_(0),
|
|
|
maxVertices_(DEFAULT_MAX_VERTICES),
|
|
maxVertices_(DEFAULT_MAX_VERTICES),
|
|
|
|
|
+ skinned_(false),
|
|
|
bufferSizeDirty_(true),
|
|
bufferSizeDirty_(true),
|
|
|
bufferDirty_(true),
|
|
bufferDirty_(true),
|
|
|
- boundingBoxDirty_(true)
|
|
|
|
|
|
|
+ boundingBoxDirty_(true),
|
|
|
|
|
+ skinningDirty_(false)
|
|
|
{
|
|
{
|
|
|
drawableFlags_ = DRAWABLE_GEOMETRY;
|
|
drawableFlags_ = DRAWABLE_GEOMETRY;
|
|
|
|
|
|
|
|
- geometry_->SetVertexBuffer(0, vertexBuffer_, MASK_POSITION | MASK_NORMAL | MASK_TEXCOORD1 | MASK_TANGENT);
|
|
|
|
|
-
|
|
|
|
|
batches_.Resize(1);
|
|
batches_.Resize(1);
|
|
|
batches_[0].geometry_ = geometry_;
|
|
batches_[0].geometry_ = geometry_;
|
|
|
}
|
|
}
|
|
@@ -102,6 +104,19 @@ void DecalSet::UpdateBatches(const FrameInfo& frame)
|
|
|
|
|
|
|
|
batches_[0].distance_ = distance_;
|
|
batches_[0].distance_ = distance_;
|
|
|
batches_[0].worldTransform_ = &worldTransform;
|
|
batches_[0].worldTransform_ = &worldTransform;
|
|
|
|
|
+
|
|
|
|
|
+ if (skinMatrices_.Size())
|
|
|
|
|
+ {
|
|
|
|
|
+ batches_[0].geometryType_ = GEOM_SKINNED;
|
|
|
|
|
+ batches_[0].shaderData_ = skinMatrices_[0].Data();
|
|
|
|
|
+ batches_[0].shaderDataSize_ = skinMatrices_.Size() * 12;
|
|
|
|
|
+ }
|
|
|
|
|
+ else
|
|
|
|
|
+ {
|
|
|
|
|
+ batches_[0].geometryType_ = GEOM_STATIC;
|
|
|
|
|
+ batches_[0].shaderData_ = 0;
|
|
|
|
|
+ batches_[0].shaderDataSize_ = 0;
|
|
|
|
|
+ }
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
void DecalSet::UpdateGeometry(const FrameInfo& frame)
|
|
void DecalSet::UpdateGeometry(const FrameInfo& frame)
|
|
@@ -111,6 +126,9 @@ void DecalSet::UpdateGeometry(const FrameInfo& frame)
|
|
|
|
|
|
|
|
if (bufferDirty_ || vertexBuffer_->IsDataLost())
|
|
if (bufferDirty_ || vertexBuffer_->IsDataLost())
|
|
|
UpdateVertexBuffer();
|
|
UpdateVertexBuffer();
|
|
|
|
|
+
|
|
|
|
|
+ if (skinningDirty_)
|
|
|
|
|
+ UpdateSkinning();
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
UpdateGeometryType DecalSet::GetUpdateGeometryType()
|
|
UpdateGeometryType DecalSet::GetUpdateGeometryType()
|
|
@@ -154,6 +172,15 @@ bool DecalSet::AddDecal(Drawable* target, const Vector3& worldPosition, const Qu
|
|
|
return false;
|
|
return false;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+ // Check for animated target and switch into skinned mode if necessary
|
|
|
|
|
+ AnimatedModel* animatedModel = dynamic_cast<AnimatedModel*>(target);
|
|
|
|
|
+ if ((animatedModel && !skinned_) || (!animatedModel && skinned_))
|
|
|
|
|
+ {
|
|
|
|
|
+ RemoveAllDecals();
|
|
|
|
|
+ skinned_ = animatedModel != 0;
|
|
|
|
|
+ bufferSizeDirty_ = true;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
Matrix3x4 targetTransform = target->GetNode()->GetWorldTransform().Inverse();
|
|
Matrix3x4 targetTransform = target->GetNode()->GetWorldTransform().Inverse();
|
|
|
|
|
|
|
|
// Build the decal frustum
|
|
// Build the decal frustum
|
|
@@ -171,7 +198,7 @@ bool DecalSet::AddDecal(Drawable* target, const Vector3& worldPosition, const Qu
|
|
|
Vector<PODVector<DecalVertex> > faces;
|
|
Vector<PODVector<DecalVertex> > faces;
|
|
|
PODVector<DecalVertex> tempFace;
|
|
PODVector<DecalVertex> tempFace;
|
|
|
|
|
|
|
|
- // Special handling for static models, as they may use LOD: use the fixed software LOD level for decals
|
|
|
|
|
|
|
+ // Special handling for static/animated models, as they may use LOD: use the fixed software LOD level for decals
|
|
|
StaticModel* staticModel = dynamic_cast<StaticModel*>(target);
|
|
StaticModel* staticModel = dynamic_cast<StaticModel*>(target);
|
|
|
if (staticModel)
|
|
if (staticModel)
|
|
|
{
|
|
{
|
|
@@ -196,7 +223,8 @@ bool DecalSet::AddDecal(Drawable* target, const Vector3& worldPosition, const Qu
|
|
|
continue;
|
|
continue;
|
|
|
|
|
|
|
|
tempFace.Resize(face.Size() + 2);
|
|
tempFace.Resize(face.Size() + 2);
|
|
|
- unsigned outVertices = ClipPolygon((float*)&face[0], (float*)&tempFace[0], face.Size(), sizeof(DecalVertex), decalFrustum.planes_[i]);
|
|
|
|
|
|
|
+ unsigned outVertices = ClipPolygon((float*)&face[0], (float*)&tempFace[0], face.Size(), sizeof(DecalVertex),
|
|
|
|
|
+ decalFrustum.planes_[i], skinned_ ? (sizeof(DecalVertex) - 4 * sizeof(float) - 4 * sizeof(unsigned char)) : 0);
|
|
|
tempFace.Resize(outVertices);
|
|
tempFace.Resize(outVertices);
|
|
|
|
|
|
|
|
face = tempFace;
|
|
face = tempFace;
|
|
@@ -274,6 +302,15 @@ void DecalSet::RemoveAllDecals()
|
|
|
numVertices_ = 0;
|
|
numVertices_ = 0;
|
|
|
MarkDecalsDirty();
|
|
MarkDecalsDirty();
|
|
|
}
|
|
}
|
|
|
|
|
+
|
|
|
|
|
+ // Remove all bones and skinning matrices
|
|
|
|
|
+ for (Vector<Bone>::Iterator i = bones_.Begin(); i != bones_.End(); ++i)
|
|
|
|
|
+ {
|
|
|
|
|
+ if (i->node_)
|
|
|
|
|
+ i->node_->RemoveListener(this);
|
|
|
|
|
+ }
|
|
|
|
|
+ bones_.Clear();
|
|
|
|
|
+ skinMatrices_.Clear();
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
Material* DecalSet::GetMaterial() const
|
|
Material* DecalSet::GetMaterial() const
|
|
@@ -352,12 +389,44 @@ VariantVector DecalSet::GetDecalsAttr() const
|
|
|
return ret;
|
|
return ret;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
-void DecalSet::OnWorldBoundingBoxUpdate()
|
|
|
|
|
|
|
+void DecalSet::OnMarkedDirty(Node* node)
|
|
|
{
|
|
{
|
|
|
- if (boundingBoxDirty_)
|
|
|
|
|
- CalculateBoundingBox();
|
|
|
|
|
|
|
+ Drawable::OnMarkedDirty(node);
|
|
|
|
|
|
|
|
- worldBoundingBox_ = boundingBox_.Transformed(node_->GetWorldTransform());
|
|
|
|
|
|
|
+ if (skinned_)
|
|
|
|
|
+ {
|
|
|
|
|
+ // If the scene node or any of the bone nodes move, mark skinning dirty
|
|
|
|
|
+ skinningDirty_ = true;
|
|
|
|
|
+ }
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+void DecalSet::OnWorldBoundingBoxUpdate()
|
|
|
|
|
+{
|
|
|
|
|
+ if (!skinned_)
|
|
|
|
|
+ {
|
|
|
|
|
+ if (boundingBoxDirty_)
|
|
|
|
|
+ CalculateBoundingBox();
|
|
|
|
|
+
|
|
|
|
|
+ worldBoundingBox_ = boundingBox_.Transformed(node_->GetWorldTransform());
|
|
|
|
|
+ }
|
|
|
|
|
+ else
|
|
|
|
|
+ {
|
|
|
|
|
+ // If uses skinning, update world bounding box based on them
|
|
|
|
|
+ worldBoundingBox_.defined_ = false;
|
|
|
|
|
+
|
|
|
|
|
+ for (Vector<Bone>::ConstIterator i = bones_.Begin(); i != bones_.End(); ++i)
|
|
|
|
|
+ {
|
|
|
|
|
+ Node* boneNode = i->node_;
|
|
|
|
|
+ if (!boneNode)
|
|
|
|
|
+ continue;
|
|
|
|
|
+
|
|
|
|
|
+ // Use hitbox if available. If not, use only half of the sphere radius
|
|
|
|
|
+ if (i->collisionMask_ & BONECOLLISION_BOX)
|
|
|
|
|
+ worldBoundingBox_.Merge(i->boundingBox_.Transformed(boneNode->GetWorldTransform()));
|
|
|
|
|
+ else if (i->collisionMask_ & BONECOLLISION_SPHERE)
|
|
|
|
|
+ worldBoundingBox_.Merge(Sphere(boneNode->GetWorldPosition(), i->radius_ * 0.5f));
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
void DecalSet::GetFaces(Vector<PODVector<DecalVertex> >& faces, Geometry* geometry, const Frustum& frustum, const Vector3& decalNormal, float normalCutoff)
|
|
void DecalSet::GetFaces(Vector<PODVector<DecalVertex> >& faces, Geometry* geometry, const Frustum& frustum, const Vector3& decalNormal, float normalCutoff)
|
|
@@ -380,8 +449,6 @@ void DecalSet::GetFaces(Vector<PODVector<DecalVertex> >& faces, Geometry* geomet
|
|
|
|
|
|
|
|
unsigned indexStart = geometry->GetIndexStart();
|
|
unsigned indexStart = geometry->GetIndexStart();
|
|
|
unsigned indexCount = geometry->GetIndexCount();
|
|
unsigned indexCount = geometry->GetIndexCount();
|
|
|
- bool hasNormals = (elementMask & MASK_NORMAL) != 0;
|
|
|
|
|
-
|
|
|
|
|
const unsigned char* srcData = (const unsigned char*)vertexData;
|
|
const unsigned char* srcData = (const unsigned char*)vertexData;
|
|
|
|
|
|
|
|
// 16-bit indices
|
|
// 16-bit indices
|
|
@@ -392,89 +459,69 @@ void DecalSet::GetFaces(Vector<PODVector<DecalVertex> >& faces, Geometry* geomet
|
|
|
|
|
|
|
|
while (indices < indicesEnd)
|
|
while (indices < indicesEnd)
|
|
|
{
|
|
{
|
|
|
- const Vector3& v0 = *((const Vector3*)(&srcData[indices[0] * vertexSize]));
|
|
|
|
|
- const Vector3& v1 = *((const Vector3*)(&srcData[indices[1] * vertexSize]));
|
|
|
|
|
- const Vector3& v2 = *((const Vector3*)(&srcData[indices[2] * vertexSize]));
|
|
|
|
|
- const Vector3& n0 = hasNormals ? *((const Vector3*)(&srcData[indices[0] * vertexSize + 3 * sizeof(float)])) :
|
|
|
|
|
- Vector3::ZERO;
|
|
|
|
|
- const Vector3& n1 = hasNormals ? *((const Vector3*)(&srcData[indices[1] * vertexSize + 3 * sizeof(float)])) :
|
|
|
|
|
- Vector3::ZERO;
|
|
|
|
|
- const Vector3& n2 = hasNormals ? *((const Vector3*)(&srcData[indices[2] * vertexSize + 3 * sizeof(float)])) :
|
|
|
|
|
- Vector3::ZERO;
|
|
|
|
|
-
|
|
|
|
|
- if (!hasNormals || decalNormal.DotProduct((n0 + n1 + n2) / 3.0f) >= normalCutoff)
|
|
|
|
|
- {
|
|
|
|
|
- // First check coarsely against all planes to avoid adding unnecessary faces to the clipping algorithm
|
|
|
|
|
- bool outside = false;
|
|
|
|
|
- for (unsigned i = PLANE_FAR; i < NUM_FRUSTUM_PLANES; --i)
|
|
|
|
|
- {
|
|
|
|
|
- const Plane& plane = frustum.planes_[i];
|
|
|
|
|
- if (plane.Distance(v0) < 0.0f && plane.Distance(v1) < 0.0f && plane.Distance(v2) < 0.0f)
|
|
|
|
|
- {
|
|
|
|
|
- outside = true;
|
|
|
|
|
- break;
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- if (!outside)
|
|
|
|
|
- {
|
|
|
|
|
- faces.Resize(faces.Size() + 1);
|
|
|
|
|
- PODVector<DecalVertex>& face = faces.Back();
|
|
|
|
|
- face.Push(DecalVertex(v0, n0));
|
|
|
|
|
- face.Push(DecalVertex(v1, n1));
|
|
|
|
|
- face.Push(DecalVertex(v2, n2));
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
|
|
+ GetFace(faces, srcData, indices[0], indices[1], indices[2], vertexSize, elementMask, frustum, decalNormal, normalCutoff);
|
|
|
indices += 3;
|
|
indices += 3;
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
- // 32-bit indices
|
|
|
|
|
else
|
|
else
|
|
|
|
|
+ // 32-bit indices
|
|
|
{
|
|
{
|
|
|
const unsigned* indices = ((const unsigned*)indexData) + indexStart;
|
|
const unsigned* indices = ((const unsigned*)indexData) + indexStart;
|
|
|
const unsigned* indicesEnd = indices + indexCount;
|
|
const unsigned* indicesEnd = indices + indexCount;
|
|
|
|
|
|
|
|
while (indices < indicesEnd)
|
|
while (indices < indicesEnd)
|
|
|
{
|
|
{
|
|
|
- const Vector3& v0 = *((const Vector3*)(&srcData[indices[0] * vertexSize]));
|
|
|
|
|
- const Vector3& v1 = *((const Vector3*)(&srcData[indices[1] * vertexSize]));
|
|
|
|
|
- const Vector3& v2 = *((const Vector3*)(&srcData[indices[2] * vertexSize]));
|
|
|
|
|
- const Vector3& n0 = hasNormals ? *((const Vector3*)(&srcData[indices[0] * vertexSize + 3 * sizeof(float)])) :
|
|
|
|
|
- Vector3::ZERO;
|
|
|
|
|
- const Vector3& n1 = hasNormals ? *((const Vector3*)(&srcData[indices[1] * vertexSize + 3 * sizeof(float)])) :
|
|
|
|
|
- Vector3::ZERO;
|
|
|
|
|
- const Vector3& n2 = hasNormals ? *((const Vector3*)(&srcData[indices[2] * vertexSize + 3 * sizeof(float)])) :
|
|
|
|
|
- Vector3::ZERO;
|
|
|
|
|
-
|
|
|
|
|
- if (!hasNormals || decalNormal.DotProduct((n0 + n1 + n2) / 3.0f) >= normalCutoff)
|
|
|
|
|
- {
|
|
|
|
|
- bool outside = false;
|
|
|
|
|
- for (unsigned i = PLANE_FAR; i < NUM_FRUSTUM_PLANES; --i)
|
|
|
|
|
- {
|
|
|
|
|
- const Plane& plane = frustum.planes_[i];
|
|
|
|
|
- if (plane.Distance(v0) < 0.0f && plane.Distance(v1) < 0.0f && plane.Distance(v2) < 0.0f)
|
|
|
|
|
- {
|
|
|
|
|
- outside = true;
|
|
|
|
|
- break;
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- if (!outside)
|
|
|
|
|
- {
|
|
|
|
|
- faces.Resize(faces.Size() + 1);
|
|
|
|
|
- PODVector<DecalVertex>& face = faces.Back();
|
|
|
|
|
- face.Push(DecalVertex(v0, n0));
|
|
|
|
|
- face.Push(DecalVertex(v1, n1));
|
|
|
|
|
- face.Push(DecalVertex(v2, n2));
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
|
|
+ GetFace(faces, srcData, indices[0], indices[1], indices[2], vertexSize, elementMask, frustum, decalNormal, normalCutoff);
|
|
|
indices += 3;
|
|
indices += 3;
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+void DecalSet::GetFace(Vector<PODVector<DecalVertex> >& faces, const unsigned char* srcData, unsigned i0, unsigned i1, unsigned i2, unsigned vertexSize, unsigned elementMask, const Frustum& frustum, const Vector3& decalNormal, float normalCutoff)
|
|
|
|
|
+{
|
|
|
|
|
+ bool hasNormals = (elementMask & MASK_NORMAL) != 0;
|
|
|
|
|
+ bool hasSkinning = skinned_ && (elementMask & MASK_BLENDWEIGHTS) != 0;
|
|
|
|
|
+ unsigned normalOffset = VertexBuffer::GetElementOffset(elementMask, ELEMENT_NORMAL);
|
|
|
|
|
+ unsigned skinningOffset = VertexBuffer::GetElementOffset(elementMask, ELEMENT_BLENDWEIGHTS);
|
|
|
|
|
+
|
|
|
|
|
+ const Vector3& v0 = *((const Vector3*)(&srcData[i0 * vertexSize]));
|
|
|
|
|
+ const Vector3& v1 = *((const Vector3*)(&srcData[i1 * vertexSize]));
|
|
|
|
|
+ const Vector3& v2 = *((const Vector3*)(&srcData[i2 * vertexSize]));
|
|
|
|
|
+ const Vector3& n0 = hasNormals ? *((const Vector3*)(&srcData[i0 * vertexSize + normalOffset])) : Vector3::ZERO;
|
|
|
|
|
+ const Vector3& n1 = hasNormals ? *((const Vector3*)(&srcData[i1 * vertexSize + normalOffset])) : Vector3::ZERO;
|
|
|
|
|
+ const Vector3& n2 = hasNormals ? *((const Vector3*)(&srcData[i2 * vertexSize + normalOffset])) : Vector3::ZERO;
|
|
|
|
|
+ const void* s0 = hasSkinning ? (const void*)(&srcData[i0 * vertexSize + skinningOffset]) : (const void*)0;
|
|
|
|
|
+ const void* s1 = hasSkinning ? (const void*)(&srcData[i0 * vertexSize + skinningOffset]) : (const void*)0;
|
|
|
|
|
+ const void* s2 = hasSkinning ? (const void*)(&srcData[i0 * vertexSize + skinningOffset]) : (const void*)0;
|
|
|
|
|
+
|
|
|
|
|
+ // Check if face is too much away from the decal normal
|
|
|
|
|
+ if (hasNormals && decalNormal.DotProduct((n0 + n1 + n2) / 3.0f) < normalCutoff)
|
|
|
|
|
+ return;
|
|
|
|
|
+
|
|
|
|
|
+ // Check if face is culled completely by any of the planes
|
|
|
|
|
+ for (unsigned i = PLANE_FAR; i < NUM_FRUSTUM_PLANES; --i)
|
|
|
|
|
+ {
|
|
|
|
|
+ const Plane& plane = frustum.planes_[i];
|
|
|
|
|
+ if (plane.Distance(v0) < 0.0f && plane.Distance(v1) < 0.0f && plane.Distance(v2) < 0.0f)
|
|
|
|
|
+ return;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ faces.Resize(faces.Size() + 1);
|
|
|
|
|
+ PODVector<DecalVertex>& face = faces.Back();
|
|
|
|
|
+ if (!hasSkinning)
|
|
|
|
|
+ {
|
|
|
|
|
+ face.Push(DecalVertex(v0, n0));
|
|
|
|
|
+ face.Push(DecalVertex(v1, n1));
|
|
|
|
|
+ face.Push(DecalVertex(v2, n2));
|
|
|
|
|
+ }
|
|
|
|
|
+ else
|
|
|
|
|
+ {
|
|
|
|
|
+ face.Push(DecalVertex(v0, n0, s0));
|
|
|
|
|
+ face.Push(DecalVertex(v1, n1, s1));
|
|
|
|
|
+ face.Push(DecalVertex(v2, n2, s2));
|
|
|
|
|
+ }
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
void DecalSet::CalculateUVs(Decal& decal, const Matrix3x4& view, float size, float aspectRatio, float depth, const Vector2& topLeftUV, const Vector2& bottomRightUV)
|
|
void DecalSet::CalculateUVs(Decal& decal, const Matrix3x4& view, float size, float aspectRatio, float depth, const Vector2& topLeftUV, const Vector2& bottomRightUV)
|
|
|
{
|
|
{
|
|
|
Matrix4 projection(Matrix4::ZERO);
|
|
Matrix4 projection(Matrix4::ZERO);
|
|
@@ -506,46 +553,46 @@ void DecalSet::CalculateTangents(Decal& decal)
|
|
|
{
|
|
{
|
|
|
for (unsigned i = 0; i < decal.vertices_.Size(); i += 3)
|
|
for (unsigned i = 0; i < decal.vertices_.Size(); i += 3)
|
|
|
{
|
|
{
|
|
|
- // Tangent generation from
|
|
|
|
|
|
|
+ // Tangent generation from
|
|
|
// http://www.terathon.com/code/tangent.html
|
|
// http://www.terathon.com/code/tangent.html
|
|
|
- const Vector3& v1 = decal.vertices_[i].position_;
|
|
|
|
|
- const Vector3& v2 = decal.vertices_[i + 1].position_;
|
|
|
|
|
- const Vector3& v3 = decal.vertices_[i + 2].position_;
|
|
|
|
|
-
|
|
|
|
|
- const Vector2& w1 = decal.vertices_[i].texCoord_;
|
|
|
|
|
- const Vector2& w2 = decal.vertices_[i + 1].texCoord_;
|
|
|
|
|
- const Vector2& w3 = decal.vertices_[i + 2].texCoord_;
|
|
|
|
|
-
|
|
|
|
|
- float x1 = v2.x_ - v1.x_;
|
|
|
|
|
- float x2 = v3.x_ - v1.x_;
|
|
|
|
|
- float y1 = v2.y_ - v1.y_;
|
|
|
|
|
- float y2 = v3.y_ - v1.y_;
|
|
|
|
|
- float z1 = v2.z_ - v1.z_;
|
|
|
|
|
- float z2 = v3.z_ - v1.z_;
|
|
|
|
|
-
|
|
|
|
|
- float s1 = w2.x_ - w1.x_;
|
|
|
|
|
- float s2 = w3.x_ - w1.x_;
|
|
|
|
|
- float t1 = w2.y_ - w1.y_;
|
|
|
|
|
- float t2 = w3.y_ - w1.y_;
|
|
|
|
|
-
|
|
|
|
|
- float r = 1.0f / (s1 * t2 - s2 * t1);
|
|
|
|
|
- Vector3 sdir((t2 * x1 - t1 * x2) * r, (t2 * y1 - t1 * y2) * r,
|
|
|
|
|
- (t2 * z1 - t1 * z2) * r);
|
|
|
|
|
- Vector3 tdir((s1 * x2 - s2 * x1) * r, (s1 * y2 - s2 * y1) * r,
|
|
|
|
|
- (s1 * z2 - s2 * z1) * r);
|
|
|
|
|
|
|
+ const Vector3& v1 = decal.vertices_[i].position_;
|
|
|
|
|
+ const Vector3& v2 = decal.vertices_[i + 1].position_;
|
|
|
|
|
+ const Vector3& v3 = decal.vertices_[i + 2].position_;
|
|
|
|
|
+
|
|
|
|
|
+ const Vector2& w1 = decal.vertices_[i].texCoord_;
|
|
|
|
|
+ const Vector2& w2 = decal.vertices_[i + 1].texCoord_;
|
|
|
|
|
+ const Vector2& w3 = decal.vertices_[i + 2].texCoord_;
|
|
|
|
|
+
|
|
|
|
|
+ float x1 = v2.x_ - v1.x_;
|
|
|
|
|
+ float x2 = v3.x_ - v1.x_;
|
|
|
|
|
+ float y1 = v2.y_ - v1.y_;
|
|
|
|
|
+ float y2 = v3.y_ - v1.y_;
|
|
|
|
|
+ float z1 = v2.z_ - v1.z_;
|
|
|
|
|
+ float z2 = v3.z_ - v1.z_;
|
|
|
|
|
+
|
|
|
|
|
+ float s1 = w2.x_ - w1.x_;
|
|
|
|
|
+ float s2 = w3.x_ - w1.x_;
|
|
|
|
|
+ float t1 = w2.y_ - w1.y_;
|
|
|
|
|
+ float t2 = w3.y_ - w1.y_;
|
|
|
|
|
+
|
|
|
|
|
+ float r = 1.0f / (s1 * t2 - s2 * t1);
|
|
|
|
|
+ Vector3 sdir((t2 * x1 - t1 * x2) * r, (t2 * y1 - t1 * y2) * r,
|
|
|
|
|
+ (t2 * z1 - t1 * z2) * r);
|
|
|
|
|
+ Vector3 tdir((s1 * x2 - s2 * x1) * r, (s1 * y2 - s2 * y1) * r,
|
|
|
|
|
+ (s1 * z2 - s2 * z1) * r);
|
|
|
|
|
|
|
|
for (unsigned j = i; j < i + 3; ++j)
|
|
for (unsigned j = i; j < i + 3; ++j)
|
|
|
{
|
|
{
|
|
|
- const Vector3& n = decal.vertices_[j].normal_;
|
|
|
|
|
- Vector3 xyz;
|
|
|
|
|
- float w;
|
|
|
|
|
-
|
|
|
|
|
- // Gram-Schmidt orthogonalize
|
|
|
|
|
- xyz = (sdir - n * n.DotProduct(sdir)).Normalized();
|
|
|
|
|
-
|
|
|
|
|
- // Calculate handedness
|
|
|
|
|
- w = n.CrossProduct(sdir).DotProduct(tdir) < 0.0f ? -1.0f : 1.0f;
|
|
|
|
|
-
|
|
|
|
|
|
|
+ const Vector3& n = decal.vertices_[j].normal_;
|
|
|
|
|
+ Vector3 xyz;
|
|
|
|
|
+ float w;
|
|
|
|
|
+
|
|
|
|
|
+ // Gram-Schmidt orthogonalize
|
|
|
|
|
+ xyz = (sdir - n * n.DotProduct(sdir)).Normalized();
|
|
|
|
|
+
|
|
|
|
|
+ // Calculate handedness
|
|
|
|
|
+ w = n.CrossProduct(sdir).DotProduct(tdir) < 0.0f ? -1.0f : 1.0f;
|
|
|
|
|
+
|
|
|
decal.vertices_[j].tangent_ = Vector4(xyz, w);
|
|
decal.vertices_[j].tangent_ = Vector4(xyz, w);
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
@@ -588,12 +635,13 @@ void DecalSet::CalculateBoundingBox()
|
|
|
|
|
|
|
|
void DecalSet::UpdateBufferSize()
|
|
void DecalSet::UpdateBufferSize()
|
|
|
{
|
|
{
|
|
|
- if (vertexBuffer_->GetVertexCount() != maxVertices_)
|
|
|
|
|
- {
|
|
|
|
|
- vertexBuffer_->SetSize(maxVertices_, MASK_POSITION | MASK_NORMAL | MASK_TEXCOORD1 | MASK_TANGENT);
|
|
|
|
|
- bufferDirty_ = true;
|
|
|
|
|
- }
|
|
|
|
|
|
|
+ if (!skinned_)
|
|
|
|
|
+ vertexBuffer_->SetSize(maxVertices_, UNSKINNED_ELEMENT_MASK);
|
|
|
|
|
+ else
|
|
|
|
|
+ vertexBuffer_->SetSize(maxVertices_, SKINNED_ELEMENT_MASK);
|
|
|
|
|
|
|
|
|
|
+ geometry_->SetVertexBuffer(0, vertexBuffer_);
|
|
|
|
|
+ bufferDirty_ = true;
|
|
|
bufferSizeDirty_ = false;
|
|
bufferSizeDirty_ = false;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
@@ -631,6 +679,23 @@ void DecalSet::UpdateVertexBuffer()
|
|
|
bufferDirty_ = false;
|
|
bufferDirty_ = false;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+void DecalSet::UpdateSkinning()
|
|
|
|
|
+{
|
|
|
|
|
+ // Use model's world transform in case a bone is missing
|
|
|
|
|
+ const Matrix3x4& worldTransform = node_->GetWorldTransform();
|
|
|
|
|
+
|
|
|
|
|
+ for (unsigned i = 0; i < bones_.Size(); ++i)
|
|
|
|
|
+ {
|
|
|
|
|
+ const Bone& bone = bones_[i];
|
|
|
|
|
+ if (bone.node_)
|
|
|
|
|
+ skinMatrices_[i] = bone.node_->GetWorldTransform() * bone.offsetMatrix_;
|
|
|
|
|
+ else
|
|
|
|
|
+ skinMatrices_[i] = worldTransform;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ skinningDirty_ = false;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
void DecalSet::HandleScenePostUpdate(StringHash eventType, VariantMap& eventData)
|
|
void DecalSet::HandleScenePostUpdate(StringHash eventType, VariantMap& eventData)
|
|
|
{
|
|
{
|
|
|
using namespace ScenePostUpdate;
|
|
using namespace ScenePostUpdate;
|