Browse Source

Refactored raycast query handling in preparation to threading it.

Lasse Öörni 14 years ago
parent
commit
950e37beb1

+ 4 - 0
Engine/Engine/GraphicsAPI.cpp

@@ -42,6 +42,10 @@
 #include "Skybox.h"
 #include "Zone.h"
 
+#ifdef _MSC_VER
+#pragma warning(disable:4345)
+#endif
+
 void FakeAddRef(void* ptr);
 void FakeReleaseRef(void* ptr);
 

+ 8 - 6
Engine/Graphics/AnimatedModel.cpp

@@ -104,16 +104,18 @@ void AnimatedModel::ApplyAttributes()
     }
 }
 
-void AnimatedModel::ProcessRayQuery(RayOctreeQuery& query, float initialDistance)
+void AnimatedModel::ProcessRayQuery(const RayOctreeQuery& query, PODVector<RayQueryResult>& results)
 {
     // If no bones or no bone-level testing, use the Drawable test
     if (query.level_ < RAY_AABB || !skeleton_.GetRootBone() || !skeleton_.GetRootBone()->node_)
     {
-        Drawable::ProcessRayQuery(query, initialDistance);
+        Drawable::ProcessRayQuery(query, results);
         return;
     }
     
-    PROFILE(RaycastAnimatedModel);
+    // Check ray hit distance to AABB before proceeding with bone-level tests
+    if (query.ray_.HitDistance(GetWorldBoundingBox()) > query.maxDistance_)
+        return;
     
     const Vector<Bone>& bones = skeleton_.GetBones();
     Sphere boneSphere;
@@ -141,7 +143,7 @@ void AnimatedModel::ProcessRayQuery(RayOctreeQuery& query, float initialDistance
                     result.node_ = GetNode();
                     result.distance_ = distance;
                     result.subObject_ = i;
-                    query.result_.Push(result);
+                    results.Push(result);
                 }
                 else
                 {
@@ -156,7 +158,7 @@ void AnimatedModel::ProcessRayQuery(RayOctreeQuery& query, float initialDistance
                         result.node_ = GetNode();
                         result.distance_ = distance;
                         result.subObject_ = i;
-                        query.result_.Push(result);
+                        results.Push(result);
                     }
                 }
             }
@@ -173,7 +175,7 @@ void AnimatedModel::ProcessRayQuery(RayOctreeQuery& query, float initialDistance
                 result.node_ = GetNode();
                 result.subObject_ = i;
                 result.distance_ = distance;
-                query.result_.Push(result);
+                results.Push(result);
             }
         }
     }

+ 2 - 2
Engine/Graphics/AnimatedModel.h

@@ -48,8 +48,8 @@ public:
     
     /// Apply attribute changes that can not be applied immediately. Called after scene load or a network update.
     virtual void ApplyAttributes();
-    /// Process octree raycast.
-    virtual void ProcessRayQuery(RayOctreeQuery& query, float initialDistance);
+    /// Process octree raycast. May be called from a worker thread.
+    virtual void ProcessRayQuery(const RayOctreeQuery& query, PODVector<RayQueryResult>& results);
     /// Update before octree reinsertion. Animation is updated here.
     virtual void Update(const FrameInfo& frame);
     /// Calculate distance and LOD level for rendering. May be called from worker thread(s), possibly re-entrantly.

+ 12 - 8
Engine/Graphics/Drawable.cpp

@@ -78,14 +78,18 @@ void Drawable::RegisterObject(Context* context)
     ACCESSOR_ATTRIBUTE(Drawable, VAR_INT, "Zone Mask", GetZoneMask, SetZoneMask, unsigned, DEFAULT_ZONEMASK, AM_DEFAULT);
 }
 
-void Drawable::ProcessRayQuery(RayOctreeQuery& query, float initialDistance)
-{
-    // By default just store the result from the bounding box raycast
-    RayQueryResult result;
-    result.drawable_ = this;
-    result.node_ = GetNode();
-    result.distance_ = initialDistance;
-    query.result_.Push(result);
+void Drawable::ProcessRayQuery(const RayOctreeQuery& query, PODVector<RayQueryResult>& results)
+{
+    float distance = query.ray_.HitDistance(GetWorldBoundingBox());
+    if (distance < query.maxDistance_)
+    {
+        RayQueryResult result;
+        result.drawable_ = this;
+        result.node_ = GetNode();
+        result.distance_ = distance;
+        result.subObject_ = M_MAX_UNSIGNED;
+        results.Push(result);
+    }
 }
 
 void Drawable::UpdateDistance(const FrameInfo& frame)

+ 3 - 2
Engine/Graphics/Drawable.h

@@ -47,6 +47,7 @@ class OcclusionBuffer;
 class Octant;
 class RayOctreeQuery;
 class Zone;
+struct RayQueryResult;
 struct WorkItem;
 
 /// Geometry update type.
@@ -87,8 +88,8 @@ public:
     /// Register object attributes. Drawable must be registered first.
     static void RegisterObject(Context* context);
     
-    /// Process octree raycast.
-    virtual void ProcessRayQuery(RayOctreeQuery& query, float initialDistance);
+    /// Process octree raycast. May be called from a worker thread.
+    virtual void ProcessRayQuery(const RayOctreeQuery& query, PODVector<RayQueryResult>& results);
     /// Update before octree reinsertion. Is called from a worker thread. Needs to be requested with MarkForUpdate().
     virtual void Update(const FrameInfo& frame) {}
     /// Calculate distance and LOD level for rendering.  May be called from worker thread(s), possibly re-entrantly.

+ 22 - 9
Engine/Graphics/Light.cpp

@@ -163,7 +163,7 @@ void Light::OnSetAttribute(const AttributeInfo& attr, const Variant& src)
     }
 }
 
-void Light::ProcessRayQuery(RayOctreeQuery& query, float initialDistance)
+void Light::ProcessRayQuery(const RayOctreeQuery& query, PODVector<RayQueryResult>& results)
 {
     PROFILE(RaycastLight);
     
@@ -173,15 +173,26 @@ void Light::ProcessRayQuery(RayOctreeQuery& query, float initialDistance)
     {
     case RAY_AABB_NOSUBOBJECTS:
     case RAY_AABB:
-    case RAY_OBB:
         // Do not record a raycast result for a directional light, as they would overwhelm all other results
+        if (lightType_ != LIGHT_DIRECTIONAL)
+            Drawable::ProcessRayQuery(query, results);
+        break;
+        
+    case RAY_OBB:
         if (lightType_ != LIGHT_DIRECTIONAL)
         {
-            RayQueryResult result;
-            result.drawable_ = this;
-            result.node_ = GetNode();
-            result.distance_ = initialDistance;
-            query.result_.Push(result);
+            Matrix3x4 inverse(GetWorldTransform().Inverse());
+            Ray localRay(inverse * query.ray_.origin_, inverse * Vector4(query.ray_.direction_, 0.0f));
+            float distance = localRay.HitDistance(GetWorldBoundingBox());
+            if (distance < query.maxDistance_)
+            {
+                RayQueryResult result;
+                result.drawable_ = this;
+                result.node_ = GetNode();
+                result.distance_ = distance;
+                result.subObject_ = M_MAX_UNSIGNED;
+                results.Push(result);
+            }
         }
         break;
         
@@ -195,7 +206,8 @@ void Light::ProcessRayQuery(RayOctreeQuery& query, float initialDistance)
                 result.drawable_ = this;
                 result.node_ = GetNode();
                 result.distance_ = distance;
-                query.result_.Push(result);
+                result.subObject_ = M_MAX_UNSIGNED;
+                results.Push(result);
             }
         }
         if (lightType_ == LIGHT_POINT)
@@ -207,7 +219,8 @@ void Light::ProcessRayQuery(RayOctreeQuery& query, float initialDistance)
                 result.drawable_ = this;
                 result.node_ = GetNode();
                 result.distance_ = distance;
-                query.result_.Push(result);
+                result.subObject_ = M_MAX_UNSIGNED;
+                results.Push(result);
             }
         }
         break;

+ 2 - 2
Engine/Graphics/Light.h

@@ -158,8 +158,8 @@ public:
     
     /// Handle attribute change.
     virtual void OnSetAttribute(const AttributeInfo& attr, const Variant& src);
-    /// Process octree raycast.
-    virtual void ProcessRayQuery(RayOctreeQuery& query, float initialDistance);
+    /// Process octree raycast. May be called from a worker thread.
+    virtual void ProcessRayQuery(const RayOctreeQuery& query, PODVector<RayQueryResult>& results);
     /// Calculate distance for rendering. May be called from worker thread(s), possibly re-entrantly.
     virtual void UpdateDistance(const FrameInfo& frame);
     /// Add debug geometry to the debug graphics.

+ 3 - 7
Engine/Graphics/Octree.cpp

@@ -197,7 +197,7 @@ void Octant::GetDrawablesInternal(OctreeQuery& query, bool inside) const
         Drawable* drawable = *i;
         
         if (!(drawable->GetDrawableFlags() & query.drawableFlags_) || !(drawable->GetViewMask() & query.viewMask_) ||
-            (query.occludersOnly_ && !drawable->IsOccluder()) || (query.shadowCastersOnly_ && !drawable->GetCastShadows()) ||
+            (query.shadowCastersOnly_ && !drawable->GetCastShadows()) ||
             !drawable->IsVisible())
             continue;
         
@@ -227,14 +227,10 @@ void Octant::GetDrawablesInternal(RayOctreeQuery& query) const
         unsigned drawableFlags = drawable->GetDrawableFlags();
         
         if (!(drawable->GetDrawableFlags() & query.drawableFlags_) || !(drawable->GetViewMask() & query.viewMask_) ||
-            !drawable->IsVisible() || (query.occludersOnly_ && !drawable->IsOccluder()) || (query.shadowCastersOnly_ &&
-            !drawable->GetCastShadows()))
+            !drawable->IsVisible() || (query.shadowCastersOnly_ && !drawable->GetCastShadows()))
             continue;
         
-        float drawableDist = query.ray_.HitDistance(drawable->GetWorldBoundingBox());
-        // The drawable will possibly do more accurate collision testing, then store the result(s)
-        if (drawableDist < query.maxDistance_)
-            drawable->ProcessRayQuery(query, drawableDist);
+        drawable->ProcessRayQuery(query, query.result_);
     }
     
     for (unsigned i = 0; i < NUM_OCTANTS; ++i)

+ 10 - 22
Engine/Graphics/OctreeQuery.h

@@ -37,11 +37,10 @@ class OctreeQuery
 {
 public:
     /// Construct with query parameters.
-    OctreeQuery(PODVector<Drawable*>& result, unsigned char drawableFlags, unsigned viewMask, bool occludersOnly, bool shadowCastersOnly) :
+    OctreeQuery(PODVector<Drawable*>& result, unsigned char drawableFlags, unsigned viewMask, bool shadowCastersOnly) :
         result_(result),
         drawableFlags_(drawableFlags),
         viewMask_(viewMask),
-        occludersOnly_(occludersOnly),
         shadowCastersOnly_(shadowCastersOnly)
     {
     }
@@ -62,8 +61,6 @@ public:
     unsigned char drawableFlags_;
     /// Drawable layers to include.
     unsigned viewMask_;
-    /// Get occluders only flag.
-    bool occludersOnly_;
     /// Get shadowcasters only flag.
     bool shadowCastersOnly_;
 };
@@ -74,8 +71,8 @@ class PointOctreeQuery : public OctreeQuery
 public:
     /// Construct with point and query parameters.
     PointOctreeQuery(PODVector<Drawable*>& result, const Vector3& point, unsigned char drawableFlags = DRAWABLE_ANY,
-        unsigned viewMask = DEFAULT_VIEWMASK, bool occludersOnly = false, bool shadowCastersOnly = false) :
-        OctreeQuery(result, drawableFlags, viewMask, occludersOnly, shadowCastersOnly),
+        unsigned viewMask = DEFAULT_VIEWMASK, bool shadowCastersOnly = false) :
+        OctreeQuery(result, drawableFlags, viewMask, shadowCastersOnly),
         point_(point)
     {
     }
@@ -95,8 +92,8 @@ class SphereOctreeQuery : public OctreeQuery
 public:
     /// Construct with sphere and query parameters.
     SphereOctreeQuery(PODVector<Drawable*>& result, const Sphere& sphere, unsigned char drawableFlags = DRAWABLE_ANY,
-        unsigned viewMask = DEFAULT_VIEWMASK, bool occludersOnly = false, bool shadowCastersOnly = false) :
-        OctreeQuery(result, drawableFlags, viewMask, occludersOnly, shadowCastersOnly),
+        unsigned viewMask = DEFAULT_VIEWMASK, bool shadowCastersOnly = false) :
+        OctreeQuery(result, drawableFlags, viewMask, shadowCastersOnly),
         sphere_(sphere)
     {
     }
@@ -116,8 +113,8 @@ class BoxOctreeQuery : public OctreeQuery
 public:
     /// Construct with bounding box and query parameters.
     BoxOctreeQuery(PODVector<Drawable*>& result, const BoundingBox& box, unsigned char drawableFlags = DRAWABLE_ANY,
-        unsigned viewMask = DEFAULT_VIEWMASK, bool occludersOnly = false, bool shadowCastersOnly = false) :
-        OctreeQuery(result, drawableFlags, viewMask, occludersOnly, shadowCastersOnly),
+        unsigned viewMask = DEFAULT_VIEWMASK, bool shadowCastersOnly = false) :
+        OctreeQuery(result, drawableFlags, viewMask, shadowCastersOnly),
         box_(box)
     {
     }
@@ -137,8 +134,8 @@ class FrustumOctreeQuery : public OctreeQuery
 public:
     /// Construct with frustum and query parameters.
     FrustumOctreeQuery(PODVector<Drawable*>& result, const Frustum& frustum, unsigned char drawableFlags = DRAWABLE_ANY,
-        unsigned viewMask = DEFAULT_VIEWMASK, bool occludersOnly = false, bool shadowCastersOnly = false) :
-        OctreeQuery(result, drawableFlags, viewMask, occludersOnly, shadowCastersOnly),
+        unsigned viewMask = DEFAULT_VIEWMASK, bool shadowCastersOnly = false) :
+        OctreeQuery(result, drawableFlags, viewMask, shadowCastersOnly),
         frustum_(frustum)
     {
     }
@@ -164,12 +161,6 @@ enum RayQueryLevel
 /// Raycast result.
 struct RayQueryResult
 {
-    /// Construct.
-    RayQueryResult() :
-        subObject_(M_MAX_UNSIGNED)
-    {
-    }
-    
     /// Drawable.
     Drawable* drawable_;
     /// Scene node.
@@ -187,14 +178,13 @@ public:
     /// Construct with ray and query parameters.
     RayOctreeQuery(PODVector<RayQueryResult>& result, const Ray& ray, RayQueryLevel level = RAY_TRIANGLE,
         float maxDistance = M_INFINITY, unsigned char drawableFlags = DRAWABLE_ANY, unsigned viewMask = DEFAULT_VIEWMASK, 
-        bool occludersOnly = false, bool shadowCastersOnly = false) :
+        bool shadowCastersOnly = false) :
         result_(result),
         ray_(ray),
         level_(level),
         maxDistance_(maxDistance),
         drawableFlags_(drawableFlags),
         viewMask_(viewMask),
-        occludersOnly_(occludersOnly),
         shadowCastersOnly_(shadowCastersOnly)
     {
     }
@@ -207,8 +197,6 @@ public:
     unsigned char drawableFlags_;
     /// Drawable layers to include.
     unsigned viewMask_;
-    /// Get occluders only flag.
-    bool occludersOnly_;
     /// Get shadowcasters only flag.
     bool shadowCastersOnly_;
     /// Maximum ray distance.

+ 1 - 1
Engine/Graphics/Skybox.cpp

@@ -45,7 +45,7 @@ void Skybox::RegisterObject(Context* context)
     COPY_BASE_ATTRIBUTES(Skybox, StaticModel);
 }
 
-void Skybox::ProcessRayQuery(RayOctreeQuery& query, float initialDistance)
+void Skybox::ProcessRayQuery(const RayOctreeQuery& query, PODVector<RayQueryResult>& results)
 {
     // Return no ray hits, as camera rays practically always originate within the bounding box, blocking any other results
 }

+ 2 - 2
Engine/Graphics/Skybox.h

@@ -38,8 +38,8 @@ public:
     /// Register object factory. StaticModel must be registered first.
     static void RegisterObject(Context* context);
     
-    /// Process octree raycast.
-    void ProcessRayQuery(RayOctreeQuery& query, float initialDistance);
+    /// Process octree raycast. May be called from a worker thread.
+    virtual void ProcessRayQuery(const RayOctreeQuery& query, PODVector<RayQueryResult>& results);
     /// Calculate distance and LOD level for rendering. May be called from worker thread(s), possibly re-entrantly.
     virtual void UpdateDistance(const FrameInfo& frame);
     /// Fill rendering batch with distance, geometry, material and world transform.

+ 6 - 12
Engine/Graphics/StaticModel.cpp

@@ -70,23 +70,15 @@ void StaticModel::RegisterObject(Context* context)
     ATTRIBUTE(StaticModel, VAR_INT, "Ray/Occl. LOD Level", softwareLodLevel_, M_MAX_UNSIGNED, AM_DEFAULT);
 }
 
-void StaticModel::ProcessRayQuery(RayOctreeQuery& query, float initialDistance)
+void StaticModel::ProcessRayQuery(const RayOctreeQuery& query, PODVector<RayQueryResult>& results)
 {
-    PROFILE(RaycastStaticModel);
-    
     RayQueryLevel level = query.level_;
     
     switch (level)
     {
     case RAY_AABB_NOSUBOBJECTS:
     case RAY_AABB:
-        {
-            RayQueryResult result;
-            result.drawable_ = this;
-            result.node_ = GetNode();
-            result.distance_ = initialDistance;
-            query.result_.Push(result);
-        }
+        Drawable::ProcessRayQuery(query, results);
         break;
         
     case RAY_OBB:
@@ -100,7 +92,8 @@ void StaticModel::ProcessRayQuery(RayOctreeQuery& query, float initialDistance)
                 result.drawable_ = this;
                 result.node_ = GetNode();
                 result.distance_ = distance;
-                query.result_.Push(result);
+                result.subObject_ = M_MAX_UNSIGNED;
+                results.Push(result);
             }
         }
         break;
@@ -133,7 +126,8 @@ void StaticModel::ProcessRayQuery(RayOctreeQuery& query, float initialDistance)
                             result.drawable_ = this;
                             result.node_ = GetNode();
                             result.distance_ = distance;
-                            query.result_.Push(result);
+                            result.subObject_ = M_MAX_UNSIGNED;
+                            results.Push(result);
                             break;
                         }
                     }

+ 2 - 2
Engine/Graphics/StaticModel.h

@@ -40,8 +40,8 @@ public:
     /// Register object factory. Drawable must be registered first.
     static void RegisterObject(Context* context);
     
-    /// Process octree raycast.
-    virtual void ProcessRayQuery(RayOctreeQuery& query, float initialDistance);
+    /// Process octree raycast. May be called from a worker thread.
+    virtual void ProcessRayQuery(const RayOctreeQuery& query, PODVector<RayQueryResult>& results);
     /// Calculate distance and LOD level for rendering. May be called from worker thread(s), possibly re-entrantly.
     virtual void UpdateDistance(const FrameInfo& frame);
     /// Return number of batches.

+ 1 - 1
Engine/Graphics/View.cpp

@@ -1094,7 +1094,7 @@ void View::ProcessLight(LightQueryResult& query, unsigned threadIndex)
         if (type != LIGHT_SPOT)
         {
             FrustumOctreeQuery octreeQuery(tempDrawables, shadowCameraFrustum, DRAWABLE_GEOMETRY,
-                camera_->GetViewMask(), false, true);
+                camera_->GetViewMask(), true);
             octree_->GetDrawables(octreeQuery);
         }