Merge remote-tracking branch 'origin/master'
This commit is contained in:
@@ -1,3 +1,3 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:d2b1dc1523cb2140db7ce5fed6e97b09d7fcebbe6cc19fca7708b5b882267040
|
||||
size 4175
|
||||
oid sha256:d3922811f0eb56cbb515c93cd53d80316740ea78219aa81118d2c9dee4a9d230
|
||||
size 4142
|
||||
|
||||
@@ -431,27 +431,6 @@ namespace FlaxEditor.Surface
|
||||
/// </summary>
|
||||
public bool HasIndependentBoxes => Archetype.IndependentBoxes != null;
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether this node has dependent boxes with assigned valid types. Otherwise any box has no dependent type assigned.
|
||||
/// </summary>
|
||||
public bool HasDependentBoxesSetup
|
||||
{
|
||||
get
|
||||
{
|
||||
if (Archetype.DependentBoxes == null || Archetype.IndependentBoxes == null)
|
||||
return true;
|
||||
|
||||
for (int i = 0; i < Archetype.DependentBoxes.Length; i++)
|
||||
{
|
||||
var b = GetBox(Archetype.DependentBoxes[i]);
|
||||
if (b != null && b.CurrentType == b.DefaultType)
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
private static readonly List<SurfaceNode> UpdateStack = new List<SurfaceNode>();
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -469,7 +469,8 @@ namespace FlaxEditor.Surface
|
||||
bool handled = base.OnMouseDown(location, button);
|
||||
if (!handled)
|
||||
CustomMouseDown?.Invoke(ref location, button, ref handled);
|
||||
if (handled)
|
||||
var root = Root;
|
||||
if (handled || root == null)
|
||||
{
|
||||
// Clear flags
|
||||
_isMovingSelection = false;
|
||||
@@ -523,11 +524,11 @@ namespace FlaxEditor.Surface
|
||||
if (_leftMouseDown && controlUnderMouse.CanSelect(ref cLocation))
|
||||
{
|
||||
// Check if user is pressing control
|
||||
if (Root.GetKey(KeyboardKeys.Control))
|
||||
if (root.GetKey(KeyboardKeys.Control))
|
||||
{
|
||||
AddToSelection(controlUnderMouse);
|
||||
}
|
||||
else if (Root.GetKey(KeyboardKeys.Shift))
|
||||
else if (root.GetKey(KeyboardKeys.Shift))
|
||||
{
|
||||
RemoveFromSelection(controlUnderMouse);
|
||||
}
|
||||
@@ -539,7 +540,7 @@ namespace FlaxEditor.Surface
|
||||
}
|
||||
|
||||
// Start moving selected nodes
|
||||
if (!Root.GetKey(KeyboardKeys.Shift))
|
||||
if (!root.GetKey(KeyboardKeys.Shift))
|
||||
{
|
||||
StartMouseCapture();
|
||||
_movingSelectionViewPos = _rootControl.Location;
|
||||
@@ -559,7 +560,7 @@ namespace FlaxEditor.Surface
|
||||
// Start selecting or commenting
|
||||
StartMouseCapture();
|
||||
|
||||
if (!Root.GetKey(KeyboardKeys.Control) && !Root.GetKey(KeyboardKeys.Shift))
|
||||
if (!root.GetKey(KeyboardKeys.Control) && !root.GetKey(KeyboardKeys.Shift))
|
||||
{
|
||||
ClearSelection();
|
||||
}
|
||||
|
||||
@@ -178,19 +178,31 @@ namespace FlaxEditor.Surface
|
||||
|
||||
// Update boxes types for nodes that dependant box types based on incoming connections
|
||||
{
|
||||
bool keepUpdating = false;
|
||||
int updateLimit = 100;
|
||||
bool keepUpdating = true;
|
||||
int updatesMin = 2, updatesMax = 100;
|
||||
do
|
||||
{
|
||||
keepUpdating = false;
|
||||
for (int i = 0; i < RootControl.Children.Count; i++)
|
||||
{
|
||||
if (RootControl.Children[i] is SurfaceNode node && !node.HasDependentBoxesSetup)
|
||||
if (RootControl.Children[i] is SurfaceNode node)
|
||||
{
|
||||
node.UpdateBoxesTypes();
|
||||
keepUpdating = true;
|
||||
var arch = node.Archetype;
|
||||
if (arch.DependentBoxes != null && arch.IndependentBoxes != null)
|
||||
{
|
||||
foreach (var boxId in arch.DependentBoxes)
|
||||
{
|
||||
var b = node.GetBox(boxId);
|
||||
if (b != null && b.CurrentType == b.DefaultType)
|
||||
{
|
||||
keepUpdating = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} while (keepUpdating && updateLimit-- > 0);
|
||||
} while ((keepUpdating && --updatesMax > 0) || --updatesMin > 0);
|
||||
}
|
||||
|
||||
Loaded?.Invoke(this);
|
||||
|
||||
@@ -14,7 +14,6 @@ using FlaxEditor.Surface;
|
||||
using FlaxEditor.Viewport.Previews;
|
||||
using FlaxEngine;
|
||||
using FlaxEngine.GUI;
|
||||
using FlaxEngine.Utilities;
|
||||
|
||||
namespace FlaxEditor.Windows.Assets
|
||||
{
|
||||
@@ -430,7 +429,7 @@ namespace FlaxEditor.Windows.Assets
|
||||
for (var i = 0; i < parameters.Length; i++)
|
||||
{
|
||||
var p = parameters[i];
|
||||
if (p.IsOverride)
|
||||
if (p.IsOverride && p.IsPublic)
|
||||
{
|
||||
p.IsOverride = false;
|
||||
actions.Add(new EditParamOverrideAction
|
||||
|
||||
@@ -246,11 +246,19 @@ void AnimGraphExecutor::ProcessAnimEvents(AnimGraphNode* node, bool loop, float
|
||||
const float duration = k.Value.Duration > 1 ? k.Value.Duration : 0.0f;
|
||||
#define ADD_OUTGOING_EVENT(type) context.Data->OutgoingEvents.Add({ k.Value.Instance, (AnimatedModel*)context.Data->Object, anim, eventTime, eventDeltaTime, AnimGraphInstanceData::OutgoingEvent::type })
|
||||
if ((k.Time <= eventTimeMax && eventTimeMin <= k.Time + duration
|
||||
&& (Math::FloorToInt(animPos) != 0 && Math::CeilToInt(animPrevPos) != Math::CeilToInt(anim->GetDuration()) && Math::FloorToInt(animPrevPos) != 0 && Math::CeilToInt(animPos) != Math::CeilToInt(anim->GetDuration())))
|
||||
&& (Math::FloorToInt(animPos) != 0 && Math::CeilToInt(animPrevPos) != Math::CeilToInt(anim->GetDuration())
|
||||
&& Math::FloorToInt(animPrevPos) != 0 && Math::CeilToInt(animPos) != Math::CeilToInt(anim->GetDuration())))
|
||||
// Handle the edge case of an event on 0 or on max animation duration during looping
|
||||
|| (loop && duration == 0.0f && Math::CeilToInt(animPos) == Math::CeilToInt(anim->GetDuration()) && k.Time == anim->GetDuration())
|
||||
|| (!loop && duration == 0.0f && Math::CeilToInt(animPos) == Math::CeilToInt(anim->GetDuration()) && Math::CeilToInt(animPrevPos) == Math::CeilToInt(anim->GetDuration()) - 1 && Math::NearEqual(k.Time, anim->GetDuration()))
|
||||
|| (loop && Math::FloorToInt(animPos) == 0 && Math::CeilToInt(animPrevPos) == Math::CeilToInt(anim->GetDuration()) && k.Time == 0.0f)
|
||||
|| (loop && Math::FloorToInt(animPrevPos) == 0 && Math::CeilToInt(animPos) == Math::CeilToInt(anim->GetDuration()) && k.Time == 0.0f)
|
||||
|| (loop && Math::FloorToInt(animPos) == 0 && Math::CeilToInt(animPrevPos) == Math::CeilToInt(anim->GetDuration()) && Math::NearEqual(k.Time, anim->GetDuration()))
|
||||
|| (loop && Math::FloorToInt(animPrevPos) == 0 && Math::CeilToInt(animPos) == Math::CeilToInt(anim->GetDuration()) && Math::NearEqual(k.Time, anim->GetDuration()))
|
||||
|| (Math::FloorToInt(animPos) == 1 && Math::FloorToInt(animPrevPos) == 0 && k.Time == 1.0f)
|
||||
|| (Math::FloorToInt(animPos) == 0 && Math::FloorToInt(animPrevPos) == 1 && k.Time == 1.0f)
|
||||
|| (Math::CeilToInt(animPos) == Math::CeilToInt(anim->GetDuration()) && Math::CeilToInt(animPrevPos) == Math::CeilToInt(anim->GetDuration()) - 1 && Math::NearEqual(k.Time, anim->GetDuration() - 1.0f))
|
||||
|| (Math::CeilToInt(animPos) == Math::CeilToInt(anim->GetDuration()) - 1 && Math::CeilToInt(animPrevPos) == Math::CeilToInt(anim->GetDuration()) && Math::NearEqual(k.Time, anim->GetDuration() - 1.0f))
|
||||
|| (Math::FloorToInt(animPos) == 0 && Math::FloorToInt(animPrevPos) == 0 && k.Time == 0.0f)
|
||||
)
|
||||
{
|
||||
int32 stateIndex = -1;
|
||||
|
||||
@@ -243,7 +243,8 @@ Asset::LoadResult MaterialInstance::load()
|
||||
ParamsChanged();
|
||||
}
|
||||
|
||||
baseMaterial->RemoveReference();
|
||||
if (baseMaterial)
|
||||
baseMaterial->RemoveReference();
|
||||
return LoadResult::Ok;
|
||||
}
|
||||
|
||||
|
||||
@@ -18,7 +18,7 @@ public:
|
||||
/// <param name="id">The asset id.</param>
|
||||
/// <returns>Loaded asset of null.</returns>
|
||||
template<typename T>
|
||||
T* LoadAsync(const Guid& id)
|
||||
T* Load(const Guid& id)
|
||||
{
|
||||
for (auto& e : *this)
|
||||
{
|
||||
@@ -26,8 +26,10 @@ public:
|
||||
return (T*)e.Get();
|
||||
}
|
||||
auto asset = (T*)::LoadAsset(id, T::TypeInitializer);
|
||||
if (asset)
|
||||
if (asset && !asset->WaitForLoaded())
|
||||
Add(asset);
|
||||
else
|
||||
asset = nullptr;
|
||||
return asset;
|
||||
}
|
||||
|
||||
|
||||
@@ -518,7 +518,7 @@ namespace
|
||||
Vector3 nextPos = transform.LocalToWorld(next->Value.Translation);
|
||||
DEBUG_DRAW_WIRE_SPHERE(BoundingSphere(nextPos, NodeSizeByDistance(nextPos, scaleByDistance)), color, 0.0f, depthTest);
|
||||
const float d = (next->Time - prev->Time) / 3.0f;
|
||||
DEBUG_DRAW_BEZIER(prevPos, prevPos + prev->TangentOut.Translation * d, nextPos + next->TangentIn.Translation * d, nextPos, color, 0.0f, depthTest);
|
||||
DEBUG_DRAW_BEZIER(prevPos, transform.LocalToWorld(prev->Value.Translation + prev->TangentOut.Translation * d), transform.LocalToWorld(next->Value.Translation + next->TangentIn.Translation * d), nextPos, color, 0.0f, depthTest);
|
||||
prev = next;
|
||||
prevPos = nextPos;
|
||||
}
|
||||
|
||||
@@ -425,8 +425,8 @@ void ParticleEmitterGPUGenerator::ProcessGroupParticles(Box* box, Node* node, Va
|
||||
case 300:
|
||||
{
|
||||
// Load function asset
|
||||
const auto function = Assets.LoadAsync<ParticleEmitterFunction>((Guid)node->Values[0]);
|
||||
if (!function || function->WaitForLoaded())
|
||||
const auto function = Assets.Load<ParticleEmitterFunction>((Guid)node->Values[0]);
|
||||
if (!function)
|
||||
{
|
||||
OnError(node, box, TEXT("Missing or invalid function."));
|
||||
value = Value::Zero;
|
||||
@@ -439,7 +439,7 @@ void ParticleEmitterGPUGenerator::ProcessGroupParticles(Box* box, Node* node, Va
|
||||
{
|
||||
if (_callStack[i]->Type == GRAPH_NODE_MAKE_TYPE(14, 300))
|
||||
{
|
||||
const auto callFunc = Assets.LoadAsync<ParticleEmitterFunction>((Guid)_callStack[i]->Values[0]);
|
||||
const auto callFunc = Assets.Load<ParticleEmitterFunction>((Guid)_callStack[i]->Values[0]);
|
||||
if (callFunc == function)
|
||||
{
|
||||
OnError(node, box, String::Format(TEXT("Recursive call to function '{0}'!"), function->ToString()));
|
||||
@@ -514,7 +514,7 @@ void ParticleEmitterGPUGenerator::ProcessGroupFunction(Box* box, Node* node, Val
|
||||
value = Value::Zero;
|
||||
break;
|
||||
}
|
||||
const auto function = Assets.LoadAsync<ParticleEmitterFunction>((Guid)functionCallNode->Values[0]);
|
||||
const auto function = Assets.Load<ParticleEmitterFunction>((Guid)functionCallNode->Values[0]);
|
||||
if (!_functions.TryGet(functionCallNode, graph) || !function)
|
||||
{
|
||||
OnError(node, box, TEXT("Missing calling function graph."));
|
||||
|
||||
@@ -52,9 +52,12 @@ private:
|
||||
void OnShaderReloading(Asset* obj)
|
||||
{
|
||||
_psDofDepthBlurGeneration->ReleaseGPU();
|
||||
_psBokehGeneration->ReleaseGPU();
|
||||
_psBokeh->ReleaseGPU();
|
||||
_psBokehComposite->ReleaseGPU();
|
||||
if (_psBokehGeneration)
|
||||
_psBokehGeneration->ReleaseGPU();
|
||||
if (_psBokeh)
|
||||
_psBokeh->ReleaseGPU();
|
||||
if (_psBokehComposite)
|
||||
_psBokehComposite->ReleaseGPU();
|
||||
invalidateResources();
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -551,9 +551,6 @@ bool GlobalSurfaceAtlasPass::Init()
|
||||
// Check platform support
|
||||
const auto device = GPUDevice::Instance;
|
||||
_supported = device->GetFeatureLevel() >= FeatureLevel::SM5 && device->Limits.HasCompute && device->Limits.HasTypedUAVLoad;
|
||||
#if PLATFORM_APPLE_FAMILY
|
||||
_supported = false; // Vulkan over Metal has some issues in complex scenes with DDGI
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@@ -21,6 +21,7 @@
|
||||
MDomain* MRootDomain = nullptr;
|
||||
MDomain* MActiveDomain = nullptr;
|
||||
Array<MDomain*, FixedAllocation<4>> MDomains;
|
||||
bool MCore::Ready = false;
|
||||
|
||||
MClass* MCore::TypeCache::Void = nullptr;
|
||||
MClass* MCore::TypeCache::Object = nullptr;
|
||||
@@ -301,6 +302,11 @@ bool MProperty::IsStatic() const
|
||||
return false;
|
||||
}
|
||||
|
||||
void MCore::OnManagedEventAfterShutdown(const char* eventName)
|
||||
{
|
||||
LOG(Error, "Found a binding leak on '{}' event used by C# scripting after shutdown. Ensure to unregister scripting events from objects during disposing.", ::String(eventName));
|
||||
}
|
||||
|
||||
MDomain* MCore::GetRootDomain()
|
||||
{
|
||||
return MRootDomain;
|
||||
|
||||
@@ -57,6 +57,10 @@ public:
|
||||
static void UnloadScriptingAssemblyLoadContext();
|
||||
#endif
|
||||
|
||||
// Utility for guarding against using C# scripting runtime after shutdown (eg. when asset delegate is not properly disposed).
|
||||
static bool Ready;
|
||||
static void OnManagedEventAfterShutdown(const char* eventName);
|
||||
|
||||
public:
|
||||
/// <summary>
|
||||
/// Utilities for C# object management.
|
||||
|
||||
@@ -316,7 +316,8 @@ bool MCore::LoadEngine()
|
||||
|
||||
char* buildInfo = CallStaticMethod<char*>(GetStaticMethodPointer(TEXT("GetRuntimeInformation")));
|
||||
LOG(Info, ".NET runtime version: {0}", ::String(buildInfo));
|
||||
MCore::GC::FreeMemory(buildInfo);
|
||||
GC::FreeMemory(buildInfo);
|
||||
Ready = true;
|
||||
|
||||
return false;
|
||||
}
|
||||
@@ -327,6 +328,7 @@ void MCore::UnloadEngine()
|
||||
return;
|
||||
PROFILE_CPU();
|
||||
CallStaticMethod<void>(GetStaticMethodPointer(TEXT("Exit")));
|
||||
Ready = false;
|
||||
MDomains.ClearDelete();
|
||||
MRootDomain = nullptr;
|
||||
ShutdownHostfxr();
|
||||
|
||||
@@ -50,8 +50,8 @@ MaterialLayer* MaterialGenerator::GetLayer(const Guid& id, Node* caller)
|
||||
}
|
||||
|
||||
// Load asset
|
||||
Asset* asset = Assets.LoadAsync<MaterialBase>(id);
|
||||
if (asset == nullptr || asset->WaitForLoaded(10 * 1000))
|
||||
Asset* asset = Assets.Load<MaterialBase>(id);
|
||||
if (asset == nullptr)
|
||||
{
|
||||
OnError(caller, nullptr, TEXT("Failed to load material asset."));
|
||||
return nullptr;
|
||||
|
||||
@@ -285,8 +285,8 @@ void MaterialGenerator::ProcessGroupMaterial(Box* box, Node* node, Value& value)
|
||||
case 24:
|
||||
{
|
||||
// Load function asset
|
||||
const auto function = Assets.LoadAsync<MaterialFunction>((Guid)node->Values[0]);
|
||||
if (!function || function->WaitForLoaded())
|
||||
const auto function = Assets.Load<MaterialFunction>((Guid)node->Values[0]);
|
||||
if (!function)
|
||||
{
|
||||
OnError(node, box, TEXT("Missing or invalid function."));
|
||||
value = Value::Zero;
|
||||
@@ -299,7 +299,7 @@ void MaterialGenerator::ProcessGroupMaterial(Box* box, Node* node, Value& value)
|
||||
{
|
||||
if (_callStack[i]->Type == GRAPH_NODE_MAKE_TYPE(1, 24))
|
||||
{
|
||||
const auto callFunc = Assets.LoadAsync<MaterialFunction>((Guid)_callStack[i]->Values[0]);
|
||||
const auto callFunc = Assets.Load<MaterialFunction>((Guid)_callStack[i]->Values[0]);
|
||||
if (callFunc == function)
|
||||
{
|
||||
OnError(node, box, String::Format(TEXT("Recursive call to function '{0}'!"), function->ToString()));
|
||||
@@ -808,7 +808,7 @@ void MaterialGenerator::ProcessGroupFunction(Box* box, Node* node, Value& value)
|
||||
value = Value::Zero;
|
||||
break;
|
||||
}
|
||||
const auto function = Assets.LoadAsync<MaterialFunction>((Guid)functionCallNode->Values[0]);
|
||||
const auto function = Assets.Load<MaterialFunction>((Guid)functionCallNode->Values[0]);
|
||||
if (!_functions.TryGet(functionCallNode, graph) || !function)
|
||||
{
|
||||
OnError(node, box, TEXT("Missing calling function graph."));
|
||||
|
||||
@@ -704,8 +704,8 @@ void ShaderGenerator::ProcessGroupTools(Box* box, Node* node, Value& value)
|
||||
case 16:
|
||||
{
|
||||
// Get the variable type
|
||||
auto asset = Assets.LoadAsync<GameplayGlobals>((Guid)node->Values[0]);
|
||||
if (!asset || asset->WaitForLoaded())
|
||||
auto asset = Assets.Load<GameplayGlobals>((Guid)node->Values[0]);
|
||||
if (!asset)
|
||||
{
|
||||
OnError(node, box, TEXT("Failed to load Gameplay Global asset."));
|
||||
value = Value::Zero;
|
||||
|
||||
@@ -96,34 +96,9 @@
|
||||
// Compiler support for HLSL 2021 that is stricter (need to use or/and/select for vector-based logical operators)
|
||||
#if !defined(__DXC_VERSION_MAJOR) || (__DXC_VERSION_MAJOR <= 1 && __DXC_VERSION_MINOR < 7)
|
||||
|
||||
bool InternalAnd(bool a, bool b) { return bool(a && b); }
|
||||
bool2 InternalAnd(bool2 a, bool2 b) { return bool2(a.x && b.x, a.y && b.y); }
|
||||
bool3 InternalAnd(bool3 a, bool3 b) { return bool3(a.x && b.x, a.y && b.y, a.z && b.z); }
|
||||
bool4 InternalAnd(bool4 a, bool4 b) { return bool4(a.x && b.x, a.y && b.y, a.z && b.z, a.w && b.w); }
|
||||
|
||||
bool InternalOr(bool a, bool b) { return bool(a || b); }
|
||||
bool2 InternalOr(bool2 a, bool2 b) { return bool2(a.x || b.x, a.y || b.y); }
|
||||
bool3 InternalOr(bool3 a, bool3 b) { return bool3(a.x || b.x, a.y || b.y, a.z || b.z); }
|
||||
bool4 InternalOr(bool4 a, bool4 b) { return bool4(a.x || b.x, a.y || b.y, a.z || b.z, a.w || b.w); }
|
||||
|
||||
#define SELECT_INTERNAL(type) \
|
||||
type InternalSelect(bool c, type a, type b) { return type (c ? a.x : b.x); } \
|
||||
type##2 InternalSelect(bool c, type##2 a, type##2 b) { return type##2(c ? a.x : b.x, c ? a.y : b.y); } \
|
||||
type##2 InternalSelect(bool2 c, type a, type b) { return type##2(c.x ? a : b, c.y ? a : b); } \
|
||||
type##2 InternalSelect(bool2 c, type##2 a, type##2 b) { return type##2(c.x ? a.x : b.x, c.y ? a.y : b.y); } \
|
||||
type##3 InternalSelect(bool c, type##3 a, type##3 b) { return type##3(c ? a.x : b.x, c ? a.y : b.y, c ? a.z : b.z); } \
|
||||
type##3 InternalSelect(bool3 c, type a, type b) { return type##3(c.x ? a : b, c.y ? a : b, c.z ? a : b); } \
|
||||
type##3 InternalSelect(bool3 c, type##3 a, type##3 b) { return type##3(c.x ? a.x : b.x, c.y ? a.y : b.y, c.z ? a.z : b.z); } \
|
||||
type##4 InternalSelect(bool c, type##4 a, type##4 b) { return type##4(c ? a.x : b.x, c ? a.y : b.y, c ? a.z : b.z, c ? a.w : b.w); } \
|
||||
type##4 InternalSelect(bool4 c, type a, type b) { return type##4(c.x ? a : b, c.y ? a : b, c.z ? a : b, c.w ? a : b); } \
|
||||
type##4 InternalSelect(bool4 c, type##4 a, type##4 b) { return type##4(c.x ? a.x : b.x, c.y ? a.y : b.y, c.z ? a.z : b.z, c.w ? a.w : b.w); }
|
||||
SELECT_INTERNAL(uint)
|
||||
SELECT_INTERNAL(float)
|
||||
#undef SELECT_INTERNAL
|
||||
|
||||
#define and(a, b) InternalAnd(a, b)
|
||||
#define or(a, b) InternalOr(a, b)
|
||||
#define select(c, a, b) InternalSelect(c, a, b)
|
||||
#define and(a, b) (a) && (b)
|
||||
#define or(a, b) (a) || (b)
|
||||
#define select(c, a, b) (c) ? (a) : (b)
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
@@ -16,13 +16,10 @@ struct BVHNode
|
||||
int Count; // Negative for non-leaf nodes
|
||||
};
|
||||
|
||||
struct BVHBuffers
|
||||
{
|
||||
StructuredBuffer<BVHNode> BVHBuffer;
|
||||
ByteAddressBuffer VertexBuffer;
|
||||
ByteAddressBuffer IndexBuffer;
|
||||
uint VertexStride;
|
||||
};
|
||||
// Pass all data via separate params (SPIR-V doesn't support buffers in structures)
|
||||
#define BVHBuffers_Param StructuredBuffer<BVHNode> BVHBuffer, ByteAddressBuffer VertexBuffer, ByteAddressBuffer IndexBuffer, uint VertexStride
|
||||
#define BVHBuffers_Init(BVHBuffer, VertexBuffer, IndexBuffer, VertexStride) BVHBuffer, VertexBuffer, IndexBuffer, VertexStride
|
||||
#define BVHBuffers_Pass BVHBuffers_Init(BVHBuffer, VertexBuffer, IndexBuffer, VertexStride)
|
||||
|
||||
struct BVHHit
|
||||
{
|
||||
@@ -30,11 +27,11 @@ struct BVHHit
|
||||
bool IsBackface;
|
||||
};
|
||||
|
||||
float3 LoadVertexBVH(BVHBuffers bvh, uint index)
|
||||
float3 LoadVertexBVH(BVHBuffers_Param, uint index)
|
||||
{
|
||||
int addr = index << 2u;
|
||||
uint vertexIndex = bvh.IndexBuffer.Load(addr);
|
||||
return asfloat(bvh.VertexBuffer.Load3(vertexIndex * bvh.VertexStride));
|
||||
uint vertexIndex = IndexBuffer.Load(addr);
|
||||
return asfloat(VertexBuffer.Load3(vertexIndex * VertexStride));
|
||||
}
|
||||
|
||||
// [https://tavianator.com/2011/ray_box.html]
|
||||
@@ -52,7 +49,7 @@ float RayTestBoxBVH(float3 rayPos, float3 rayDir, float3 boxMin, float3 boxMax)
|
||||
}
|
||||
|
||||
// Performs raytracing against the BVH acceleration structure to find the closest intersection with a triangle.
|
||||
bool RayCastBVH(BVHBuffers bvh, float3 rayPos, float3 rayDir, out BVHHit hit, float maxDistance = 1000000.0f)
|
||||
bool RayCastBVH(BVHBuffers_Param, float3 rayPos, float3 rayDir, out BVHHit hit, float maxDistance = 1000000.0f)
|
||||
{
|
||||
hit = (BVHHit)0;
|
||||
hit.Distance = maxDistance;
|
||||
@@ -66,7 +63,7 @@ bool RayCastBVH(BVHBuffers bvh, float3 rayPos, float3 rayDir, out BVHHit hit, fl
|
||||
LOOP
|
||||
while (stackCount > 0)
|
||||
{
|
||||
BVHNode node = bvh.BVHBuffer[stack[--stackCount]];
|
||||
BVHNode node = BVHBuffer[stack[--stackCount]];
|
||||
|
||||
// Raytrace bounds
|
||||
float boundsHit = RayTestBoxBVH(rayPos, rayDir, node.BoundsMin, node.BoundsMax);
|
||||
@@ -82,9 +79,9 @@ bool RayCastBVH(BVHBuffers bvh, float3 rayPos, float3 rayDir, out BVHHit hit, fl
|
||||
for (uint i = indexStart; i < indexEnd;)
|
||||
{
|
||||
// Load triangle
|
||||
float3 v0 = LoadVertexBVH(bvh, i++);
|
||||
float3 v1 = LoadVertexBVH(bvh, i++);
|
||||
float3 v2 = LoadVertexBVH(bvh, i++);
|
||||
float3 v0 = LoadVertexBVH(BVHBuffers_Pass, i++);
|
||||
float3 v1 = LoadVertexBVH(BVHBuffers_Pass, i++);
|
||||
float3 v2 = LoadVertexBVH(BVHBuffers_Pass, i++);
|
||||
|
||||
// Raytrace triangle
|
||||
float distance;
|
||||
@@ -109,7 +106,7 @@ bool RayCastBVH(BVHBuffers bvh, float3 rayPos, float3 rayDir, out BVHHit hit, fl
|
||||
}
|
||||
|
||||
// Performs a query against the BVH acceleration structure to find the closest distance to a triangle from a given point.
|
||||
bool PointQueryBVH(BVHBuffers bvh, float3 pos, out BVHHit hit, float maxDistance = 1000000.0f)
|
||||
bool PointQueryBVH(BVHBuffers_Param, float3 pos, out BVHHit hit, float maxDistance = 1000000.0f)
|
||||
{
|
||||
hit = (BVHHit)0;
|
||||
hit.Distance = maxDistance;
|
||||
@@ -123,7 +120,7 @@ bool PointQueryBVH(BVHBuffers bvh, float3 pos, out BVHHit hit, float maxDistance
|
||||
LOOP
|
||||
while (stackCount > 0)
|
||||
{
|
||||
BVHNode node = bvh.BVHBuffer[stack[--stackCount]];
|
||||
BVHNode node = BVHBuffer[stack[--stackCount]];
|
||||
|
||||
// Skip too far nodes
|
||||
if (PointDistanceBox(node.BoundsMin, node.BoundsMax, pos) >= hit.Distance)
|
||||
@@ -138,9 +135,9 @@ bool PointQueryBVH(BVHBuffers bvh, float3 pos, out BVHHit hit, float maxDistance
|
||||
for (uint i = indexStart; i < indexEnd;)
|
||||
{
|
||||
// Load triangle
|
||||
float3 v0 = LoadVertexBVH(bvh, i++);
|
||||
float3 v1 = LoadVertexBVH(bvh, i++);
|
||||
float3 v2 = LoadVertexBVH(bvh, i++);
|
||||
float3 v0 = LoadVertexBVH(BVHBuffers_Pass, i++);
|
||||
float3 v1 = LoadVertexBVH(BVHBuffers_Pass, i++);
|
||||
float3 v2 = LoadVertexBVH(BVHBuffers_Pass, i++);
|
||||
|
||||
// Check triangle
|
||||
float distance = sqrt(DistancePointToTriangle2(pos, v0, v1, v2));
|
||||
|
||||
@@ -77,15 +77,9 @@ void CS_RasterizeTriangles(uint3 GroupId : SV_GroupID, uint3 GroupThreadID : SV_
|
||||
int3 voxelCoord = GetVoxelCoord(voxelIndex);
|
||||
float3 voxelPos = GetVoxelPos(voxelCoord);
|
||||
|
||||
BVHBuffers bvh;
|
||||
bvh.BVHBuffer = BVHBuffer;
|
||||
bvh.VertexBuffer = VertexBuffer;
|
||||
bvh.IndexBuffer = IndexBuffer;
|
||||
bvh.VertexStride = VertexStride;
|
||||
|
||||
// Point query to find the distance to the closest surface
|
||||
BVHHit hit;
|
||||
PointQueryBVH(bvh, voxelPos, hit, MaxDistance);
|
||||
PointQueryBVH(BVHBuffers_Init(BVHBuffer, VertexBuffer, IndexBuffer, VertexStride), voxelPos, hit, MaxDistance);
|
||||
float sdf = hit.Distance;
|
||||
|
||||
// Raycast triangles around voxel to count triangle backfaces hit
|
||||
@@ -104,7 +98,7 @@ void CS_RasterizeTriangles(uint3 GroupId : SV_GroupID, uint3 GroupThreadID : SV_
|
||||
for (uint i = 0; i < CLOSEST_CACHE_SIZE; i++)
|
||||
{
|
||||
float3 rayDir = closestDirections[i];
|
||||
if (RayCastBVH(bvh, voxelPos, rayDir, hit, MaxDistance))
|
||||
if (RayCastBVH(BVHBuffers_Init(BVHBuffer, VertexBuffer, IndexBuffer, VertexStride), voxelPos, rayDir, hit, MaxDistance))
|
||||
{
|
||||
sdf = min(sdf, hit.Distance);
|
||||
if (hit.IsBackface)
|
||||
|
||||
@@ -2043,6 +2043,7 @@ namespace Flax.Build.Bindings
|
||||
contents.Append(')').AppendLine();
|
||||
contents.Append(" {").AppendLine();
|
||||
contents.Append(" static MMethod* method = nullptr;").AppendLine();
|
||||
contents.AppendFormat(" if (!MCore::Ready) {{ MCore::OnManagedEventAfterShutdown(\"{0}.{1}\"); return; }}", classTypeNameManaged, eventInfo.Name).AppendLine();
|
||||
contents.AppendFormat(" if (!method) {{ method = {1}::TypeInitializer.GetClass()->GetMethod(\"Internal_{0}_Invoke\", {2}); CHECK(method); }}", eventInfo.Name, classTypeNameNative, paramsCount).AppendLine();
|
||||
contents.Append(" MObject* exception = nullptr;").AppendLine();
|
||||
if (paramsCount == 0)
|
||||
|
||||
Reference in New Issue
Block a user