Merge branch 'master' into Visject-ConvertConstantToParameter

This commit is contained in:
Nils Hausfeld
2023-10-18 18:33:08 +02:00
23 changed files with 219 additions and 74 deletions

Binary file not shown.

View File

@@ -15,7 +15,7 @@ if errorlevel 1 goto BuildToolFailed
:: Build bindings for all editor configurations
echo Building C# bindings...
Binaries\Tools\Flax.Build.exe -build -BuildBindingsOnly -arch=x64 -platform=Windows --buildTargets=FlaxEditor,FlaxGame
Binaries\Tools\Flax.Build.exe -build -BuildBindingsOnly -arch=x64 -platform=Windows --buildTargets=FlaxEditor
popd
echo Done!

View File

@@ -14,4 +14,4 @@ bash ./Development/Scripts/Mac/CallBuildTool.sh --genproject "$@"
# Build bindings for all editor configurations
echo Building C# bindings...
# TODO: Detect the correct architecture here
Binaries/Tools/Flax.Build -build -BuildBindingsOnly -arch=ARM64 -platform=Mac --buildTargets=FlaxEditor,FlaxGame
Binaries/Tools/Flax.Build -build -BuildBindingsOnly -arch=ARM64 -platform=Mac --buildTargets=FlaxEditor

View File

@@ -14,4 +14,4 @@ bash ./Development/Scripts/Linux/CallBuildTool.sh --genproject "$@"
# Build bindings for all editor configurations
echo Building C# bindings...
# TODO: Detect the correct architecture here
Binaries/Tools/Flax.Build -build -BuildBindingsOnly -arch=x64 -platform=Linux --buildTargets=FlaxEditor,FlaxGame
Binaries/Tools/Flax.Build -build -BuildBindingsOnly -arch=x64 -platform=Linux --buildTargets=FlaxEditor

View File

@@ -30,6 +30,12 @@ namespace FlaxEditor.Content
return item is SceneItem;
}
/// <inheritdoc />
public override bool AcceptsAsset(string typeName, string path)
{
return (typeName == Scene.AssetTypename || typeName == Scene.EditorPickerTypename) && path.EndsWith(FileExtension, StringComparison.OrdinalIgnoreCase);
}
/// <inheritdoc />
public override bool CanCreate(ContentFolder targetLocation)
{

View File

@@ -406,18 +406,16 @@ namespace FlaxEditor.Content.Thumbnails
for (int i = 0; i < maxChecks; i++)
{
var request = _requests[i];
try
{
if (request.IsReady)
{
return request;
}
}
catch (Exception ex)
{
Editor.LogWarning(ex);
Editor.LogWarning($"Failed to prepare thumbnail rendering for {request.Item.ShortName}.");
Editor.LogWarning(ex);
_requests.RemoveAt(i--);
}
}
@@ -515,7 +513,6 @@ namespace FlaxEditor.Content.Thumbnails
for (int i = 0; i < checks; i++)
{
var request = _requests[i];
try
{
if (request.IsReady)
@@ -529,8 +526,9 @@ namespace FlaxEditor.Content.Thumbnails
}
catch (Exception ex)
{
Editor.LogWarning(ex);
Editor.LogWarning($"Failed to prepare thumbnail rendering for {request.Item.ShortName}.");
Editor.LogWarning(ex);
_requests.RemoveAt(i--);
}
}

View File

@@ -811,10 +811,9 @@ namespace FlaxEditor.Modules
{
if (node == null)
return;
// Temporary data
var folder = node.Folder;
var path = folder.Path;
var canHaveAssets = node.CanHaveAssets;
if (_isDuringFastSetup)
{
@@ -833,20 +832,38 @@ namespace FlaxEditor.Modules
var child = folder.Children[i];
if (!child.Exists)
{
// Send info
// Item doesn't exist anymore
Editor.Log(string.Format($"Content item \'{child.Path}\' has been removed"));
// Destroy it
Delete(child, false);
i--;
}
else if (canHaveAssets && child is AssetItem childAsset)
{
// Check if asset type doesn't match the item proxy (eg. item reimported as Material Instance instead of Material)
if (FlaxEngine.Content.GetAssetInfo(child.Path, out var assetInfo))
{
bool changed = assetInfo.ID != childAsset.ID;
if (!changed && assetInfo.TypeName != childAsset.TypeName)
{
// Use proxy check (eg. scene asset might accept different typename than AssetInfo reports)
var proxy = GetAssetProxy(childAsset.TypeName, child.Path);
if (proxy == null)
proxy = GetAssetProxy(assetInfo.TypeName, child.Path);
changed = !proxy.AcceptsAsset(assetInfo.TypeName, child.Path);
}
if (changed)
{
OnAssetTypeInfoChanged(childAsset, ref assetInfo);
i--;
}
}
}
}
}
// Find files
var files = Directory.GetFiles(path, "*.*", SearchOption.TopDirectoryOnly);
if (node.CanHaveAssets)
if (canHaveAssets)
{
LoadAssets(node, files);
}
@@ -1157,19 +1174,8 @@ namespace FlaxEditor.Modules
// For eg. change texture to sprite atlas on reimport
if (binaryAssetItem.TypeName != assetInfo.TypeName)
{
// Asset type has been changed!
Editor.LogWarning(string.Format("Asset \'{0}\' changed type from {1} to {2}", item.Path, binaryAssetItem.TypeName, assetInfo.TypeName));
Editor.Windows.CloseAllEditors(item);
// Remove this item from the database and some related data
var toRefresh = binaryAssetItem.ParentFolder;
binaryAssetItem.Dispose();
toRefresh.Children.Remove(binaryAssetItem);
if (!binaryAssetItem.HasDefaultThumbnail)
{
// Delete old thumbnail and remove it from the cache
Editor.Instance.Thumbnails.DeletePreview(binaryAssetItem);
}
OnAssetTypeInfoChanged(binaryAssetItem, ref assetInfo);
// Refresh the parent folder to find the new asset (it should have different type or some other format)
RefreshFolder(toRefresh, false);
@@ -1186,6 +1192,23 @@ namespace FlaxEditor.Modules
}
}
private void OnAssetTypeInfoChanged(AssetItem assetItem, ref AssetInfo assetInfo)
{
// Asset type has been changed!
Editor.LogWarning(string.Format("Asset \'{0}\' changed type from {1} to {2}", assetItem.Path, assetItem.TypeName, assetInfo.TypeName));
Editor.Windows.CloseAllEditors(assetItem);
// Remove this item from the database and some related data
assetItem.Dispose();
assetItem.ParentFolder.Children.Remove(assetItem);
// Delete old thumbnail and remove it from the cache
if (!assetItem.HasDefaultThumbnail)
{
Editor.Instance.Thumbnails.DeletePreview(assetItem);
}
}
internal void OnDirectoryEvent(MainContentTreeNode node, FileSystemEventArgs e)
{
// Ensure to be ready for external events

View File

@@ -2,7 +2,6 @@
using System;
using System.IO;
using System.Linq;
using System.Collections.Generic;
using FlaxEditor.Gizmo;
using FlaxEditor.GUI;
@@ -11,7 +10,6 @@ using FlaxEditor.GUI.Dialogs;
using FlaxEditor.GUI.Input;
using FlaxEditor.Progress.Handlers;
using FlaxEditor.SceneGraph;
using FlaxEditor.SceneGraph.Actors;
using FlaxEditor.Utilities;
using FlaxEditor.Viewport.Cameras;
using FlaxEditor.Windows;
@@ -208,6 +206,7 @@ namespace FlaxEditor.Modules
_toolStripScale.Checked = gizmoMode == TransformGizmoBase.Mode.Scale;
//
_toolStripBuildScenes.Enabled = (canEditScene && !isPlayMode) || Editor.StateMachine.BuildingScenesState.IsActive;
_toolStripBuildScenes.Visible = Editor.Options.Options.General.BuildActions?.Length != 0;
_toolStripCook.Enabled = Editor.Windows.GameCookerWin.CanBuild(Platform.PlatformType) && !GameCooker.IsRunning;
//
var play = _toolStripPlay;
@@ -653,7 +652,7 @@ namespace FlaxEditor.Modules
cm.AddButton("Information about Flax", () => new AboutDialog().Show());
}
private void OnOptionsChanged(FlaxEditor.Options.EditorOptions options)
private void OnOptionsChanged(EditorOptions options)
{
var inputOptions = options.Input;
@@ -688,6 +687,8 @@ namespace FlaxEditor.Modules
_menuToolsTakeScreenshot.ShortKeys = inputOptions.TakeScreenshot.ToString();
MainMenuShortcutKeysUpdated?.Invoke();
UpdateToolstrip();
}
private void InitToolstrip(RootControl mainWindow)
@@ -709,11 +710,11 @@ namespace FlaxEditor.Modules
_toolStripScale = (ToolStripButton)ToolStrip.AddButton(Editor.Icons.Scale32, () => Editor.MainTransformGizmo.ActiveMode = TransformGizmoBase.Mode.Scale).LinkTooltip($"Change Gizmo tool mode to Scale ({inputOptions.ScaleMode})");
ToolStrip.AddSeparator();
// Cook scenes
// Build scenes
_toolStripBuildScenes = (ToolStripButton)ToolStrip.AddButton(Editor.Icons.Build64, Editor.BuildScenesOrCancel).LinkTooltip($"Build scenes data - CSG, navmesh, static lighting, env probes - configurable via Build Actions in editor options ({inputOptions.BuildScenesData})");
// Cook and run
_toolStripCook = (ToolStripButton)ToolStrip.AddButton(Editor.Icons.ShipIt64, Editor.Windows.GameCookerWin.BuildAndRun).LinkTooltip($"Cook & Run - build game for the current platform and run it locally ({inputOptions.Play})");
_toolStripCook = (ToolStripButton)ToolStrip.AddButton(Editor.Icons.ShipIt64, Editor.Windows.GameCookerWin.BuildAndRun).LinkTooltip($"Cook & Run - build game for the current platform and run it locally ({inputOptions.CookAndRun})");
_toolStripCook.ContextMenu = new ContextMenu();
_toolStripCook.ContextMenu.AddButton("Run cooked game", Editor.Windows.GameCookerWin.RunCooked);
_toolStripCook.ContextMenu.AddSeparator();

View File

@@ -117,7 +117,7 @@ namespace FlaxEditor.Options
/// <summary>
/// Gets or sets the sequence of actions to perform when using Build Scenes button. Can be used to configure this as button (eg. compile code or just update navmesh).
/// </summary>
[EditorDisplay("General"), EditorOrder(200), Tooltip("The sequence of actions to perform when using Build Scenes button. Can be used to configure this as button (eg. compile code or just update navmesh).")]
[EditorDisplay("General"), EditorOrder(200), ExpandGroups, Tooltip("The sequence of actions to perform when using Build Scenes button. Can be used to configure this as button (eg. compile code or just update navmesh).")]
public BuildAction[] BuildActions { get; set; } =
{
BuildAction.CSG,

View File

@@ -388,14 +388,16 @@ namespace FlaxEditor.Windows.Assets
protected override void OnShow()
{
// Check if has no asset (but has item linked)
if (_asset == null && _item != null)
var item = _item;
if (_asset == null && item != null)
{
// Load asset
_asset = LoadAsset();
if (_asset == null)
{
Editor.LogError(string.Format("Cannot load asset \'{0}\' ({1})", _item.Path, typeof(T)));
Editor.LogError(string.Format("Cannot load asset \'{0}\' ({1})", item.Path, typeof(T)));
Close();
Editor.ContentDatabase.RefreshFolder(item, false);
return;
}

View File

@@ -521,8 +521,11 @@ namespace FlaxEditor.Windows.Assets
/// <inheritdoc />
protected override void OnClose()
{
// Discard unsaved changes
_properties.DiscardChanges();
if (Asset)
{
// Discard unsaved changes
_properties.DiscardChanges();
}
// Cleanup
_undo.Clear();

View File

@@ -20,6 +20,7 @@
#include "Engine/ShadersCompilation/Config.h"
#if BUILD_DEBUG
#include "Engine/Engine/Globals.h"
#include "Engine/Scripting/BinaryModule.h"
#endif
#endif
@@ -256,7 +257,9 @@ Asset::LoadResult Material::load()
#if BUILD_DEBUG && USE_EDITOR
// Dump generated material source to the temporary file
BinaryModule::Locker.Lock();
source.SaveToFile(Globals::ProjectCacheFolder / TEXT("material.txt"));
BinaryModule::Locker.Unlock();
#endif
// Encrypt source code

View File

@@ -124,7 +124,8 @@ CreateAssetResult ImportModelFile::Import(CreateAssetContext& context)
// Import model file
ModelData modelData;
String errorMsg;
String autoImportOutput = String(StringUtils::GetDirectoryName(context.TargetAssetPath)) / StringUtils::GetFileNameWithoutExtension(context.InputPath);
String autoImportOutput(StringUtils::GetDirectoryName(context.TargetAssetPath));
autoImportOutput /= options.SubAssetFolder.HasChars() ? options.SubAssetFolder.TrimTrailing() : String(StringUtils::GetFileNameWithoutExtension(context.InputPath));
if (ModelTool::ImportModel(context.InputPath, modelData, options, errorMsg, autoImportOutput))
{
LOG(Error, "Cannot import model file. {0}", errorMsg);

View File

@@ -100,7 +100,7 @@ public:
int32 _chunkIndex;
int32 _index;
Iterator(ChunkedArray const* collection, const int32 index)
Iterator(const ChunkedArray* collection, const int32 index)
: _collection(const_cast<ChunkedArray*>(collection))
, _chunkIndex(index / ChunkSize)
, _index(index % ChunkSize)
@@ -122,29 +122,29 @@ public:
{
}
public:
FORCE_INLINE ChunkedArray* GetChunkedArray() const
Iterator(Iterator&& i)
: _collection(i._collection)
, _chunkIndex(i._chunkIndex)
, _index(i._index)
{
return _collection;
}
public:
FORCE_INLINE int32 Index() const
{
return _chunkIndex * ChunkSize + _index;
}
public:
bool IsEnd() const
FORCE_INLINE bool IsEnd() const
{
return Index() == _collection->Count();
return (_chunkIndex * ChunkSize + _index) == _collection->_count;
}
bool IsNotEnd() const
FORCE_INLINE bool IsNotEnd() const
{
return Index() != _collection->Count();
return (_chunkIndex * ChunkSize + _index) != _collection->_count;
}
public:
FORCE_INLINE T& operator*() const
{
return _collection->_chunks[_chunkIndex]->At(_index);
@@ -155,7 +155,6 @@ public:
return &_collection->_chunks[_chunkIndex]->At(_index);
}
public:
FORCE_INLINE bool operator==(const Iterator& v) const
{
return _collection == v._collection && _chunkIndex == v._chunkIndex && _index == v._index;
@@ -166,17 +165,22 @@ public:
return _collection != v._collection || _chunkIndex != v._chunkIndex || _index != v._index;
}
public:
Iterator& operator=(const Iterator& v)
{
_collection = v._collection;
_chunkIndex = v._chunkIndex;
_index = v._index;
return *this;
}
Iterator& operator++()
{
// Check if it is not at end
const int32 end = _collection->Count();
if (Index() != end)
if ((_chunkIndex * ChunkSize + _index) != _collection->_count)
{
// Move forward within chunk
_index++;
// Check if need to change chunk
if (_index == ChunkSize && _chunkIndex < _collection->_chunks.Count() - 1)
{
// Move to next chunk
@@ -189,9 +193,9 @@ public:
Iterator operator++(int)
{
Iterator temp = *this;
++temp;
return temp;
Iterator i = *this;
++i;
return i;
}
Iterator& operator--()
@@ -199,7 +203,6 @@ public:
// Check if it's not at beginning
if (_index != 0 || _chunkIndex != 0)
{
// Check if need to change chunk
if (_index == 0)
{
// Move to previous chunk
@@ -217,9 +220,9 @@ public:
Iterator operator--(int)
{
Iterator temp = *this;
--temp;
return temp;
Iterator i = *this;
--i;
return i;
}
};
@@ -294,7 +297,7 @@ public:
{
if (IsEmpty())
return;
ASSERT(i.GetChunkedArray() == this);
ASSERT(i._collection == this);
ASSERT(i._chunkIndex < _chunks.Count() && i._index < ChunkSize);
ASSERT(i.Index() < Count());
@@ -432,11 +435,31 @@ public:
Iterator End() const
{
return Iterator(this, Count());
return Iterator(this, _count);
}
Iterator IteratorAt(int32 index) const
{
return Iterator(this, index);
}
FORCE_INLINE Iterator begin()
{
return Iterator(this, 0);
}
FORCE_INLINE Iterator end()
{
return Iterator(this, _count);
}
FORCE_INLINE const Iterator begin() const
{
return Iterator(this, 0);
}
FORCE_INLINE const Iterator end() const
{
return Iterator(this, _count);
}
};

View File

@@ -107,6 +107,26 @@ public:
ASSERT(index >= 0 && index < _length);
return _data[index];
}
FORCE_INLINE T* begin()
{
return _data;
}
FORCE_INLINE T* end()
{
return _data + _length;
}
FORCE_INLINE const T* begin() const
{
return _data;
}
FORCE_INLINE const T* end() const
{
return _data + _length;
}
};
template<typename T>

View File

@@ -634,15 +634,12 @@ void Foliage::RemoveFoliageType(int32 index)
int32 Foliage::GetFoliageTypeInstancesCount(int32 index) const
{
PROFILE_CPU();
int32 result = 0;
for (auto i = Instances.Begin(); i.IsNotEnd(); i++)
for (auto i = Instances.Begin(); i.IsNotEnd(); ++i)
{
if (i->Type == index)
result++;
}
return result;
}

View File

@@ -19,6 +19,7 @@
#include "Engine/Particles/Graph/GPU/ParticleEmitterGraph.GPU.h"
#if BUILD_DEBUG
#include "Engine/Engine/Globals.h"
#include "Engine/Scripting/BinaryModule.h"
#endif
#endif
#if COMPILE_WITH_GPU_PARTICLES
@@ -185,7 +186,9 @@ Asset::LoadResult ParticleEmitter::load()
#if BUILD_DEBUG && USE_EDITOR
// Dump generated shader source to the temporary file
BinaryModule::Locker.Lock();
source.SaveToFile(Globals::ProjectCacheFolder / TEXT("particle_emitter.txt"));
BinaryModule::Locker.Unlock();
#endif
// Encrypt source code

View File

@@ -47,10 +47,16 @@ int32 SpriteAtlas::GetSpritesCount() const
Sprite SpriteAtlas::GetSprite(int32 index) const
{
CHECK_RETURN(index >= 0 && index < Sprites.Count(), Sprite())
CHECK_RETURN(index >= 0 && index < Sprites.Count(), Sprite());
return Sprites.Get()[index];
}
void SpriteAtlas::GetSpriteArea(int32 index, Rectangle& result) const
{
CHECK(index >= 0 && index < Sprites.Count());
result = Sprites.Get()[index].Area;
}
void SpriteAtlas::SetSprite(int32 index, const Sprite& value)
{
CHECK(index >= 0 && index < Sprites.Count());

View File

@@ -70,7 +70,13 @@ namespace FlaxEngine
[NoSerialize]
public Float2 Size
{
get => Area.Size * Atlas.Size;
get
{
if (Atlas == null)
throw new InvalidOperationException("Cannot use invalid sprite.");
Atlas.GetSpriteArea(Index, out var area);
return area.Size * Atlas.Size;
}
set
{
var area = Area;
@@ -89,7 +95,8 @@ namespace FlaxEngine
{
if (Atlas == null)
throw new InvalidOperationException("Cannot use invalid sprite.");
return Atlas.GetSprite(Index).Area;
Atlas.GetSpriteArea(Index, out var area);
return area;
}
set
{

View File

@@ -120,6 +120,14 @@ public:
/// <returns>The sprite data.</returns>
API_FUNCTION() Sprite GetSprite(int32 index) const;
/// <summary>
/// Gets the sprite area.
/// </summary>
/// <param name="index">The index.</param>
/// <param name="result">The output sprite area.</param>
/// <returns>The sprite data.</returns>
API_FUNCTION() void GetSpriteArea(int32 index, API_PARAM(Out) Rectangle& result) const;
/// <summary>
/// Sets the sprite data.
/// </summary>

View File

@@ -22,6 +22,7 @@
#include "Engine/Core/Types/DateTime.h"
#include "Engine/Core/Types/TimeSpan.h"
#include "Engine/Core/Types/Pair.h"
#include "Engine/Core/Types/Variant.h"
#include "Engine/Graphics/Models/SkeletonUpdater.h"
#include "Engine/Graphics/Models/SkeletonMapping.h"
#include "Engine/Core/Utilities.h"
@@ -396,6 +397,7 @@ void ModelTool::Options::Serialize(SerializeStream& stream, const void* otherObj
SERIALIZE(SDFResolution);
SERIALIZE(SplitObjects);
SERIALIZE(ObjectIndex);
SERIALIZE(SubAssetFolder);
}
void ModelTool::Options::Deserialize(DeserializeStream& stream, ISerializeModifier* modifier)
@@ -441,6 +443,7 @@ void ModelTool::Options::Deserialize(DeserializeStream& stream, ISerializeModifi
DESERIALIZE(SDFResolution);
DESERIALIZE(SplitObjects);
DESERIALIZE(ObjectIndex);
DESERIALIZE(SubAssetFolder);
// [Deprecated on 23.11.2021, expires on 21.11.2023]
int32 AnimationIndex = -1;
@@ -744,6 +747,32 @@ void MeshOptDeallocate(void* ptr)
Allocator::Free(ptr);
}
void TrySetupMaterialParameter(MaterialInstance* instance, Span<const Char*> paramNames, const Variant& value, MaterialParameterType type)
{
for (const Char* name : paramNames)
{
for (MaterialParameter& param : instance->Params)
{
const MaterialParameterType paramType = param.GetParameterType();
if (type != paramType)
{
if (type == MaterialParameterType::Color)
{
if (paramType != MaterialParameterType::Vector3 ||
paramType != MaterialParameterType::Vector4)
continue;
}
else
continue;
}
if (StringUtils::CompareIgnoreCase(name, param.GetName().Get()) != 0)
continue;
param.SetValue(value);
return;
}
}
}
bool ModelTool::ImportModel(const String& path, ModelData& meshData, Options& options, String& errorMsg, const String& autoImportOutput)
{
LOG(Info, "Importing model from \'{0}\'", path);
@@ -1014,9 +1043,18 @@ bool ModelTool::ImportModel(const String& path, ModelData& meshData, Options& op
{
// Create material instance
AssetsImportingManager::Create(AssetsImportingManager::CreateMaterialInstanceTag, assetPath, material.AssetID);
if (MaterialInstance* materialInstance = Content::Load<MaterialInstance>(assetPath))
if (auto* materialInstance = Content::Load<MaterialInstance>(assetPath))
{
materialInstance->SetBaseMaterial(options.InstanceToImportAs);
// Customize base material based on imported material (blind guess based on the common names used in materials)
const Char* diffuseColorNames[] = { TEXT("color"), TEXT("col"), TEXT("diffuse"), TEXT("basecolor"), TEXT("base color") };
TrySetupMaterialParameter(materialInstance, ToSpan(diffuseColorNames, ARRAY_COUNT(diffuseColorNames)), material.Diffuse.Color, MaterialParameterType::Color);
const Char* emissiveColorNames[] = { TEXT("emissive"), TEXT("emission"), TEXT("light") };
TrySetupMaterialParameter(materialInstance, ToSpan(emissiveColorNames, ARRAY_COUNT(emissiveColorNames)), material.Emissive.Color, MaterialParameterType::Color);
const Char* opacityValueNames[] = { TEXT("opacity"), TEXT("alpha") };
TrySetupMaterialParameter(materialInstance, ToSpan(opacityValueNames, ARRAY_COUNT(opacityValueNames)), material.Opacity.Value, MaterialParameterType::Float);
materialInstance->Save();
}
else

View File

@@ -370,6 +370,12 @@ public:
API_FIELD(Attributes="EditorOrder(2010), EditorDisplay(\"Splitting\")")
int32 ObjectIndex = -1;
public: // Other
// If specified, will be used as sub-directory name for automatically imported sub assets such as textures and materials. Set to whitespace (single space) to import to the same directory.
API_FIELD(Attributes="EditorOrder(3030), EditorDisplay(\"Other\")")
String SubAssetFolder = TEXT("");
// Runtime data for objects splitting during import (used internally)
void* SplitContext = nullptr;
Function<bool(Options& splitOptions, const String& objectName)> OnSplitImport;

View File

@@ -211,7 +211,7 @@ float SampleSDF(uint3 voxelCoordMip, int3 offset)
float result = GlobalSDFTex[voxelCoordMip].r;
// Extend by distance to the sampled texel location
float distanceInWorldUnits = length(offset) * (MaxDistance / (float)GenerateMipTexResolution);
float distanceInWorldUnits = length((float3)offset) * (MaxDistance / (float)GenerateMipTexResolution);
float distanceToVoxel = distanceInWorldUnits / MaxDistance;
result = CombineDistanceToSDF(result, distanceToVoxel);