Просмотр исходного кода

Added terrain raycast & occlusion.

Lasse Öörni 13 лет назад
Родитель
Сommit
69d7e27179
3 измененных файлов с 108 добавлено и 1 удалено
  1. 6 0
      Engine/Graphics/Terrain.cpp
  2. 96 1
      Engine/Graphics/TerrainPatch.cpp
  3. 6 0
      Engine/Graphics/TerrainPatch.h

+ 6 - 0
Engine/Graphics/Terrain.cpp

@@ -310,7 +310,10 @@ void Terrain::UpdatePatchGeometry(TerrainPatch* patch)
     VertexBuffer* vertexBuffer = patch->vertexBuffer_;
     if (vertexBuffer->GetVertexCount() != vertexDataRow * vertexDataRow)
         vertexBuffer->SetSize(vertexDataRow * vertexDataRow, MASK_POSITION | MASK_NORMAL | MASK_TEXCOORD1 | MASK_TANGENT);
+    patch->cpuVertexData_ = new Vector3[vertexDataRow * vertexDataRow];
+    
     float* vertexData = (float*)vertexBuffer->Lock(0, vertexBuffer->GetVertexCount());
+    float* cpuVertexData = (float*)patch->cpuVertexData_.Get();
     
     if (vertexData)
     {
@@ -329,6 +332,9 @@ void Terrain::UpdatePatchGeometry(TerrainPatch* patch)
                 *vertexData++ = position.x_;
                 *vertexData++ = position.y_;
                 *vertexData++ = position.z_;
+                *cpuVertexData++ = position.x_;
+                *cpuVertexData++ = position.y_;
+                *cpuVertexData++ = position.z_;
                 
                 box.Merge(position);
                 

+ 96 - 1
Engine/Graphics/TerrainPatch.cpp

@@ -27,6 +27,8 @@
 #include "Geometry.h"
 #include "IndexBuffer.h"
 #include "Node.h"
+#include "OcclusionBuffer.h"
+#include "OctreeQuery.h"
 #include "Terrain.h"
 #include "TerrainPatch.h"
 #include "VertexBuffer.h"
@@ -65,7 +67,62 @@ TerrainPatch::~TerrainPatch()
 
 void TerrainPatch::ProcessRayQuery(const RayOctreeQuery& query, PODVector<RayQueryResult>& results)
 {
-    /// \todo Implement
+    RayQueryLevel level = query.level_;
+    
+    switch (level)
+    {
+    case RAY_AABB_NOSUBOBJECTS:
+    case RAY_AABB:
+        Drawable::ProcessRayQuery(query, results);
+        break;
+        
+    case RAY_OBB:
+        {
+            Matrix3x4 inverse(node_->GetWorldTransform().Inverse());
+            Ray localRay(inverse * query.ray_.origin_, inverse * Vector4(query.ray_.direction_, 0.0f));
+            float distance = localRay.HitDistance(boundingBox_);
+            if (distance <= query.maxDistance_)
+            {
+                RayQueryResult result;
+                result.drawable_ = this;
+                result.node_ = GetNode();
+                result.distance_ = distance;
+                result.subObject_ = M_MAX_UNSIGNED;
+                results.Push(result);
+            }
+        }
+        break;
+        
+    case RAY_TRIANGLE:
+        {
+            // Do a pretest using the OBB
+            Matrix3x4 inverse(node_->GetWorldTransform().Inverse());
+            Ray localRay(inverse * query.ray_.origin_, inverse * Vector4(query.ray_.direction_, 0.0f));
+            float distance = localRay.HitDistance(boundingBox_);
+            if (distance <= query.maxDistance_)
+            {
+                // Then the actual test using triangle geometry
+                const void* indexData = geometry_->GetIndexBuffer() ? geometry_->GetIndexBuffer()->GetShadowData() : 0;
+                if (indexData && cpuVertexData_)
+                {
+                    distance = localRay.HitDistance(cpuVertexData_.Get(), sizeof(Vector3), indexData, sizeof(unsigned short),
+                        geometry_->GetIndexStart(), geometry_->GetIndexCount());
+                    
+                    if (distance <= query.maxDistance_)
+                    {
+                        RayQueryResult result;
+                        result.drawable_ = this;
+                        result.node_ = GetNode();
+                        result.distance_ = distance;
+                        result.subObject_ = M_MAX_UNSIGNED;
+                        results.Push(result);
+                        break;
+                    }
+                }
+            }
+        }
+        break;
+    }
 }
 
 void TerrainPatch::UpdateBatches(const FrameInfo& frame)
@@ -110,6 +167,44 @@ void TerrainPatch::UpdateGeometry(const FrameInfo& frame)
     lodDirty_ = false;
 }
 
+
+unsigned TerrainPatch::GetNumOccluderTriangles()
+{
+    // Check that the material is suitable for occlusion (default material always is)
+    Material* mat = batches_[0].material_;
+    if (mat && !mat->GetOcclusion())
+        return 0;
+    else
+        return geometry_->GetIndexCount() / 3;
+}
+
+bool TerrainPatch::DrawOcclusion(OcclusionBuffer* buffer)
+{
+    bool success = true;
+    
+    // Check that the material is suitable for occlusion (default material always is) and set culling mode
+    Material* material = batches_[0].material_;
+    if (material)
+    {
+        if (!material->GetOcclusion())
+            return success;
+        buffer->SetCullMode(material->GetCullMode());
+    }
+    else
+        buffer->SetCullMode(CULL_CCW);
+    
+    const unsigned char* indexData = geometry_->GetIndexBuffer() ? geometry_->GetIndexBuffer()->GetShadowData() : 0;
+    if (!indexData || !cpuVertexData_)
+        return success;
+    
+    // Draw and check for running out of triangles
+    if (!buffer->Draw(node_->GetWorldTransform(), cpuVertexData_.Get(), sizeof(Vector3), indexData, sizeof(unsigned short),
+        geometry_->GetIndexStart(), geometry_->GetIndexCount()))
+        success = false;
+    
+    return success;
+}
+
 UpdateGeometryType TerrainPatch::GetUpdateGeometryType()
 {
     // If any of the neighbour patches have changed LOD, must update stitching

+ 6 - 0
Engine/Graphics/TerrainPatch.h

@@ -49,6 +49,10 @@ public:
     virtual void UpdateGeometry(const FrameInfo& frame);
     /// Return whether a geometry update is necessary, and if it can happen in a worker thread.
     virtual UpdateGeometryType GetUpdateGeometryType();
+    /// Return number of occlusion geometry triangles.
+    virtual unsigned GetNumOccluderTriangles();
+    /// Draw to occlusion buffer. Return true if did not run out of triangles.
+    virtual bool DrawOcclusion(OcclusionBuffer* buffer);
     
 protected:
     /// Recalculate the world-space bounding box.
@@ -59,6 +63,8 @@ private:
     SharedPtr<Geometry> geometry_;
     /// Vertex buffer.
     SharedPtr<VertexBuffer> vertexBuffer_;
+    /// CPU-side position-only vertex data for raycasting and occlusion.
+    SharedArrayPtr<Vector3> cpuVertexData_;
     /// Parent terrain.
     Terrain* owner_;
     /// North neighbor patch.