Formalize builtin fullscreen shaders

This commit is contained in:
2026-04-07 04:30:26 +08:00
parent 7f0d1f0b08
commit 5bfe484f5d
26 changed files with 746 additions and 713 deletions

View File

@@ -1,16 +0,0 @@
// XC_BUILTIN_COLOR_SCALE_POST_PROCESS_OPENGL_PS
#version 430
layout(binding = 0) uniform sampler2D uSourceColorTexture;
layout(std140, binding = 0) uniform PostProcessConstants {
vec4 gColorScale;
};
in vec2 vTexCoord;
layout(location = 0) out vec4 fragColor;
void main() {
fragColor = texture(uSourceColorTexture, vTexCoord) * gColorScale;
}

View File

@@ -1,17 +0,0 @@
// XC_BUILTIN_COLOR_SCALE_POST_PROCESS_VULKAN_PS
#version 450
layout(set = 0, binding = 0, std140) uniform PostProcessConstants {
vec4 gColorScale;
};
layout(set = 1, binding = 0) uniform texture2D uSourceColorTexture;
layout(set = 2, binding = 0) uniform sampler uLinearClampSampler;
layout(location = 0) in vec2 vTexCoord;
layout(location = 0) out vec4 fragColor;
void main() {
fragColor = texture(sampler2D(uSourceColorTexture, uLinearClampSampler), vTexCoord) * gColorScale;
}

View File

@@ -1,16 +0,0 @@
// XC_BUILTIN_COLOR_SCALE_POST_PROCESS_D3D12_PS
Texture2D gSourceColorTexture : register(t0);
SamplerState gLinearClampSampler : register(s0);
cbuffer PostProcessConstants : register(b0) {
float4 gColorScale;
};
struct PSInput {
float4 position : SV_POSITION;
float2 texcoord : TEXCOORD0;
};
float4 MainPS(PSInput input) : SV_TARGET {
return gSourceColorTexture.Sample(gLinearClampSampler, input.texcoord) * gColorScale;
}

View File

@@ -4,24 +4,63 @@ Shader "Builtin Color Scale Post Process"
{
_ColorScale ("Color Scale", Color) = (0.65,0.80,1.00,1.0)
}
HLSLINCLUDE
cbuffer PostProcessConstants : register(b0)
{
float4 gColorScale;
};
Texture2D gSourceColorTexture : register(t0);
SamplerState gLinearClampSampler : register(s0);
struct VSOutput
{
float4 position : SV_POSITION;
float2 texcoord : TEXCOORD0;
};
VSOutput MainVS(uint vertexId : SV_VertexID)
{
const float2 positions[3] = {
float2(-1.0f, -1.0f),
float2(-1.0f, 3.0f),
float2( 3.0f, -1.0f)
};
const float2 position = positions[vertexId];
VSOutput output;
output.position = float4(position, 1.0f, 1.0f);
float2 uv = float2(
position.x * 0.5f + 0.5f,
position.y * 0.5f + 0.5f);
#if UNITY_UV_STARTS_AT_TOP
uv.y = 1.0f - uv.y;
#endif
output.texcoord = uv;
return output;
}
float4 MainPS(VSOutput input) : SV_TARGET
{
return gSourceColorTexture.Sample(gLinearClampSampler, input.texcoord) * gColorScale;
}
ENDHLSL
SubShader
{
Pass
{
Name "ColorScale"
Tags { "LightMode" = "PostProcess" }
Resources
{
PostProcessConstants (ConstantBuffer, 0, 0)
SourceColorTexture (Texture2D, 1, 0)
LinearClampSampler (Sampler, 2, 0)
}
Cull Off
ZWrite Off
ZTest Always
Blend Off
HLSLPROGRAM
#pragma target 4.5
#pragma vertex MainVS
#pragma fragment MainPS
#pragma backend D3D12 HLSL "color-scale-post-process.vs.hlsl" "color-scale-post-process.ps.hlsl" vs_5_0 ps_5_0
#pragma backend OpenGL GLSL "color-scale-post-process.vert.glsl" "color-scale-post-process.frag.glsl"
#pragma backend Vulkan GLSL "color-scale-post-process.vert.vk.glsl" "color-scale-post-process.frag.vk.glsl"
ENDHLSL
}
}

View File

@@ -1,16 +0,0 @@
// XC_BUILTIN_COLOR_SCALE_POST_PROCESS_OPENGL_VS
#version 430
out vec2 vTexCoord;
void main() {
const vec2 positions[3] = vec2[3](
vec2(-1.0, -1.0),
vec2(-1.0, 3.0),
vec2( 3.0, -1.0)
);
vec2 position = positions[gl_VertexID];
gl_Position = vec4(position, 1.0, 1.0);
vTexCoord = position * 0.5 + 0.5;
}

View File

@@ -1,18 +0,0 @@
// XC_BUILTIN_COLOR_SCALE_POST_PROCESS_VULKAN_VS
#version 450
layout(location = 0) out vec2 vTexCoord;
void main() {
const vec2 positions[3] = vec2[3](
vec2(-1.0, -1.0),
vec2(-1.0, 3.0),
vec2( 3.0, -1.0)
);
vec2 position = positions[gl_VertexIndex];
gl_Position = vec4(position, 1.0, 1.0);
vTexCoord = vec2(
position.x * 0.5 + 0.5,
1.0 - (position.y * 0.5 + 0.5));
}

View File

@@ -1,22 +0,0 @@
// XC_BUILTIN_COLOR_SCALE_POST_PROCESS_D3D12_VS
struct VSOutput {
float4 position : SV_POSITION;
float2 texcoord : TEXCOORD0;
};
VSOutput MainVS(uint vertexId : SV_VertexID) {
const float2 positions[3] = {
float2(-1.0f, -1.0f),
float2(-1.0f, 3.0f),
float2( 3.0f, -1.0f)
};
const float2 position = positions[vertexId];
VSOutput output;
output.position = float4(position, 1.0f, 1.0f);
output.texcoord = float2(
position.x * 0.5f + 0.5f,
1.0f - (position.y * 0.5f + 0.5f));
return output;
}

View File

@@ -1,65 +0,0 @@
// XC_BUILTIN_FINAL_COLOR_OPENGL_PS
#version 430
layout(binding = 0) uniform sampler2D uSourceColorTexture;
layout(std140, binding = 0) uniform FinalColorConstants {
vec4 gColorScale;
vec4 gFinalColorParams;
};
in vec2 vTexCoord;
layout(location = 0) out vec4 fragColor;
float SRGBEncodeChannel(float value) {
float linear = max(value, 0.0);
return linear <= 0.0031308
? linear * 12.92
: 1.055 * pow(linear, 1.0 / 2.4) - 0.055;
}
vec3 ApplyLinearToSRGB(vec3 color) {
return vec3(
SRGBEncodeChannel(color.r),
SRGBEncodeChannel(color.g),
SRGBEncodeChannel(color.b));
}
vec3 ApplyNeutralToneMapping(vec3 color) {
return color / (color + vec3(1.0));
}
vec3 ApplyAcesToneMapping(vec3 color) {
const float a = 2.51;
const float b = 0.03;
const float c = 2.43;
const float d = 0.59;
const float e = 0.14;
return clamp((color * (a * color + b)) / (color * (c * color + d) + e), 0.0, 1.0);
}
vec3 ApplyToneMapping(vec3 color, float toneMappingMode) {
if (toneMappingMode > 1.5) {
return ApplyAcesToneMapping(color);
}
if (toneMappingMode > 0.5) {
return ApplyNeutralToneMapping(color);
}
return color;
}
void main() {
vec4 color = texture(uSourceColorTexture, vTexCoord);
color.rgb *= max(gFinalColorParams.x, 0.0);
color *= gColorScale;
color.rgb = ApplyToneMapping(color.rgb, gFinalColorParams.z);
if (gFinalColorParams.y > 0.5) {
color.rgb = ApplyLinearToSRGB(color.rgb);
}
fragColor = color;
}

View File

@@ -1,66 +0,0 @@
// XC_BUILTIN_FINAL_COLOR_VULKAN_PS
#version 450
layout(set = 0, binding = 0, std140) uniform FinalColorConstants {
vec4 gColorScale;
vec4 gFinalColorParams;
};
layout(set = 1, binding = 0) uniform texture2D uSourceColorTexture;
layout(set = 2, binding = 0) uniform sampler uLinearClampSampler;
layout(location = 0) in vec2 vTexCoord;
layout(location = 0) out vec4 fragColor;
float SRGBEncodeChannel(float value) {
float linear = max(value, 0.0);
return linear <= 0.0031308
? linear * 12.92
: 1.055 * pow(linear, 1.0 / 2.4) - 0.055;
}
vec3 ApplyLinearToSRGB(vec3 color) {
return vec3(
SRGBEncodeChannel(color.r),
SRGBEncodeChannel(color.g),
SRGBEncodeChannel(color.b));
}
vec3 ApplyNeutralToneMapping(vec3 color) {
return color / (color + vec3(1.0));
}
vec3 ApplyAcesToneMapping(vec3 color) {
const float a = 2.51;
const float b = 0.03;
const float c = 2.43;
const float d = 0.59;
const float e = 0.14;
return clamp((color * (a * color + b)) / (color * (c * color + d) + e), 0.0, 1.0);
}
vec3 ApplyToneMapping(vec3 color, float toneMappingMode) {
if (toneMappingMode > 1.5) {
return ApplyAcesToneMapping(color);
}
if (toneMappingMode > 0.5) {
return ApplyNeutralToneMapping(color);
}
return color;
}
void main() {
vec4 color = texture(sampler2D(uSourceColorTexture, uLinearClampSampler), vTexCoord);
color.rgb *= max(gFinalColorParams.x, 0.0);
color *= gColorScale;
color.rgb = ApplyToneMapping(color.rgb, gFinalColorParams.z);
if (gFinalColorParams.y > 0.5) {
color.rgb = ApplyLinearToSRGB(color.rgb);
}
fragColor = color;
}

View File

@@ -1,65 +0,0 @@
// XC_BUILTIN_FINAL_COLOR_D3D12_PS
Texture2D gSourceColorTexture : register(t0);
SamplerState gLinearClampSampler : register(s0);
cbuffer FinalColorConstants : register(b0) {
float4 gColorScale;
float4 gFinalColorParams;
};
struct PSInput {
float4 position : SV_POSITION;
float2 texcoord : TEXCOORD0;
};
float SRGBEncodeChannel(float value) {
const float linearValue = max(value, 0.0f);
return linearValue <= 0.0031308f
? linearValue * 12.92f
: 1.055f * pow(linearValue, 1.0f / 2.4f) - 0.055f;
}
float3 ApplyLinearToSRGB(float3 color) {
return float3(
SRGBEncodeChannel(color.r),
SRGBEncodeChannel(color.g),
SRGBEncodeChannel(color.b));
}
float3 ApplyNeutralToneMapping(float3 color) {
return color / (color + 1.0f);
}
float3 ApplyAcesToneMapping(float3 color) {
const float a = 2.51f;
const float b = 0.03f;
const float c = 2.43f;
const float d = 0.59f;
const float e = 0.14f;
return saturate((color * (a * color + b)) / (color * (c * color + d) + e));
}
float3 ApplyToneMapping(float3 color, float toneMappingMode) {
if (toneMappingMode > 1.5f) {
return ApplyAcesToneMapping(color);
}
if (toneMappingMode > 0.5f) {
return ApplyNeutralToneMapping(color);
}
return color;
}
float4 MainPS(PSInput input) : SV_TARGET {
float4 color = gSourceColorTexture.Sample(gLinearClampSampler, input.texcoord);
color.rgb *= max(gFinalColorParams.x, 0.0f);
color *= gColorScale;
color.rgb = ApplyToneMapping(color.rgb, gFinalColorParams.z);
if (gFinalColorParams.y > 0.5f) {
color.rgb = ApplyLinearToSRGB(color.rgb);
}
return color;
}

View File

@@ -7,24 +7,117 @@ Shader "Builtin Final Color"
_OutputTransferMode ("Output Transfer Mode", Float) = 0.0
_ToneMappingMode ("Tone Mapping Mode", Float) = 0.0
}
HLSLINCLUDE
cbuffer FinalColorConstants : register(b0)
{
float4 gColorScale;
float4 gFinalColorParams;
};
Texture2D gSourceColorTexture : register(t0);
SamplerState gLinearClampSampler : register(s0);
struct VSOutput
{
float4 position : SV_POSITION;
float2 texcoord : TEXCOORD0;
};
VSOutput MainVS(uint vertexId : SV_VertexID)
{
const float2 positions[3] = {
float2(-1.0f, -1.0f),
float2(-1.0f, 3.0f),
float2( 3.0f, -1.0f)
};
const float2 position = positions[vertexId];
VSOutput output;
output.position = float4(position, 1.0f, 1.0f);
float2 uv = float2(
position.x * 0.5f + 0.5f,
position.y * 0.5f + 0.5f);
#if UNITY_UV_STARTS_AT_TOP
uv.y = 1.0f - uv.y;
#endif
output.texcoord = uv;
return output;
}
float SRGBEncodeChannel(float value)
{
const float linearValue = max(value, 0.0f);
return linearValue <= 0.0031308f
? linearValue * 12.92f
: 1.055f * pow(linearValue, 1.0f / 2.4f) - 0.055f;
}
float3 ApplyLinearToSRGB(float3 color)
{
return float3(
SRGBEncodeChannel(color.r),
SRGBEncodeChannel(color.g),
SRGBEncodeChannel(color.b));
}
float3 ApplyNeutralToneMapping(float3 color)
{
return color / (color + 1.0f);
}
float3 ApplyAcesToneMapping(float3 color)
{
const float a = 2.51f;
const float b = 0.03f;
const float c = 2.43f;
const float d = 0.59f;
const float e = 0.14f;
return saturate((color * (a * color + b)) / (color * (c * color + d) + e));
}
float3 ApplyToneMapping(float3 color, float toneMappingMode)
{
if (toneMappingMode > 1.5f) {
return ApplyAcesToneMapping(color);
}
if (toneMappingMode > 0.5f) {
return ApplyNeutralToneMapping(color);
}
return color;
}
float4 MainPS(VSOutput input) : SV_TARGET
{
float4 color = gSourceColorTexture.Sample(gLinearClampSampler, input.texcoord);
color.rgb *= max(gFinalColorParams.x, 0.0f);
color *= gColorScale;
color.rgb = ApplyToneMapping(color.rgb, gFinalColorParams.z);
if (gFinalColorParams.y > 0.5f) {
color.rgb = ApplyLinearToSRGB(color.rgb);
}
return color;
}
ENDHLSL
SubShader
{
Pass
{
Name "FinalColor"
Tags { "LightMode" = "FinalOutput" }
Resources
{
FinalColorConstants (ConstantBuffer, 0, 0)
SourceColorTexture (Texture2D, 1, 0)
LinearClampSampler (Sampler, 2, 0)
}
Cull Off
ZWrite Off
ZTest Always
Blend Off
HLSLPROGRAM
#pragma target 4.5
#pragma vertex MainVS
#pragma fragment MainPS
#pragma backend D3D12 HLSL "final-color.vs.hlsl" "final-color.ps.hlsl" vs_5_0 ps_5_0
#pragma backend OpenGL GLSL "final-color.vert.glsl" "final-color.frag.glsl"
#pragma backend Vulkan GLSL "final-color.vert.vk.glsl" "final-color.frag.vk.glsl"
ENDHLSL
}
}

View File

@@ -1,16 +0,0 @@
// XC_BUILTIN_FINAL_COLOR_OPENGL_VS
#version 430
out vec2 vTexCoord;
void main() {
const vec2 positions[3] = vec2[3](
vec2(-1.0, -1.0),
vec2(-1.0, 3.0),
vec2( 3.0, -1.0)
);
vec2 position = positions[gl_VertexID];
gl_Position = vec4(position, 1.0, 1.0);
vTexCoord = position * 0.5 + 0.5;
}

View File

@@ -1,18 +0,0 @@
// XC_BUILTIN_FINAL_COLOR_VULKAN_VS
#version 450
layout(location = 0) out vec2 vTexCoord;
void main() {
const vec2 positions[3] = vec2[3](
vec2(-1.0, -1.0),
vec2(-1.0, 3.0),
vec2( 3.0, -1.0)
);
vec2 position = positions[gl_VertexIndex];
gl_Position = vec4(position, 1.0, 1.0);
vTexCoord = vec2(
position.x * 0.5 + 0.5,
1.0 - (position.y * 0.5 + 0.5));
}

View File

@@ -1,22 +0,0 @@
// XC_BUILTIN_FINAL_COLOR_D3D12_VS
struct VSOutput {
float4 position : SV_POSITION;
float2 texcoord : TEXCOORD0;
};
VSOutput MainVS(uint vertexId : SV_VertexID) {
const float2 positions[3] = {
float2(-1.0f, -1.0f),
float2(-1.0f, 3.0f),
float2( 3.0f, -1.0f)
};
const float2 position = positions[vertexId];
VSOutput output;
output.position = float4(position, 1.0f, 1.0f);
output.texcoord = float2(
position.x * 0.5f + 0.5f,
1.0f - (position.y * 0.5f + 0.5f));
return output;
}

View File

@@ -1,79 +0,0 @@
// XC_BUILTIN_SKYBOX_OPENGL_PS
#version 430
layout(binding = 0) uniform sampler2D uSkyboxPanoramicTexture;
layout(binding = 1) uniform samplerCube uSkyboxTexture;
layout(std140, binding = 0) uniform EnvironmentConstants {
vec4 gSkyboxTopColor;
vec4 gSkyboxHorizonColor;
vec4 gSkyboxBottomColor;
vec4 gCameraRightAndTanHalfFov;
vec4 gCameraUpAndAspect;
vec4 gCameraForwardAndUnused;
};
layout(std140, binding = 1) uniform MaterialConstants {
vec4 gSkyboxTintAndExposure;
vec4 gSkyboxRotationAndMode;
};
in vec2 vNdc;
layout(location = 0) out vec4 fragColor;
const float XC_PI = 3.14159265358979323846;
const float XC_INV_PI = 0.31830988618379067154;
const float XC_INV_TWO_PI = 0.15915494309189533577;
vec3 EvaluateProceduralSkybox(vec3 viewRay) {
float vertical = clamp(viewRay.y, -1.0, 1.0);
vec3 color = gSkyboxHorizonColor.rgb;
if (vertical >= 0.0) {
color = mix(gSkyboxHorizonColor.rgb, gSkyboxTopColor.rgb, pow(clamp(vertical, 0.0, 1.0), 0.65));
} else {
color = mix(gSkyboxHorizonColor.rgb, gSkyboxBottomColor.rgb, pow(clamp(-vertical, 0.0, 1.0), 0.55));
}
return color;
}
vec3 RotateAroundY(vec3 viewRay) {
float rotation = gSkyboxRotationAndMode.x;
float sinTheta = sin(rotation);
float cosTheta = cos(rotation);
return normalize(vec3(
viewRay.x * cosTheta - viewRay.z * sinTheta,
viewRay.y,
viewRay.x * sinTheta + viewRay.z * cosTheta));
}
vec2 ComputePanoramicUv(vec3 viewRay) {
vec3 rotatedRay = RotateAroundY(viewRay);
float u = fract(atan(rotatedRay.z, rotatedRay.x) * XC_INV_TWO_PI + 0.5);
float v = acos(clamp(rotatedRay.y, -1.0, 1.0)) * XC_INV_PI;
return vec2(u, clamp(v, 0.0, 1.0));
}
void main() {
float tanHalfFov = gCameraRightAndTanHalfFov.w;
float aspect = gCameraUpAndAspect.w;
vec3 viewRay = normalize(
gCameraForwardAndUnused.xyz +
vNdc.x * aspect * tanHalfFov * gCameraRightAndTanHalfFov.xyz +
vNdc.y * tanHalfFov * gCameraUpAndAspect.xyz);
vec3 color = EvaluateProceduralSkybox(viewRay);
if (gSkyboxRotationAndMode.y > 1.5) {
color = texture(uSkyboxTexture, RotateAroundY(viewRay)).rgb *
gSkyboxTintAndExposure.rgb *
gSkyboxTintAndExposure.w;
} else if (gSkyboxRotationAndMode.y > 0.5) {
color = texture(uSkyboxPanoramicTexture, ComputePanoramicUv(viewRay)).rgb *
gSkyboxTintAndExposure.rgb *
gSkyboxTintAndExposure.w;
}
fragColor = vec4(color, 1.0);
}

View File

@@ -1,80 +0,0 @@
// XC_BUILTIN_SKYBOX_VULKAN_PS
#version 450
layout(set = 0, binding = 0, std140) uniform EnvironmentConstants {
vec4 gSkyboxTopColor;
vec4 gSkyboxHorizonColor;
vec4 gSkyboxBottomColor;
vec4 gCameraRightAndTanHalfFov;
vec4 gCameraUpAndAspect;
vec4 gCameraForwardAndUnused;
};
layout(set = 1, binding = 0, std140) uniform MaterialConstants {
vec4 gSkyboxTintAndExposure;
vec4 gSkyboxRotationAndMode;
};
layout(set = 2, binding = 0) uniform texture2D uSkyboxPanoramicTexture;
layout(set = 3, binding = 0) uniform textureCube uSkyboxTexture;
layout(set = 4, binding = 0) uniform sampler uLinearSampler;
layout(location = 0) in vec2 vNdc;
layout(location = 0) out vec4 fragColor;
const float XC_PI = 3.14159265358979323846;
const float XC_INV_PI = 0.31830988618379067154;
const float XC_INV_TWO_PI = 0.15915494309189533577;
vec3 EvaluateProceduralSkybox(vec3 viewRay) {
float vertical = clamp(viewRay.y, -1.0, 1.0);
vec3 color = gSkyboxHorizonColor.rgb;
if (vertical >= 0.0) {
color = mix(gSkyboxHorizonColor.rgb, gSkyboxTopColor.rgb, pow(clamp(vertical, 0.0, 1.0), 0.65));
} else {
color = mix(gSkyboxHorizonColor.rgb, gSkyboxBottomColor.rgb, pow(clamp(-vertical, 0.0, 1.0), 0.55));
}
return color;
}
vec3 RotateAroundY(vec3 viewRay) {
float rotation = gSkyboxRotationAndMode.x;
float sinTheta = sin(rotation);
float cosTheta = cos(rotation);
return normalize(vec3(
viewRay.x * cosTheta - viewRay.z * sinTheta,
viewRay.y,
viewRay.x * sinTheta + viewRay.z * cosTheta));
}
vec2 ComputePanoramicUv(vec3 viewRay) {
vec3 rotatedRay = RotateAroundY(viewRay);
float u = fract(atan(rotatedRay.z, rotatedRay.x) * XC_INV_TWO_PI + 0.5);
float v = acos(clamp(rotatedRay.y, -1.0, 1.0)) * XC_INV_PI;
return vec2(u, clamp(v, 0.0, 1.0));
}
void main() {
float tanHalfFov = gCameraRightAndTanHalfFov.w;
float aspect = gCameraUpAndAspect.w;
vec3 viewRay = normalize(
gCameraForwardAndUnused.xyz +
vNdc.x * aspect * tanHalfFov * gCameraRightAndTanHalfFov.xyz +
vNdc.y * tanHalfFov * gCameraUpAndAspect.xyz);
vec3 color = EvaluateProceduralSkybox(viewRay);
if (gSkyboxRotationAndMode.y > 1.5) {
color = texture(samplerCube(uSkyboxTexture, uLinearSampler), RotateAroundY(viewRay)).rgb *
gSkyboxTintAndExposure.rgb *
gSkyboxTintAndExposure.w;
} else if (gSkyboxRotationAndMode.y > 0.5) {
color = texture(sampler2D(uSkyboxPanoramicTexture, uLinearSampler), ComputePanoramicUv(viewRay)).rgb *
gSkyboxTintAndExposure.rgb *
gSkyboxTintAndExposure.w;
}
fragColor = vec4(color, 1.0);
}

View File

@@ -1,79 +0,0 @@
// XC_BUILTIN_SKYBOX_D3D12_PS
Texture2D gSkyboxPanoramicTexture : register(t0);
TextureCube gSkyboxTexture : register(t1);
SamplerState gLinearSampler : register(s0);
cbuffer EnvironmentConstants : register(b0) {
float4 gSkyboxTopColor;
float4 gSkyboxHorizonColor;
float4 gSkyboxBottomColor;
float4 gCameraRightAndTanHalfFov;
float4 gCameraUpAndAspect;
float4 gCameraForwardAndUnused;
}
cbuffer MaterialConstants : register(b1) {
float4 gSkyboxTintAndExposure;
float4 gSkyboxRotationAndMode;
}
struct PSInput {
float4 position : SV_POSITION;
float2 ndc : TEXCOORD0;
};
static const float XC_PI = 3.14159265358979323846f;
static const float XC_INV_PI = 0.31830988618379067154f;
static const float XC_INV_TWO_PI = 0.15915494309189533577f;
float3 EvaluateProceduralSkybox(float3 viewRay) {
const float vertical = clamp(viewRay.y, -1.0f, 1.0f);
float3 color = gSkyboxHorizonColor.rgb;
if (vertical >= 0.0f) {
color = lerp(gSkyboxHorizonColor.rgb, gSkyboxTopColor.rgb, pow(saturate(vertical), 0.65f));
} else {
color = lerp(gSkyboxHorizonColor.rgb, gSkyboxBottomColor.rgb, pow(saturate(-vertical), 0.55f));
}
return color;
}
float3 RotateAroundY(float3 viewRay) {
const float rotation = gSkyboxRotationAndMode.x;
const float sinTheta = sin(rotation);
const float cosTheta = cos(rotation);
return normalize(float3(
viewRay.x * cosTheta - viewRay.z * sinTheta,
viewRay.y,
viewRay.x * sinTheta + viewRay.z * cosTheta));
}
float2 ComputePanoramicUv(float3 viewRay) {
const float3 rotatedRay = RotateAroundY(viewRay);
const float u = frac(atan2(rotatedRay.z, rotatedRay.x) * XC_INV_TWO_PI + 0.5f);
const float v = acos(clamp(rotatedRay.y, -1.0f, 1.0f)) * XC_INV_PI;
return float2(u, saturate(v));
}
float4 MainPS(PSInput input) : SV_Target {
const float tanHalfFov = gCameraRightAndTanHalfFov.w;
const float aspect = gCameraUpAndAspect.w;
float3 viewRay = normalize(
gCameraForwardAndUnused.xyz +
input.ndc.x * aspect * tanHalfFov * gCameraRightAndTanHalfFov.xyz +
input.ndc.y * tanHalfFov * gCameraUpAndAspect.xyz);
float3 color = EvaluateProceduralSkybox(viewRay);
if (gSkyboxRotationAndMode.y > 1.5f) {
color = gSkyboxTexture.Sample(gLinearSampler, RotateAroundY(viewRay)).rgb *
gSkyboxTintAndExposure.rgb *
gSkyboxTintAndExposure.w;
} else if (gSkyboxRotationAndMode.y > 0.5f) {
color = gSkyboxPanoramicTexture.Sample(gLinearSampler, ComputePanoramicUv(viewRay)).rgb *
gSkyboxTintAndExposure.rgb *
gSkyboxTintAndExposure.w;
}
return float4(color, 1.0f);
}

View File

@@ -8,26 +8,121 @@ Shader "Builtin Skybox"
_MainTex ("Panoramic", 2D) = "white" [Semantic(SkyboxPanoramicTexture)]
_Tex ("Cubemap (HDR)", Cube) = "white" [Semantic(SkyboxTexture)]
}
HLSLINCLUDE
cbuffer EnvironmentConstants : register(b0)
{
float4 gSkyboxTopColor;
float4 gSkyboxHorizonColor;
float4 gSkyboxBottomColor;
float4 gCameraRightAndTanHalfFov;
float4 gCameraUpAndAspect;
float4 gCameraForwardAndUnused;
};
cbuffer MaterialConstants : register(b1)
{
float4 gSkyboxTintAndExposure;
float4 gSkyboxRotationAndMode;
};
Texture2D SkyboxPanoramicTexture : register(t0);
TextureCube SkyboxTexture : register(t1);
SamplerState LinearClampSampler : register(s0);
struct VSOutput
{
float4 position : SV_POSITION;
float2 ndc : TEXCOORD0;
};
static const float XC_PI = 3.14159265358979323846f;
static const float XC_INV_PI = 0.31830988618379067154f;
static const float XC_INV_TWO_PI = 0.15915494309189533577f;
VSOutput MainVS(uint vertexId : SV_VertexID)
{
const float2 positions[3] = {
float2(-1.0f, -1.0f),
float2(-1.0f, 3.0f),
float2( 3.0f, -1.0f)
};
VSOutput output;
output.position = float4(positions[vertexId], 1.0f, 1.0f);
output.ndc = positions[vertexId];
return output;
}
float3 EvaluateProceduralSkybox(float3 viewRay)
{
const float vertical = clamp(viewRay.y, -1.0f, 1.0f);
float3 color = gSkyboxHorizonColor.rgb;
if (vertical >= 0.0f) {
color = lerp(gSkyboxHorizonColor.rgb, gSkyboxTopColor.rgb, pow(saturate(vertical), 0.65f));
} else {
color = lerp(gSkyboxHorizonColor.rgb, gSkyboxBottomColor.rgb, pow(saturate(-vertical), 0.55f));
}
return color;
}
float3 RotateAroundY(float3 viewRay)
{
const float rotation = gSkyboxRotationAndMode.x;
const float sinTheta = sin(rotation);
const float cosTheta = cos(rotation);
return normalize(float3(
viewRay.x * cosTheta - viewRay.z * sinTheta,
viewRay.y,
viewRay.x * sinTheta + viewRay.z * cosTheta));
}
float2 ComputePanoramicUv(float3 viewRay)
{
const float3 rotatedRay = RotateAroundY(viewRay);
const float u = frac(atan2(rotatedRay.z, rotatedRay.x) * XC_INV_TWO_PI + 0.5f);
const float v = acos(clamp(rotatedRay.y, -1.0f, 1.0f)) * XC_INV_PI;
return float2(u, saturate(v));
}
float4 MainPS(VSOutput input) : SV_TARGET
{
const float tanHalfFov = gCameraRightAndTanHalfFov.w;
const float aspect = gCameraUpAndAspect.w;
const float3 viewRay = normalize(
gCameraForwardAndUnused.xyz +
input.ndc.x * aspect * tanHalfFov * gCameraRightAndTanHalfFov.xyz +
input.ndc.y * tanHalfFov * gCameraUpAndAspect.xyz);
float3 color = EvaluateProceduralSkybox(viewRay);
if (gSkyboxRotationAndMode.y > 1.5f) {
color = SkyboxTexture.Sample(LinearClampSampler, RotateAroundY(viewRay)).rgb *
gSkyboxTintAndExposure.rgb *
gSkyboxTintAndExposure.w;
} else if (gSkyboxRotationAndMode.y > 0.5f) {
color = SkyboxPanoramicTexture.Sample(LinearClampSampler, ComputePanoramicUv(viewRay)).rgb *
gSkyboxTintAndExposure.rgb *
gSkyboxTintAndExposure.w;
}
return float4(color, 1.0f);
}
ENDHLSL
SubShader
{
Pass
{
Name "Skybox"
Tags { "LightMode" = "Skybox" }
Resources
{
EnvironmentConstants (ConstantBuffer, 0, 0) [Semantic(Environment)]
MaterialConstants (ConstantBuffer, 1, 0) [Semantic(Material)]
SkyboxPanoramicTexture (Texture2D, 2, 0) [Semantic(SkyboxPanoramicTexture)]
SkyboxTexture (TextureCube, 3, 0) [Semantic(SkyboxTexture)]
LinearClampSampler (Sampler, 4, 0) [Semantic(LinearClampSampler)]
}
Cull Off
ZWrite Off
ZTest LEqual
Blend Off
HLSLPROGRAM
#pragma target 4.5
#pragma vertex MainVS
#pragma fragment MainPS
#pragma backend D3D12 HLSL "skybox.vs.hlsl" "skybox.ps.hlsl" vs_5_0 ps_5_0
#pragma backend OpenGL GLSL "skybox.vert.glsl" "skybox.frag.glsl"
#pragma backend Vulkan GLSL "skybox.vert.vk.glsl" "skybox.frag.vk.glsl"
ENDHLSL
}
}

View File

@@ -1,16 +0,0 @@
// XC_BUILTIN_SKYBOX_OPENGL_VS
#version 430
out vec2 vNdc;
void main() {
const vec2 positions[3] = vec2[3](
vec2(-1.0, -1.0),
vec2(-1.0, 3.0),
vec2( 3.0, -1.0)
);
vec2 position = positions[gl_VertexID];
gl_Position = vec4(position, 1.0, 1.0);
vNdc = position;
}

View File

@@ -1,16 +0,0 @@
// XC_BUILTIN_SKYBOX_VULKAN_VS
#version 450
layout(location = 0) out vec2 vNdc;
void main() {
const vec2 positions[3] = vec2[3](
vec2(-1.0, -1.0),
vec2(-1.0, 3.0),
vec2( 3.0, -1.0)
);
vec2 position = positions[gl_VertexIndex];
gl_Position = vec4(position, 1.0, 1.0);
vNdc = position;
}

View File

@@ -1,18 +0,0 @@
// XC_BUILTIN_SKYBOX_D3D12_VS
struct VSOutput {
float4 position : SV_POSITION;
float2 ndc : TEXCOORD0;
};
VSOutput MainVS(uint vertexId : SV_VertexID) {
const float2 positions[3] = {
float2(-1.0f, -1.0f),
float2(-1.0f, 3.0f),
float2( 3.0f, -1.0f)
};
VSOutput output;
output.position = float4(positions[vertexId], 1.0f, 1.0f);
output.ndc = positions[vertexId];
return output;
}