2
0
Эх сурвалжийг харах

Added more accurate but more expensive raycast for BillboardSet, which approximates the individual billboards as spheres and gives the billboard index as the subobject. RAY_TRIANGLE level raycast must be used to enable it. Removed the RAY_AABB_NOSUBOBJECTS raycast level, as it was not used anywhere.

Lasse Öörni 12 жил өмнө
parent
commit
3491baafd0

+ 44 - 0
Source/Engine/Graphics/BillboardSet.cpp

@@ -31,6 +31,7 @@
 #include "Material.h"
 #include "Material.h"
 #include "MemoryBuffer.h"
 #include "MemoryBuffer.h"
 #include "Node.h"
 #include "Node.h"
+#include "OctreeQuery.h"
 #include "Profiler.h"
 #include "Profiler.h"
 #include "ResourceCache.h"
 #include "ResourceCache.h"
 #include "Sort.h"
 #include "Sort.h"
@@ -100,6 +101,49 @@ void BillboardSet::RegisterObject(Context* context)
     REF_ACCESSOR_ATTRIBUTE(BillboardSet, VAR_BUFFER, "Network Billboards", GetNetBillboardsAttr, SetNetBillboardsAttr, PODVector<unsigned char>, Variant::emptyBuffer, AM_NET | AM_NOEDIT);
     REF_ACCESSOR_ATTRIBUTE(BillboardSet, VAR_BUFFER, "Network Billboards", GetNetBillboardsAttr, SetNetBillboardsAttr, PODVector<unsigned char>, Variant::emptyBuffer, AM_NET | AM_NOEDIT);
 }
 }
 
 
+void BillboardSet::ProcessRayQuery(const RayOctreeQuery& query, PODVector<RayQueryResult>& results)
+{
+    // If no billboard-level testing, use the Drawable test
+    if (query.level_ < RAY_TRIANGLE)
+    {
+        Drawable::ProcessRayQuery(query, results);
+        return;
+    }
+
+    // Check ray hit distance to AABB before proceeding with billboard-level tests
+    if (query.ray_.HitDistance(GetWorldBoundingBox()) >= query.maxDistance_)
+        return;
+    
+    const Matrix3x4& worldTransform = node_->GetWorldTransform();
+    Matrix3x4 billboardTransform = relative_ ? worldTransform : Matrix3x4::IDENTITY;
+    Vector3 billboardScale = scaled_ ? worldTransform.Scale() : Vector3::ONE;
+    
+    for (unsigned i = 0; i < billboards_.Size(); ++i)
+    {
+        if (!billboards_[i].enabled_)
+            continue;
+        
+        // Approximate the billboards as spheres for raycasting
+        float size = INV_SQRT_TWO * (billboards_[i].size_.x_ * billboardScale.x_ + billboards_[i].size_.y_ * billboardScale.y_);
+        Vector3 center = billboardTransform * billboards_[i].position_;
+        Sphere billboardSphere(center, size);
+        
+        float distance = query.ray_.HitDistance(billboardSphere);
+        if (distance < query.maxDistance_)
+        {
+            // If the code reaches here then we have a hit
+            RayQueryResult result;
+            result.position_ = query.ray_.origin_ + distance * query.ray_.direction_;
+            result.normal_ = -query.ray_.direction_;
+            result.distance_ = distance;
+            result.drawable_ = this;
+            result.node_ = node_;
+            result.subObject_ = i;
+            results.Push(result);
+        }
+    }
+}
+
 void BillboardSet::UpdateBatches(const FrameInfo& frame)
 void BillboardSet::UpdateBatches(const FrameInfo& frame)
 {
 {
     // Check if position relative to camera has changed, and re-sort in that case
     // Check if position relative to camera has changed, and re-sort in that case

+ 2 - 0
Source/Engine/Graphics/BillboardSet.h

@@ -68,6 +68,8 @@ public:
     /// Register object factory.
     /// Register object factory.
     static void RegisterObject(Context* context);
     static void RegisterObject(Context* context);
     
     
+    /// Process octree raycast. May be called from a worker thread.
+    virtual void ProcessRayQuery(const RayOctreeQuery& query, PODVector<RayQueryResult>& results);
     /// Calculate distance and prepare batches for rendering. May be called from worker thread(s), possibly re-entrantly.
     /// Calculate distance and prepare batches for rendering. May be called from worker thread(s), possibly re-entrantly.
     virtual void UpdateBatches(const FrameInfo& frame);
     virtual void UpdateBatches(const FrameInfo& frame);
     /// Prepare geometry for rendering. Called from a worker thread if possible (no GPU update.)
     /// Prepare geometry for rendering. Called from a worker thread if possible (no GPU update.)

+ 0 - 1
Source/Engine/Graphics/CustomGeometry.cpp

@@ -81,7 +81,6 @@ void CustomGeometry::ProcessRayQuery(const RayOctreeQuery& query, PODVector<RayQ
     
     
     switch (level)
     switch (level)
     {
     {
-    case RAY_AABB_NOSUBOBJECTS:
     case RAY_AABB:
     case RAY_AABB:
         Drawable::ProcessRayQuery(query, results);
         Drawable::ProcessRayQuery(query, results);
         break;
         break;

+ 0 - 1
Source/Engine/Graphics/Light.cpp

@@ -167,7 +167,6 @@ void Light::ProcessRayQuery(const RayOctreeQuery& query, PODVector<RayQueryResul
     float distance;
     float distance;
     switch (query.level_)
     switch (query.level_)
     {
     {
-    case RAY_AABB_NOSUBOBJECTS:
     case RAY_AABB:
     case RAY_AABB:
         Drawable::ProcessRayQuery(query, results);
         Drawable::ProcessRayQuery(query, results);
         return;
         return;

+ 1 - 2
Source/Engine/Graphics/OctreeQuery.h

@@ -170,8 +170,7 @@ struct URHO3D_API OctreeQueryResult
 /// Graphics raycast detail level.
 /// Graphics raycast detail level.
 enum RayQueryLevel
 enum RayQueryLevel
 {
 {
-    RAY_AABB_NOSUBOBJECTS = 0,
-    RAY_AABB,
+    RAY_AABB = 0,
     RAY_OBB,
     RAY_OBB,
     RAY_TRIANGLE
     RAY_TRIANGLE
 };
 };

+ 0 - 1
Source/Engine/Graphics/StaticModel.cpp

@@ -77,7 +77,6 @@ void StaticModel::ProcessRayQuery(const RayOctreeQuery& query, PODVector<RayQuer
     
     
     switch (level)
     switch (level)
     {
     {
-    case RAY_AABB_NOSUBOBJECTS:
     case RAY_AABB:
     case RAY_AABB:
         Drawable::ProcessRayQuery(query, results);
         Drawable::ProcessRayQuery(query, results);
         break;
         break;

+ 0 - 1
Source/Engine/Graphics/TerrainPatch.cpp

@@ -77,7 +77,6 @@ void TerrainPatch::ProcessRayQuery(const RayOctreeQuery& query, PODVector<RayQue
     
     
     switch (level)
     switch (level)
     {
     {
-    case RAY_AABB_NOSUBOBJECTS:
     case RAY_AABB:
     case RAY_AABB:
         Drawable::ProcessRayQuery(query, results);
         Drawable::ProcessRayQuery(query, results);
         break;
         break;

+ 1 - 2
Source/Engine/LuaScript/pkgs/Graphics/OctreeQuery.pkg

@@ -10,8 +10,7 @@ struct OctreeQueryResult
 
 
 enum RayQueryLevel
 enum RayQueryLevel
 {
 {
-    RAY_AABB_NOSUBOBJECTS = 0,
-    RAY_AABB,
+    RAY_AABB = 0,
     RAY_OBB,
     RAY_OBB,
     RAY_TRIANGLE
     RAY_TRIANGLE
 };
 };

+ 1 - 2
Source/Engine/Script/GraphicsAPI.cpp

@@ -1453,8 +1453,7 @@ static Octree* GetOctree()
 static void RegisterOctree(asIScriptEngine* engine)
 static void RegisterOctree(asIScriptEngine* engine)
 {
 {
     engine->RegisterEnum("RayQueryLevel");
     engine->RegisterEnum("RayQueryLevel");
-    engine->RegisterEnumValue("RayQueryLevel", "RAY_AABB_NOSUBOBJECTS", RAY_AABB_NOSUBOBJECTS);
-    engine->RegisterEnumValue("RayQueryLevel", "RAY_AABB", RAY_AABB_NOSUBOBJECTS);
+    engine->RegisterEnumValue("RayQueryLevel", "RAY_AABB", RAY_AABB);
     engine->RegisterEnumValue("RayQueryLevel", "RAY_OBB", RAY_OBB);
     engine->RegisterEnumValue("RayQueryLevel", "RAY_OBB", RAY_OBB);
     engine->RegisterEnumValue("RayQueryLevel", "RAY_TRIANGLE", RAY_TRIANGLE);
     engine->RegisterEnumValue("RayQueryLevel", "RAY_TRIANGLE", RAY_TRIANGLE);