130 lines
4.0 KiB
GLSL
130 lines
4.0 KiB
GLSL
Shader "Builtin Skybox"
|
|
{
|
|
Properties
|
|
{
|
|
_Tint ("Tint", Color) = (1,1,1,1) [Semantic(Tint)]
|
|
_Exposure ("Exposure", Float) = 1.0 [Semantic(Exposure)]
|
|
_Rotation ("Rotation", Float) = 0.0 [Semantic(Rotation)]
|
|
_MainTex ("Panoramic", 2D) = "white" [Semantic(SkyboxPanoramicTexture)]
|
|
_Tex ("Cubemap (HDR)", Cube) = "white" [Semantic(SkyboxTexture)]
|
|
}
|
|
HLSLINCLUDE
|
|
cbuffer EnvironmentConstants
|
|
{
|
|
float4 gSkyboxTopColor;
|
|
float4 gSkyboxHorizonColor;
|
|
float4 gSkyboxBottomColor;
|
|
float4 gCameraRightAndTanHalfFov;
|
|
float4 gCameraUpAndAspect;
|
|
float4 gCameraForwardAndUnused;
|
|
};
|
|
|
|
cbuffer MaterialConstants
|
|
{
|
|
float4 gSkyboxTintAndExposure;
|
|
float4 gSkyboxRotationAndMode;
|
|
};
|
|
|
|
Texture2D SkyboxPanoramicTexture;
|
|
TextureCube SkyboxTexture;
|
|
SamplerState LinearClampSampler;
|
|
|
|
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" }
|
|
Cull Off
|
|
ZWrite Off
|
|
ZTest LEqual
|
|
Blend Off
|
|
HLSLPROGRAM
|
|
#pragma target 4.5
|
|
#pragma vertex MainVS
|
|
#pragma fragment MainPS
|
|
ENDHLSL
|
|
}
|
|
}
|
|
}
|