Browse Source

Clip decals as polygons and retriangulate after clipping for less vertices.
Refactored polygon clipping into an utility function.

Lasse Öörni 13 years ago
parent
commit
55e90c3ee3

+ 94 - 111
Engine/Graphics/DecalSet.cpp

@@ -27,6 +27,7 @@
 #include "Context.h"
 #include "Context.h"
 #include "DecalSet.h"
 #include "DecalSet.h"
 #include "Geometry.h"
 #include "Geometry.h"
+#include "GeometryUtils.h"
 #include "Graphics.h"
 #include "Graphics.h"
 #include "Log.h"
 #include "Log.h"
 #include "Node.h"
 #include "Node.h"
@@ -170,25 +171,55 @@ bool DecalSet::AddDecal(Drawable* target, const Vector3& worldPosition, const Qu
     Decal& newDecal = decals_.Back();
     Decal& newDecal = decals_.Back();
     newDecal.timeToLive_ = timeToLive;
     newDecal.timeToLive_ = timeToLive;
     
     
+    Vector<PODVector<DecalVertex> > faces;
+    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 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)
     {
     {
         for (unsigned i = 0; i < staticModel->GetNumGeometries(); ++i)
         for (unsigned i = 0; i < staticModel->GetNumGeometries(); ++i)
-            AddVertices(newDecal, decalFrustum.planes_[PLANE_FAR], staticModel->GetSoftwareGeometry(i), decalNormal, normalCutoff);
+            GetFaces(faces, staticModel->GetSoftwareGeometry(i), decalFrustum, decalNormal, normalCutoff);
     }
     }
     else
     else
     {
     {
         // Else use the Drawable API to find out the source geometries
         // Else use the Drawable API to find out the source geometries
         const Vector<SourceBatch>& batches = target->GetBatches();
         const Vector<SourceBatch>& batches = target->GetBatches();
         for (unsigned i = 0; i < batches.Size(); ++i)
         for (unsigned i = 0; i < batches.Size(); ++i)
-            AddVertices(newDecal, decalFrustum.planes_[PLANE_FAR], batches[i].geometry_, decalNormal, normalCutoff);
+            GetFaces(faces, batches[i].geometry_, decalFrustum, decalNormal, normalCutoff);
     }
     }
     
     
-    // Clip the acquired vertices with rest of the decal frustum planes
-    PODVector<DecalVertex> tempVertices;
-    for (unsigned i = PLANE_NEAR; i < PLANE_FAR; ++i)
-        ClipVertices(newDecal, decalFrustum.planes_[i], tempVertices);
+    // Clip the acquired faces against all frustum planes
+    for (unsigned i = 0; i < NUM_FRUSTUM_PLANES; ++i)
+    {
+        for (unsigned j = 0; j < faces.Size(); ++j)
+        {
+            PODVector<DecalVertex>& face = faces[j];
+            if (face.Empty())
+                continue;
+            
+            tempFace.Resize(face.Size() + 2);
+            unsigned outVertices = ClipPolygon((float*)&face[0], (float*)&tempFace[0], face.Size(), sizeof(DecalVertex), decalFrustum.planes_[i]);
+            tempFace.Resize(outVertices);
+            
+            face = tempFace;
+        }
+    }
+    
+    // Now triangulate the resulting faces into decal vertices
+    for (unsigned i = 0; i < faces.Size(); ++i)
+    {
+        PODVector<DecalVertex>& face = faces[i];
+        if (face.Size() < 3)
+            continue;
+        
+        for (unsigned j = 2; j < face.Size(); ++j)
+        {
+            newDecal.vertices_.Push(face[0]);
+            newDecal.vertices_.Push(face[j - 1]);
+            newDecal.vertices_.Push(face[j]);
+        }
+    }
     
     
     // Check if resulted in no triangles
     // Check if resulted in no triangles
     if (newDecal.vertices_.Empty())
     if (newDecal.vertices_.Empty())
@@ -219,7 +250,7 @@ bool DecalSet::AddDecal(Drawable* target, const Vector3& worldPosition, const Qu
     while (decals_.Size() && numVertices_ > maxVertices_)
     while (decals_.Size() && numVertices_ > maxVertices_)
         RemoveDecals(1);
         RemoveDecals(1);
     
     
-    LOGINFO("Added decal with " + String(newDecal.vertices_.Size()) + " vertices");
+    LOGDEBUG("Added decal with " + String(newDecal.vertices_.Size()) + " vertices");
     
     
     MarkDecalsDirty();
     MarkDecalsDirty();
     return true;
     return true;
@@ -269,7 +300,7 @@ void DecalSet::OnWorldBoundingBoxUpdate()
     worldBoundingBox_ = boundingBox_.Transformed(node_->GetWorldTransform());
     worldBoundingBox_ = boundingBox_.Transformed(node_->GetWorldTransform());
 }
 }
 
 
-void DecalSet::AddVertices(Decal& decal, const Plane& plane, Geometry* geometry, const Vector3& decalNormal, float normalCutoff)
+void DecalSet::GetFaces(Vector<PODVector<DecalVertex> >& faces, Geometry* geometry, const Frustum& frustum, const Vector3& decalNormal, float normalCutoff)
 {
 {
     if (!geometry)
     if (!geometry)
         return;
         return;
@@ -303,12 +334,36 @@ void DecalSet::AddVertices(Decal& decal, const Plane& plane, Geometry* geometry,
             const Vector3& v0 = *((const Vector3*)(&srcData[indices[0] * vertexSize]));
             const Vector3& v0 = *((const Vector3*)(&srcData[indices[0] * vertexSize]));
             const Vector3& v1 = *((const Vector3*)(&srcData[indices[1] * vertexSize]));
             const Vector3& v1 = *((const Vector3*)(&srcData[indices[1] * vertexSize]));
             const Vector3& v2 = *((const Vector3*)(&srcData[indices[2] * 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;
+            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)
             if (!hasNormals || decalNormal.DotProduct((n0 + n1 + n2) / 3.0f) >= normalCutoff)
-                AddTriangle(decal.vertices_, plane, v0, v1, v2, n0, n1, n2);
+            {
+                // 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, Vector2::ZERO));
+                    face.Push(DecalVertex(v1, n1, Vector2::ZERO));
+                    face.Push(DecalVertex(v2, n2, Vector2::ZERO));
+                }
+            }
             
             
             indices += 3;
             indices += 3;
         }
         }
@@ -324,113 +379,41 @@ void DecalSet::AddVertices(Decal& decal, const Plane& plane, Geometry* geometry,
             const Vector3& v0 = *((const Vector3*)(&srcData[indices[0] * vertexSize]));
             const Vector3& v0 = *((const Vector3*)(&srcData[indices[0] * vertexSize]));
             const Vector3& v1 = *((const Vector3*)(&srcData[indices[1] * vertexSize]));
             const Vector3& v1 = *((const Vector3*)(&srcData[indices[1] * vertexSize]));
             const Vector3& v2 = *((const Vector3*)(&srcData[indices[2] * 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;
+            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)
             if (!hasNormals || decalNormal.DotProduct((n0 + n1 + n2) / 3.0f) >= normalCutoff)
-                AddTriangle(decal.vertices_, plane, v0, v1, v2, n0, n1, n2);
+            {
+                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, Vector2::ZERO));
+                    face.Push(DecalVertex(v1, n1, Vector2::ZERO));
+                    face.Push(DecalVertex(v2, n2, Vector2::ZERO));
+                }
+            }
             
             
             indices += 3;
             indices += 3;
         }
         }
     }
     }
 }
 }
 
 
-void DecalSet::AddTriangle(PODVector<DecalVertex>& dest, const Plane& plane, Vector3 v0, Vector3 v1, Vector3 v2, Vector3 n0, Vector3 n1, Vector3 n2)
-{
-    /// \todo This should be optimized by turning the triangles into polyhedrons during clipping and finally triangulating them
-    float d0 = plane.Distance(v0);
-    float d1 = plane.Distance(v1);
-    float d2 = plane.Distance(v2);
-    
-    // Reject triangle if all vertices behind the plane
-    if (d0 < 0.0f && d1 < 0.0f && d2 < 0.0f)
-        return;
-    // If 2 vertices behind the plane, create a new triangle in-place
-    else if (d0 < 0.0f && d1 < 0.0f)
-    {
-        v0 = ClipEdge(v0, v2, d0, d2);
-        v1 = ClipEdge(v1, v2, d1, d2);
-        n0 = ClipEdge(n0, n2, d0, d2);
-        n1 = ClipEdge(n1, n2, d1, d2);
-    }
-    else if (d0 < 0.0f && d2 < 0.0f)
-    {
-        v0 = ClipEdge(v0, v1, d0, d1);
-        v2 = ClipEdge(v2, v1, d2, d1);
-        n0 = ClipEdge(n0, n1, d0, d1);
-        n2 = ClipEdge(n2, n1, d2, d1);
-    }
-    else if (d1 < 0.0f && d2 < 0.0f)
-    {
-        v1 = ClipEdge(v1, v0, d1, d0);
-        v2 = ClipEdge(v2, v0, d2, d0);
-        n1 = ClipEdge(n1, n0, d1, d0);
-        n2 = ClipEdge(n2, n0, d2, d0);
-    }
-    // 1 vertex behind the plane: create one new triangle, and modify one in-place
-    else if (d0 < 0.0f)
-    {
-        Vector3 v3, v4, v5, n3, n4, n5;
-        v3 = ClipEdge(v0, v2, d0, d2);
-        v4 = v0 = ClipEdge(v0, v1, d0, d1);
-        v5 = v2;
-        n3 = ClipEdge(n0, n2, d0, d2);
-        n4 = n0 = ClipEdge(n0, n1, d0, d1);
-        n5 = n2;
-        
-        dest.Push(DecalVertex(v3, n3, Vector2::ZERO));
-        dest.Push(DecalVertex(v4, n4, Vector2::ZERO));
-        dest.Push(DecalVertex(v5, n5, Vector2::ZERO));
-    }
-    else if (d1 < 0.0f)
-    {
-        Vector3 v3, v4, v5, n3, n4, n5;
-        v4 = ClipEdge(v1, v0, d1, d0);
-        v5 = v1 = ClipEdge(v1, v2, d1, d2);
-        v3 = v0;
-        n4 = ClipEdge(n1, n0, d1, d0);
-        n5 = n1 = ClipEdge(n1, n2, d1, d2);
-        n3 = n0;
-        
-        dest.Push(DecalVertex(v3, n3, Vector2::ZERO));
-        dest.Push(DecalVertex(v4, n4, Vector2::ZERO));
-        dest.Push(DecalVertex(v5, n5, Vector2::ZERO));
-    }
-    else if (d2 < 0.0f)
-    {
-        Vector3 v3, v4, v5, n3, n4, n5;
-        v5 = ClipEdge(v2, v1, d2, d1);
-        v3 = v2 = ClipEdge(v2, v0, d2, d0);
-        v4 = v1;
-        n5 = ClipEdge(n2, n1, d2, d1);
-        n3 = n2 = ClipEdge(n2, n0, d2, d0);
-        n4 = n1;
-        
-        dest.Push(DecalVertex(v3, n3, Vector2::ZERO));
-        dest.Push(DecalVertex(v4, n4, Vector2::ZERO));
-        dest.Push(DecalVertex(v5, n5, Vector2::ZERO));
-    }
-    
-    dest.Push(DecalVertex(v0, n0, Vector2::ZERO));
-    dest.Push(DecalVertex(v1, n1, Vector2::ZERO));
-    dest.Push(DecalVertex(v2, n2, Vector2::ZERO));
-}
-
-void DecalSet::ClipVertices(Decal& decal, const Plane& plane, PODVector<DecalVertex>& tempVertices)
-{
-    tempVertices.Clear();
-    
-    for (unsigned i = 0; i < decal.vertices_.Size(); i += 3)
-    {
-        AddTriangle(tempVertices, plane, decal.vertices_[i].position_, decal.vertices_[i + 1].position_,
-            decal.vertices_[i + 2].position_, decal.vertices_[i].normal_, decal.vertices_[i + 1].normal_,
-            decal.vertices_[i + 2].normal_);
-    }
-    
-    decal.vertices_ = tempVertices;
-}
-
 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);

+ 3 - 6
Engine/Graphics/DecalSet.h

@@ -24,6 +24,7 @@
 #pragma once
 #pragma once
 
 
 #include "Drawable.h"
 #include "Drawable.h"
+#include "Frustum.h"
 #include "List.h"
 #include "List.h"
 
 
 /// Decal vertex.
 /// Decal vertex.
@@ -121,12 +122,8 @@ protected:
     virtual void OnWorldBoundingBoxUpdate();
     virtual void OnWorldBoundingBoxUpdate();
     
     
 private:
 private:
-    /// Add vertices to decal from a geometry and clip with the initial plane.
-    void AddVertices(Decal& decal, const Plane& plane, Geometry* geometry, const Vector3& decalNormal, float normalCutoff);
-    /// Clip and add one triangle with a plane.
-    void AddTriangle(PODVector<DecalVertex>& dest, const Plane& plane, Vector3 v0, Vector3 v1, Vector3 v2, Vector3 n0, Vector3 n1, Vector3 n2);
-    /// Clip decal's vertices with a plane.
-    void ClipVertices(Decal& decal, const Plane& plane, PODVector<DecalVertex>& tempVertices);
+    /// Get triangle faces from the target geometry.
+    void GetFaces(Vector<PODVector<DecalVertex> >& faces, Geometry* geometry, const Frustum& frustum, const Vector3& decalNormal, float normalCutoff);
     /// Calculate UV coordinates for the decal.
     /// Calculate UV coordinates for the decal.
     void CalculateUVs(Decal& decal, const Matrix3x4& view, float size, float aspectRatio, float depth, const Vector2& topLeftUV, const Vector2& bottomRightUV);
     void CalculateUVs(Decal& decal, const Matrix3x4& view, float size, float aspectRatio, float depth, const Vector2& topLeftUV, const Vector2& bottomRightUV);
     /// Transform decal's vertices from the target geometry to the decal set local space.
     /// Transform decal's vertices from the target geometry to the decal set local space.

+ 117 - 0
Engine/Math/GeometryUtils.cpp

@@ -0,0 +1,117 @@
+//
+// Urho3D Engine
+// Copyright (c) 2008-2012 Lasse Öörni
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+//
+
+#include "Precompiled.h"
+#include "GeometryUtils.h"
+#include "Plane.h"
+
+inline void ClipEdge(float* output, float* v0, float* v1, float d0, float d1, unsigned components)
+{
+    float t = d0 / (d0 - d1);
+    
+    for (unsigned i = 0; i < components; ++i)
+        output[i] = v0[i] + t * (v1[i] - v0[i]);
+}
+
+inline void CopyVertex(float* output, float* input, unsigned components)
+{
+    for (unsigned i = 0; i < components; ++i)
+        output[i] = input[i];
+}
+
+unsigned ClipPolygon(float* input, float* output, unsigned vertexCount, unsigned vertexSize, const Plane& plane, float* clip, unsigned* clipVertexCount)
+{
+    unsigned components = vertexSize / sizeof(float);
+    unsigned outVertexCount = 0;
+    float* lastVertex = input;
+    float lastDistance = 0.0f;
+    
+    if (clipVertexCount)
+        *clipVertexCount = 0;
+    
+    for (unsigned i = 0; i < vertexCount; ++i)
+    {
+        float* vertex = input + i * components;
+        const Vector3& position = *((Vector3*)vertex);
+        float distance = plane.Distance(position);
+        if (distance >= 0.0f)
+        {
+            if (lastDistance < 0.0f)
+            {
+                ClipEdge(output, lastVertex, vertex, lastDistance, distance, components);
+                if (clip && clipVertexCount)
+                {
+                    CopyVertex(clip, output, components);
+                    clip += components;
+                    ++(*clipVertexCount);
+                }
+                output += components;
+                ++outVertexCount;
+            }
+            
+            for (unsigned j = 0; j < components; ++j)
+                output[j] = vertex[j];
+            output += components;
+            ++outVertexCount;
+        }
+        else
+        {
+            if (lastDistance >= 0.0f && i != 0)
+            {
+                ClipEdge(output, lastVertex, vertex, lastDistance, distance, components);
+                if (clip && clipVertexCount)
+                {
+                    CopyVertex(clip, output, components);
+                    clip += components;
+                    ++(*clipVertexCount);
+                }
+                output += components;
+                ++outVertexCount;
+            }
+        }
+        
+        lastVertex = vertex;
+        lastDistance = distance;
+    }
+    
+    // Recheck the distances of the last and first vertices and add the final clipped vertex if applicable
+    {
+        float* vertex = input;
+        const Vector3& position = *((Vector3*)vertex);
+        float distance = plane.Distance(position);
+        if ((lastDistance < 0.0f && distance >= 0.0f) || (lastDistance >= 0.0f && distance < 0.0f))
+        {
+            ClipEdge(output, lastVertex, vertex, lastDistance, distance, components);
+            if (clip && clipVertexCount)
+            {
+                CopyVertex(clip, output, components);
+                clip += components;
+                ++(*clipVertexCount);
+            }
+            output += components;
+            ++outVertexCount;
+        }
+    }
+    
+    return outVertexCount;
+}

+ 30 - 0
Engine/Math/GeometryUtils.h

@@ -0,0 +1,30 @@
+//
+// Urho3D Engine
+// Copyright (c) 2008-2012 Lasse Öörni
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+//
+
+#pragma once
+
+class Plane;
+
+/// Clip a convex polygon with a plane. Output may be two vertices more than input. Vertices can have additional float values which will be interpolated. Return number of output vertices. Optionally put clipped vertices into a separate output array.
+unsigned ClipPolygon(float* input, float* output, unsigned vertexCount, unsigned vertexSize, const Plane& plane, float* clip = 0, unsigned* clipVertexCount = 0);
+

+ 18 - 46
Engine/Math/Polyhedron.cpp

@@ -23,6 +23,7 @@
 
 
 #include "Precompiled.h"
 #include "Precompiled.h"
 #include "Frustum.h"
 #include "Frustum.h"
+#include "GeometryUtils.h"
 #include "Polyhedron.h"
 #include "Polyhedron.h"
 
 
 Polyhedron::~Polyhedron()
 Polyhedron::~Polyhedron()
@@ -91,61 +92,32 @@ void Polyhedron::AddFace(const PODVector<Vector3>& face)
 
 
 void Polyhedron::Clip(const Plane& plane)
 void Polyhedron::Clip(const Plane& plane)
 {
 {
-    clippedVertices_.Clear();
+    unsigned totalVertices = 0;
+    unsigned totalClippedVertices = 0;
+    for (unsigned i = 0; i < faces_.Size(); ++i)
+        totalVertices += faces_[i].Size();
+    
+    // Clipping may produce max. 1 vertex more for each face
+    clippedVertices_.Resize(totalVertices + faces_.Size());
     
     
     for (unsigned i = 0; i < faces_.Size(); ++i)
     for (unsigned i = 0; i < faces_.Size(); ++i)
     {
     {
         PODVector<Vector3>& face = faces_[i];
         PODVector<Vector3>& face = faces_[i];
-        outFace_.Clear();
+        if (face.Empty())
+            continue;
         
         
-        Vector3 lastVertex;
-        float lastDistance = 0.0f;
-        for (unsigned j = 0; j < face.Size(); ++j)
-        {
-            float distance = plane.Distance(face[j]);
-            if (distance >= 0.0f)
-            {
-                if (lastDistance < 0.0f)
-                {
-                    float t = lastDistance / (lastDistance - distance);
-                    Vector3 clippedVertex = lastVertex + t * (face[j] - lastVertex);
-                    outFace_.Push(clippedVertex);
-                    clippedVertices_.Push(clippedVertex);
-                }
-                
-                outFace_.Push(face[j]);
-            }
-            else
-            {
-                if (lastDistance >= 0.0f && j != 0)
-                {
-                    float t = lastDistance / (lastDistance - distance);
-                    Vector3 clippedVertex = lastVertex + t * (face[j] - lastVertex);
-                    outFace_.Push(clippedVertex);
-                    clippedVertices_.Push(clippedVertex);
-                }
-            }
-            
-            lastVertex = face[j];
-            lastDistance = distance;
-        }
-        // Recheck the distances of the last and first vertices and add the final clipped vertex if applicable
-        float distance = plane.Distance(face[0]);
-        if ((lastDistance < 0.0f && distance >= 0.0f) || (lastDistance >= 0.0f && distance < 0.0f))
-        {
-            float t = lastDistance / (lastDistance - distance);
-            Vector3 clippedVertex = lastVertex + t * (face[0] - lastVertex);
-            outFace_.Push(clippedVertex);
-            clippedVertices_.Push(clippedVertex);
-        }
+        outFace_.Resize(face.Size() + 2);
         
         
-        // Do not keep faces which are less than triangles
-        if (outFace_.Size() < 3)
-            outFace_.Clear();
+        unsigned outClippedVertices = 0;
+        unsigned outVertices = ClipPolygon((float*)&face[0], (float*)&outFace_[0], face.Size(), sizeof(Vector3), plane,
+            (float*)&clippedVertices_[totalClippedVertices], &outClippedVertices);
+        totalClippedVertices += outClippedVertices;
         
         
-        face = outFace_;
+        outFace_.Resize(outVertices);
     }
     }
     
     
+    clippedVertices_.Resize(totalClippedVertices);
+    
     // Remove empty faces
     // Remove empty faces
     for (unsigned i = faces_.Size() - 1; i < faces_.Size(); --i)
     for (unsigned i = faces_.Size() - 1; i < faces_.Size(); --i)
     {
     {