Merge remote-tracking branch 'origin/master'

This commit is contained in:
Wojtek Figat
2025-11-20 06:26:09 -08:00
22 changed files with 97 additions and 116 deletions

View File

@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:d2b1dc1523cb2140db7ce5fed6e97b09d7fcebbe6cc19fca7708b5b882267040
size 4175
oid sha256:d3922811f0eb56cbb515c93cd53d80316740ea78219aa81118d2c9dee4a9d230
size 4142

View File

@@ -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>

View File

@@ -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();
}

View File

@@ -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);

View File

@@ -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

View File

@@ -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;

View File

@@ -243,7 +243,8 @@ Asset::LoadResult MaterialInstance::load()
ParamsChanged();
}
baseMaterial->RemoveReference();
if (baseMaterial)
baseMaterial->RemoveReference();
return LoadResult::Ok;
}

View File

@@ -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;
}

View File

@@ -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;
}

View File

@@ -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."));

View File

@@ -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

View File

@@ -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;
}

View File

@@ -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;

View File

@@ -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.

View File

@@ -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();

View File

@@ -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;

View File

@@ -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."));

View File

@@ -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;

View File

@@ -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

View File

@@ -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));

View File

@@ -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)

View File

@@ -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)