From b6e1bbafc926a072d3d39475c9f6a5dee1b43115 Mon Sep 17 00:00:00 2001 From: Janine Liu Date: Thu, 7 Aug 2025 12:33:49 -0400 Subject: [PATCH 1/5] Implement linear interpolation in shader [skip ci] --- .../Materials/Layers/ML_CesiumVoxel.uasset | Bin 48841 -> 49805 bytes Shaders/Private/CesiumVoxelTemplate.usf | 66 +++++++++++++++--- .../Private/CesiumVoxelMetadataComponent.cpp | 17 +++++ 3 files changed, 73 insertions(+), 10 deletions(-) diff --git a/Content/Materials/Layers/ML_CesiumVoxel.uasset b/Content/Materials/Layers/ML_CesiumVoxel.uasset index 9619eb7f7044248ba7009558138b876d7bda86be..41703125a5376149171a1f803089a8efab0914fa 100644 GIT binary patch delta 8395 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

NM7Q1)U!fU( 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 LW&hf&W(4^kC|S#I diff --git a/Shaders/Private/CesiumVoxelTemplate.usf b/Shaders/Private/CesiumVoxelTemplate.usf index 230c4e902..8e058a55b 100644 --- a/Shaders/Private/CesiumVoxelTemplate.usf +++ b/Shaders/Private/CesiumVoxelTemplate.usf @@ -48,18 +48,37 @@ struct VoxelMegatextures uint3 PaddingBefore; uint3 PaddingAfter; + bool UseLinearInterpolation; + int3 TileIndexToCoords(in int Index) { if (TileCount.x == 0 || TileCount.y == 0 || TileCount.z == 0) { return 0; } + int ZSlice = TileCount.x * TileCount.y; int Z = Index / ZSlice; int Y = (Index % ZSlice) / TileCount.x; int X = Index % TileCount.x; return int3(X, Y, Z) * (GridDimensions + PaddingBefore + PaddingAfter); } + + CustomShaderProperties GetPropertiesAtCoords(int3 Coords) + { + CustomShaderProperties Properties = (CustomShaderProperties) 0; + %s + + return Properties; + } + + CustomShaderProperties InterpolateProperties(CustomShaderProperties A, CustomShaderProperties B, float t) + { + CustomShaderProperties Result = (CustomShaderProperties) 0; + %s + + return Result; + } CustomShaderProperties GetProperties(in TileSample Sample) { @@ -69,6 +88,7 @@ struct VoxelMegatextures // Compute int coordinates of the voxel within the tile. float3 LocalUV = Sample.LocalUV; uint3 DataDimensions = GridDimensions + PaddingBefore + PaddingAfter; + float3 MaxVoxelCoords = float3(DataDimensions - 1u); if (ShapeConstant == BOX) { @@ -81,18 +101,43 @@ struct VoxelMegatextures // The start of the angular bounds has to be adjusted for full cylinders (root tile only). float adjustedAngle = WrapCylinderUV && Sample.Coords.w == 0 ? frac(LocalUV.y + 0.5) : LocalUV.y; LocalUV = float3(LocalUV.x, LocalUV.z, adjustedAngle); - } - - float3 VoxelCoords = floor(LocalUV * float3(GridDimensions)); - // Account for padding - VoxelCoords = clamp(VoxelCoords + float3(PaddingBefore), 0, float3(DataDimensions - 1u)); - - int3 Coords = TileCoords + VoxelCoords; + } - CustomShaderProperties Properties = (CustomShaderProperties) 0; - %s + float3 VoxelCoords = LocalUV * float3(GridDimensions) + float3(PaddingBefore); + VoxelCoords = clamp(VoxelCoords, 0, MaxVoxelCoords); - return Properties; + int3 Coords = TileCoords + floor(VoxelCoords); + + if (UseLinearInterpolation) + { + float3 t = frac(VoxelCoords); + float3 MaxCoords = TileCoords + MaxVoxelCoords; + + // Linear interpolation must be confined within a tile to avoid sampling data that is not physicall adjacent. + // That means we must manually interpolate instead of relying on a linear texture filter. + CustomShaderProperties x0y0z0 = GetPropertiesAtCoords(Coords); + CustomShaderProperties x1y0z0 = GetPropertiesAtCoords(min(Coords + int3(1, 0, 0), MaxCoords)); + CustomShaderProperties x0y1z0 = GetPropertiesAtCoords(min(Coords + int3(0, 1, 0), MaxCoords)); + CustomShaderProperties x1y1z0 = GetPropertiesAtCoords(min(Coords + int3(1, 1, 0), MaxCoords)); + CustomShaderProperties x0y0z1 = GetPropertiesAtCoords(min(Coords + int3(0, 0, 1), MaxCoords)); + CustomShaderProperties x1y0z1 = GetPropertiesAtCoords(min(Coords + int3(1, 0, 1), MaxCoords)); + CustomShaderProperties x0y1z1 = GetPropertiesAtCoords(min(Coords + int3(0, 1, 1), MaxCoords)); + CustomShaderProperties x1y1z1 = GetPropertiesAtCoords(min(Coords + int3(1, 1, 1), MaxCoords)); + + CustomShaderProperties y0z0 = InterpolateProperties(x0y0z0, x1y0z0, t.x); + CustomShaderProperties y1z0 = InterpolateProperties(x0y1z0, x1y1z0, t.x); + CustomShaderProperties y0z1 = InterpolateProperties(x0y0z1, x1y0z1, t.x); + CustomShaderProperties y1z1 = InterpolateProperties(x0y1z1, x1y1z1, t.x); + + CustomShaderProperties z0 = InterpolateProperties(y0z0, y1z0, t.y); + CustomShaderProperties z1 = InterpolateProperties(y1z1, y1z1, t.y); + + return InterpolateProperties(z0, z1, t.z); + } + else + { + return GetPropertiesAtCoords(Coords); + } } }; @@ -167,6 +212,7 @@ VoxelMegatextures DataTextures; DataTextures.ShapeConstant = ShapeConstant; DataTextures.TileCount = TileCount; DataTextures.WrapCylinderUV = (ShapeConstant == CYLINDER) ? (Octree.GridShape.CylinderShape.AngleRangeFlag == 0) : false; +DataTextures.UseLinearInterpolation = UseLinearInterpolation; // Account for y-up -> z-up conventions for certain shapes. switch (ShapeConstant) { diff --git a/Source/CesiumRuntime/Private/CesiumVoxelMetadataComponent.cpp b/Source/CesiumRuntime/Private/CesiumVoxelMetadataComponent.cpp index a91b9b350..e961f1ea7 100644 --- a/Source/CesiumRuntime/Private/CesiumVoxelMetadataComponent.cpp +++ b/Source/CesiumRuntime/Private/CesiumVoxelMetadataComponent.cpp @@ -256,6 +256,7 @@ struct MaterialResourceLibrary { struct CustomShaderBuilder { FString DeclareShaderProperties; FString SamplePropertiesFromTexture; + FString InterpolateProperties; FString DeclareDataTextureVariables; FString SetDataTextures; @@ -429,6 +430,20 @@ struct CustomShaderBuilder { } } + /** + * Adds code for linearly interpolating the property in the corresponding + * shader function. + */ + void AddPropertyInterpolation(const FString& PropertyName) { + if (!InterpolateProperties.IsEmpty()) { + InterpolateProperties += "\n\t\t"; + } + + // Example: Result.Property = lerp(A.Property, B.Property, t); + InterpolateProperties += "Result." + PropertyName + " = lerp(A." + + PropertyName + ", B." + PropertyName + ", t);"; + } + /** * Comprehensively adds the declaration for properties and data textures, as * well as the code to correctly retrieve the property values from the data @@ -441,6 +456,7 @@ struct CustomShaderBuilder { AddPropertyDeclaration(PropertyName, Property); AddDataTexture(PropertyName, TextureParameterName); AddPropertyRetrieval(PropertyName, Property); + AddPropertyInterpolation(PropertyName); } }; } // namespace @@ -831,6 +847,7 @@ static void GenerateMaterialNodes( LazyPrintf.PushParam(*Component->CustomShader); LazyPrintf.PushParam(*Builder.DeclareDataTextureVariables); LazyPrintf.PushParam(*Builder.SamplePropertiesFromTexture); + LazyPrintf.PushParam(*Builder.InterpolateProperties); LazyPrintf.PushParam(*Builder.SetDataTextures); RaymarchNode->Code = LazyPrintf.GetResultString(); From 17fe7de1532433532e1b81f5d033df32587cbe05 Mon Sep 17 00:00:00 2001 From: Janine Liu Date: Thu, 7 Aug 2025 14:49:23 -0400 Subject: [PATCH 2/5] Add linear interpolation setting on tileset --- Shaders/Private/CesiumVoxelTemplate.usf | 2 +- .../CesiumRuntime/Private/Cesium3DTileset.cpp | 17 ++++++++++ .../Private/CesiumVoxelMetadataComponent.cpp | 2 +- .../Private/CesiumVoxelRendererComponent.cpp | 23 +++++++++++-- .../Private/CesiumVoxelRendererComponent.h | 3 ++ Source/CesiumRuntime/Public/Cesium3DTileset.h | 23 +++++++++++++ .../Public/CesiumVoxelRenderingOptions.h | 34 +++++++++++++++++++ 7 files changed, 100 insertions(+), 4 deletions(-) create mode 100644 Source/CesiumRuntime/Public/CesiumVoxelRenderingOptions.h diff --git a/Shaders/Private/CesiumVoxelTemplate.usf b/Shaders/Private/CesiumVoxelTemplate.usf index 8e058a55b..545ea8cd9 100644 --- a/Shaders/Private/CesiumVoxelTemplate.usf +++ b/Shaders/Private/CesiumVoxelTemplate.usf @@ -212,7 +212,7 @@ VoxelMegatextures DataTextures; DataTextures.ShapeConstant = ShapeConstant; DataTextures.TileCount = TileCount; DataTextures.WrapCylinderUV = (ShapeConstant == CYLINDER) ? (Octree.GridShape.CylinderShape.AngleRangeFlag == 0) : false; -DataTextures.UseLinearInterpolation = UseLinearInterpolation; +DataTextures.UseLinearInterpolation = bool(UseLinearInterpolation); // Account for y-up -> z-up conventions for certain shapes. switch (ShapeConstant) { diff --git a/Source/CesiumRuntime/Private/Cesium3DTileset.cpp b/Source/CesiumRuntime/Private/Cesium3DTileset.cpp index a77b2a16d..868a6f57c 100644 --- a/Source/CesiumRuntime/Private/Cesium3DTileset.cpp +++ b/Source/CesiumRuntime/Private/Cesium3DTileset.cpp @@ -569,6 +569,17 @@ void ACesium3DTileset::SetPointCloudShading( } } +void ACesium3DTileset::SetVoxelRenderingOptions( + FCesiumVoxelRenderingOptions InVoxelRenderingOptions) { + if (VoxelRenderingOptions != InVoxelRenderingOptions) { + VoxelRenderingOptions = InVoxelRenderingOptions; + if (this->_pVoxelRendererComponent) { + this->_pVoxelRendererComponent->SetVoxelRenderingOptions( + InVoxelRenderingOptions); + } + } +} + void ACesium3DTileset::SetRuntimeVirtualTextures( TArray InRuntimeVirtualTextures) { if (this->RuntimeVirtualTextures != InRuntimeVirtualTextures) { @@ -2308,6 +2319,12 @@ void ACesium3DTileset::PostEditChangeChainProperty( if (PropName == GET_MEMBER_NAME_CHECKED(ACesium3DTileset, PointCloudShading)) { FCesiumGltfPointsSceneProxyUpdater::UpdateSettingsInProxies(this); + } else if ( + PropName == + GET_MEMBER_NAME_CHECKED(ACesium3DTileset, VoxelRenderingOptions)) { + if (this->_pVoxelRendererComponent) { + this->_pVoxelRendererComponent->SetVoxelRenderingOptions(VoxelRenderingOptions); + } } } diff --git a/Source/CesiumRuntime/Private/CesiumVoxelMetadataComponent.cpp b/Source/CesiumRuntime/Private/CesiumVoxelMetadataComponent.cpp index e961f1ea7..b37cf0bb4 100644 --- a/Source/CesiumRuntime/Private/CesiumVoxelMetadataComponent.cpp +++ b/Source/CesiumRuntime/Private/CesiumVoxelMetadataComponent.cpp @@ -739,7 +739,7 @@ static void GenerateMaterialNodes( auto* VectorParameterNode = Cast(NewExpression); if (VectorParameterNode && - VectorParameterNode->ParameterName.ToString() == "Tile Count") { + VectorParameterNode->ParameterName.ToString() == "Use Linear Interpolation") { DataSectionX = VectorParameterNode->MaterialExpressionEditorX; DataSectionY = VectorParameterNode->MaterialExpressionEditorY; } diff --git a/Source/CesiumRuntime/Private/CesiumVoxelRendererComponent.cpp b/Source/CesiumRuntime/Private/CesiumVoxelRendererComponent.cpp index 60ebb3541..9a8a3707f 100644 --- a/Source/CesiumRuntime/Private/CesiumVoxelRendererComponent.cpp +++ b/Source/CesiumRuntime/Private/CesiumVoxelRendererComponent.cpp @@ -1051,6 +1051,25 @@ UCesiumVoxelRendererComponent::CreateVoxelMaterial( return pVoxelComponent; } +void UCesiumVoxelRendererComponent::SetVoxelRenderingOptions( + const FCesiumVoxelRenderingOptions& Options) { + UMaterialInstanceDynamic* pMaterial = nullptr; + if (this->MeshComponent) { + UMaterialInterface* pMaterialInterface = + this->MeshComponent->GetMaterial(0); + pMaterial = Cast(pMaterialInterface); + } + + if (pMaterial) { + pMaterial->SetScalarParameterValueByInfo( + FMaterialParameterInfo( + UTF8_TO_TCHAR("Use Linear Interpolation"), + EMaterialParameterAssociation::LayerParameter, + 0), + float(Options.EnableLinearInterpolation)); + } +} + namespace { template void forEachRenderableVoxelTile(const auto& tiles, Func&& f) { @@ -1231,8 +1250,8 @@ void UCesiumVoxelRendererComponent::UpdateTiles( namespace { /** - * Updates the input voxel material to account for origin shifting or ellipsoid - * changes from the tileset's georeference. + * Updates the input voxel material to account for origin shifting or + * ellipsoid changes from the tileset's georeference. */ void updateEllipsoidVoxelParameters( UMaterialInstanceDynamic* pMaterial, diff --git a/Source/CesiumRuntime/Private/CesiumVoxelRendererComponent.h b/Source/CesiumRuntime/Private/CesiumVoxelRendererComponent.h index 1dfa57828..7e3761c59 100644 --- a/Source/CesiumRuntime/Private/CesiumVoxelRendererComponent.h +++ b/Source/CesiumRuntime/Private/CesiumVoxelRendererComponent.h @@ -2,6 +2,7 @@ #pragma once +#include "CesiumVoxelRenderingOptions.h" #include "Components/SceneComponent.h" #include "Components/StaticMeshComponent.h" #include "CoreMinimal.h" @@ -90,6 +91,8 @@ class UCesiumVoxelRendererComponent : public USceneComponent { const std::vector& VisibleTiles, const std::vector& VisibleTileScreenSpaceErrors); + void SetVoxelRenderingOptions(const FCesiumVoxelRenderingOptions& Options); + private: static UMaterialInstanceDynamic* CreateVoxelMaterial( UCesiumVoxelRendererComponent* pVoxelComponent, diff --git a/Source/CesiumRuntime/Public/Cesium3DTileset.h b/Source/CesiumRuntime/Public/Cesium3DTileset.h index 0382d7e83..e6a03eb82 100644 --- a/Source/CesiumRuntime/Public/Cesium3DTileset.h +++ b/Source/CesiumRuntime/Public/Cesium3DTileset.h @@ -14,18 +14,21 @@ #include "CesiumPointCloudShading.h" #include "CesiumSampleHeightResult.h" #include "CesiumVoxelMetadataComponent.h" +#include "CesiumVoxelRenderingOptions.h" #include "CoreMinimal.h" #include "CustomDepthParameters.h" #include "Engine/EngineTypes.h" #include "GameFramework/Actor.h" #include "Interfaces/IHttpRequest.h" #include "PrimitiveSceneProxy.h" + #include #include #include #include #include #include + #include "Cesium3DTileset.generated.h" #ifdef CESIUM_DEBUG_TILE_STATES @@ -956,6 +959,17 @@ class CESIUMRUNTIME_API ACesium3DTileset : public AActor { Category = "Cesium|Rendering") FCesiumPointCloudShading PointCloudShading; + /** + * If this tileset contains voxels, their appearance can be configured with + * these voxel rendering parameters. + */ + UPROPERTY( + EditAnywhere, + BlueprintGetter = GetVoxelRenderingOptions, + BlueprintSetter = SetVoxelRenderingOptions, + Category = "Cesium|Rendering") + FCesiumVoxelRenderingOptions VoxelRenderingOptions; + /** * Array of runtime virtual textures into which we draw the mesh for this * actor. The material also needs to be set up to output to a virtual texture. @@ -1164,6 +1178,15 @@ class CESIUMRUNTIME_API ACesium3DTileset : public AActor { UFUNCTION(BlueprintSetter, Category = "Cesium|Rendering") void SetPointCloudShading(FCesiumPointCloudShading InPointCloudShading); + UFUNCTION(BlueprintGetter, Category = "Cesium|Rendering") + FCesiumVoxelRenderingOptions GetVoxelRenderingOptions() const { + return VoxelRenderingOptions; + } + + UFUNCTION(BlueprintSetter, Category = "Cesium|Rendering") + void SetVoxelRenderingOptions( + FCesiumVoxelRenderingOptions InVoxelRenderingOptions); + UFUNCTION(BlueprintCallable, Category = "Cesium|Rendering") void PlayMovieSequencer(); diff --git a/Source/CesiumRuntime/Public/CesiumVoxelRenderingOptions.h b/Source/CesiumRuntime/Public/CesiumVoxelRenderingOptions.h new file mode 100644 index 000000000..486b7888b --- /dev/null +++ b/Source/CesiumRuntime/Public/CesiumVoxelRenderingOptions.h @@ -0,0 +1,34 @@ +// Copyright 2020-2024 CesiumGS, Inc. and Contributors + +#pragma once + +#include "CoreMinimal.h" + +#include "CesiumVoxelRenderingOptions.generated.h" + +/** + * Options for adjusting how voxels are rendered using 3D Tiles. + */ +USTRUCT(BlueprintType) +struct CESIUMRUNTIME_API FCesiumVoxelRenderingOptions { + GENERATED_USTRUCT_BODY() + + /** + * Whether to enable linear interpolation when rendering voxels. This can + * result in a smoother appearance across a large voxel tileset. If false, + * nearest sampling will be used. + */ + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Cesium") + bool EnableLinearInterpolation = false; + + bool operator==( + const FCesiumVoxelRenderingOptions& OtherVoxelRenderingOptions) const { + return EnableLinearInterpolation == + OtherVoxelRenderingOptions.EnableLinearInterpolation; + } + + bool operator!=( + const FCesiumVoxelRenderingOptions& OtherVoxelRenderingOptions) const { + return !(*this == OtherVoxelRenderingOptions); + } +}; From 6145136dfdec3998f9866f40f121f7ef9f530e2e Mon Sep 17 00:00:00 2001 From: Janine Liu Date: Fri, 8 Aug 2025 14:04:18 -0400 Subject: [PATCH 3/5] Fix interpolation bugs --- Shaders/Private/CesiumVoxelTemplate.usf | 37 ++++++++++--------- .../CesiumRuntime/Private/Cesium3DTileset.cpp | 6 ++- 2 files changed, 25 insertions(+), 18 deletions(-) diff --git a/Shaders/Private/CesiumVoxelTemplate.usf b/Shaders/Private/CesiumVoxelTemplate.usf index 545ea8cd9..4d4d401f5 100644 --- a/Shaders/Private/CesiumVoxelTemplate.usf +++ b/Shaders/Private/CesiumVoxelTemplate.usf @@ -103,26 +103,27 @@ struct VoxelMegatextures LocalUV = float3(LocalUV.x, LocalUV.z, adjustedAngle); } - float3 VoxelCoords = LocalUV * float3(GridDimensions) + float3(PaddingBefore); - VoxelCoords = clamp(VoxelCoords, 0, MaxVoxelCoords); + float3 VoxelCoords = LocalUV * float3(GridDimensions); - int3 Coords = TileCoords + floor(VoxelCoords); - if (UseLinearInterpolation) { - float3 t = frac(VoxelCoords); - float3 MaxCoords = TileCoords + MaxVoxelCoords; + // Account for padding + VoxelCoords += float3(PaddingBefore); + + float3 t = frac(VoxelCoords + 0.5); + float3 Coords = TileCoords + VoxelCoords; + int3 MaxCoords = TileCoords + MaxVoxelCoords; - // Linear interpolation must be confined within a tile to avoid sampling data that is not physicall adjacent. + // Linear interpolation must be confined within a tile to avoid sampling data that is not physically adjacent. // That means we must manually interpolate instead of relying on a linear texture filter. - CustomShaderProperties x0y0z0 = GetPropertiesAtCoords(Coords); - CustomShaderProperties x1y0z0 = GetPropertiesAtCoords(min(Coords + int3(1, 0, 0), MaxCoords)); - CustomShaderProperties x0y1z0 = GetPropertiesAtCoords(min(Coords + int3(0, 1, 0), MaxCoords)); - CustomShaderProperties x1y1z0 = GetPropertiesAtCoords(min(Coords + int3(1, 1, 0), MaxCoords)); - CustomShaderProperties x0y0z1 = GetPropertiesAtCoords(min(Coords + int3(0, 0, 1), MaxCoords)); - CustomShaderProperties x1y0z1 = GetPropertiesAtCoords(min(Coords + int3(1, 0, 1), MaxCoords)); - CustomShaderProperties x0y1z1 = GetPropertiesAtCoords(min(Coords + int3(0, 1, 1), MaxCoords)); - CustomShaderProperties x1y1z1 = GetPropertiesAtCoords(min(Coords + int3(1, 1, 1), MaxCoords)); + CustomShaderProperties x0y0z0 = GetPropertiesAtCoords(clamp(floor(Coords + float3(-0.5, -0.5, -0.5)), 0, MaxCoords)); + CustomShaderProperties x1y0z0 = GetPropertiesAtCoords(clamp(floor(Coords + float3 (0.5, -0.5, -0.5)), 0, MaxCoords)); + CustomShaderProperties x0y1z0 = GetPropertiesAtCoords(clamp(floor(Coords + float3(-0.5, 0.5, -0.5)), 0, MaxCoords)); + CustomShaderProperties x1y1z0 = GetPropertiesAtCoords(clamp(floor(Coords + float3( 0.5, 0.5, -0.5)), 0, MaxCoords)); + CustomShaderProperties x0y0z1 = GetPropertiesAtCoords(clamp(floor(Coords + float3(-0.5, -0.5, 0.5)), 0, MaxCoords)); + CustomShaderProperties x1y0z1 = GetPropertiesAtCoords(clamp(floor(Coords + float3( 0.5, -0.5, 0.5)), 0, MaxCoords)); + CustomShaderProperties x0y1z1 = GetPropertiesAtCoords(clamp(floor(Coords + float3(-0.5, 0.5, 0.5)), 0, MaxCoords)); + CustomShaderProperties x1y1z1 = GetPropertiesAtCoords(clamp(floor(Coords + float3( 0.5, 0.5, 0.5)), 0, MaxCoords)); CustomShaderProperties y0z0 = InterpolateProperties(x0y0z0, x1y0z0, t.x); CustomShaderProperties y1z0 = InterpolateProperties(x0y1z0, x1y1z0, t.x); @@ -130,13 +131,15 @@ struct VoxelMegatextures CustomShaderProperties y1z1 = InterpolateProperties(x0y1z1, x1y1z1, t.x); CustomShaderProperties z0 = InterpolateProperties(y0z0, y1z0, t.y); - CustomShaderProperties z1 = InterpolateProperties(y1z1, y1z1, t.y); + CustomShaderProperties z1 = InterpolateProperties(y0z1, y1z1, t.y); return InterpolateProperties(z0, z1, t.z); } else { - return GetPropertiesAtCoords(Coords); + // Account for padding + VoxelCoords = clamp(floor(VoxelCoords) + float3(PaddingBefore), 0, MaxVoxelCoords); + return GetPropertiesAtCoords(TileCoords + VoxelCoords); } } }; diff --git a/Source/CesiumRuntime/Private/Cesium3DTileset.cpp b/Source/CesiumRuntime/Private/Cesium3DTileset.cpp index 868a6f57c..382727b4f 100644 --- a/Source/CesiumRuntime/Private/Cesium3DTileset.cpp +++ b/Source/CesiumRuntime/Private/Cesium3DTileset.cpp @@ -2323,7 +2323,8 @@ void ACesium3DTileset::PostEditChangeChainProperty( PropName == GET_MEMBER_NAME_CHECKED(ACesium3DTileset, VoxelRenderingOptions)) { if (this->_pVoxelRendererComponent) { - this->_pVoxelRendererComponent->SetVoxelRenderingOptions(VoxelRenderingOptions); + this->_pVoxelRendererComponent->SetVoxelRenderingOptions( + VoxelRenderingOptions); } } } @@ -2437,5 +2438,8 @@ void ACesium3DTileset::createVoxelRenderer( Warning, TEXT("Voxel renderer could not be attached to root")); } + + this->_pVoxelRendererComponent->SetVoxelRenderingOptions( + this->VoxelRenderingOptions); } } From 6f07d6acfcfb6b01151c80d8e5b8315e34e64bc9 Mon Sep 17 00:00:00 2001 From: Janine Liu Date: Fri, 8 Aug 2025 16:20:07 -0400 Subject: [PATCH 4/5] Fix clamp bug, don't interpolate noData values --- Shaders/Private/CesiumVoxelTemplate.usf | 16 +++---- .../Private/CesiumVoxelMetadataComponent.cpp | 44 ++++++++++++++----- 2 files changed, 42 insertions(+), 18 deletions(-) diff --git a/Shaders/Private/CesiumVoxelTemplate.usf b/Shaders/Private/CesiumVoxelTemplate.usf index 4d4d401f5..7b939a52b 100644 --- a/Shaders/Private/CesiumVoxelTemplate.usf +++ b/Shaders/Private/CesiumVoxelTemplate.usf @@ -116,14 +116,14 @@ struct VoxelMegatextures // Linear interpolation must be confined within a tile to avoid sampling data that is not physically adjacent. // That means we must manually interpolate instead of relying on a linear texture filter. - CustomShaderProperties x0y0z0 = GetPropertiesAtCoords(clamp(floor(Coords + float3(-0.5, -0.5, -0.5)), 0, MaxCoords)); - CustomShaderProperties x1y0z0 = GetPropertiesAtCoords(clamp(floor(Coords + float3 (0.5, -0.5, -0.5)), 0, MaxCoords)); - CustomShaderProperties x0y1z0 = GetPropertiesAtCoords(clamp(floor(Coords + float3(-0.5, 0.5, -0.5)), 0, MaxCoords)); - CustomShaderProperties x1y1z0 = GetPropertiesAtCoords(clamp(floor(Coords + float3( 0.5, 0.5, -0.5)), 0, MaxCoords)); - CustomShaderProperties x0y0z1 = GetPropertiesAtCoords(clamp(floor(Coords + float3(-0.5, -0.5, 0.5)), 0, MaxCoords)); - CustomShaderProperties x1y0z1 = GetPropertiesAtCoords(clamp(floor(Coords + float3( 0.5, -0.5, 0.5)), 0, MaxCoords)); - CustomShaderProperties x0y1z1 = GetPropertiesAtCoords(clamp(floor(Coords + float3(-0.5, 0.5, 0.5)), 0, MaxCoords)); - CustomShaderProperties x1y1z1 = GetPropertiesAtCoords(clamp(floor(Coords + float3( 0.5, 0.5, 0.5)), 0, MaxCoords)); + CustomShaderProperties x0y0z0 = GetPropertiesAtCoords(clamp(floor(Coords + float3(-0.5, -0.5, -0.5)), TileCoords, MaxCoords)); + CustomShaderProperties x1y0z0 = GetPropertiesAtCoords(clamp(floor(Coords + float3 (0.5, -0.5, -0.5)), TileCoords, MaxCoords)); + CustomShaderProperties x0y1z0 = GetPropertiesAtCoords(clamp(floor(Coords + float3(-0.5, 0.5, -0.5)), TileCoords, MaxCoords)); + CustomShaderProperties x1y1z0 = GetPropertiesAtCoords(clamp(floor(Coords + float3( 0.5, 0.5, -0.5)), TileCoords, MaxCoords)); + CustomShaderProperties x0y0z1 = GetPropertiesAtCoords(clamp(floor(Coords + float3(-0.5, -0.5, 0.5)), TileCoords, MaxCoords)); + CustomShaderProperties x1y0z1 = GetPropertiesAtCoords(clamp(floor(Coords + float3( 0.5, -0.5, 0.5)), TileCoords, MaxCoords)); + CustomShaderProperties x0y1z1 = GetPropertiesAtCoords(clamp(floor(Coords + float3(-0.5, 0.5, 0.5)), TileCoords, MaxCoords)); + CustomShaderProperties x1y1z1 = GetPropertiesAtCoords(clamp(floor(Coords + float3( 0.5, 0.5, 0.5)), TileCoords, MaxCoords)); CustomShaderProperties y0z0 = InterpolateProperties(x0y0z0, x1y0z0, t.x); CustomShaderProperties y1z0 = InterpolateProperties(x0y1z0, x1y1z0, t.x); diff --git a/Source/CesiumRuntime/Private/CesiumVoxelMetadataComponent.cpp b/Source/CesiumRuntime/Private/CesiumVoxelMetadataComponent.cpp index b37cf0bb4..f38187489 100644 --- a/Source/CesiumRuntime/Private/CesiumVoxelMetadataComponent.cpp +++ b/Source/CesiumRuntime/Private/CesiumVoxelMetadataComponent.cpp @@ -434,14 +434,38 @@ struct CustomShaderBuilder { * Adds code for linearly interpolating the property in the corresponding * shader function. */ - void AddPropertyInterpolation(const FString& PropertyName) { + void AddPropertyInterpolation( + const FString& PropertyName, + const FCesiumPropertyAttributePropertyDescription& Property) { if (!InterpolateProperties.IsEmpty()) { InterpolateProperties += "\n\t\t"; } // Example: Result.Property = lerp(A.Property, B.Property, t); - InterpolateProperties += "Result." + PropertyName + " = lerp(A." + - PropertyName + ", B." + PropertyName + ", t);"; + FString lerp = "Result." + PropertyName + " = lerp(A." + PropertyName + + ", B." + PropertyName + ", t);\n"; + + // Any "noData" values should be omitted from inteprolation. Otherwise, they + // may result in nonsensical data. + if (Property.PropertyDetails.bHasNoDataValue) { + FString NoDataName = PropertyName + MaterialPropertyNoDataSuffix; + // Example: if {A.Property == Property_NODATA) { + // Result.Property = B.Property; + // } + // else if (B.Property == Property_NODATA) { + // Result.Property = A.Property; + // } else { + // Result.Property = lerp(A.Property, B.Property, t); + // } + InterpolateProperties += + "if (A." + PropertyName + " == " + NoDataName + ") {\n\t\t" + + "Result." + PropertyName + " = B." + PropertyName + ";\n}\n\t" + + "else if (B." + PropertyName + " == " + NoDataName + ") {\n\t\t" + + "Result." + PropertyName + " = A." + PropertyName + ";\n}\n\t" + + "else {\n\t\t" + lerp + "}\n"; + } else { + InterpolateProperties += lerp; + } } /** @@ -456,7 +480,7 @@ struct CustomShaderBuilder { AddPropertyDeclaration(PropertyName, Property); AddDataTexture(PropertyName, TextureParameterName); AddPropertyRetrieval(PropertyName, Property); - AddPropertyInterpolation(PropertyName); + AddPropertyInterpolation(PropertyName, Property); } }; } // namespace @@ -736,12 +760,12 @@ static void GenerateMaterialNodes( continue; } - auto* VectorParameterNode = - Cast(NewExpression); - if (VectorParameterNode && - VectorParameterNode->ParameterName.ToString() == "Use Linear Interpolation") { - DataSectionX = VectorParameterNode->MaterialExpressionEditorX; - DataSectionY = VectorParameterNode->MaterialExpressionEditorY; + auto* ScalarParameterNode = + Cast(NewExpression); + if (ScalarParameterNode && ScalarParameterNode->ParameterName.ToString() == + "Use Linear Interpolation") { + DataSectionX = ScalarParameterNode->MaterialExpressionEditorX; + DataSectionY = ScalarParameterNode->MaterialExpressionEditorY; } } From bc28bb49151766cf5b50e251b85d1a44ae33e2ff Mon Sep 17 00:00:00 2001 From: Janine Liu Date: Wed, 20 Aug 2025 14:43:56 -0400 Subject: [PATCH 5/5] Fix CI --- Source/CesiumRuntime/Private/CesiumVoxelRendererComponent.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/Source/CesiumRuntime/Private/CesiumVoxelRendererComponent.cpp b/Source/CesiumRuntime/Private/CesiumVoxelRendererComponent.cpp index 55845cda9..a0b0606f2 100644 --- a/Source/CesiumRuntime/Private/CesiumVoxelRendererComponent.cpp +++ b/Source/CesiumRuntime/Private/CesiumVoxelRendererComponent.cpp @@ -13,6 +13,7 @@ #include "Engine/Texture.h" #include "Materials/MaterialInstanceDynamic.h" #include "PhysicsEngine/BodySetup.h" +#include "SceneInterface.h" #include "UObject/ConstructorHelpers.h" #include "VecMath.h"