Files
FlaxEngine/Source/Engine/Visject/ShaderGraphUtilities.cpp
2021-04-30 16:27:57 +02:00

376 lines
13 KiB
C++

// Copyright (c) 2012-2021 Wojciech Figat. All rights reserved.
#if USE_EDITOR
#include "ShaderGraphUtilities.h"
#include "ShaderGraphValue.h"
#include "Engine/Core/Types/StringBuilder.h"
#include "Engine/Core/Math/Vector4.h"
#include "Engine/Content/Content.h"
#include "Engine/Engine/GameplayGlobals.h"
#include "Engine/Graphics/Config.h"
void ShaderGraphUtilities::GenerateShaderConstantBuffer(TextWriterUnicode& writer, Array<SerializedMaterialParam>& parameters)
{
int32 constantsOffset = 0;
int32 paddingIndex = 0;
for (int32 i = 0; i < parameters.Count(); i++)
{
auto& param = parameters[i];
const Char* format = nullptr;
int32 size;
int32 alignment;
switch (param.Type)
{
case MaterialParameterType::Bool:
size = 4;
alignment = 4;
format = TEXT("bool {0};");
break;
case MaterialParameterType::Integer:
size = 4;
alignment = 4;
format = TEXT("int {0};");
break;
case MaterialParameterType::Float:
size = 4;
alignment = 4;
format = TEXT("float {0};");
break;
case MaterialParameterType::Vector2:
size = 8;
alignment = 8;
format = TEXT("float2 {0};");
break;
case MaterialParameterType::Vector3:
size = 12;
alignment = 16;
format = TEXT("float3 {0};");
break;
case MaterialParameterType::Vector4:
case MaterialParameterType::ChannelMask:
case MaterialParameterType::Color:
size = 16;
alignment = 16;
format = TEXT("float4 {0};");
break;
case MaterialParameterType::Matrix:
size = 16 * 4;
alignment = 16;
format = TEXT("float4x4 {0};");
break;
case MaterialParameterType::GameplayGlobal:
{
auto asset = Content::LoadAsync<GameplayGlobals>(param.AsGuid);
if (!asset || asset->WaitForLoaded())
break;
GameplayGlobals::Variable variable;
if (!asset->Variables.TryGet(param.Name, variable))
break;
switch (variable.DefaultValue.Type.Type)
{
case VariantType::Bool:
size = 4;
alignment = 4;
format = TEXT("bool {0};");
break;
case VariantType::Int:
size = 4;
alignment = 4;
format = TEXT("int {0};");
break;
case VariantType::Uint:
size = 4;
alignment = 4;
format = TEXT("uint {0};");
break;
case VariantType::Float:
size = 4;
alignment = 4;
format = TEXT("float {0};");
break;
case VariantType::Vector2:
size = 8;
alignment = 8;
format = TEXT("float2 {0};");
break;
case VariantType::Vector3:
size = 12;
alignment = 16;
format = TEXT("float3 {0};");
break;
case VariantType::Vector4:
case VariantType::Color:
size = 16;
alignment = 16;
format = TEXT("float4 {0};");
break;
default: ;
}
break;
}
default: ;
}
if (format)
{
int32 padding = Math::Abs((alignment - (constantsOffset % 16))) % alignment;
if (padding != 0)
{
constantsOffset += padding;
padding /= 4;
while (padding-- > 0)
{
writer.WriteLine(TEXT("uint PADDING_{0};"), paddingIndex++);
}
}
param.RegisterIndex = 0;
param.Offset = constantsOffset;
writer.WriteLine(format, param.ShaderName);
constantsOffset += size;
}
}
}
const Char* ShaderGraphUtilities::GenerateShaderResources(TextWriterUnicode& writer, Array<SerializedMaterialParam>& parameters, int32 startRegister)
{
int32 registerIndex = startRegister;
for (int32 i = 0; i < parameters.Count(); i++)
{
auto& param = parameters[i];
const Char* format;
switch (param.Type)
{
case MaterialParameterType::NormalMap:
case MaterialParameterType::GPUTexture:
case MaterialParameterType::SceneTexture:
case MaterialParameterType::Texture:
format = TEXT("Texture2D {0} : register(t{1});");
break;
case MaterialParameterType::GPUTextureCube:
case MaterialParameterType::CubeTexture:
format = TEXT("TextureCube {0} : register(t{1});");
break;
case MaterialParameterType::GPUTextureArray:
format = TEXT("Texture2DArray {0} : register(t{1});");
break;
case MaterialParameterType::GPUTextureVolume:
format = TEXT("Texture3D {0} : register(t{1});");
break;
default:
format = nullptr;
break;
}
if (format)
{
param.Offset = 0;
param.RegisterIndex = registerIndex;
writer.WriteLine(format, param.ShaderName, static_cast<int32>(registerIndex));
registerIndex++;
// Validate Shader Resource count limit
if (param.RegisterIndex >= GPU_MAX_SR_BINDED)
{
return TEXT("Too many textures used. The maximum supported amount is " MACRO_TO_STR(GPU_MAX_SR_BINDED) " (including lightmaps and utility textures for lighting).");
}
}
}
return nullptr;
}
template<typename T>
const Char* GetTypename()
{
return TEXT("");
}
template<>
const Char* GetTypename<float>()
{
return TEXT("float");
}
template<>
const Char* GetTypename<Vector2>()
{
return TEXT("float2");
}
template<>
const Char* GetTypename<Vector3>()
{
return TEXT("float3");
}
template<>
const Char* GetTypename<Vector4>()
{
return TEXT("float4");
}
template<typename T>
void ShaderGraphUtilities::SampleCurve(TextWriterUnicode& writer, const BezierCurve<T>& curve, const String& time, const String& value)
{
const auto& keyframes = curve.GetKeyframes();
if (keyframes.Count() == 0)
{
writer.Write(
TEXT(
" {{\n"
" // Curve ({1})\n"
" {0} = 0;\n"
" }}\n"
),
value, // {0}
GetTypename<T>() // {1}
);
}
else if (keyframes.Count() == 1)
{
writer.Write(
TEXT(
" {{\n"
" // Curve ({1})\n"
" {0} = {2};\n"
" }}\n"
),
value, // {0}
GetTypename<T>(), // {1}
ShaderGraphValue(keyframes[0].Value).Value // {2}
);
}
else if (keyframes.Count() == 2)
{
writer.Write(
TEXT(
" {{\n"
" // Curve ({4})\n"
" const float leftTime = {3};\n"
" const float rightTime = {5};\n"
" const float lengthTime = rightTime - leftTime;\n"
" float time = clamp({0}, leftTime, rightTime);\n"
" float alpha = lengthTime < 0.0000001 ? 0.0f : (time - leftTime) / lengthTime;\n"
" const {4} leftValue = {6};\n"
" const {4} rightValue = {7};\n"
" const float oneThird = 1.0f / 3.0f;\n"
" {4} leftTangent = leftValue + {8} * (lengthTime * oneThird);\n"
" {4} rightTangent = rightValue + {1} * (lengthTime * oneThird);\n"
" {4} p01 = lerp(leftValue, leftTangent, alpha);\n"
" {4} p12 = lerp(leftTangent, rightTangent, alpha);\n"
" {4} p23 = lerp(rightTangent, rightValue, alpha);\n"
" {4} p012 = lerp(p01, p12, alpha);\n"
" {4} p123 = lerp(p12, p23, alpha);\n"
" {2} = lerp(p012, p123, alpha);\n"
" }}\n"
),
time, // {0}
ShaderGraphValue(keyframes[1].TangentIn).Value, // {1}
value, // {2}
StringUtils::ToString(keyframes[0].Time), // {3}
GetTypename<T>(), // {4}
StringUtils::ToString(keyframes[1].Time), // {5}
ShaderGraphValue(keyframes[0].Value).Value, // {6}
ShaderGraphValue(keyframes[1].Value).Value, // {7}
ShaderGraphValue(keyframes[0].TangentOut).Value // {8}
);
}
else
{
StringBuilder keyframesTime, keyframesValue, keyframesTangentIn, keyframesTangentOut;
for (int32 i = 0; i < keyframes.Count(); i++)
{
const auto& keyframe = keyframes[i];
if (i != 0)
{
keyframesTime.Append(',');
keyframesValue.Append(',');
keyframesTangentIn.Append(',');
keyframesTangentOut.Append(',');
}
keyframesTime.Append(StringUtils::ToString(keyframe.Time));
keyframesValue.Append(ShaderGraphValue(keyframe.Value).Value);
keyframesTangentIn.Append(ShaderGraphValue(keyframe.TangentIn).Value);
keyframesTangentOut.Append(ShaderGraphValue(keyframe.TangentOut).Value);
}
keyframesTime.Append('\0');
keyframesValue.Append('\0');
keyframesTangentIn.Append('\0');
keyframesTangentOut.Append('\0');
writer.Write(
TEXT(
" {{\n"
" // Curve ({4})\n"
" int count = {0};\n"
" float time = clamp({1}, 0.0, {2});\n"
" static float keyframesTime[] = {{ {5} }};\n"
" static {4} keyframesValue[] = {{ {6} }};\n"
" static {4} keyframesTangentIn[] = {{ {7} }};\n"
" static {4} keyframesTangentOut[] = {{ {8} }};\n"
" int start = 0;\n"
" int searchLength = count;\n"
" while (searchLength > 0)\n"
" {{\n"
" int halfPos = searchLength >> 1;\n"
" int midPos = start + halfPos;\n"
" if (time < keyframesTime[midPos])\n"
" {{\n"
" searchLength = halfPos;\n"
" }}\n"
" else\n"
" {{\n"
" start = midPos + 1;\n"
" searchLength -= halfPos + 1;\n"
" }}\n"
" }}\n"
" int leftKey = max(0, start - 1);\n"
" int rightKey = min(start, count - 1);\n"
" const float leftTime = keyframesTime[leftKey];\n"
" const float rightTime = keyframesTime[rightKey];\n"
" const float lengthTime = rightTime - leftTime;\n"
" float alpha = lengthTime < 0.0000001 ? 0.0f : (time - leftTime) / lengthTime;\n"
" const {4} leftValue = keyframesValue[leftKey];\n"
" const {4} rightValue = keyframesValue[rightKey];\n"
" const float oneThird = 1.0f / 3.0f;\n"
" {4} leftTangent = leftValue + keyframesTangentOut[leftKey] * (lengthTime * oneThird);\n"
" {4} rightTangent = rightValue + keyframesTangentIn[rightKey] * (lengthTime * oneThird);\n"
" {4} p01 = lerp(leftValue, leftTangent, alpha);\n"
" {4} p12 = lerp(leftTangent, rightTangent, alpha);\n"
" {4} p23 = lerp(rightTangent, rightValue, alpha);\n"
" {4} p012 = lerp(p01, p12, alpha);\n"
" {4} p123 = lerp(p12, p23, alpha);\n"
" {3} = lerp(p012, p123, alpha);\n"
" }}\n"
),
keyframes.Count(), // {0}
time, // {1}
curve.GetLength(), // {2}
value, // {3}
GetTypename<T>(), // {4}
*keyframesTime, // {5}
*keyframesValue, // {6}
*keyframesTangentIn, // {7}
*keyframesTangentOut // {8}
);
}
}
template void ShaderGraphUtilities::SampleCurve(TextWriterUnicode& writer, const BezierCurve<float>& curve, const String& time, const String& value);
template void ShaderGraphUtilities::SampleCurve(TextWriterUnicode& writer, const BezierCurve<Vector2>& curve, const String& time, const String& value);
template void ShaderGraphUtilities::SampleCurve(TextWriterUnicode& writer, const BezierCurve<Vector3>& curve, const String& time, const String& value);
template void ShaderGraphUtilities::SampleCurve(TextWriterUnicode& writer, const BezierCurve<Vector4>& curve, const String& time, const String& value);
#endif