mirror of https://github.com/axmolengine/axmol.git
1186 lines
28 KiB
C++
1186 lines
28 KiB
C++
#include "ShaderGenerator.h"
|
|
#include "../Common/ShaderGeneratorCommon.h"
|
|
|
|
#include "../../Effekseer/Effekseer/Material/Effekseer.MaterialCompiler.h"
|
|
|
|
#ifdef _WIN32
|
|
#undef max
|
|
#undef min
|
|
#endif
|
|
|
|
namespace Effekseer
|
|
{
|
|
namespace DirectX
|
|
{
|
|
namespace HLSL
|
|
{
|
|
|
|
static const char* material_light_vs = R"(
|
|
float3 GetLightDirection() {
|
|
return float3(0,0,0);
|
|
}
|
|
float3 GetLightColor() {
|
|
return float3(0,0,0);
|
|
}
|
|
float3 GetLightAmbientColor() {
|
|
return float3(0,0,0);
|
|
}
|
|
)";
|
|
|
|
static const char* material_light_ps = R"(
|
|
float3 GetLightDirection() {
|
|
return lightDirection.xyz;
|
|
}
|
|
float3 GetLightColor() {
|
|
return lightColor.xyz;
|
|
}
|
|
float3 GetLightAmbientColor() {
|
|
return lightAmbientColor.xyz;
|
|
}
|
|
)";
|
|
|
|
inline std::string GetMaterialCommonDefine(ShaderGeneratorTarget type)
|
|
{
|
|
std::stringstream ss;
|
|
|
|
ss << R"(
|
|
#define MOD fmod
|
|
#define FRAC frac
|
|
#define LERP lerp
|
|
)";
|
|
if (type == ShaderGeneratorTarget::DirectX11 || type == ShaderGeneratorTarget::DirectX12)
|
|
{
|
|
ss << R"(
|
|
#define C_LINEAR linear
|
|
#define C_CENTROID centroid
|
|
)";
|
|
}
|
|
else
|
|
{
|
|
ss << R"(
|
|
#define C_LINEAR
|
|
#define C_CENTROID
|
|
)";
|
|
}
|
|
|
|
if (type == ShaderGeneratorTarget::DirectX9)
|
|
{
|
|
ss << R"(
|
|
#define POSITION0 POSITION
|
|
#define SV_POSITION POSITION
|
|
#define SV_Target COLOR
|
|
)";
|
|
}
|
|
|
|
if (type == ShaderGeneratorTarget::PSSL)
|
|
{
|
|
ss << R"(
|
|
#define SV_POSITION S_POSITION
|
|
#define cbuffer ConstantBuffer
|
|
#define SV_Target S_TARGET_OUTPUT
|
|
#define SampleLevel SampleLOD
|
|
#define SV_InstanceID S_INSTANCE_ID
|
|
)";
|
|
}
|
|
|
|
return ss.str();
|
|
}
|
|
|
|
static char* material_common_vs_functions = R"(
|
|
|
|
float2 GetUV(float2 uv)
|
|
{
|
|
uv.y = mUVInversed.x + mUVInversed.y * uv.y;
|
|
return uv;
|
|
}
|
|
|
|
float2 GetUVBack(float2 uv)
|
|
{
|
|
uv.y = mUVInversed.z + mUVInversed.w * uv.y;
|
|
return uv;
|
|
}
|
|
|
|
// Dummy
|
|
float CalcDepthFade(float2 screenUV, float meshZ, float softParticleParam) { return 1.0f; }
|
|
|
|
)";
|
|
|
|
static char* material_sprite_vs_pre_simple = R"(
|
|
|
|
struct VS_Input
|
|
{
|
|
float3 Pos : POSITION0;
|
|
float4 Color : NORMAL0;
|
|
float2 UV : TEXCOORD0;
|
|
};
|
|
|
|
struct VS_Output
|
|
{
|
|
float4 Position : SV_POSITION;
|
|
C_LINEAR C_CENTROID float4 VColor : COLOR;
|
|
C_LINEAR C_CENTROID float2 UV1 : TEXCOORD0;
|
|
C_LINEAR C_CENTROID float2 UV2 : TEXCOORD1;
|
|
float3 WorldP : TEXCOORD2;
|
|
float3 WorldN : TEXCOORD3;
|
|
float3 WorldT : TEXCOORD4;
|
|
float3 WorldB : TEXCOORD5;
|
|
float4 PosP : TEXCOORD6;
|
|
//float2 ScreenUV : TEXCOORD6;
|
|
};
|
|
|
|
cbuffer VSConstantBuffer : register(b0) {
|
|
|
|
float4x4 mCamera : register(c0);
|
|
float4x4 mProj : register(c4);
|
|
float4 mUVInversed : register(c8);
|
|
float4 predefined_uniform : register(c9);
|
|
float4 cameraPosition : register(c10);
|
|
|
|
)";
|
|
|
|
static char* material_sprite_vs_pre = R"(
|
|
|
|
struct VS_Input
|
|
{
|
|
float3 Pos : POSITION0;
|
|
float4 Color : NORMAL0;
|
|
float4 Normal : NORMAL1;
|
|
float4 Tangent : NORMAL2;
|
|
float2 UV1 : TEXCOORD0;
|
|
float2 UV2 : TEXCOORD1;
|
|
//$C_IN1$
|
|
//$C_IN2$
|
|
};
|
|
|
|
struct VS_Output
|
|
{
|
|
float4 Position : SV_POSITION;
|
|
C_LINEAR C_CENTROID float4 VColor : COLOR;
|
|
C_LINEAR C_CENTROID float2 UV1 : TEXCOORD0;
|
|
C_LINEAR C_CENTROID float2 UV2 : TEXCOORD1;
|
|
float3 WorldP : TEXCOORD2;
|
|
float3 WorldN : TEXCOORD3;
|
|
float3 WorldT : TEXCOORD4;
|
|
float3 WorldB : TEXCOORD5;
|
|
float4 PosP : TEXCOORD6;
|
|
//float2 ScreenUV : TEXCOORD6;
|
|
//$C_OUT1$
|
|
//$C_OUT2$
|
|
};
|
|
|
|
cbuffer VSConstantBuffer : register(b0) {
|
|
|
|
float4x4 mCamera : register(c0);
|
|
float4x4 mProj : register(c4);
|
|
float4 mUVInversed : register(c8);
|
|
float4 predefined_uniform : register(c9);
|
|
float4 cameraPosition : register(c10);
|
|
|
|
)";
|
|
|
|
static char* material_sprite_vs_suf1_simple = R"(
|
|
|
|
|
|
VS_Output main( const VS_Input Input )
|
|
{
|
|
VS_Output Output = (VS_Output)0;
|
|
float4 worldPos = { Input.Pos.x, Input.Pos.y, Input.Pos.z, 1.0 };
|
|
float3 worldNormal = float3(0.0, 0.0, 0.0);
|
|
float3 worldBinormal = float3(0.0, 0.0, 0.0);
|
|
float3 worldTangent = float3(0.0, 0.0, 0.0);
|
|
float3 objectScale = float3(1.0, 1.0, 1.0);
|
|
|
|
// UV
|
|
float uv1 = Input.UV;
|
|
float uv2 = Input.UV;
|
|
//uv1.y = mUVInversed.x + mUVInversed.y * uv1.y;
|
|
//uv2.y = mUVInversed.x + mUVInversed.y * uv2.y;
|
|
|
|
// NBT
|
|
Output.WorldN = worldNormal;
|
|
Output.WorldB = worldBinormal;
|
|
Output.WorldT = worldTangent;
|
|
|
|
float3 pixelNormalDir = worldNormal;
|
|
float4 vcolor = Input.Color;
|
|
|
|
// Dummy
|
|
float2 screenUV = float2(0.0, 0.0);
|
|
float meshZ = 0.0f;
|
|
)";
|
|
|
|
static char* material_sprite_vs_suf1 = R"(
|
|
|
|
VS_Output main( const VS_Input Input )
|
|
{
|
|
VS_Output Output = (VS_Output)0;
|
|
float3 worldPos = Input.Pos;
|
|
float3 worldNormal = (Input.Normal - float3(0.5, 0.5, 0.5)) * 2.0;
|
|
float3 worldTangent = (Input.Tangent - float3(0.5, 0.5, 0.5)) * 2.0;
|
|
float3 worldBinormal = cross(worldNormal, worldTangent);
|
|
float3 objectScale = float3(1.0, 1.0, 1.0);
|
|
|
|
// UV
|
|
float2 uv1 = Input.UV1;
|
|
float2 uv2 = Input.UV2;
|
|
//uv1.y = mUVInversed.x + mUVInversed.y * uv1.y;
|
|
//uv2.y = mUVInversed.x + mUVInversed.y * uv2.y;
|
|
|
|
// NBT
|
|
Output.WorldN = worldNormal;
|
|
Output.WorldB = worldBinormal;
|
|
Output.WorldT = worldTangent;
|
|
|
|
float3 pixelNormalDir = worldNormal;
|
|
float4 vcolor = Input.Color;
|
|
|
|
// Dummy
|
|
float2 screenUV = float2(0.0, 0.0);
|
|
float meshZ = 0.0f;
|
|
)";
|
|
|
|
static char* material_sprite_vs_suf2 = R"(
|
|
|
|
worldPos = worldPos + worldPositionOffset;
|
|
|
|
float4 cameraPos = mul(mCamera, float4(worldPos, 1.0));
|
|
cameraPos = cameraPos / cameraPos.w;
|
|
Output.Position = mul(mProj, cameraPos);
|
|
|
|
Output.WorldP = worldPos;
|
|
Output.VColor = Input.Color;
|
|
Output.UV1 = uv1;
|
|
Output.UV2 = uv2;
|
|
|
|
Output.PosP = Output.Position;
|
|
//Output.ScreenUV = Output.Position.xy / Output.Position.w;
|
|
//Output.ScreenUV.xy = float2(Output.ScreenUV.x + 1.0, 1.0 - Output.ScreenUV.y) * 0.5;
|
|
|
|
return Output;
|
|
}
|
|
|
|
)";
|
|
|
|
inline std::string GetModelVS_Pre(ShaderGeneratorTarget type)
|
|
{
|
|
std::stringstream ss;
|
|
|
|
ss << R"(
|
|
struct VS_Input
|
|
{
|
|
float3 Pos : POSITION0;
|
|
float3 Normal : NORMAL0;
|
|
float3 Binormal : NORMAL1;
|
|
float3 Tangent : NORMAL2;
|
|
float2 UV : TEXCOORD0;
|
|
float4 Color : NORMAL3;
|
|
)";
|
|
|
|
if (type == ShaderGeneratorTarget::DirectX9)
|
|
{
|
|
ss << R"(
|
|
float Index : BLENDINDICES0;
|
|
)";
|
|
}
|
|
else
|
|
{
|
|
ss << R"(
|
|
uint Index : SV_InstanceID;
|
|
)";
|
|
}
|
|
|
|
ss << R"(
|
|
};
|
|
|
|
struct VS_Output
|
|
{
|
|
float4 Position : SV_POSITION;
|
|
C_LINEAR C_CENTROID float4 VColor : COLOR;
|
|
C_LINEAR C_CENTROID float2 UV1 : TEXCOORD0;
|
|
C_LINEAR C_CENTROID float2 UV2 : TEXCOORD1;
|
|
float3 WorldP : TEXCOORD2;
|
|
float3 WorldN : TEXCOORD3;
|
|
float3 WorldT : TEXCOORD4;
|
|
float3 WorldB : TEXCOORD5;
|
|
float4 PosP : TEXCOORD6;
|
|
//float2 ScreenUV : TEXCOORD6;
|
|
//$C_OUT1$
|
|
//$C_OUT2$
|
|
};
|
|
|
|
cbuffer VSConstantBuffer : register(b0) {
|
|
)";
|
|
|
|
if (type == ShaderGeneratorTarget::DirectX9)
|
|
{
|
|
ss << R"(
|
|
float4x4 mCameraProj : register( c0 );
|
|
float4x4 mModel[10] : register( c4 );
|
|
float4 fUV[10] : register( c44 );
|
|
float4 fModelColor[10] : register( c54 );
|
|
|
|
float4 mUVInversed : register(c64);
|
|
float4 predefined_uniform : register(c65);
|
|
float4 cameraPosition : register(c66);
|
|
)";
|
|
}
|
|
else
|
|
{
|
|
ss << R"(
|
|
float4x4 mCameraProj : register( c0 );
|
|
float4x4 mModel[40] : register( c4 );
|
|
float4 fUV[40] : register( c164 );
|
|
float4 fModelColor[40] : register( c204 );
|
|
|
|
float4 mUVInversed : register(c244);
|
|
float4 predefined_uniform : register(c245);
|
|
float4 cameraPosition : register(c246);
|
|
)";
|
|
}
|
|
|
|
ss << R"(
|
|
// custom1
|
|
// custom2
|
|
)";
|
|
return ss.str();
|
|
}
|
|
|
|
static char* model_vs_suf1 = R"(
|
|
|
|
VS_Output main( const VS_Input Input )
|
|
{
|
|
float4x4 matModel = mModel[Input.Index];
|
|
float4 uv = fUV[Input.Index];
|
|
float4 modelColor = fModelColor[Input.Index] * Input.Color;
|
|
|
|
VS_Output Output = (VS_Output)0;
|
|
float4 localPosition = { Input.Pos.x, Input.Pos.y, Input.Pos.z, 1.0 };
|
|
|
|
float3x3 matRotModel = (float3x3)matModel;
|
|
|
|
float3 worldPos = mul( matModel, localPosition ).xyz;
|
|
float3 worldNormal = normalize( mul( matRotModel, Input.Normal ) );
|
|
float3 worldBinormal = normalize( mul( matRotModel, Input.Binormal ) );
|
|
float3 worldTangent = normalize( mul( matRotModel, Input.Tangent ) );
|
|
float3 objectScale = float3(1.0, 1.0, 1.0);
|
|
|
|
// Calculate ObjectScale
|
|
objectScale.x = length(mul(matRotModel, float3(1.0, 0.0, 0.0)));
|
|
objectScale.y = length(mul(matRotModel, float3(0.0, 1.0, 0.0)));
|
|
objectScale.z = length(mul(matRotModel, float3(0.0, 0.0, 1.0)));
|
|
|
|
float2 uv1;
|
|
uv1.x = Input.UV.x * uv.z + uv.x;
|
|
uv1.y = Input.UV.y * uv.w + uv.y;
|
|
float2 uv2 = Input.UV;
|
|
|
|
//uv1.y = mUVInversed.x + mUVInversed.y * uv1.y;
|
|
//uv2.y = mUVInversed.x + mUVInversed.y * uv2.y;
|
|
|
|
float3 pixelNormalDir = worldNormal;
|
|
float4 vcolor = modelColor;
|
|
|
|
// Dummy
|
|
float2 screenUV = float2(0.0, 0.0);
|
|
float meshZ = 0.0f;
|
|
)";
|
|
|
|
static char* model_vs_suf2 = R"(
|
|
|
|
worldPos = worldPos + worldPositionOffset;
|
|
|
|
Output.Position = mul( mCameraProj, float4(worldPos, 1.0) );
|
|
|
|
Output.WorldP = worldPos;
|
|
Output.WorldN = worldNormal;
|
|
Output.WorldB = worldBinormal;
|
|
Output.WorldT = worldTangent;
|
|
|
|
Output.VColor = modelColor;
|
|
Output.UV1 = uv1;
|
|
Output.UV2 = uv2;
|
|
|
|
Output.PosP = Output.Position;
|
|
//Output.ScreenUV = Output.Position.xy / Output.Position.w;
|
|
//Output.ScreenUV.xy = float2(Output.ScreenUV.x + 1.0, 1.0 - Output.ScreenUV.y) * 0.5;
|
|
|
|
return Output;
|
|
}
|
|
|
|
)";
|
|
|
|
inline std::string GetMaterialPS_Pre(ShaderGeneratorTarget type)
|
|
{
|
|
std::stringstream ss;
|
|
|
|
ss << R"(
|
|
struct PS_Input
|
|
{
|
|
)";
|
|
|
|
if (type != ShaderGeneratorTarget::DirectX9)
|
|
{
|
|
ss << R"(
|
|
float4 Position : SV_POSITION;
|
|
)";
|
|
}
|
|
|
|
ss << R"(
|
|
C_LINEAR C_CENTROID float4 VColor : COLOR;
|
|
C_LINEAR C_CENTROID float2 UV1 : TEXCOORD0;
|
|
C_LINEAR C_CENTROID float2 UV2 : TEXCOORD1;
|
|
float3 WorldP : TEXCOORD2;
|
|
float3 WorldN : TEXCOORD3;
|
|
float3 WorldT : TEXCOORD4;
|
|
float3 WorldB : TEXCOORD5;
|
|
float4 PosP : TEXCOORD6;
|
|
//float2 ScreenUV : TEXCOORD6;
|
|
//$C_PIN1$
|
|
//$C_PIN2$
|
|
};
|
|
)";
|
|
|
|
if (type == ShaderGeneratorTarget::DirectX9 || type == ShaderGeneratorTarget::DirectX11 || type == ShaderGeneratorTarget::PSSL)
|
|
{
|
|
ss << R"(
|
|
cbuffer PSConstantBuffer : register(b0) {
|
|
)";
|
|
}
|
|
else
|
|
{
|
|
ss << R"(
|
|
cbuffer PSConstantBuffer : register(b1) {
|
|
)";
|
|
}
|
|
|
|
return ss.str();
|
|
}
|
|
|
|
inline std::string GetMaterialPS_Suf1(ShaderGeneratorTarget type)
|
|
{
|
|
std::stringstream ss;
|
|
|
|
ss << R"(
|
|
|
|
float2 GetUV(float2 uv)
|
|
{
|
|
uv.y = mUVInversedBack.x + mUVInversedBack.y * uv.y;
|
|
return uv;
|
|
}
|
|
|
|
float2 GetUVBack(float2 uv)
|
|
{
|
|
uv.y = mUVInversedBack.z + mUVInversedBack.w * uv.y;
|
|
return uv;
|
|
}
|
|
|
|
float CalcDepthFade(float2 screenUV, float meshZ, float softParticleParam)
|
|
{
|
|
)";
|
|
|
|
if (type == ShaderGeneratorTarget::DirectX9)
|
|
{
|
|
ss << R"(
|
|
float backgroundZ = tex2D(efk_depth_sampler, GetUVBack(screenUV)).x;
|
|
)";
|
|
}
|
|
else
|
|
{
|
|
ss << R"(
|
|
float backgroundZ = efk_depth_texture.Sample(efk_depth_sampler, GetUVBack(screenUV)).x;
|
|
)";
|
|
}
|
|
|
|
ss << R"(
|
|
float distance = softParticleParam * predefined_uniform.y;
|
|
float2 rescale = reconstructionParam1.xy;
|
|
float4 params = reconstructionParam2;
|
|
|
|
float2 zs = float2(backgroundZ * rescale.x + rescale.y, meshZ);
|
|
|
|
float2 depth = (zs * params.w - params.y) / (params.x - zs * params.z);
|
|
float dir = sign(depth.x);
|
|
depth *= dir;
|
|
return min(max((depth.x - depth.y) / distance, 0.0), 1.0);
|
|
}
|
|
|
|
|
|
#ifdef _MATERIAL_LIT_
|
|
|
|
#define lightScale 3.14
|
|
|
|
float calcD_GGX(float roughness, float dotNH)
|
|
{
|
|
float alpha = roughness*roughness;
|
|
float alphaSqr = alpha*alpha;
|
|
float pi = 3.14159;
|
|
float denom = dotNH * dotNH *(alphaSqr-1.0) + 1.0;
|
|
return (alpha / denom) * (alpha / denom) / pi;
|
|
}
|
|
|
|
float calcF(float F0, float dotLH)
|
|
{
|
|
float dotLH5 = pow(1.0-dotLH,5.0);
|
|
return F0 + (1.0-F0)*(dotLH5);
|
|
}
|
|
|
|
float calcG_Schlick(float roughness, float dotNV, float dotNL)
|
|
{
|
|
// UE4
|
|
float k = (roughness + 1.0) * (roughness + 1.0) / 8.0;
|
|
// float k = roughness * roughness / 2.0;
|
|
|
|
float gV = dotNV*(1.0 - k) + k;
|
|
float gL = dotNL*(1.0 - k) + k;
|
|
|
|
return 1.0 / (gV * gL);
|
|
}
|
|
|
|
float calcLightingGGX(float3 N, float3 V, float3 L, float roughness, float F0)
|
|
{
|
|
float3 H = normalize(V+L);
|
|
|
|
float dotNL = saturate( dot(N,L) );
|
|
float dotLH = saturate( dot(L,H) );
|
|
float dotNH = saturate( dot(N,H) ) - 0.001;
|
|
float dotNV = saturate( dot(N,V) ) + 0.001;
|
|
|
|
float D = calcD_GGX(roughness, dotNH);
|
|
float F = calcF(F0, dotLH);
|
|
float G = calcG_Schlick(roughness, dotNV, dotNL);
|
|
|
|
return dotNL * D * F * G / 4.0;
|
|
}
|
|
|
|
float3 calcDirectionalLightDiffuseColor(float3 diffuseColor, float3 normal, float3 lightDir, float ao)
|
|
{
|
|
float3 color = float3(0.0,0.0,0.0);
|
|
|
|
float NoL = dot(normal,lightDir);
|
|
color.xyz = lightColor.xyz * lightScale * max(NoL,0.0) * ao / 3.14;
|
|
color.xyz = color.xyz * diffuseColor.xyz;
|
|
return color;
|
|
}
|
|
|
|
#endif
|
|
|
|
float4 main( const PS_Input Input ) : SV_Target
|
|
{
|
|
float2 uv1 = Input.UV1;
|
|
float2 uv2 = Input.UV2;
|
|
float3 worldPos = Input.WorldP;
|
|
float3 worldNormal = Input.WorldN;
|
|
float3 worldBinormal = Input.WorldB;
|
|
float3 worldTangent = Input.WorldT;
|
|
float3 objectScale = float3(1.0, 1.0, 1.0);
|
|
|
|
float3 pixelNormalDir = worldNormal;
|
|
float4 vcolor = Input.VColor;
|
|
|
|
float2 screenUV = Input.PosP.xy / Input.PosP.w;
|
|
float meshZ = Input.PosP.z / Input.PosP.w;
|
|
screenUV.xy = float2(screenUV.x + 1.0, 1.0 - screenUV.y) * 0.5;
|
|
)";
|
|
|
|
return ss.str();
|
|
}
|
|
|
|
static char* g_material_ps_suf2_unlit = R"(
|
|
|
|
float4 Output = float4(emissive, opacity);
|
|
|
|
if(opacityMask <= 0.0f) discard;
|
|
if(opacity <= 0.0) discard;
|
|
|
|
return ConvertToScreen(Output);
|
|
}
|
|
|
|
)";
|
|
|
|
static char* g_material_ps_suf2_lit = R"(
|
|
float3 viewDir = normalize(cameraPosition.xyz - worldPos);
|
|
float3 diffuse = calcDirectionalLightDiffuseColor(baseColor, pixelNormalDir, lightDirection.xyz, ambientOcclusion);
|
|
float3 specular = lightColor.xyz * lightScale * calcLightingGGX(pixelNormalDir, viewDir, lightDirection.xyz, roughness, 0.9);
|
|
|
|
float4 Output = float4(metallic * specular + (1.0 - metallic) * diffuse + baseColor * lightAmbientColor.xyz * ambientOcclusion, opacity);
|
|
Output.xyz = Output.xyz + emissive.xyz;
|
|
|
|
if(opacityMask <= 0.0) discard;
|
|
if(opacity <= 0.0) discard;
|
|
|
|
return ConvertToScreen(Output);
|
|
}
|
|
|
|
)";
|
|
|
|
inline std::string GetMaterialPS_Suf2_Refraction(ShaderGeneratorTarget type)
|
|
{
|
|
std::stringstream ss;
|
|
|
|
ss << R"(
|
|
|
|
float airRefraction = 1.0;
|
|
float3 dir = mul((float3x3)cameraMat, pixelNormalDir);
|
|
dir.y = -dir.y;
|
|
|
|
float2 distortUV = dir.xy * (refraction - airRefraction);
|
|
|
|
distortUV += screenUV;
|
|
distortUV = GetUVBack(distortUV);
|
|
|
|
)";
|
|
|
|
if (type == ShaderGeneratorTarget::DirectX9)
|
|
{
|
|
ss << R"(
|
|
float4 bg = tex2D(efk_background_sampler, distortUV);
|
|
)";
|
|
}
|
|
else
|
|
{
|
|
ss << R"(
|
|
float4 bg = efk_background_texture.Sample(efk_background_sampler, distortUV);
|
|
)";
|
|
}
|
|
|
|
ss << R"(
|
|
float4 Output = bg;
|
|
|
|
if(opacityMask <= 0.0) discard;
|
|
if(opacity <= 0.0) discard;
|
|
|
|
return Output;
|
|
}
|
|
|
|
)";
|
|
|
|
return ss.str();
|
|
}
|
|
|
|
} // namespace HLSL
|
|
|
|
std::string ShaderGenerator::Replace(std::string target, std::string from_, std::string to_)
|
|
{
|
|
std::string::size_type Pos(target.find(from_));
|
|
|
|
while (Pos != std::string::npos)
|
|
{
|
|
target.replace(Pos, from_.length(), to_);
|
|
Pos = target.find(from_, Pos + to_.length());
|
|
}
|
|
|
|
return target;
|
|
}
|
|
|
|
std::string ShaderGenerator::GetType(int32_t i)
|
|
{
|
|
if (i == 1)
|
|
return "float";
|
|
if (i == 2)
|
|
return "float2";
|
|
if (i == 3)
|
|
return "float3";
|
|
if (i == 4)
|
|
return "float4";
|
|
if (i == 16)
|
|
return "float4x4";
|
|
assert(0);
|
|
return "";
|
|
}
|
|
|
|
std::string ShaderGenerator::GetElement(int32_t i)
|
|
{
|
|
if (i == 1)
|
|
return ".x";
|
|
if (i == 2)
|
|
return ".xy";
|
|
if (i == 3)
|
|
return ".xyz";
|
|
if (i == 4)
|
|
return ".xyzw";
|
|
assert(0);
|
|
return "";
|
|
}
|
|
|
|
void ShaderGenerator::ExportUniform(std::ostringstream& maincode, int32_t type, const char* name, int32_t registerId)
|
|
{
|
|
maincode << GetType(type) << " " << name << " : register(c" << registerId << ");" << std::endl;
|
|
}
|
|
|
|
void ShaderGenerator::ExportTexture(std::ostringstream& maincode, const char* name, int32_t registerId)
|
|
{
|
|
maincode << "Texture2D " << name << "_texture : register(t" << registerId << ");" << std::endl;
|
|
|
|
if (target_ == ShaderGeneratorTarget::DirectX9)
|
|
{
|
|
maincode << "sampler2D " << name << "_sampler : register(s" << registerId << ");" << std::endl;
|
|
}
|
|
else
|
|
{
|
|
maincode << "SamplerState " << name << "_sampler : register(s" << registerId << ");" << std::endl;
|
|
}
|
|
}
|
|
|
|
int32_t ShaderGenerator::ExportHeader(std::ostringstream& maincode, MaterialFile* materialFile, int stage, bool isSprite, int instanceCount)
|
|
{
|
|
auto cind = 0;
|
|
|
|
maincode << common_define_;
|
|
|
|
// gradient
|
|
bool hasGradient = false;
|
|
bool hasNoise = false;
|
|
|
|
for (const auto& type : materialFile->RequiredMethods)
|
|
{
|
|
if (type == MaterialFile::RequiredPredefinedMethodType::Gradient)
|
|
{
|
|
hasGradient = true;
|
|
}
|
|
else if (type == MaterialFile::RequiredPredefinedMethodType::Noise)
|
|
{
|
|
hasNoise = true;
|
|
}
|
|
}
|
|
|
|
if (hasGradient)
|
|
{
|
|
maincode << Effekseer::Shader::GetGradientFunctions();
|
|
}
|
|
|
|
if (hasNoise)
|
|
{
|
|
maincode << Effekseer::Shader::GetNoiseFunctions();
|
|
}
|
|
|
|
for (const auto& gradient : materialFile->FixedGradients)
|
|
{
|
|
maincode << Effekseer::Shader::GetFixedGradient(gradient.Name.c_str(), gradient.Data);
|
|
}
|
|
|
|
if (stage == 0)
|
|
{
|
|
if (isSprite)
|
|
{
|
|
if (materialFile->GetIsSimpleVertex())
|
|
{
|
|
maincode << sprite_vs_pre_simple_;
|
|
}
|
|
else
|
|
{
|
|
maincode << sprite_vs_pre_;
|
|
}
|
|
cind = 11;
|
|
}
|
|
else
|
|
{
|
|
maincode << model_vs_pre_;
|
|
cind = 7 + instanceCount * 6;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
maincode << ps_pre_;
|
|
cind = 2;
|
|
}
|
|
|
|
return cind;
|
|
}
|
|
|
|
void ShaderGenerator::ExportMain(std::ostringstream& maincode,
|
|
MaterialFile* materialFile,
|
|
int stage,
|
|
bool isSprite,
|
|
MaterialShaderType shaderType,
|
|
const std::string& baseCode)
|
|
{
|
|
if (stage == 0)
|
|
{
|
|
if (isSprite)
|
|
{
|
|
if (materialFile->GetIsSimpleVertex())
|
|
{
|
|
maincode << sprite_vs_suf1_simple_;
|
|
}
|
|
else
|
|
{
|
|
maincode << sprite_vs_suf1_;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
maincode << model_vs_suf1_;
|
|
}
|
|
|
|
if (materialFile->GetCustomData1Count() > 0)
|
|
{
|
|
if (isSprite)
|
|
{
|
|
maincode << GetType(materialFile->GetCustomData1Count()) + " customData1 = Input.CustomData1;\n";
|
|
}
|
|
else
|
|
{
|
|
maincode << GetType(materialFile->GetCustomData1Count()) + " customData1 = customData1_[Input.Index];\n";
|
|
}
|
|
maincode << "Output.CustomData1 = customData1" + GetElement(materialFile->GetCustomData1Count()) + ";\n";
|
|
}
|
|
|
|
if (materialFile->GetCustomData2Count() > 0)
|
|
{
|
|
if (isSprite)
|
|
{
|
|
maincode << GetType(materialFile->GetCustomData2Count()) + " customData2 = Input.CustomData2;\n";
|
|
}
|
|
else
|
|
{
|
|
maincode << GetType(materialFile->GetCustomData2Count()) + " customData2 = customData2_[Input.Index];\n";
|
|
}
|
|
maincode << "Output.CustomData2 = customData2" + GetElement(materialFile->GetCustomData2Count()) + ";\n";
|
|
}
|
|
}
|
|
else
|
|
{
|
|
maincode << ps_suf1_;
|
|
|
|
if (materialFile->GetCustomData1Count() > 0)
|
|
{
|
|
maincode << GetType(materialFile->GetCustomData1Count()) + " customData1 = Input.CustomData1;\n";
|
|
}
|
|
|
|
if (materialFile->GetCustomData2Count() > 0)
|
|
{
|
|
maincode << GetType(materialFile->GetCustomData2Count()) + " customData2 = Input.CustomData2;\n";
|
|
}
|
|
}
|
|
|
|
maincode << baseCode;
|
|
|
|
if (stage == 0)
|
|
{
|
|
if (isSprite)
|
|
{
|
|
maincode << sprite_vs_suf2_;
|
|
}
|
|
else
|
|
{
|
|
maincode << model_vs_suf2_;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (shaderType == MaterialShaderType::Refraction || shaderType == MaterialShaderType::RefractionModel)
|
|
{
|
|
maincode << ps_suf2_refraction_;
|
|
}
|
|
else
|
|
{
|
|
if (materialFile->GetShadingModel() == Effekseer::ShadingModelType::Lit)
|
|
{
|
|
maincode << ps_suf2_lit_;
|
|
}
|
|
else if (materialFile->GetShadingModel() == Effekseer::ShadingModelType::Unlit)
|
|
{
|
|
maincode << ps_suf2_unlit_;
|
|
}
|
|
else
|
|
{
|
|
assert(0);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
ShaderGenerator::ShaderGenerator(
|
|
ShaderGeneratorTarget target)
|
|
: common_define_(HLSL::GetMaterialCommonDefine(target).c_str())
|
|
, common_vs_define_(HLSL::material_common_vs_functions)
|
|
, sprite_vs_pre_(HLSL::material_sprite_vs_pre)
|
|
, sprite_vs_pre_simple_(HLSL::material_sprite_vs_pre_simple)
|
|
, model_vs_pre_(HLSL::GetModelVS_Pre(target).c_str())
|
|
, sprite_vs_suf1_(HLSL::material_sprite_vs_suf1)
|
|
, sprite_vs_suf1_simple_(HLSL::material_sprite_vs_suf1_simple)
|
|
, model_vs_suf1_(HLSL::model_vs_suf1)
|
|
, sprite_vs_suf2_(HLSL::material_sprite_vs_suf2)
|
|
, model_vs_suf2_(HLSL::model_vs_suf2)
|
|
, ps_pre_(HLSL::GetMaterialPS_Pre(target).c_str())
|
|
, ps_suf1_(HLSL::GetMaterialPS_Suf1(target).c_str())
|
|
, ps_suf2_lit_(HLSL::g_material_ps_suf2_lit)
|
|
, ps_suf2_unlit_(HLSL::g_material_ps_suf2_unlit)
|
|
, ps_suf2_refraction_(HLSL::GetMaterialPS_Suf2_Refraction(target).c_str())
|
|
, target_(target)
|
|
{
|
|
}
|
|
|
|
ShaderData ShaderGenerator::GenerateShader(MaterialFile* materialFile,
|
|
MaterialShaderType shaderType,
|
|
int32_t maximumUniformCount,
|
|
int32_t maximumTextureCount,
|
|
int32_t pixelShaderTextureSlotOffset,
|
|
int32_t instanceCount)
|
|
{
|
|
ShaderData shaderData;
|
|
|
|
bool isSprite = shaderType == MaterialShaderType::Standard || shaderType == MaterialShaderType::Refraction;
|
|
bool isRefrection = materialFile->GetHasRefraction() &&
|
|
(shaderType == MaterialShaderType::Refraction || shaderType == MaterialShaderType::RefractionModel);
|
|
|
|
for (int stage = 0; stage < 2; stage++)
|
|
{
|
|
std::ostringstream maincode;
|
|
|
|
auto cind = ExportHeader(maincode, materialFile, stage, isSprite, instanceCount);
|
|
|
|
if (stage == 1)
|
|
{
|
|
ExportUniform(maincode, 4, "mUVInversedBack", 0);
|
|
ExportUniform(maincode, 4, "predefined_uniform", 1);
|
|
ExportUniform(maincode, 4, "cameraPosition", cind + 0);
|
|
ExportUniform(maincode, 4, "reconstructionParam1", cind + 1);
|
|
ExportUniform(maincode, 4, "reconstructionParam2", cind + 2);
|
|
cind += 3;
|
|
}
|
|
|
|
if (stage == 1)
|
|
{
|
|
ExportUniform(maincode, 4, "lightDirection", cind);
|
|
cind++;
|
|
ExportUniform(maincode, 4, "lightColor", cind);
|
|
cind++;
|
|
ExportUniform(maincode, 4, "lightAmbientColor", cind);
|
|
cind++;
|
|
}
|
|
|
|
if (materialFile->GetShadingModel() == ::Effekseer::ShadingModelType::Lit && stage == 1)
|
|
{
|
|
maincode << "#define _MATERIAL_LIT_ 1" << std::endl;
|
|
}
|
|
else if (materialFile->GetShadingModel() == ::Effekseer::ShadingModelType::Unlit)
|
|
{
|
|
}
|
|
|
|
if (isRefrection && stage == 1)
|
|
{
|
|
ExportUniform(maincode, 16, "cameraMat", cind);
|
|
cind += 4;
|
|
}
|
|
|
|
if (!isSprite && stage == 0)
|
|
{
|
|
if (materialFile->GetCustomData1Count() > 0)
|
|
{
|
|
maincode << "float4 customData1_[" << instanceCount << "]"
|
|
<< " : register(c" << cind << ");" << std::endl;
|
|
cind += instanceCount;
|
|
}
|
|
if (materialFile->GetCustomData2Count() > 0)
|
|
{
|
|
maincode << "float4 customData2_[" << instanceCount << "]"
|
|
<< " : register(c" << cind << ");" << std::endl;
|
|
cind += instanceCount;
|
|
}
|
|
}
|
|
|
|
int32_t actualUniformCount = std::min(maximumUniformCount, materialFile->GetUniformCount());
|
|
|
|
for (int32_t i = 0; i < actualUniformCount; i++)
|
|
{
|
|
ExportUniform(maincode, 4, materialFile->GetUniformName(i), cind);
|
|
cind++;
|
|
}
|
|
|
|
for (size_t i = 0; i < materialFile->Gradients.size(); i++)
|
|
{
|
|
// TODO : remove a magic number
|
|
for (size_t j = 0; j < 13; j++)
|
|
{
|
|
ExportUniform(maincode, 4, (materialFile->Gradients[i].Name + "_" + std::to_string(j)).c_str(), cind);
|
|
cind++;
|
|
}
|
|
}
|
|
|
|
// finish constant buffer
|
|
maincode << "};" << std::endl;
|
|
|
|
for (int32_t i = actualUniformCount; i < materialFile->GetUniformCount(); i++)
|
|
{
|
|
maincode << "const " << GetType(4) << " " << materialFile->GetUniformName(i) << " = float4(0,0,0,0);" << std::endl;
|
|
}
|
|
|
|
int32_t textureSlotOffset = 0;
|
|
|
|
if (stage == 1)
|
|
{
|
|
textureSlotOffset = pixelShaderTextureSlotOffset;
|
|
}
|
|
|
|
int32_t actualTextureCount = std::min(maximumTextureCount, materialFile->GetTextureCount());
|
|
|
|
for (int32_t i = 0; i < actualTextureCount; i++)
|
|
{
|
|
ExportTexture(maincode, materialFile->GetTextureName(i), i + textureSlotOffset);
|
|
}
|
|
|
|
textureSlotOffset += actualTextureCount;
|
|
|
|
// background
|
|
ExportTexture(maincode, "efk_background", 0 + textureSlotOffset);
|
|
|
|
// depth
|
|
ExportTexture(maincode, "efk_depth", 1 + textureSlotOffset);
|
|
|
|
if (std::find(materialFile->RequiredMethods.begin(), materialFile->RequiredMethods.end(), MaterialFile::RequiredPredefinedMethodType::Light) != materialFile->RequiredMethods.end())
|
|
{
|
|
if (stage == 0)
|
|
{
|
|
maincode << HLSL::material_light_vs;
|
|
}
|
|
else
|
|
{
|
|
maincode << HLSL::material_light_ps;
|
|
}
|
|
}
|
|
|
|
auto baseCode = std::string(materialFile->GetGenericCode());
|
|
baseCode = Replace(baseCode, "$F1$", "float");
|
|
baseCode = Replace(baseCode, "$F2$", "float2");
|
|
baseCode = Replace(baseCode, "$F3$", "float3");
|
|
baseCode = Replace(baseCode, "$F4$", "float4");
|
|
baseCode = Replace(baseCode, "$TIME$", "predefined_uniform.x");
|
|
baseCode = Replace(baseCode, "$EFFECTSCALE$", "predefined_uniform.y");
|
|
baseCode = Replace(baseCode, "$LOCALTIME$", "predefined_uniform.w");
|
|
baseCode = Replace(baseCode, "$UV$", "uv");
|
|
baseCode = Replace(baseCode, "$MOD", "fmod");
|
|
|
|
// replace textures
|
|
for (int32_t i = 0; i < actualTextureCount; i++)
|
|
{
|
|
|
|
std::string prefix;
|
|
std::string suffix;
|
|
|
|
if (materialFile->GetTextureColorType(i) == Effekseer::TextureColorType::Color)
|
|
{
|
|
prefix = "ConvertFromSRGBTexture(";
|
|
suffix = ")";
|
|
}
|
|
|
|
std::string keyP = "$TEX_P" + std::to_string(materialFile->GetTextureIndex(i)) + "$";
|
|
std::string keyS = "$TEX_S" + std::to_string(materialFile->GetTextureIndex(i)) + "$";
|
|
|
|
if (target_ == ShaderGeneratorTarget::DirectX9)
|
|
{
|
|
if (stage == 0)
|
|
{
|
|
baseCode = Replace(baseCode, keyP, prefix + std::string("tex2Dlod(") + materialFile->GetTextureName(i) + "_sampler,float4(GetUV(");
|
|
baseCode = Replace(baseCode, keyS, "),0,1))" + suffix);
|
|
}
|
|
else
|
|
{
|
|
baseCode = Replace(baseCode, keyP, prefix + std::string("tex2D(") + materialFile->GetTextureName(i) + "_sampler,GetUV(");
|
|
baseCode = Replace(baseCode, keyS, "))" + suffix);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (stage == 0)
|
|
{
|
|
baseCode = Replace(baseCode,
|
|
keyP,
|
|
prefix + std::string(materialFile->GetTextureName(i)) + "_texture.SampleLevel(" +
|
|
materialFile->GetTextureName(i) + "_sampler,GetUV(");
|
|
baseCode = Replace(baseCode, keyS, "),0)" + suffix);
|
|
}
|
|
else
|
|
{
|
|
baseCode = Replace(baseCode,
|
|
keyP,
|
|
prefix + std::string(materialFile->GetTextureName(i)) + "_texture.Sample(" + materialFile->GetTextureName(i) +
|
|
"_sampler,GetUV(");
|
|
baseCode = Replace(baseCode, keyS, "))" + suffix);
|
|
}
|
|
}
|
|
}
|
|
|
|
// invalid texture
|
|
for (int32_t i = actualTextureCount; i < materialFile->GetTextureCount(); i++)
|
|
{
|
|
auto textureIndex = materialFile->GetTextureIndex(i);
|
|
auto textureName = std::string(materialFile->GetTextureName(i));
|
|
|
|
std::string keyP = "$TEX_P" + std::to_string(textureIndex) + "$";
|
|
std::string keyS = "$TEX_S" + std::to_string(textureIndex) + "$";
|
|
|
|
baseCode = Replace(baseCode, keyP, "float4(");
|
|
baseCode = Replace(baseCode, keyS, ",0.0,1.0)");
|
|
}
|
|
|
|
maincode << Effekseer::Shader::GetLinearGammaFunctions();
|
|
|
|
if (stage == 0)
|
|
{
|
|
maincode << common_vs_define_;
|
|
}
|
|
|
|
ExportMain(maincode, materialFile, stage, isSprite, shaderType, baseCode);
|
|
|
|
if (stage == 0)
|
|
{
|
|
shaderData.CodeVS = maincode.str();
|
|
}
|
|
else
|
|
{
|
|
shaderData.CodePS = maincode.str();
|
|
}
|
|
}
|
|
|
|
// custom data
|
|
int32_t inputSlot = 2;
|
|
int32_t outputSlot = 7;
|
|
if (materialFile->GetCustomData1Count() > 0)
|
|
{
|
|
if (isSprite)
|
|
{
|
|
shaderData.CodeVS =
|
|
Replace(shaderData.CodeVS,
|
|
"//$C_IN1$",
|
|
GetType(materialFile->GetCustomData1Count()) + " CustomData1 : TEXCOORD" + std::to_string(inputSlot) + ";");
|
|
}
|
|
|
|
shaderData.CodeVS =
|
|
Replace(shaderData.CodeVS,
|
|
"//$C_OUT1$",
|
|
GetType(materialFile->GetCustomData1Count()) + " CustomData1 : TEXCOORD" + std::to_string(outputSlot) + ";");
|
|
shaderData.CodePS =
|
|
Replace(shaderData.CodePS,
|
|
"//$C_PIN1$",
|
|
GetType(materialFile->GetCustomData1Count()) + " CustomData1 : TEXCOORD" + std::to_string(outputSlot) + ";");
|
|
|
|
inputSlot++;
|
|
outputSlot++;
|
|
}
|
|
|
|
if (materialFile->GetCustomData2Count() > 0)
|
|
{
|
|
if (isSprite)
|
|
{
|
|
shaderData.CodeVS =
|
|
Replace(shaderData.CodeVS,
|
|
"//$C_IN2$",
|
|
GetType(materialFile->GetCustomData2Count()) + " CustomData2 : TEXCOORD" + std::to_string(inputSlot) + ";");
|
|
}
|
|
shaderData.CodeVS =
|
|
Replace(shaderData.CodeVS,
|
|
"//$C_OUT2$",
|
|
GetType(materialFile->GetCustomData2Count()) + " CustomData2 : TEXCOORD" + std::to_string(outputSlot) + ";");
|
|
shaderData.CodePS =
|
|
Replace(shaderData.CodePS,
|
|
"//$C_PIN2$",
|
|
GetType(materialFile->GetCustomData2Count()) + " CustomData2 : TEXCOORD" + std::to_string(outputSlot) + ";");
|
|
}
|
|
|
|
return shaderData;
|
|
}
|
|
|
|
} // namespace DirectX
|
|
|
|
} // namespace Effekseer
|