CelticCraft/Plugins/VoxelFree/Source/Voxel/Private/VoxelRender/VoxelMaterialExpressions.cpp

224 lines
6.1 KiB
C++
Raw Permalink Normal View History

2023-07-03 16:17:13 +00:00
// Copyright 2020 Phyronnaz
#include "VoxelRender/VoxelMaterialExpressions.h"
#include "VoxelContainers/VoxelStaticArray.h"
#include "MaterialCompiler.h"
#include "Materials/HLSLMaterialTranslator.h"
#if WITH_EDITOR
class FHLSLCompilerChild : public FHLSLMaterialTranslator
{
public:
auto& GetStaticParameters() const
{
return StaticParameters;
}
};
class FVoxelMaterialCompiler : public FProxyMaterialCompiler
{
public:
static TSet<FMaterialCompiler*>& GetVoxelCompilers()
{
static TSet<FMaterialCompiler*> Set;
return Set;
}
FVoxelMaterialCompiler(FMaterialCompiler* InCompiler)
: FProxyMaterialCompiler(InCompiler)
{
GetVoxelCompilers().Add(this);
}
~FVoxelMaterialCompiler()
{
ensure(GetVoxelCompilers().Contains(this));
GetVoxelCompilers().Remove(this);
}
FMaterialCompiler* GetBaseCompiler() const
{
if (GetVoxelCompilers().Contains(Compiler))
{
// Can happen in recursive calls
return static_cast<FVoxelMaterialCompiler*>(Compiler)->GetBaseCompiler();
}
else
{
return Compiler;
}
}
virtual int32 StaticTerrainLayerWeight(FName ParameterName, int32 Default) override
{
FHLSLCompilerChild* HLSLCompiler = static_cast<FHLSLCompilerChild*>(GetBaseCompiler());
auto& TerrainLayerWeightParameters = HLSLCompiler->GetStaticParameters().EditorOnly.TerrainLayerWeightParameters;
TArray<int32> VoxelIndices;
int32 ParameterVoxelIndex = -1;
for (auto& Parameter : TerrainLayerWeightParameters)
{
const int32 WeightmapIndex = Parameter.WeightmapIndex - 1000000;
if (WeightmapIndex >= 0)
{
VoxelIndices.Add(WeightmapIndex);
if (Parameter.LayerName == ParameterName)
{
ParameterVoxelIndex = WeightmapIndex;
}
}
}
if (VoxelIndices.Num() == 0)
{
// Default to regular behavior in case we're compiling a real landscape material
return Compiler->StaticTerrainLayerWeight(ParameterName, Default);
}
if (ParameterName == UMaterialExpressionLandscapeVisibilityMask::ParameterName)
{
// No support for visibility mask
return INDEX_NONE;
}
if (!ensureVoxelSlow(ParameterVoxelIndex != -1))
{
// We should have all the parameters overriden
return INDEX_NONE;
}
if (ParameterVoxelIndex == 6)
{
// Valid index: means it's not used
// Make sure to return 0 to avoid inconsistencies
return Constant(0.f);
}
if (!ensureVoxelSlow(ParameterVoxelIndex >= 0 && ParameterVoxelIndex < 6))
{
// Invalid index
return INDEX_NONE;
}
// Remove all unused layers
VoxelIndices.Remove(6);
const int32 NumBlends = VoxelIndices.Num();
ensure(NumBlends > 0 && NumBlends <= 6);
const int32 R = ComponentMask(VertexColor(), true, false, false, false);
const int32 G = ComponentMask(VertexColor(), false, true, false, false);
const int32 B = ComponentMask(VertexColor(), false, false, true, false);
const int32 U = ComponentMask(TextureCoordinate(1, false, false), true, false, false, false);
const int32 V = ComponentMask(TextureCoordinate(1, false, false), false, true, false, false);
TVoxelStaticArray<int32, 6> Inputs;
for (int32& Input : Inputs)
{
Input = Constant(0.f);
}
Inputs[ParameterVoxelIndex] = Constant(1.f);
int32 Output = Inputs[0];
if (NumBlends > 1) Output = Lerp(Output, Inputs[1], R);
if (NumBlends > 2) Output = Lerp(Output, Inputs[2], G);
if (NumBlends > 3) Output = Lerp(Output, Inputs[3], B);
if (NumBlends > 4) Output = Lerp(Output, Inputs[4], U);
if (NumBlends > 5) Output = Lerp(Output, Inputs[5], V);
return Output;
}
public:
virtual int32 ReflectionAboutCustomWorldNormal(int32 CustomWorldNormal, int32 bNormalizeCustomWorldNormal) override
{
return Compiler->ReflectionAboutCustomWorldNormal(CustomWorldNormal, bNormalizeCustomWorldNormal);
}
virtual int32 ParticleRelativeTime() override
{
return Compiler->ParticleRelativeTime();
}
virtual int32 ParticleMotionBlurFade() override
{
return Compiler->ParticleMotionBlurFade();
}
virtual int32 ParticleRandom() override
{
return Compiler->ParticleRandom();
}
virtual int32 ParticleDirection() override
{
return Compiler->ParticleDirection();
}
virtual int32 ParticleSpeed() override
{
return Compiler->ParticleSpeed();
}
virtual int32 ParticleSize() override
{
return Compiler->ParticleSize();
}
virtual int32 VertexInterpolator(uint32 InterpolatorIndex) override
{
return Compiler->VertexInterpolator(InterpolatorIndex);
}
virtual int32 MaterialBakingWorldPosition() override
{
return Compiler->MaterialBakingWorldPosition();
}
};
#define FORWARD_CLASS(Name) \
void Name::GetCaption(TArray<FString>& OutCaptions) const \
{ \
Super::GetCaption(OutCaptions); \
OutCaptions[0] += " (voxel)"; \
} \
\
int32 Name::Compile(FMaterialCompiler* Compiler, int32 OutputIndex) \
{ \
FVoxelMaterialCompiler VoxelCompiler(Compiler); \
return Super::Compile(&VoxelCompiler, OutputIndex); \
}
FORWARD_CLASS(UMaterialExpressionVoxelLandscapeLayerBlend)
FORWARD_CLASS(UMaterialExpressionVoxelLandscapeLayerSwitch)
FORWARD_CLASS(UMaterialExpressionVoxelLandscapeLayerWeight)
FORWARD_CLASS(UMaterialExpressionVoxelLandscapeLayerSample)
FORWARD_CLASS(UMaterialExpressionVoxelLandscapeVisibilityMask)
#undef FORWARD_CLASS
bool NeedsToBeConvertedToVoxelImp(const TArray<UMaterialExpression*>& Expressions, TSet<UMaterialFunction*>& VisitedFunctions)
{
for (auto* Expression : Expressions)
{
if (FVoxelMaterialExpressionUtilities::GetVoxelExpression(Expression->GetClass()))
{
return true;
}
if (auto* FunctionCall = Cast<UMaterialExpressionMaterialFunctionCall>(Expression))
{
auto* Function = Cast<UMaterialFunction>(FunctionCall->MaterialFunction);
if (Function && !VisitedFunctions.Contains(Function))
{
VisitedFunctions.Add(Function);
if (NeedsToBeConvertedToVoxelImp(Function->GetEditorOnlyData()->ExpressionCollection.Expressions, VisitedFunctions))
{
return true;
}
}
}
}
return false;
}
bool FVoxelMaterialExpressionUtilities::NeedsToBeConvertedToVoxel(const TArray<UMaterialExpression*>& Expressions)
{
TSet<UMaterialFunction*> VisitedFunctions;
return NeedsToBeConvertedToVoxelImp(Expressions, VisitedFunctions);
}
#endif