Merge remote-tracking branch 'upstream/master' into Statusbar-Imrpovements

This commit is contained in:
davevanegdom
2023-09-22 13:19:57 +02:00
41 changed files with 323 additions and 127 deletions

View File

@@ -559,6 +559,19 @@ namespace FlaxEngine.Interop
return managedArray.Pointer;
}
[UnmanagedCallersOnly]
internal static IntPtr GetArray(ManagedHandle handle)
{
if (!handle.IsAllocated)
return IntPtr.Zero;
object value = handle.Target;
if (value is ManagedArray)
return (IntPtr)handle;
if (value is Array)
return Invoker.MarshalReturnValueGeneric(value.GetType(), value);
return IntPtr.Zero;
}
[UnmanagedCallersOnly]
internal static int GetArrayLength(ManagedHandle arrayHandle)
{

View File

@@ -24,7 +24,8 @@ namespace FlaxEngine.Interop
/// <summary>
/// Provides a Mono-like API for native code to access managed runtime.
/// </summary>
internal static unsafe partial class NativeInterop
[HideInEditor]
public static unsafe partial class NativeInterop
{
internal static Dictionary<string, string> AssemblyLocations = new();
@@ -147,7 +148,27 @@ namespace FlaxEngine.Interop
NativeMemory.AlignedFree(ptr);
}
internal static T[] GCHandleArrayToManagedArray<T>(ManagedArray ptrArray) where T : class
/// <summary>
/// Converts a delegate into a function pointer that is callable from unmanaged code via <see cref="Marshal.GetFunctionPointerForDelegate{TDelegate}"/> but cached <paramref name="d"/> delegate to prevent collecting it by GC.
/// </summary>
/// <typeparam name="TDelegate">The type of delegate to convert.</typeparam>
/// <param name="d">The delegate to be passed to unmanaged code.</param>
/// <returns>A value that can be passed to unmanaged code, which, in turn, can use it to call the underlying managed delegate.</returns>
public static IntPtr GetFunctionPointerForDelegate<TDelegate>(TDelegate d) where TDelegate : notnull
{
// Example use-case: C# script runs actions via JobSystem.Dispatch which causes crash due to GC collecting Delegate object
ManagedHandle.Alloc(d, GCHandleType.Weak);
return Marshal.GetFunctionPointerForDelegate<TDelegate>(d);
}
/// <summary>
/// Converts array of GC Handles from native runtime to managed array.
/// </summary>
/// <typeparam name="T">Array element type.</typeparam>
/// <param name="ptrArray">Input array.</param>
/// <returns>Output array.</returns>
public static T[] GCHandleArrayToManagedArray<T>(ManagedArray ptrArray) where T : class
{
Span<IntPtr> span = ptrArray.ToSpan<IntPtr>();
T[] managedArray = new T[ptrArray.Length];
@@ -156,7 +177,12 @@ namespace FlaxEngine.Interop
return managedArray;
}
internal static IntPtr[] ManagedArrayToGCHandleArray(Array array)
/// <summary>
/// Converts managed array wrapper into array of GC Handles for native runtime.
/// </summary>
/// <param name="array">Input array.</param>
/// <returns>Output array.</returns>
public static IntPtr[] ManagedArrayToGCHandleArray(Array array)
{
if (array.Length == 0)
return Array.Empty<IntPtr>();
@@ -170,13 +196,26 @@ namespace FlaxEngine.Interop
return pointerArray;
}
internal static ManagedArray ManagedArrayToGCHandleWrappedArray(Array array)
/// <summary>
/// Converts managed array wrapper into array of GC Handles for native runtime.
/// </summary>
/// <param name="array">Input array.</param>
/// <returns>Output array.</returns>
public static ManagedArray ManagedArrayToGCHandleWrappedArray(Array array)
{
IntPtr[] pointerArray = ManagedArrayToGCHandleArray(array);
return ManagedArray.WrapNewArray(pointerArray, array.GetType());
}
internal static TDst[] ConvertArray<TSrc, TDst>(Span<TSrc> src, Func<TSrc, TDst> convertFunc)
/// <summary>
/// Converts array with a custom converter function for each element.
/// </summary>
/// <typeparam name="TSrc">Input data type.</typeparam>
/// <typeparam name="TDst">Output data type.</typeparam>
/// <param name="src">The input array.</param>
/// <param name="convertFunc">Converter callback.</param>
/// <returns>The output array.</returns>
public static TDst[] ConvertArray<TSrc, TDst>(Span<TSrc> src, Func<TSrc, TDst> convertFunc)
{
TDst[] dst = new TDst[src.Length];
for (int i = 0; i < src.Length; i++)
@@ -184,7 +223,15 @@ namespace FlaxEngine.Interop
return dst;
}
internal static TDst[] ConvertArray<TSrc, TDst>(TSrc[] src, Func<TSrc, TDst> convertFunc)
/// <summary>
/// Converts array with a custom converter function for each element.
/// </summary>
/// <typeparam name="TSrc">Input data type.</typeparam>
/// <typeparam name="TDst">Output data type.</typeparam>
/// <param name="src">The input array.</param>
/// <param name="convertFunc">Converter callback.</param>
/// <returns>The output array.</returns>
public static TDst[] ConvertArray<TSrc, TDst>(TSrc[] src, Func<TSrc, TDst> convertFunc)
{
TDst[] dst = new TDst[src.Length];
for (int i = 0; i < src.Length; i++)
@@ -1024,11 +1071,12 @@ namespace FlaxEngine.Interop
private static uint pinnedBoxedValuesPointer = 0;
private static (IntPtr ptr, int size)[] pinnedAllocations = new (IntPtr ptr, int size)[256];
private static uint pinnedAllocationsPointer = 0;
private delegate TInternal ToNativeDelegate<T, TInternal>(T value);
private delegate IntPtr UnboxerDelegate(object value, object converter);
private static ConcurrentDictionary<Type, (UnboxerDelegate deleg, object toNativeDeleg)> unboxers = new (1, 3);
private static ConcurrentDictionary<Type, (UnboxerDelegate deleg, object toNativeDeleg)> unboxers = new(1, 3);
private static MethodInfo unboxerMethod = typeof(ValueTypeUnboxer).GetMethod(nameof(ValueTypeUnboxer.UnboxPointer), BindingFlags.Static | BindingFlags.NonPublic);
private static MethodInfo unboxerToNativeMethod = typeof(ValueTypeUnboxer).GetMethod(nameof(ValueTypeUnboxer.UnboxPointerWithConverter), BindingFlags.Static | BindingFlags.NonPublic);
@@ -1089,7 +1137,8 @@ namespace FlaxEngine.Interop
return new IntPtr(Unsafe.AsPointer(ref Unsafe.Unbox<T>(value)));
}
private static IntPtr UnboxPointerWithConverter<T, TInternal>(object value, object converter) where T : struct where TInternal : struct
private static IntPtr UnboxPointerWithConverter<T, TInternal>(object value, object converter) where T : struct
where TInternal : struct
{
ToNativeDelegate<T, TInternal> toNative = Unsafe.As<ToNativeDelegate<T, TInternal>>(converter);
return PinValue<TInternal>(toNative(Unsafe.Unbox<T>(value)));
@@ -1099,12 +1148,12 @@ namespace FlaxEngine.Interop
private delegate IntPtr InvokeThunkDelegate(ManagedHandle instanceHandle, IntPtr param1, IntPtr param2, IntPtr param3, IntPtr param4, IntPtr param5, IntPtr param6, IntPtr param7);
/// <summary>
/// Returns all types that that owned by this assembly.
/// Returns all types owned by this assembly.
/// </summary>
private static Type[] GetAssemblyTypes(Assembly assembly)
{
var referencedAssemblies = assembly.GetReferencedAssemblies();
var allAssemblies = AppDomain.CurrentDomain.GetAssemblies();
var allAssemblies = Utils.GetAssemblies();
var referencedTypes = new List<string>();
foreach (var assemblyName in referencedAssemblies)
{

View File

@@ -76,11 +76,11 @@ void ForwardShadingFeature::Bind(MaterialShader::BindParameters& params, Span<by
// Set reflection probe data
EnvironmentProbe* probe = nullptr;
// TODO: optimize env probe searching for a transparent material - use spatial cache for renderer to find it
const Vector3 drawCallOrigin = drawCall.ObjectPosition + view.Origin;
const BoundingSphere objectBoundsWorld(drawCall.ObjectPosition + view.Origin, drawCall.ObjectRadius);
for (int32 i = 0; i < cache->EnvironmentProbes.Count(); i++)
{
const auto p = cache->EnvironmentProbes[i];
if (p->GetSphere().Contains(drawCallOrigin) != ContainmentType::Disjoint)
if (CollisionsHelper::SphereIntersectsSphere(objectBoundsWorld, p->GetSphere()))
{
probe = p;
break;
@@ -99,10 +99,12 @@ void ForwardShadingFeature::Bind(MaterialShader::BindParameters& params, Span<by
// Set local lights
data.LocalLightsCount = 0;
const BoundingSphere objectBounds(drawCall.ObjectPosition, drawCall.ObjectRadius);
// TODO: optimize lights searching for a transparent material - use spatial cache for renderer to find it
for (int32 i = 0; i < cache->PointLights.Count() && data.LocalLightsCount < MaxLocalLights; i++)
{
const auto& light = cache->PointLights[i];
if (BoundingSphere(light.Position, light.Radius).Contains(drawCall.ObjectPosition) != ContainmentType::Disjoint)
if (CollisionsHelper::SphereIntersectsSphere(objectBounds, BoundingSphere(light.Position, light.Radius)))
{
light.SetupLightData(&data.LocalLights[data.LocalLightsCount], false);
data.LocalLightsCount++;
@@ -111,7 +113,7 @@ void ForwardShadingFeature::Bind(MaterialShader::BindParameters& params, Span<by
for (int32 i = 0; i < cache->SpotLights.Count() && data.LocalLightsCount < MaxLocalLights; i++)
{
const auto& light = cache->SpotLights[i];
if (BoundingSphere(light.Position, light.Radius).Contains(drawCall.ObjectPosition) != ContainmentType::Disjoint)
if (CollisionsHelper::SphereIntersectsSphere(objectBounds, BoundingSphere(light.Position, light.Radius)))
{
light.SetupLightData(&data.LocalLights[data.LocalLightsCount], false);
data.LocalLightsCount++;

View File

@@ -429,6 +429,7 @@ void Mesh::Draw(const RenderContext& renderContext, MaterialBase* material, cons
drawCall.Material = material;
drawCall.World = world;
drawCall.ObjectPosition = drawCall.World.GetTranslation();
drawCall.ObjectRadius = _sphere.Radius * drawCall.World.GetScaleVector().GetAbsolute().MaxValue();
drawCall.Surface.GeometrySize = _box.GetSize();
drawCall.Surface.PrevWorld = world;
drawCall.Surface.Lightmap = nullptr;
@@ -495,6 +496,7 @@ void Mesh::Draw(const RenderContext& renderContext, const DrawInfo& info, float
drawCall.Material = material;
drawCall.World = *info.World;
drawCall.ObjectPosition = drawCall.World.GetTranslation();
drawCall.ObjectRadius = info.Bounds.Radius; // TODO: should it be kept in sync with ObjectPosition?
drawCall.Surface.GeometrySize = _box.GetSize();
drawCall.Surface.PrevWorld = info.DrawState->PrevWorld;
drawCall.Surface.Lightmap = (info.Flags & StaticFlags::Lightmap) != StaticFlags::None ? info.Lightmap : nullptr;
@@ -555,6 +557,7 @@ void Mesh::Draw(const RenderContextBatch& renderContextBatch, const DrawInfo& in
drawCall.Material = material;
drawCall.World = *info.World;
drawCall.ObjectPosition = drawCall.World.GetTranslation();
drawCall.ObjectRadius = info.Bounds.Radius; // TODO: should it be kept in sync with ObjectPosition?
drawCall.Surface.GeometrySize = _box.GetSize();
drawCall.Surface.PrevWorld = info.DrawState->PrevWorld;
drawCall.Surface.Lightmap = (info.Flags & StaticFlags::Lightmap) != StaticFlags::None ? info.Lightmap : nullptr;

View File

@@ -198,6 +198,7 @@ void SkinnedMesh::Draw(const RenderContext& renderContext, const DrawInfo& info,
drawCall.Material = material;
drawCall.World = *info.World;
drawCall.ObjectPosition = drawCall.World.GetTranslation();
drawCall.ObjectRadius = info.Bounds.Radius; // TODO: should it be kept in sync with ObjectPosition?
drawCall.Surface.GeometrySize = _box.GetSize();
drawCall.Surface.PrevWorld = info.DrawState->PrevWorld;
drawCall.Surface.Lightmap = nullptr;
@@ -258,6 +259,7 @@ void SkinnedMesh::Draw(const RenderContextBatch& renderContextBatch, const DrawI
drawCall.Material = material;
drawCall.World = *info.World;
drawCall.ObjectPosition = drawCall.World.GetTranslation();
drawCall.ObjectRadius = info.Bounds.Radius; // TODO: should it be kept in sync with ObjectPosition?
drawCall.Surface.GeometrySize = _box.GetSize();
drawCall.Surface.PrevWorld = info.DrawState->PrevWorld;
drawCall.Surface.Lightmap = nullptr;

View File

@@ -122,7 +122,7 @@ GPUShaderProgram* GPUShaderDX11::CreateGPUShaderProgram(ShaderStage type, const
{
// Create shader
ID3D11DomainShader* buffer = nullptr;
VALIDATE_DIRECTX_CALL(_device->GetDevice()->CreateDomainShader(cacheBytes, cacheSize, nullptr, &buffer));
result = _device->GetDevice()->CreateDomainShader(cacheBytes, cacheSize, nullptr, &buffer);
LOG_DIRECTX_RESULT_WITH_RETURN(result, nullptr);
// Create object

View File

@@ -100,6 +100,7 @@ void Skybox::ApplySky(GPUContext* context, RenderContext& renderContext, const M
Platform::MemoryClear(&drawCall, sizeof(DrawCall));
drawCall.World = world;
drawCall.ObjectPosition = drawCall.World.GetTranslation();
drawCall.ObjectRadius = _sphere.Radius;
drawCall.Surface.GeometrySize = _box.GetSize();
drawCall.WorldDeterminantSign = Math::FloatSelect(world.RotDeterminant(), 1, -1);
drawCall.PerInstanceRandom = GetPerInstanceRandom();

View File

@@ -405,6 +405,7 @@ void SplineModel::Draw(RenderContext& renderContext)
const Transform splineTransform = GetTransform();
renderContext.View.GetWorldMatrix(splineTransform, drawCall.World);
drawCall.ObjectPosition = drawCall.World.GetTranslation() + drawCall.Deformable.LocalMatrix.GetTranslation();
drawCall.ObjectRadius = _sphere.Radius; // TODO: use radius for the spline chunk rather than whole spline
const float worldDeterminantSign = drawCall.World.RotDeterminant() * drawCall.Deformable.LocalMatrix.RotDeterminant();
for (int32 segment = 0; segment < _instances.Count(); segment++)
{

View File

@@ -32,7 +32,7 @@ void SceneTicking::TickData::RemoveTick(void* callee)
{
for (int32 i = 0; i < Ticks.Count(); i++)
{
if (Ticks[i].Callee == callee)
if (Ticks.Get()[i].Callee == callee)
{
Ticks.RemoveAt(i);
break;
@@ -45,7 +45,7 @@ void SceneTicking::TickData::Tick()
TickScripts(Scripts);
for (int32 i = 0; i < Ticks.Count(); i++)
Ticks[i].Call();
Ticks.Get()[i].Call();
}
#if USE_EDITOR
@@ -54,7 +54,7 @@ void SceneTicking::TickData::RemoveTickExecuteInEditor(void* callee)
{
for (int32 i = 0; i < TicksExecuteInEditor.Count(); i++)
{
if (TicksExecuteInEditor[i].Callee == callee)
if (TicksExecuteInEditor.Get()[i].Callee == callee)
{
TicksExecuteInEditor.RemoveAt(i);
break;
@@ -67,7 +67,7 @@ void SceneTicking::TickData::TickExecuteInEditor()
TickScripts(ScriptsExecuteInEditor);
for (int32 i = 0; i < TicksExecuteInEditor.Count(); i++)
TicksExecuteInEditor[i].Call();
TicksExecuteInEditor.Get()[i].Call();
}
#endif

View File

@@ -938,7 +938,8 @@ void Particles::DrawParticles(RenderContext& renderContext, ParticleEffect* effe
// Setup a draw call common data
DrawCall drawCall;
drawCall.PerInstanceRandom = effect->GetPerInstanceRandom();
drawCall.ObjectPosition = effect->GetPosition();
drawCall.ObjectPosition = effect->GetSphere().Center - view.Origin;
drawCall.ObjectRadius = effect->GetSphere().Radius;
// Draw all emitters
for (int32 emitterIndex = 0; emitterIndex < effect->Instance.Emitters.Count(); emitterIndex++)

View File

@@ -85,27 +85,34 @@ NSString* AppleUtils::ToNSString(const char* string)
NSArray* AppleUtils::ParseArguments(NSString* argsString) {
NSMutableArray *argsArray = [NSMutableArray array];
NSScanner *scanner = [NSScanner scannerWithString:argsString];
NSString *currentArg = nil;
NSMutableString *currentArg = [NSMutableString string];
BOOL insideQuotes = NO;
while (![scanner isAtEnd]) {
if (insideQuotes) {
[scanner scanUpToString:@"\"" intoString:&currentArg];
[scanner scanString:@"\"" intoString:NULL];
insideQuotes = NO;
} else {
[scanner scanUpToString:@" " intoString:&currentArg];
[scanner scanString:@" " intoString:NULL];
}
for (NSInteger i = 0; i < argsString.length; ++i) {
unichar c = [argsString characterAtIndex:i];
if ([currentArg isEqualToString:@"\""]) {
insideQuotes = YES;
} else if (currentArg) {
[argsArray addObject:currentArg];
if (c == '\"') {
if (insideQuotes) {
[argsArray addObject:[currentArg copy]];
[currentArg setString:@""];
insideQuotes = NO;
} else {
insideQuotes = YES;
}
} else if (c == ' ' && !insideQuotes) {
if (currentArg.length > 0) {
[argsArray addObject:[currentArg copy]];
[currentArg setString:@""];
}
} else {
[currentArg appendFormat:@"%C", c];
}
}
if (currentArg.length > 0) {
[argsArray addObject:[currentArg copy]];
}
return [argsArray copy];
}

View File

@@ -23,6 +23,7 @@ namespace FlaxEngine
AllowDragAndDrop = true,
IsRegularWindow = true,
HasSizingFrame = true,
ShowAfterFirstPaint = true,
};
}
}

View File

@@ -131,7 +131,7 @@ DECLARE_SCRIPTING_TYPE_MINIMAL(CreateWindowSettings);
/// <summary>
/// Enable/disable window auto-show after the first paint.
/// </summary>
API_FIELD() bool ShowAfterFirstPaint = false;
API_FIELD() bool ShowAfterFirstPaint = true;
/// <summary>
/// The custom data (platform dependant).

View File

@@ -258,6 +258,11 @@ struct DrawCall
/// </summary>
Float3 ObjectPosition;
/// <summary>
/// Object bounding sphere radius that contains it whole (sphere at ObjectPosition).
/// </summary>
float ObjectRadius;
/// <summary>
/// The world matrix determinant sign (used for geometry that is two sided or has inverse scale - needs to flip normal vectors and change triangles culling).
/// </summary>

View File

@@ -464,6 +464,7 @@ void GBufferPass::DrawDecals(RenderContext& renderContext, GPUTextureView* light
transform.Scale *= decal->GetSize();
renderContext.View.GetWorldMatrix(transform, drawCall.World);
drawCall.ObjectPosition = drawCall.World.GetTranslation();
drawCall.ObjectRadius = decal->GetSphere().Radius;
context->ResetRenderTarget();

View File

@@ -855,6 +855,7 @@ DRAW:
{
auto& batch = BatchedDrawCalls.Get()[list.PreBatchedDrawCalls.Get()[i]];
auto drawCall = batch.DrawCall;
drawCall.ObjectRadius = 0.0f;
bindParams.FirstDrawCall = &drawCall;
const auto* instancesData = batch.Instances.Get();

View File

@@ -85,6 +85,7 @@ public:
static MClass* GetClass(MClass* elementKlass);
static int32 GetLength(const MArray* obj);
static void* GetAddress(const MArray* obj);
static MArray* Unbox(MObject* obj);
template<typename T>
FORCE_INLINE static T* GetAddress(const MArray* obj)

View File

@@ -363,11 +363,12 @@ struct MConverter<Array<T>>
void Unbox(Array<T>& result, MObject* data)
{
const int32 length = data ? MCore::Array::GetLength((MArray*)data) : 0;
MArray* array = MCore::Array::Unbox(data);
const int32 length = array ? MCore::Array::GetLength(array) : 0;
result.Resize(length);
MConverter<T> converter;
Span<T> resultSpan(result.Get(), length);
converter.ToNativeArray(resultSpan, (MArray*)data);
converter.ToNativeArray(resultSpan, array);
}
};

View File

@@ -408,6 +408,12 @@ void* MCore::Array::GetAddress(const MArray* obj)
return CallStaticMethod<void*, void*>(GetArrayPointerPtr, (void*)obj);
}
MArray* MCore::Array::Unbox(MObject* obj)
{
static void* GetArrayPtr = GetStaticMethodPointer(TEXT("GetArray"));
return (MArray*)CallStaticMethod<void*, void*>(GetArrayPtr, (void*)obj);
}
MGCHandle MCore::GCHandle::New(MObject* obj, bool pinned)
{
ASSERT(obj);

View File

@@ -804,6 +804,11 @@ void* MCore::Array::GetAddress(const MArray* obj)
return mono_array_addr_with_size((MonoArray*)obj, 0, 0);
}
MArray* MCore::Array::Unbox(MObject* obj)
{
return (MArray*)obj;
}
MGCHandle MCore::GCHandle::New(MObject* obj, bool pinned)
{
return mono_gchandle_new(obj, pinned);

View File

@@ -141,6 +141,11 @@ void* MCore::Array::GetAddress(const MArray* obj)
return nullptr;
}
MArray* MCore::Array::Unbox(MObject* obj)
{
return nullptr;
}
MGCHandle MCore::GCHandle::New(MObject* obj, bool pinned)
{
return (MGCHandle)(uintptr)obj;

View File

@@ -45,7 +45,7 @@ bool TerrainChunk::PrepareDraw(const RenderContext& renderContext)
// Calculate chunk distance to view
const auto lodView = (renderContext.LodProxyView ? renderContext.LodProxyView : &renderContext.View);
const float distance = Float3::Distance(_boundsCenter - lodView->Origin, lodView->Position);
const float distance = Float3::Distance(_sphere.Center - lodView->Origin, lodView->Position);
lod = (int32)Math::Pow(distance / chunkEdgeSize, lodDistribution);
lod += lodBias;
@@ -88,6 +88,7 @@ void TerrainChunk::Draw(const RenderContext& renderContext) const
drawCall.Material = _cachedDrawMaterial;
renderContext.View.GetWorldMatrix(_transform, drawCall.World);
drawCall.ObjectPosition = drawCall.World.GetTranslation();
drawCall.ObjectRadius = _sphere.Radius;
drawCall.Terrain.Patch = _patch;
drawCall.Terrain.HeightmapUVScaleBias = _heightmapUVScaleBias;
drawCall.Terrain.OffsetUV = Vector2((float)(_patch->_x * TerrainPatch::CHUNKS_COUNT_EDGE + _x), (float)(_patch->_z * TerrainPatch::CHUNKS_COUNT_EDGE + _z));
@@ -145,6 +146,7 @@ void TerrainChunk::Draw(const RenderContext& renderContext, MaterialBase* materi
drawCall.Material = material;
renderContext.View.GetWorldMatrix(_transform, drawCall.World);
drawCall.ObjectPosition = drawCall.World.GetTranslation();
drawCall.ObjectRadius = _sphere.Radius;
drawCall.Terrain.Patch = _patch;
drawCall.Terrain.HeightmapUVScaleBias = _heightmapUVScaleBias;
drawCall.Terrain.OffsetUV = Vector2((float)(_patch->_x * TerrainPatch::CHUNKS_COUNT_EDGE + _x), (float)(_patch->_z * TerrainPatch::CHUNKS_COUNT_EDGE + _z));
@@ -202,7 +204,7 @@ void TerrainChunk::UpdateBounds()
OrientedBoundingBox obb(Vector3::Zero, Vector3::One);
obb.Transform(localTransform);
obb.GetBoundingBox(_bounds);
_boundsCenter = _bounds.GetCenter();
BoundingSphere::FromBox(_bounds, _sphere);
_bounds.Minimum -= boundsExtent;
_bounds.Maximum += boundsExtent;

View File

@@ -3,6 +3,7 @@
#pragma once
#include "Engine/Core/Math/BoundingBox.h"
#include "Engine/Core/Math/BoundingSphere.h"
#include "Engine/Core/Math/Matrix.h"
#include "Engine/Core/Math/Transform.h"
#include "Engine/Core/ISerializable.h"
@@ -29,7 +30,7 @@ private:
Float4 _heightmapUVScaleBias;
Transform _transform;
BoundingBox _bounds;
Vector3 _boundsCenter;
BoundingSphere _sphere;
float _perInstanceRandom;
float _yOffset, _yHeight;

View File

@@ -366,6 +366,7 @@ void TextRender::Draw(RenderContext& renderContext)
DrawCall drawCall;
drawCall.World = world;
drawCall.ObjectPosition = drawCall.World.GetTranslation();
drawCall.ObjectRadius = _sphere.Radius;
drawCall.Surface.GeometrySize = _localBox.GetSize();
drawCall.Surface.PrevWorld = _drawState.PrevWorld;
drawCall.Surface.Lightmap = nullptr;

View File

@@ -40,11 +40,11 @@ ShaderGraphValue::ShaderGraphValue(const Variant& v)
break;
case VariantType::Float:
Type = VariantType::Types::Float;
Value = String::Format(TEXT("{}"), v.AsFloat);
Value = String::Format(TEXT("{:.8f}"), v.AsFloat);
break;
case VariantType::Double:
Type = VariantType::Types::Float;
Value = String::Format(TEXT("{}"), (float)v.AsDouble);
Value = String::Format(TEXT("{:.8f}"), (float)v.AsDouble);
break;
case VariantType::Float2:
{