Files
expvintl 419f2e4752 init
2025-02-23 17:40:52 +08:00

1633 lines
56 KiB
HLSL

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// PIOTR DUBLA //
// Sky shader (clouds, sun, stars, moon) //
// 10/11/2009 //
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
#pragma dcl position texcoord0 texcoord1
#if __WIN32PC
#pragma warning (disable: 3205)
#endif
// DEFINES
#define NO_SKINNING
#define FOG_SKY
// INCLUDES
#include "../common.fxh"
#include "../Util/macros.fxh"
#include "../Util/GSInst.fxh"
// EXTRAS
// We don't care for no skinning matrices here, so we can use a bigger constant register file
#pragma constant 130
#define OPTIMIZE CGC_FLAGS("-unroll all -fastmath")
//#define OPTIMIZE
#define FOG_OFF false
#define SUN_OFF false
#define MOON_OFF false
#define CLOUDS_OFF false
#define STARS_OFF false
#define DEBUG_OFF false
#define FOG_ON true
#define SUN_ON true
#define MOON_ON true
#define CLOUDS_ON true
#define STARS_ON true
#define DEBUG_ON true
#if __XENON
#define kDitherScale 0.0002 // 360 only has 10 bits, so we need more dither
#else
#define kDitherScale 0.0001
#endif
// ------------------------------------------------------------------------------------------------------------------//
// VARIABLES //
// ------------------------------------------------------------------------------------------------------------------//
#define GEN_SKY_FUNCS(typeName, passName, sunEnabled, moonEnabled, cloudsEnabled, starsEnabled, debugEnabled) \
\
JOIN3(VS_,typeName,_OUTPUT) JOIN4(vs_,typeName,_normal_,passName)(JOIN3(VS_,typeName,_INPUT) IN) \
{ \
float4 transPos = mul(IN.pos, gWorldViewProj); \
return JOIN3(vs_,typeName,_main)(transPos, IN, FOG_ON, sunEnabled, moonEnabled, cloudsEnabled, starsEnabled, debugEnabled); \
} \
OutHalf4Color JOIN4(ps_,typeName,_normal_,passName)(JOIN3(PS_,typeName,_INPUT) IN) \
{ \
half4 colour = JOIN3(ps_,typeName,_main)(IN, FOG_ON, sunEnabled, moonEnabled, cloudsEnabled, starsEnabled, debugEnabled); \
return CastOutHalf4Color(PackHdr(colour)); \
} \
JOIN3(VS_,typeName,_OUTPUT) JOIN4(vs_,typeName,_water_reflection_,passName)(JOIN3(VS_,typeName,_INPUT) IN) \
{ \
float4 transPos = mul(IN.pos, gWorldViewProj); \
return JOIN3(vs_,typeName,_main)(transPos, IN, FOG_ON, sunEnabled, moonEnabled, cloudsEnabled, starsEnabled, debugEnabled); \
} \
OutHalf4Color JOIN4(ps_,typeName,_water_reflection_,passName)(JOIN3(PS_,typeName,_INPUT) IN) \
{ \
half4 colour = JOIN3(ps_,typeName,_main)(IN, FOG_ON, sunEnabled, moonEnabled, cloudsEnabled, starsEnabled, debugEnabled); \
return CastOutHalf4Color(PackReflection(colour)); \
} \
JOIN3(VS_,typeName,_OUTPUT) JOIN4(vs_,typeName,_mirror_reflection_,passName)(JOIN3(VS_,typeName,_INPUT) IN) \
{ \
float4 transPos = mul(IN.pos, gWorldViewProj); \
return JOIN3(vs_,typeName,_main)(transPos, IN, FOG_ON, sunEnabled, moonEnabled, cloudsEnabled, starsEnabled, debugEnabled); \
} \
OutHalf4Color JOIN4(ps_,typeName,_mirror_reflection_,passName)(JOIN3(PS_,typeName,_INPUT) IN) \
{ \
half4 colour = JOIN3(ps_,typeName,_main)(IN, FOG_ON, sunEnabled, moonEnabled, cloudsEnabled, starsEnabled, debugEnabled); \
return CastOutHalf4Color(PackHdr(colour)); \
} \
// ------------------------------------------------------------------------------------------------------------------//
#define GEN_PASS(typeName, techName, passName) \
pass JOIN(p_, passName) \
{ \
VertexShader = compile VERTEXSHADER JOIN6(vs_,typeName,_,techName,_,passName)(); \
PixelShader = compile PIXELSHADER JOIN6(ps_,typeName,_,techName,_,passName)() OPTIMIZE; \
} \
// ------------------------------------------------------------------------------------------------------------------//
// VARIABLES //
// ------------------------------------------------------------------------------------------------------------------//
BEGIN_RAGE_CONSTANT_BUFFER(sky_system_locals,b0)
// Sky variables
float3 azimuthEastColor;
float3 azimuthWestColor;
float3 azimuthTransitionColor;
half azimuthTransitionPosition;
float3 zenithColor;
float3 zenithTransitionColor;
const half4 zenithConstants;
#define zenithTransitionPosition half(zenithConstants.x)
#define zenithTransitionEastBlend half(zenithConstants.y)
#define zenithTransitionWestBlend half(zenithConstants.z)
#define oneMinusZenithBlendStart half(zenithConstants.w)
float4 skyPlaneColor;
float4 skyPlaneParams;
#define skyPlaneFogFadeStart float(skyPlaneParams.x)
#define skyPlaneFogFadeEnd float(skyPlaneParams.y)
#define skyPlaneFogFadeOneOverDiff float(skyPlaneParams.z)
half hdrIntensity;
// Sun variables
half3 sunColor;
half3 sunColorHdr;
half3 sunDiscColorHdr;
// Mie constants need to be full float, otherwise sun has bands (B*789750)
const float4 sunConstants;
#define miePhaseTimesTwo float(sunConstants.x)
#define miePhaseSqrPlusOne float(sunConstants.y)
#define mieConstantTimesScatter float(sunConstants.z)
#define mieIntensityMult float(sunConstants.w)
const float3 sunDirection;
const float3 sunPosition;
// Cloud variables
half3 cloudBaseMinusMidColour;
half3 cloudMidColour;
half3 cloudShadowMinusBaseColourTimesShadowStrength;
const half4 cloudDetailConstants;
#define cloudEdgeDetailStrength half(cloudDetailConstants.x)
#define cloudEdgeDetailScale half(cloudDetailConstants.y)
#define cloudOverallDetailStrength half(cloudDetailConstants.z)
#define cloudOverallDetailScale half(cloudDetailConstants.w)
const half4 cloudConstants1;
#define cloudBaseStrength half(cloudConstants1.x)
#define cloudDensityMultiplier half(cloudConstants1.y)
#define cloudDensityBias half(cloudConstants1.z)
#define cloudFadeOut half(cloudConstants1.w)
const half4 cloudConstants2;
#define cloudShadowStrength half(cloudConstants2.x)
#define cloudOffset half(cloudConstants2.y)
#define cloudOverallColorStrength half(cloudConstants2.z)
#define cloudHdrIntensity half(cloudConstants2.w)
const half4 smallCloudConstants;
#define smallCloudDetailScale half(smallCloudConstants.x)
#define smallCloudDetailStrength half(smallCloudConstants.y)
#define smallCloudDensityMultiplier half(smallCloudConstants.z)
#define smallCloudDensityBias half(smallCloudConstants.w)
half3 smallCloudColorHdr;
const half4 effectsConstants;
#define sunInfluenceRadius half(effectsConstants.x)
#define sunScatterIntensity half(effectsConstants.y)
#define moonInfluenceRadius half(effectsConstants.z)
#define moonScatterIntensity half(effectsConstants.w)
// Misc variables
const half horizonLevel;
const half3 speedConstants;
#define smallCloudOffset half(speedConstants.x)
#define overallDetailOffset half(speedConstants.y)
#define edgeDetailOffset half(speedConstants.z)
// Night
const half starfieldIntensity;
const float3 moonDirection;
const float3 moonPosition;
const half moonIntensity;
const float3 lunarCycle;
const half3 moonColor;
// Perlin
const float noiseFrequency;
const float noiseScale;
const float noiseThreshold;
const float noiseSoftness;
const float noiseDensityOffset;
const float2 noisePhase;
#if !defined(SHADER_FINAL)
float4 debugCloudsParams[3];
#endif // !defined(SHADER_FINAL)
EndConstantBufferDX10(sky_system_locals)
// ------------------------------------------------------------------------------------------------------------------//
// TEXTURES //
// ------------------------------------------------------------------------------------------------------------------//
BeginSampler(sampler2D, noiseTexture, NoiseSampler, noiseTexture)
string UIName = "Noise Layer Texture";
ContinueSampler(sampler2D, noiseTexture, NoiseSampler, noiseTexture)
AddressU = WRAP;
AddressV = WRAP;
AddressW = WRAP;
MINFILTER = LINEAR;
MAGFILTER = LINEAR;
MIPFILTER = LINEAR;
MipMapLodBias = 0;
EndSampler;
BeginSampler(sampler2D, perlinNoiseRT, perlinSampler, perlinNoiseRT)
string UIName = "Perlin Noise Map";
ContinueSampler(sampler2D, perlinNoiseRT, perlinSampler, perlinNoiseRT)
AddressU = WRAP;
AddressV = WRAP;
AddressW = WRAP;
MIPFILTER = LINEAR;
MINFILTER = LINEAR;
MAGFILTER = LINEAR;
MipMapLodBias = 0;
EndSampler;
BeginSampler(sampler2D, highDetailNoiseTex, highDetailSampler, highDetailNoiseTex)
string UIName = "High Detail Noise Map";
ContinueSampler(sampler2D, highDetailNoiseTex, highDetailSampler, highDetailNoiseTex)
AddressU = WRAP;
AddressV = WRAP;
AddressW = WRAP;
MIPFILTER = LINEAR;
MINFILTER = LINEAR;
MAGFILTER = LINEAR;
MipMapLodBias = 0;
EndSampler;
BeginSampler(sampler2D, starFieldTex, starFieldSampler, starFieldTex)
string UIName = "Starfield Map";
ContinueSampler(sampler2D, starFieldTex, starFieldSampler, starFieldTex)
AddressU = WRAP;
AddressV = WRAP;
AddressW = WRAP;
MIPFILTER = LINEAR;
MINFILTER = LINEAR;
MAGFILTER = LINEAR;
MipMapLodBias = 0;
EndSampler;
BeginSampler(sampler2D, ditherTex, ditherSampler, ditherTex)
string UIName = "Dither Map";
ContinueSampler(sampler2D, ditherTex, ditherSampler, ditherTex)
AddressU = WRAP;
AddressV = WRAP;
AddressW = WRAP;
MIPFILTER = LINEAR;
MINFILTER = LINEAR;
MAGFILTER = LINEAR;
MipMapLodBias = 0;
EndSampler;
BeginSampler(sampler2D, moonTex, moonSampler, moonTex)
string UIName = "Moon Map";
ContinueSampler(sampler2D, moonTex, moonSampler, moonTex)
AddressU = CLAMP;
AddressV = CLAMP;
AddressW = CLAMP;
MIPFILTER = LINEAR;
MINFILTER = LINEAR;
MAGFILTER = LINEAR;
MipMapLodBias = 0;
EndSampler;
// ------------------------------------------------------------------------------------------------------------------//
// STRUCTURES //
// ------------------------------------------------------------------------------------------------------------------//
struct VS_sky_INPUT
{
float4 pos : POSITION;
half2 texCoord0 : TEXCOORD0;
half2 texCoord1 : TEXCOORD1;
#if RAGE_INSTANCED_TECH
uint InstID : SV_InstanceID;
#endif
};
// ------------------------------------------------------------------------------------------------------------------//
struct VS_sky_OUTPUT
{
DECLARE_POSITION(pos)
half4 texCoord: TEXCOORD0;
float4 worldPos : TEXCOORD1;
float4 skyCol : TEXCOORD2;
half4 detailTexCoord : TEXCOORD3;
half4 ditherAndSmallCloudTexCoord : TEXCOORD4; // ditherTexCoord and smallCloudTexCoords packed into one interpolator
half2 starTexCoords : TEXCOORD5;
float4 fogData : TEXCOORD6; // do not change to half4, it results in banding/errors in dark fog conditions (especially under water)
// watch out for addition attribute. may need to fix VS_sky_OUTPUTCubeInst.
};
// ------------------------------------------------------------------------------------------------------------------//
struct PS_sky_INPUT
{
DECLARE_POSITION_PSIN(pos)
half4 texCoord : TEXCOORD0;
float4 worldPos : TEXCOORD1;
float4 skyCol : TEXCOORD2;
half4 detailTexCoord : TEXCOORD3;
half4 ditherAndSmallCloudTexCoord : TEXCOORD4;
half2 starTexCoords : TEXCOORD5;
float4 fogData : TEXCOORD6; // do not change to half4
};
#define ditherTexCoord ditherAndSmallCloudTexCoord.xy
#define smallCloudTexCoords ditherAndSmallCloudTexCoord.zw
// ------------------------------------------------------------------------------------------------------------------//
struct VS_moon_INPUT
{
float4 inPos : POSITION;
half2 inTexCoords : TEXCOORD0;
#if RAGE_INSTANCED_TECH
uint InstID : SV_InstanceID;
#endif
};
// ------------------------------------------------------------------------------------------------------------------//
struct VS_moon_OUTPUT
{
#if RSG_ORBIS
DECLARE_POSITION(pos)
#else
half4 pos : POSITION;
#endif
half2 texCoord : TEXCOORD0;
float4 worldPos : TEXCOORD1;
};
// ------------------------------------------------------------------------------------------------------------------//
struct PS_moon_INPUT
{
half2 texCoord: TEXCOORD0;
float4 worldPos : TEXCOORD1;
};
// ------------------------------------------------------------------------------------------------------------------//
struct VS_sun_INPUT
{
float4 inPos : POSITION;
half2 inTexCoords: TEXCOORD0;
#if RAGE_INSTANCED_TECH
uint InstID : SV_InstanceID;
#endif
};
// ------------------------------------------------------------------------------------------------------------------//
struct VS_sun_OUTPUT
{
#if RSG_ORBIS
DECLARE_POSITION(pos)
#else
half4 pos : POSITION;
#endif
float4 fogData : TEXCOORD0; // do not change to half4
};
// ------------------------------------------------------------------------------------------------------------------//
struct VS_sun_parab_OUTPUT
{
#if RSG_ORBIS
DECLARE_POSITION(pos)
#else
half4 pos : POSITION;
#endif
float3 worldPos : TEXCOORD0;
float4 fogData : TEXCOORD1; // do not change to half4
};
// ------------------------------------------------------------------------------------------------------------------//
struct VS_sun_vis_OUTPUT
{
#if RSG_ORBIS
DECLARE_POSITION(pos)
#else
half4 pos : POSITION;
#endif
float fogBlend : TEXCOORD0;
};
// ------------------------------------------------------------------------------------------------------------------//
struct PS_sun_vis_INPUT
{
#if !__XENON
DECLARE_POSITION_PSIN(pos)
#endif
float fogBlend : TEXCOORD0;
};
// ------------------------------------------------------------------------------------------------------------------//
struct PS_sun_INPUT
{
float3 worldPos : TEXCOORD0;
float4 fogData : TEXCOORD1; // do not change to half4
};
// ------------------------------------------------------------------------------------------------------------------//
struct VS_PERLIN_OUTPUT
{
DECLARE_POSITION(pos)
float2 texCoord : TEXCOORD0;
};
// ------------------------------------------------------------------------------------------------------------------//
struct VS_SKY_PLANE_INPUT
{
float4 pos : POSITION;
#if RAGE_INSTANCED_TECH
uint InstID : SV_InstanceID;
#endif
};
// ------------------------------------------------------------------------------------------------------------------//
struct VS_SKY_PLANE_OUTPUT
{
DECLARE_POSITION(pos)
float3 color : TEXCOORD0;
float4 eyeToWorld : TEXCOORD1;
};
// ------------------------------------------------------------------------------------------------------------------//
struct VS_SKY_PLANE_PARAB_OUTPUT
{
DECLARE_POSITION(pos)
float3 color : TEXCOORD0;
float4 eyeToWorld : TEXCOORD1;
float3 worldPos : TEXCOORD2;
};
// ------------------------------------------------------------------------------------------------------------------//
// ------------------------------------------------------------------------------------------------------------------//
struct TEX_DATA
{
float2 perlin;
float2 offsetPerlin;
float detailOverall;
float2 detailEdge;
float dither;
float3 stars;
};
// ------------------------------------------------------------------------------------------------------------------//
struct SUN_RESULT
{
half3 color;
half cosTheta;
float invAlpha;
};
// ------------------------------------------------------------------------------------------------------------------//
struct CLOUD_RESULT
{
half3 color;
half dimming;
half noise;
half2 alpha;
};
// ------------------------------------------------------------------------------------------------------------------//
struct EFFECTS_RESULT
{
half3 color;
};
// ------------------------------------------------------------------------------------------------------------------//
// HELPER FUNCTIONS //
// ------------------------------------------------------------------------------------------------------------------//
half2 RageNormalize2(half2 d)
{
const half mag = dot(d, d);
const half recip = rsqrt(mag);
return (mag == 0.0f) ? 0.0f : d * recip;
}
// ------------------------------------------------------------------------------------------------------------------//
half2 sphericalWarp(half2 tex)
{
tex = tex - 0.5;
const half mag = dot(tex, tex);
tex = mag * RageNormalize2(tex) + 0.5;
return tex;
}
// ------------------------------------------------------------------------------------------------------------------//
half2 sphericalWarpOffset(half2 tex , half2 offset)
{
const half2 t = (2.0f * tex - 1.0f);
return offset * (1.0f - dot(t, t));
}
// ------------------------------------------------------------------------------------------------------------------//
// FUNCTIONS //
// ------------------------------------------------------------------------------------------------------------------//
// Calculate sun colour
SUN_RESULT calcSunData(float3 viewDir)
{
half cosTheta = dot(viewDir, -sunDirection);
const half cosThetaSq = cosTheta * cosTheta;
const half phase = (1.0f + cosThetaSq) / ragePow((miePhaseSqrPlusOne - (miePhaseTimesTwo * cosTheta)), 1.5f) * mieConstantTimesScatter;
SUN_RESULT OUT;
OUT.color = (sunColorHdr * saturate(phase)) * mieIntensityMult;
OUT.cosTheta = saturate(-cosTheta);
OUT.invAlpha = saturate(1.0 - phase);
return OUT;
}
// ------------------------------------------------------------------------------------------------------------------//
// Calculate sky colour
half3 calcAtmosphereColor(half3 viewDir)
{
// Azimuth blend = cos(angle) [-1..1] -> [0..1] and used as a lerp factor
// Zenith blend = cos(angle) [0..1] (as its only from the horizon upwards)
const half azimuthBlend = sqrt(-viewDir.x * 0.5 + 0.5);
const half zenithBlend = abs(viewDir.z);
// Defines where along the arc the transition color is used
const half3 azimuthColor = (azimuthBlend < azimuthTransitionPosition) ?
lerp(azimuthEastColor, azimuthTransitionColor, azimuthBlend / azimuthTransitionPosition) :
lerp(azimuthTransitionColor, azimuthWestColor, (azimuthBlend - azimuthTransitionPosition) / (1.0 - azimuthTransitionPosition));
// Blend the zenith transition color with the already calculated azimuthBlend
const half zenithTransitionBlend = lerp(zenithTransitionEastBlend, zenithTransitionWestBlend, azimuthBlend);
const half3 newZenithTransitionColor = lerp(azimuthColor, zenithTransitionColor, zenithTransitionBlend);
// Define where along the hemisphere a blend between the azimuth and zenith color occurs
half zenithTransitionToTop = saturate((zenithBlend - zenithTransitionPosition) / (1.0f - zenithTransitionPosition));
half bottomToZenithTransition = (zenithBlend / zenithTransitionPosition);
zenithTransitionToTop = saturate(zenithTransitionToTop / oneMinusZenithBlendStart);
const half3 skyColor = (zenithBlend < zenithTransitionPosition) ?
lerp(azimuthColor, newZenithTransitionColor, bottomToZenithTransition) :
lerp(newZenithTransitionColor, zenithColor, zenithTransitionToTop);
return skyColor;
}
// ------------------------------------------------------------------------------------------------------------------//
CLOUD_RESULT calcCloudData(PS_sky_INPUT IN, half3 viewDir, TEX_DATA texData)
{
// ------------------------- //
// Calculate base for clouds //
// ------------------------- //
half cloudBase = texData.offsetPerlin.x;
cloudBase += texData.detailOverall * cloudOverallColorStrength * cloudOverallDetailStrength;
cloudBase = cloudBase * cloudBaseStrength * texData.perlin.x;
// ----------------------- //
// Calculate cloud density //
// ----------------------- //
// Work done in two channels, x = large clouds, y = small clouds
half2 detailAmt = half2(texData.detailOverall, 1.0-texData.perlin.y) * half2(cloudOverallDetailStrength, smallCloudDetailStrength);
detailAmt += texData.detailEdge * half2(cloudEdgeDetailStrength, smallCloudDetailStrength) * saturate(1.0f - cloudBase * 2.0f) * texData.perlin.y;
const half2 cloud = half2(texData.perlin.x, 0.0) + detailAmt;
const half2 cloudDensity = saturate(half2(cloudDensityMultiplier, smallCloudDensityMultiplier) *
cloud -
half2(cloudDensityBias, smallCloudDensityBias));
half2 amount = cloudDensity * cloudDensity;
// Fade
const half fade = saturate(viewDir.z * 5.0f - cloudFadeOut);
amount *= fade;
half invAmount = saturate(1.0 - amount.x);
// -------- //
// The rest //
// -------- //
// Compile output structure
CLOUD_RESULT OUT;
// So shadow isn't additive
// half3 finalBaseColor = lerp(cloudBaseColour.xyz, cloudShadowColour, (texData.offsetPerlin.y + detailAmt.x) * cloudShadowStrength);
// OUT.color = lerp(cloudMidColour.xyz, finalBaseColor, cloudBase);
half shadowAmount = (texData.offsetPerlin.y + detailAmt.x);
half3 finalBaseColorMinusMid = shadowAmount * cloudShadowMinusBaseColourTimesShadowStrength + cloudBaseMinusMidColour;
OUT.color = cloudBase * (finalBaseColorMinusMid) + cloudMidColour;
OUT.dimming = amount.x + (amount.y * 0.3 * invAmount); // Reduce light on filler clouds
OUT.noise = cloud.x;
OUT.alpha = amount;
return OUT;
}
// ------------------------------------------------------------------------------------------------------------------//
EFFECTS_RESULT calcEffectsDataSun(float3 viewDir, CLOUD_RESULT cloudResults, SUN_RESULT sunResults)
{
const float influenceRange = 1.0 - saturate((1.0 - sunResults.cosTheta) / effectsConstants.x * 100.0);
float dimming = influenceRange * cloudResults.dimming * saturate(1.0 - cloudResults.noise);
dimming *= dimming;
dimming *= dimming;
dimming *= sunScatterIntensity;
EFFECTS_RESULT OUT;
OUT.color = sunColor * dimming;
return OUT;
}
// ------------------------------------------------------------------------------------------------------------------//
EFFECTS_RESULT calcEffectsDataMoon(float3 viewDir, CLOUD_RESULT cloudResults, float moonAngle)
{
const float influenceRange = 1.0 - saturate((1.0 - moonAngle) / effectsConstants.z * 100.0);
float dimming = influenceRange * cloudResults.dimming * saturate(1.0 - cloudResults.noise);
dimming *= dimming;
dimming *= dimming;
dimming *= (moonScatterIntensity * (lunarCycle.y * 0.5 + 0.5));
EFFECTS_RESULT OUT;
OUT.color = moonColor * dimming;
return OUT;
}
// ------------------------------------------------------------------------------------------------------------------//
EFFECTS_RESULT calcEffectsDataSunMoon(float3 viewDir, CLOUD_RESULT cloudResults, SUN_RESULT sunResults, float moonAngle)
{
// A fade from 1 to sunInfluence radius, 0 beyond that
const half2 cosTheta = half2(sunResults.cosTheta, moonAngle);
// effectsConstants.xz = sun/moon influence radius
const half2 influenceRange = 1.0 - saturate((1.0 - cosTheta) / effectsConstants.xz * 100.0);
half2 dimming = influenceRange * cloudResults.dimming * saturate(1.0 - cloudResults.noise);
dimming *= dimming;
dimming *= dimming;
dimming *= half2(sunScatterIntensity, moonScatterIntensity * (lunarCycle.y * 0.5 + 0.5));
EFFECTS_RESULT OUT;
OUT.color = (sunColor * dimming.xxx) + (moonColor * dimming.yyy);
return OUT;
}
// ------------------------------------------------------------------------------------------------------------------//
// Get all the texture data upfront
TEX_DATA getTexData(PS_sky_INPUT IN)
{
TEX_DATA OUT;
OUT.perlin = h3tex2D(perlinSampler, IN.texCoord.xy).xz;
OUT.offsetPerlin = h2tex2D(perlinSampler, IN.texCoord.zw).xy;
OUT.detailOverall = h1tex2D(highDetailSampler, IN.detailTexCoord.zw).x - 0.5f;
OUT.detailEdge.x = h1tex2D(highDetailSampler, IN.detailTexCoord.xy).x - 0.5f;
OUT.detailEdge.y = h1tex2D(highDetailSampler, IN.smallCloudTexCoords.xy).x - 0.5f;
OUT.dither = h1tex2D(ditherSampler, IN.ditherTexCoord.xy).x - 0.5;
OUT.stars = h3tex2D(starFieldSampler, IN.starTexCoords.xy).rgb;
return OUT;
}
// ------------------------------------------------------------------------------------------------------------------//
// Calculate Noise
half calculateCloudNoise(VS_PERLIN_OUTPUT IN)
{
// amp = amplitude
// point = position of point
// freq = frequency
// Persistance = gain
half2 p = ((IN.texCoord.xy - 0.5) * noiseScale + 0.5) / 128.0 + noisePhase;
float finalnoise = 0.0f;
float amp = 1.0f;
for(int i = 0 ; i < 3 ;i++)
{
half3 noiseVal = (h3tex2D(NoiseSampler, p.xy).xyz - 0.5) * 2.0;
finalnoise += noiseVal[i] * amp;
p *= noiseFrequency;
amp *= 0.5;
}
return finalnoise / 1.75;
}
// ------------------------------------------------------------------------------------------------------------------//
// SKY TECHNIQUE //
// ------------------------------------------------------------------------------------------------------------------//
VS_sky_OUTPUT vs_sky_main(
float4 transPos, VS_sky_INPUT IN,
uniform bool fogEnabled,
uniform bool sunEnabled,
uniform bool moonEnabled,
uniform bool cloudsEnabled,
uniform bool starsEnabled,
uniform bool debugEnabled,
uniform bool useInst
)
{
VS_sky_OUTPUT OUT;
OUT.pos = transPos;
OUT.texCoord.xy = IN.texCoord0.xy;
float3 camPos = float3(0,0,0);
#if GS_INSTANCED_CUBEMAP
if (useInst)
{
OUT.worldPos.xyz = (float3)mul(IN.pos, gInstWorld);
camPos = gInstViewInverse[IN.InstID][3].xyz;
}
else
#endif
{
// Set world pos (subtract any translation in world matrix)
OUT.worldPos.xyz = (float3)mul(IN.pos, gWorld);
camPos = gViewInverse[3].xyz;
}
OUT.fogData = CalcFogDataNoHaze( OUT.worldPos - camPos.xyz );
// Set camera to always be at the horizon (this way sun doesn't move
// up and down the skydome
const half3 cameraPos = half3(camPos.xy, horizonLevel);
// Calculate sky color and pass to fragment shader
const half3 viewDir = normalize(OUT.worldPos.xyz - cameraPos);
float3 skyCol = calcAtmosphereColor(viewDir);
OUT.skyCol.rgb = skyCol * hdrIntensity;
OUT.skyCol.a = 0.0f;
// Azimuth blend
float zenithBlend = saturate(dot(normalize(OUT.worldPos.xyz), half3(0.0f, 0.0f, 1.0f)));
zenithBlend = saturate(zenithBlend / 0.2);
OUT.worldPos.w = zenithBlend;
// Calculate offset for bottom of cloud
const half2 ofs = (cloudOffset / 10.0f) * (sunDirection.xyz - viewDir.xyz).xy;
// This is used to offset clouds away from the sun (the base layer)
OUT.texCoord.zw = IN.texCoord0.xy + sphericalWarpOffset(IN.texCoord0.xy, -ofs);
OUT.detailTexCoord.xy = ((IN.texCoord0.xy - 0.5) + edgeDetailOffset) * cloudEdgeDetailScale ; // for edge of clouds
OUT.detailTexCoord.zw = ((IN.texCoord0.yx - 0.5) + overallDetailOffset) * cloudOverallDetailScale; // for sky in general
OUT.ditherTexCoord.xy = IN.texCoord1.xy * 64.0; // for dither texture (2nd UV set)
OUT.smallCloudTexCoords.xy = ((IN.texCoord0.xy - 0.5) + smallCloudOffset) * smallCloudDetailScale; // small cloud tex coords
OUT.starTexCoords.xy = IN.texCoord1.xy * 12.0; // star uv coords (2nd UV set)
return OUT;
}
// ------------------------------------------------------------------------------------------------------------------//
VS_sky_OUTPUT vs_sky_main(
float4 transPos, VS_sky_INPUT IN,
uniform bool fogEnabled,
uniform bool sunEnabled,
uniform bool moonEnabled,
uniform bool cloudsEnabled,
uniform bool starsEnabled,
uniform bool debugEnabled
)
{
return vs_sky_main(transPos, IN, fogEnabled, sunEnabled, moonEnabled, cloudsEnabled, starsEnabled, debugEnabled, false);
}
// ------------------------------------------------------------------------------------------------------------------//
float4 ps_sky_main(
PS_sky_INPUT IN,
uniform bool fogEnabled,
uniform bool sunEnabled,
uniform bool moonEnabled,
uniform bool cloudsEnabled,
uniform bool starsEnabled,
uniform bool debugEnabled)
{
#if !defined(SHADER_FINAL)
if (debugEnabled)
{
IN.texCoord *= debugCloudsParams[2].x;
IN.detailTexCoord *= debugCloudsParams[2].x;
IN.ditherAndSmallCloudTexCoord *= debugCloudsParams[2].x;
// note: we've modified the texcoords in 'IN' above ..
TEX_DATA texData = getTexData(IN);
const float4 texData_perlin_texcoord_x = float4(IN.texCoord.xz, 0, 0);
const float4 texData_perlin_texcoord_y = float4(IN.texCoord.yw, 0, 0);
const float4 texData_detail_texcoord_x = float4(IN.detailTexCoord.x, IN.smallCloudTexCoords.x, IN.detailTexCoord.z, IN.ditherTexCoord.x);
const float4 texData_detail_texcoord_y = float4(IN.detailTexCoord.y, IN.smallCloudTexCoords.y, IN.detailTexCoord.w, IN.ditherTexCoord.y);
const float4 texData_perlin = float4(texData.perlin, texData.offsetPerlin);
const float4 texData_detail = float4(texData.detailEdge, texData.detailOverall, texData.dither);
float3 OUT;
OUT.x = dot(texData_perlin_texcoord_x, debugCloudsParams[0]) + dot(texData_detail_texcoord_x, debugCloudsParams[1]);
OUT.y = dot(texData_perlin_texcoord_y, debugCloudsParams[0]) + dot(texData_detail_texcoord_y, debugCloudsParams[1]);
OUT.z = dot(texData_perlin , debugCloudsParams[0]) + dot(texData_detail , debugCloudsParams[1]);
if (debugCloudsParams[2].y == 4) // wireframe
{
return float4(0.5,0,1,1);
}
else if (debugCloudsParams[2].y == 2) // density (large=red, small=green)
{
return float4(calcCloudData(IN, normalize(IN.worldPos), texData).alpha.xy, 0, 1);
}
else
{
return float4(lerp(OUT.zzz, float3(frac(OUT.xy), 0), debugCloudsParams[2].y), 1);
}
}
#endif // !defined(SHADER_FINAL)
TEX_DATA texData = getTexData(IN);
// view and adjusted moon direction
half3 viewDir = normalize(IN.worldPos);
half3 skyColor = half3(0.0, 0.0, 0.0);
SUN_RESULT sunResults = (SUN_RESULT)0;
CLOUD_RESULT cloudResults = (CLOUD_RESULT)0;
const float moonAngle = dot(viewDir, moonDirection);
// Add in sun to sky color, make sure its not additive
sunResults = calcSunData(viewDir);
skyColor += IN.skyCol.rgb * sunResults.invAlpha;
skyColor += sunResults.color;
if (cloudsEnabled)
{
// Blend in small clouds and then big clouds
cloudResults = calcCloudData(IN, viewDir, texData);
skyColor = lerp(skyColor, smallCloudColorHdr, cloudResults.alpha.y);
skyColor = lerp(skyColor, cloudResults.color * cloudHdrIntensity, cloudResults.alpha.x);
}
else
{
// These are needed for effects
cloudResults.dimming = 0.0f;
cloudResults.noise = texData.perlin.x;
}
if (sunEnabled || moonEnabled)
{
// Add in effects
EFFECTS_RESULT effectResults;
if (sunEnabled && !moonEnabled)
{
effectResults = calcEffectsDataSun(viewDir, cloudResults, sunResults);
}
if (moonEnabled && !sunEnabled)
{
effectResults = calcEffectsDataMoon(viewDir, cloudResults, moonAngle);
}
if (sunEnabled && moonEnabled)
{
effectResults = calcEffectsDataSunMoon(viewDir, cloudResults, sunResults, moonAngle);
}
skyColor += effectResults.color;
}
if (starsEnabled)
{
// Stars (don't add where there are clouds or the moon)
const half moonDisk = step(0.00054475, 1.0 - moonAngle);
half3 stars = saturate(texData.stars * 2.0 - 0.1f);
skyColor += stars * starfieldIntensity * moonDisk * (1.0 - cloudResults.dimming);
}
// need to blend in fog here
if (fogEnabled)
{
#if defined(USE_FOGRAY_FORWARDPASS) && !__LOW_QUALITY
IN.fogData.a *= GetFogRayIntensity(IN.pos.xy * gooScreenSize.xy);
#endif
}
skyColor = lerp(skyColor, IN.fogData.rgb, IN.fogData.a);
// Dithering
skyColor += texData.dither*kDitherScale;
// Write final colour with alpha
half4 finalColor = half4(skyColor, saturate(IN.worldPos.w - (cloudResults.alpha.x + cloudResults.alpha.y)));
return finalColor;
}
// ------------------------------------------------------------------------------------------------------------------//
GEN_SKY_FUNCS(sky, none, SUN_OFF, MOON_OFF, CLOUDS_OFF, STARS_OFF, DEBUG_OFF)
GEN_SKY_FUNCS(sky, stars, SUN_OFF, MOON_OFF, CLOUDS_OFF, STARS_ON, DEBUG_OFF)
GEN_SKY_FUNCS(sky, clouds, SUN_OFF, MOON_OFF, CLOUDS_ON, STARS_OFF, DEBUG_OFF)
GEN_SKY_FUNCS(sky, clouds_stars, SUN_OFF, MOON_OFF, CLOUDS_ON, STARS_ON, DEBUG_OFF)
GEN_SKY_FUNCS(sky, moon, SUN_OFF, MOON_ON, CLOUDS_OFF, STARS_OFF, DEBUG_OFF)
GEN_SKY_FUNCS(sky, moon_stars, SUN_OFF, MOON_ON, CLOUDS_OFF, STARS_ON, DEBUG_OFF)
GEN_SKY_FUNCS(sky, moon_clouds, SUN_OFF, MOON_ON, CLOUDS_ON, STARS_OFF, DEBUG_OFF)
GEN_SKY_FUNCS(sky, moon_clouds_stars, SUN_OFF, MOON_ON, CLOUDS_ON, STARS_ON, DEBUG_OFF)
GEN_SKY_FUNCS(sky, sun, SUN_ON, MOON_OFF, CLOUDS_OFF, STARS_OFF, DEBUG_OFF)
GEN_SKY_FUNCS(sky, sun_stars, SUN_ON, MOON_OFF, CLOUDS_OFF, STARS_ON, DEBUG_OFF)
GEN_SKY_FUNCS(sky, sun_clouds, SUN_ON, MOON_OFF, CLOUDS_ON, STARS_OFF, DEBUG_OFF)
GEN_SKY_FUNCS(sky, sun_clouds_stars, SUN_ON, MOON_OFF, CLOUDS_ON, STARS_ON, DEBUG_OFF)
GEN_SKY_FUNCS(sky, sun_moon, SUN_ON, MOON_ON, CLOUDS_OFF, STARS_OFF, DEBUG_OFF)
GEN_SKY_FUNCS(sky, sun_moon_stars, SUN_ON, MOON_ON, CLOUDS_OFF, STARS_ON, DEBUG_OFF)
GEN_SKY_FUNCS(sky, sun_moon_clouds, SUN_ON, MOON_ON, CLOUDS_ON, STARS_OFF, DEBUG_OFF)
GEN_SKY_FUNCS(sky, all, SUN_ON, MOON_ON, CLOUDS_ON, STARS_ON, DEBUG_OFF)
#if !defined(SHADER_FINAL)
GEN_SKY_FUNCS(sky, dbg_clouds, SUN_OFF, MOON_OFF, CLOUDS_ON, STARS_OFF, DEBUG_ON )
#endif // !defined(SHADER_FINAL)
// ------------------------------------------------------------------------------------------------------------------//
technique sky
{
GEN_PASS(sky, normal, none)
GEN_PASS(sky, normal, stars)
GEN_PASS(sky, normal, clouds)
GEN_PASS(sky, normal, clouds_stars)
GEN_PASS(sky, normal, moon)
GEN_PASS(sky, normal, moon_stars)
GEN_PASS(sky, normal, moon_clouds)
GEN_PASS(sky, normal, moon_clouds_stars)
GEN_PASS(sky, normal, sun)
GEN_PASS(sky, normal, sun_stars)
GEN_PASS(sky, normal, sun_clouds)
GEN_PASS(sky, normal, sun_clouds_stars)
GEN_PASS(sky, normal, sun_moon)
GEN_PASS(sky, normal, sun_moon_stars)
GEN_PASS(sky, normal, sun_moon_clouds)
GEN_PASS(sky, normal, all)
#if !defined(SHADER_FINAL)
GEN_PASS(sky, normal, dbg_clouds)
#endif // !defined(SHADER_FINAL)
}
technique sky_water_reflection
{
GEN_PASS(sky, water_reflection, none)
GEN_PASS(sky, water_reflection, stars)
GEN_PASS(sky, water_reflection, clouds)
GEN_PASS(sky, water_reflection, clouds_stars)
GEN_PASS(sky, water_reflection, moon)
GEN_PASS(sky, water_reflection, moon_stars)
GEN_PASS(sky, water_reflection, moon_clouds)
GEN_PASS(sky, water_reflection, moon_clouds_stars)
GEN_PASS(sky, water_reflection, sun)
GEN_PASS(sky, water_reflection, sun_stars)
GEN_PASS(sky, water_reflection, sun_clouds)
GEN_PASS(sky, water_reflection, sun_clouds_stars)
GEN_PASS(sky, water_reflection, sun_moon)
GEN_PASS(sky, water_reflection, sun_moon_stars)
GEN_PASS(sky, water_reflection, sun_moon_clouds)
GEN_PASS(sky, water_reflection, all)
#if !defined(SHADER_FINAL)
// GEN_PASS(sky, water_reflection, dbg_clouds) -- don't need this for sky_water_reflection
#endif // !defined(SHADER_FINAL)
}
technique sky_mirror_reflection
{
GEN_PASS(sky, mirror_reflection, none)
GEN_PASS(sky, mirror_reflection, stars)
GEN_PASS(sky, mirror_reflection, clouds)
GEN_PASS(sky, mirror_reflection, clouds_stars)
GEN_PASS(sky, mirror_reflection, moon)
GEN_PASS(sky, mirror_reflection, moon_stars)
GEN_PASS(sky, mirror_reflection, moon_clouds)
GEN_PASS(sky, mirror_reflection, moon_clouds_stars)
GEN_PASS(sky, mirror_reflection, sun)
GEN_PASS(sky, mirror_reflection, sun_stars)
GEN_PASS(sky, mirror_reflection, sun_clouds)
GEN_PASS(sky, mirror_reflection, sun_clouds_stars)
GEN_PASS(sky, mirror_reflection, sun_moon)
GEN_PASS(sky, mirror_reflection, sun_moon_stars)
GEN_PASS(sky, mirror_reflection, sun_moon_clouds)
GEN_PASS(sky, mirror_reflection, all)
#if !defined(SHADER_FINAL)
// GEN_PASS(sky, mirror_reflection, dbg_clouds) -- don't need this for sky_mirror_reflection
#endif // !defined(SHADER_FINAL)
}
#if GS_INSTANCED_CUBEMAP
GEN_GSINST_TYPE(Sky,VS_sky_OUTPUT,SV_RenderTargetArrayIndex)
GEN_GSINST_FUNC(Sky,sky_none,VS_sky_INPUT,VS_sky_OUTPUT,PS_sky_INPUT
,vs_sky_main(mul(IN.pos, mul(gInstWorld,gInstWorldViewProj[IN.InstID])),IN,FOG_ON,SUN_OFF, MOON_OFF, CLOUDS_OFF, STARS_OFF, DEBUG_OFF,true)
,CastOutHalf4Color(PackHdr(ps_sky_main(IN,FOG_ON,SUN_OFF, MOON_OFF, CLOUDS_OFF, STARS_OFF, DEBUG_OFF))))
GEN_GSINST_FUNC(Sky,sky_stars,VS_sky_INPUT,VS_sky_OUTPUT,PS_sky_INPUT
,vs_sky_main(mul(IN.pos, mul(gInstWorld,gInstWorldViewProj[IN.InstID])),IN,FOG_ON,SUN_OFF, MOON_OFF, CLOUDS_OFF, STARS_ON, DEBUG_OFF,true)
,CastOutHalf4Color(PackHdr(ps_sky_main(IN,FOG_ON,SUN_OFF, MOON_OFF, CLOUDS_OFF, STARS_ON, DEBUG_OFF))))
GEN_GSINST_FUNC(Sky,sky_clouds,VS_sky_INPUT,VS_sky_OUTPUT,PS_sky_INPUT
,vs_sky_main(mul(IN.pos, mul(gInstWorld,gInstWorldViewProj[IN.InstID])),IN,FOG_ON,SUN_OFF, MOON_OFF, CLOUDS_ON, STARS_OFF, DEBUG_OFF,true)
,CastOutHalf4Color(PackHdr(ps_sky_main(IN,FOG_ON,SUN_OFF, MOON_OFF, CLOUDS_ON, STARS_OFF, DEBUG_OFF))))
GEN_GSINST_FUNC(Sky,sky_clouds_stars,VS_sky_INPUT,VS_sky_OUTPUT,PS_sky_INPUT
,vs_sky_main(mul(IN.pos, mul(gInstWorld,gInstWorldViewProj[IN.InstID])),IN,FOG_ON,SUN_OFF, MOON_OFF, CLOUDS_ON, STARS_ON, DEBUG_OFF,true)
,CastOutHalf4Color(PackHdr(ps_sky_main(IN,FOG_ON,SUN_OFF, MOON_OFF, CLOUDS_ON, STARS_ON, DEBUG_OFF))))
GEN_GSINST_FUNC(Sky,sky_moon,VS_sky_INPUT,VS_sky_OUTPUT,PS_sky_INPUT
,vs_sky_main(mul(IN.pos, mul(gInstWorld,gInstWorldViewProj[IN.InstID])),IN,FOG_ON,SUN_OFF, MOON_ON, CLOUDS_OFF, STARS_OFF, DEBUG_OFF,true)
,CastOutHalf4Color(PackHdr(ps_sky_main(IN,FOG_ON,SUN_OFF, MOON_ON, CLOUDS_OFF, STARS_OFF, DEBUG_OFF))))
GEN_GSINST_FUNC(Sky,sky_moon_stars,VS_sky_INPUT,VS_sky_OUTPUT,PS_sky_INPUT
,vs_sky_main(mul(IN.pos, mul(gInstWorld,gInstWorldViewProj[IN.InstID])),IN,FOG_ON,SUN_OFF, MOON_ON, CLOUDS_OFF, STARS_ON, DEBUG_OFF,true)
,CastOutHalf4Color(PackHdr(ps_sky_main(IN,FOG_ON,SUN_OFF, MOON_ON, CLOUDS_OFF, STARS_ON, DEBUG_OFF))))
GEN_GSINST_FUNC(Sky,sky_moon_clouds,VS_sky_INPUT,VS_sky_OUTPUT,PS_sky_INPUT
,vs_sky_main(mul(IN.pos, mul(gInstWorld,gInstWorldViewProj[IN.InstID])),IN,FOG_ON,SUN_OFF, MOON_ON, CLOUDS_ON, STARS_OFF, DEBUG_OFF,true)
,CastOutHalf4Color(PackHdr(ps_sky_main(IN,FOG_ON,SUN_OFF, MOON_ON, CLOUDS_ON, STARS_OFF, DEBUG_OFF))))
GEN_GSINST_FUNC(Sky,sky_moon_clouds_stars,VS_sky_INPUT,VS_sky_OUTPUT,PS_sky_INPUT
,vs_sky_main(mul(IN.pos, mul(gInstWorld,gInstWorldViewProj[IN.InstID])),IN,FOG_ON,SUN_OFF, MOON_ON, CLOUDS_ON, STARS_ON, DEBUG_OFF,true)
,CastOutHalf4Color(PackHdr(ps_sky_main(IN,FOG_ON,SUN_OFF, MOON_ON, CLOUDS_ON, STARS_ON, DEBUG_OFF))))
GEN_GSINST_FUNC(Sky,sky_sun,VS_sky_INPUT,VS_sky_OUTPUT,PS_sky_INPUT
,vs_sky_main(mul(IN.pos, mul(gInstWorld,gInstWorldViewProj[IN.InstID])),IN,FOG_ON,SUN_ON, MOON_OFF, CLOUDS_OFF, STARS_OFF, DEBUG_OFF,true)
,CastOutHalf4Color(PackHdr(ps_sky_main(IN,FOG_ON,SUN_ON, MOON_OFF, CLOUDS_OFF, STARS_OFF, DEBUG_OFF))))
GEN_GSINST_FUNC(Sky,sky_sun_stars,VS_sky_INPUT,VS_sky_OUTPUT,PS_sky_INPUT
,vs_sky_main(mul(IN.pos, mul(gInstWorld,gInstWorldViewProj[IN.InstID])),IN,FOG_ON,SUN_ON, MOON_OFF, CLOUDS_OFF, STARS_ON, DEBUG_OFF,true)
,CastOutHalf4Color(PackHdr(ps_sky_main(IN,FOG_ON,SUN_ON, MOON_OFF, CLOUDS_OFF, STARS_ON, DEBUG_OFF))))
GEN_GSINST_FUNC(Sky,sky_sun_clouds,VS_sky_INPUT,VS_sky_OUTPUT,PS_sky_INPUT
,vs_sky_main(mul(IN.pos, mul(gInstWorld,gInstWorldViewProj[IN.InstID])),IN,FOG_ON,SUN_ON, MOON_OFF, CLOUDS_ON, STARS_OFF, DEBUG_OFF,true)
,CastOutHalf4Color(PackHdr(ps_sky_main(IN,FOG_ON,SUN_ON, MOON_OFF, CLOUDS_ON, STARS_OFF, DEBUG_OFF))))
GEN_GSINST_FUNC(Sky,sky_sun_clouds_stars,VS_sky_INPUT,VS_sky_OUTPUT,PS_sky_INPUT
,vs_sky_main(mul(IN.pos, mul(gInstWorld,gInstWorldViewProj[IN.InstID])),IN,FOG_ON,SUN_ON, MOON_OFF, CLOUDS_ON, STARS_ON, DEBUG_OFF,true)
,CastOutHalf4Color(PackHdr(ps_sky_main(IN,FOG_ON,SUN_ON, MOON_OFF, CLOUDS_ON, STARS_ON, DEBUG_OFF))))
GEN_GSINST_FUNC(Sky,sky_sun_moon,VS_sky_INPUT,VS_sky_OUTPUT,PS_sky_INPUT
,vs_sky_main(mul(IN.pos, mul(gInstWorld,gInstWorldViewProj[IN.InstID])),IN,FOG_ON,SUN_ON, MOON_ON, CLOUDS_OFF, STARS_OFF, DEBUG_OFF,true)
,CastOutHalf4Color(PackHdr(ps_sky_main(IN,FOG_ON,SUN_ON, MOON_ON, CLOUDS_OFF, STARS_OFF, DEBUG_OFF))))
GEN_GSINST_FUNC(Sky,sky_sun_moon_stars,VS_sky_INPUT,VS_sky_OUTPUT,PS_sky_INPUT
,vs_sky_main(mul(IN.pos, mul(gInstWorld,gInstWorldViewProj[IN.InstID])),IN,FOG_ON,SUN_ON, MOON_ON, CLOUDS_OFF, STARS_ON, DEBUG_OFF,true)
,CastOutHalf4Color(PackHdr(ps_sky_main(IN,FOG_ON,SUN_ON, MOON_ON, CLOUDS_OFF, STARS_ON, DEBUG_OFF))))
GEN_GSINST_FUNC(Sky,sky_sun_moon_clouds,VS_sky_INPUT,VS_sky_OUTPUT,PS_sky_INPUT
,vs_sky_main(mul(IN.pos, mul(gInstWorld,gInstWorldViewProj[IN.InstID])),IN,FOG_ON,SUN_ON, MOON_ON, CLOUDS_ON, STARS_OFF, DEBUG_OFF,true)
,CastOutHalf4Color(PackHdr(ps_sky_main(IN,FOG_ON,SUN_ON, MOON_ON, CLOUDS_ON, STARS_OFF, DEBUG_OFF))))
GEN_GSINST_FUNC(Sky,sky_all,VS_sky_INPUT,VS_sky_OUTPUT,PS_sky_INPUT
,vs_sky_main(mul(IN.pos, mul(gInstWorld,gInstWorldViewProj[IN.InstID])),IN,FOG_ON,SUN_ON, MOON_ON, CLOUDS_ON, STARS_ON, DEBUG_OFF,true)
,CastOutHalf4Color(PackHdr(ps_sky_main(IN,FOG_ON,SUN_ON, MOON_ON, CLOUDS_ON, STARS_ON, DEBUG_OFF))))
#if !defined(SHADER_FINAL)
GEN_GSINST_FUNC(Sky, dbg_clouds,VS_sky_INPUT,VS_sky_OUTPUT,PS_sky_INPUT
,vs_sky_main(mul(IN.pos, mul(gInstWorld,gInstWorldViewProj[IN.InstID])),IN,FOG_ON,SUN_OFF, MOON_OFF, CLOUDS_ON, STARS_OFF, DEBUG_ON,true)
,CastOutHalf4Color(PackHdr(ps_sky_main(IN,FOG_ON,SUN_OFF, MOON_OFF, CLOUDS_ON, STARS_OFF, DEBUG_ON))))
#endif // !defined(SHADER_FINAL)
technique sky_cubemap
{
GEN_GSINST_TECHPASS(sky_none, none)
GEN_GSINST_TECHPASS(sky_stars, stars)
GEN_GSINST_TECHPASS(sky_clouds, clouds)
GEN_GSINST_TECHPASS(sky_clouds_stars, clouds_stars)
GEN_GSINST_TECHPASS(sky_moon, moon)
GEN_GSINST_TECHPASS(sky_moon_stars, moon_stars)
GEN_GSINST_TECHPASS(sky_moon_clouds, moon_clouds)
GEN_GSINST_TECHPASS(sky_moon_clouds_stars, moon_clouds_stars)
GEN_GSINST_TECHPASS(sky_sun, sun)
GEN_GSINST_TECHPASS(sky_sun_stars, sun_stars)
GEN_GSINST_TECHPASS(sky_sun_clouds, sun_clouds)
GEN_GSINST_TECHPASS(sky_sun_clouds_stars, sun_clouds_stars)
GEN_GSINST_TECHPASS(sky_sun_moon, sun_moon)
GEN_GSINST_TECHPASS(sky_sun_moon_stars, sun_moon_stars)
GEN_GSINST_TECHPASS(sky_sun_moon_clouds, sun_moon_clouds)
GEN_GSINST_TECHPASS(sky_all, all)
}
#endif
// ------------------------------------------------------------------------------------------------------------------//
// MOON TECHNIQUES //
// ------------------------------------------------------------------------------------------------------------------//
float4 vs_moon_main(float4 inPos
#if GS_INSTANCED_CUBEMAP
,uniform bool bUseInst,uint InstID
#endif
)
{
// Create the billboard matrix, don't use the camera up vector as this
// will make the moon rotate around as that changes, so its fixed
float3x3 bMat;
#if GS_INSTANCED_CUBEMAP
if (bUseInst)
bMat[1] = normalize(gInstViewInverse[InstID][3].xyz - moonPosition.xyz);
else
#endif
bMat[1] = normalize(gViewInverse[3].xyz - moonPosition.xyz);
bMat[0] = normalize(cross(float3(0, 0, 1.0), bMat[1]));
bMat[2] = cross(bMat[1], bMat[0]);
return float4(mul(inPos.xyz, bMat) + moonPosition, inPos.w);
}
// ------------------------------------------------------------------------------------------------------------------//
VS_moon_OUTPUT vs_moon_common(VS_moon_INPUT IN
#if GS_INSTANCED_CUBEMAP
,uniform bool bUseInst
#endif
)
{
float4 pos = vs_moon_main(IN.inPos
#if GS_INSTANCED_CUBEMAP
,bUseInst
,IN.InstID
#endif
);
VS_moon_OUTPUT OUT;
#if GS_INSTANCED_CUBEMAP
if (bUseInst)
{
OUT.pos = mul(pos, mul(gInstWorld,gInstWorldViewProj[IN.InstID]));
OUT.worldPos = mul(pos, gInstWorld);
OUT.worldPos.w = saturate(1.0 - CalcFogDataNoHaze(normalize(OUT.worldPos - gInstViewInverse[IN.InstID][3].xyz) * 25000.0f).a);
}
else
#endif
{
OUT.pos = mul(pos, gWorldViewProj);
OUT.worldPos = mul(pos, gWorld);
OUT.worldPos.w = saturate(1.0 - CalcFogDataNoHaze(normalize(OUT.worldPos - gViewInverse[3].xyz) * 25000.0f).a);
}
OUT.texCoord.xy = float2(IN.inTexCoords.x, 1.0f - IN.inTexCoords.y);
float zenithBlend = saturate(dot(normalize(OUT.worldPos.xyz), half3(0.0f, 0.0f, 1.0f)));
zenithBlend = saturate(zenithBlend / 0.2);
OUT.worldPos.w *= zenithBlend;
return OUT;
}
VS_moon_OUTPUT vs_moon(VS_moon_INPUT IN)
{
return vs_moon_common(IN
#if GS_INSTANCED_CUBEMAP
,false
#endif
);
}
// ------------------------------------------------------------------------------------------------------------------//
half4 ps_moon_main(VS_moon_OUTPUT IN)
{
half4 moonBrightness = h4tex2D(moonSampler, IN.texCoord.xy);
// Tex-coords are stretched out so bring them back into [0..1]
float2 normCoords = IN.texCoord.xy - float2(0.5, 0.5);
normCoords *= 2.0;
// Work out normal
float3 normal = float3(normCoords.x, sqrt(1.0 - dot(normCoords.xy, normCoords.xy)), normCoords.y);
normal = normalize(normal);
// Do standard diffuse lighting on the fake sphere
half3 L = normalize(lunarCycle);
half light = max(0.0, dot(normal, L));
const half3 moon = (moonBrightness.rgb * moonColor) * light * moonIntensity;
half4 result = half4(moon, 1.0f);
result.rgb = result.rgb * moonBrightness.a * IN.worldPos.w;
return result;
}
// ------------------------------------------------------------------------------------------------------------------//
OutHalf4Color ps_moon(VS_moon_OUTPUT IN)
{
return CastOutHalf4Color(PackHdr(ps_moon_main(IN)));
}
OutHalf4Color ps_moon_water_reflection(VS_moon_OUTPUT IN)
{
half4 mainMoonColor = ps_moon_main(IN);
mainMoonColor.rgb *= 0.03125;
return CastOutHalf4Color(mainMoonColor);
}
OutHalf4Color ps_moon_mirror_reflection(VS_moon_OUTPUT IN)
{
half4 mainMoonColor = ps_moon_main(IN);
return CastOutHalf4Color(mainMoonColor);
}
// ------------------------------------------------------------------------------------------------------------------//
technique moon
{
pass p0
{
VertexShader = compile VERTEXSHADER vs_moon();
PixelShader = compile PIXELSHADER ps_moon() OPTIMIZE;
}
}
technique moon_water_reflection
{
pass p0
{
VertexShader = compile VERTEXSHADER vs_moon();
PixelShader = compile PIXELSHADER ps_moon_water_reflection() OPTIMIZE;
}
}
technique moon_mirror_reflection
{
pass p0
{
VertexShader = compile VERTEXSHADER vs_moon();
PixelShader = compile PIXELSHADER ps_moon_mirror_reflection() OPTIMIZE;
}
}
#if GS_INSTANCED_CUBEMAP
GEN_GSINST_TYPE(Moon,VS_moon_OUTPUT,SV_RenderTargetArrayIndex)
GEN_GSINST_FUNC(Moon,Moon,VS_moon_INPUT,VS_moon_OUTPUT,VS_moon_OUTPUT,vs_moon_common(IN,true),ps_moon(IN))
technique moon_cubemap
{
GEN_GSINST_TECHPASS(Moon, all)
}
#endif
// ------------------------------------------------------------------------------------------------------------------//
// SUN TECHNIQUES //
// ------------------------------------------------------------------------------------------------------------------//
float4 vs_sun_main(float4 inPos
#if GS_INSTANCED_CUBEMAP
,uniform bool bUseInst, uint InstID
#endif
)
{
float3x3 bMat;
#if GS_INSTANCED_CUBEMAP
if (bUseInst)
bMat[1] = normalize(gInstViewInverse[InstID][3].xyz - sunPosition.xyz);
else
#endif
bMat[1] = normalize(gViewInverse[3].xyz - sunPosition.xyz);
bMat[0] = normalize(cross(float3(0, 0, 1.0), bMat[1]));
bMat[2] = cross(bMat[1], bMat[0]);
return float4(mul(inPos.xyz, bMat) + sunPosition.xyz, inPos.w);
}
// ------------------------------------------------------------------------------------------------------------------//
VS_sun_OUTPUT vs_sun_common(VS_sun_INPUT IN
#if GS_INSTANCED_CUBEMAP
,uniform bool bUseInst
#endif
)
{
float4 pos = vs_sun_main(IN.inPos
#if GS_INSTANCED_CUBEMAP
,bUseInst, IN.InstID
#endif
);
VS_sun_OUTPUT OUT;
#if GS_INSTANCED_CUBEMAP
if (bUseInst)
{
OUT.pos = mul(pos, mul(gInstWorld,gInstWorldViewProj[IN.InstID]));
float3 worldPos = (float3)mul(pos, gInstWorld);
OUT.fogData = CalcFogDataNoHaze(normalize(worldPos - gInstViewInverse[IN.InstID][3].xyz) * 25000.0f);
}
else
#endif
{
OUT.pos = mul(pos, gWorldViewProj);
float3 worldPos = (float3)mul(pos, gWorld);
OUT.fogData = CalcFogDataNoHaze(normalize(worldPos - gViewInverse[3].xyz) * 25000.0f);
}
return OUT;
}
VS_sun_OUTPUT vs_sun(VS_sun_INPUT IN)
{
return vs_sun_common(IN
#if GS_INSTANCED_CUBEMAP
,false
#endif
);
}
// ------------------------------------------------------------------------------------------------------------------//
half4 ps_sun_main(half4 fogData)
{
half4 result = half4(sunDiscColorHdr, 1.0);
result.rgb = lerp(result.rgb, fogData.rgb, fogData.a);
return result;
}
// ------------------------------------------------------------------------------------------------------------------//
OutHalf4Color ps_sun(VS_sun_OUTPUT IN)
{
return CastOutHalf4Color(PackHdr(ps_sun_main(IN.fogData)));
}
// ------------------------------------------------------------------------------------------------------------------//
OutHalf4Color ps_sun_water_reflection(VS_sun_OUTPUT IN)
{
return CastOutHalf4Color(PackReflection(ps_sun_main(IN.fogData)));
}
// ------------------------------------------------------------------------------------------------------------------//
OutHalf4Color ps_sun_mirror_reflection(VS_sun_OUTPUT IN)
{
return CastOutHalf4Color(PackHdr(ps_sun_main(IN.fogData)));
}
// ------------------------------------------------------------------------------------------------------------------//
OutHalf4Color ps_sun_seethrough(VS_sun_OUTPUT IN)
{
half4 result;
result.xy = 0.0f.xx;
float visibility = 0.5f;
result.z = visibility;
result.w = 1.0f;
return CastOutHalf4Color(result);
}
// ------------------------------------------------------------------------------------------------------------------//
technique sun
{
pass p0
{
AlphaBlendEnable = true;
SrcBlend = DESTALPHA;
DestBlend = INVDESTALPHA;
VertexShader = compile VERTEXSHADER vs_sun();
PixelShader = compile PIXELSHADER ps_sun() OPTIMIZE;
}
}
technique sun_water_reflection
{
pass p0
{
VertexShader = compile VERTEXSHADER vs_sun();
PixelShader = compile PIXELSHADER ps_sun_water_reflection() OPTIMIZE;
}
}
technique sun_mirror_reflection
{
pass p0
{
VertexShader = compile VERTEXSHADER vs_sun();
PixelShader = compile PIXELSHADER ps_sun_mirror_reflection() OPTIMIZE;
}
}
technique sun_seethrough
{
pass p0
{
AlphaBlendEnable = true;
SrcBlend = DESTALPHA;
DestBlend = INVDESTALPHA;
VertexShader = compile VERTEXSHADER vs_sun();
PixelShader = compile PIXELSHADER ps_sun_seethrough() OPTIMIZE;
}
}
#if GS_INSTANCED_CUBEMAP
GEN_GSINST_TYPE(Sun,VS_sun_OUTPUT,SV_RenderTargetArrayIndex)
GEN_GSINST_FUNC(Sun,Sun,VS_sun_INPUT,VS_sun_OUTPUT,VS_sun_OUTPUT,vs_sun_common(IN,true),ps_sun(IN))
technique sun_cubemap
{
GEN_GSINST_TECHPASS(Sun,all)
}
#endif
// ------------------------------------------------------------------------------------------------------------------//
// PERLIN TECHNIQUES //
// ------------------------------------------------------------------------------------------------------------------//
VS_PERLIN_OUTPUT vs_perlin(float4 inPos: POSITION0)
{
VS_PERLIN_OUTPUT OUT;
OUT.pos = float4(inPos.xy * 2.0 - 1.0, 0.0, 1.0);
OUT.texCoord.x = inPos.x;
OUT.texCoord.y = 1.0 - inPos.y;
return OUT;
}
// ------------------------------------------------------------------------------------------------------------------//
OutHalf4Color ps_perlin_main(VS_PERLIN_OUTPUT IN)
{
const half finalNoise = calculateCloudNoise(IN) * 0.5f + 0.5f;
const half minValue = noiseThreshold - noiseSoftness,
maxValue = noiseThreshold + noiseSoftness;
return CastOutHalf4Color(half4(smoothstep(minValue, maxValue, finalNoise),
smoothstep(minValue + noiseDensityOffset,
maxValue + noiseDensityOffset,
finalNoise),
finalNoise,
0.0));
}
// ------------------------------------------------------------------------------------------------------------------//
VS_sun_vis_OUTPUT vs_sun_visibility(float4 inPos: POSITION)
{
float4 pos = vs_sun_main(inPos
#if GS_INSTANCED_CUBEMAP
,false,0
#endif
);
VS_sun_vis_OUTPUT OUT;
OUT.pos = mul(pos, gWorldViewProj);
OUT.fogBlend = 1.0 - CalcFogDataNoHaze(normalize(mul(pos, gWorld).xyz - gViewInverse[3].xyz) * 25000.0f).a * noiseSoftness;
return OUT;
}
// ------------------------------------------------------------------------------------------------------------------//
#if !__XENON
void StippleAlpha(float fStippleAlpha, float2 vPos)
{
#if __WIN32PC && __SHADERMODEL < 40
half2 s = frac(vPos * 0.5f); // PC + DX9 VPOS is always a whole number
#else
half2 s = frac((vPos - 0.5) * 0.5f); // PS3 or PC + DX10/11 VPOS always contains .5
#endif // __WIN32PC && __SHADERMODEL < 40
// This is scientific
// s:
// Even Odd
// /-----------\
// |.0,.0|.5,.0|
// |-----------|
// |.0,.5|.5,.5|
// \-----------/
// fAlphaRef:
// /-------\
// |.2 |.7 |
// |-------|
// |.45|.95|
// \-------/
half fAlphaRef = 0.5 * dot( s.xy, float2(1.0, 2.0)) + 0.2;
rageDiscard(fStippleAlpha <= fAlphaRef || fStippleAlpha < noiseThreshold);
}
#endif // !__XENON
// ------------------------------------------------------------------------------------------------------------------//
OutHalf4Color ps_sun_visibility(PS_sun_vis_INPUT IN)
{
#if !__XENON
StippleAlpha(IN.fogBlend.x, IN.pos);
#endif // !__XENON
return CastOutHalf4Color(1.0f);
}
// ------------------------------------------------------------------------------------------------------------------//
technique draw_perlin_noise
{
pass p0
{
VertexShader = compile VERTEXSHADER vs_perlin();
PixelShader = compile PIXELSHADER ps_perlin_main() OPTIMIZE;
}
}
// ------------------------------------------------------------------------------------------------------------------//
// SKY PLANE TECHNIQUES //
// ------------------------------------------------------------------------------------------------------------------//
VS_SKY_PLANE_OUTPUT vs_sky_plane_common(VS_SKY_PLANE_INPUT IN
#if GS_INSTANCED_CUBEMAP
,uniform bool bUseInst
#endif
)
{
VS_SKY_PLANE_OUTPUT OUT;
float3 camPos = float3(0.0, 0.0, 0.0);
float3 worldPos = float3(0.0, 0.0, 0.0);
#if GS_INSTANCED_CUBEMAP
if (bUseInst)
{
worldPos = (float3)mul(IN.pos, gInstWorld);
camPos = gInstViewInverse[IN.InstID][3].xyz;
OUT.pos = mul(IN.pos, mul(gInstWorld,gInstWorldViewProj[IN.InstID]));
}
else
#endif
{
OUT.pos = mul(IN.pos, gWorldViewProj);
worldPos = (float3)mul(IN.pos, gWorld);
camPos = gViewInverse[3].xyz;
}
OUT.eyeToWorld.xyz = float3(worldPos.xy, horizonLevel) - camPos.xyz;
OUT.eyeToWorld.w = saturate((camPos.z - skyPlaneFogFadeStart) * skyPlaneFogFadeOneOverDiff);
OUT.color = (skyPlaneColor.rgb * skyPlaneColor.rgb) * skyPlaneColor.a;
return OUT;
}
VS_SKY_PLANE_OUTPUT vs_sky_plane(VS_SKY_PLANE_INPUT IN )
{
return vs_sky_plane_common(IN
#if GS_INSTANCED_CUBEMAP
,false
#endif
);
}
// ------------------------------------------------------------------------------------------------------------------//
OutHalf4Color ps_sky_plane(VS_SKY_PLANE_OUTPUT IN)
{
float4 fogData = CalcFogData(IN.eyeToWorld.xyz);
float3 finalColour = lerp(IN.color.rgb, fogData.rgb, fogData.a * IN.eyeToWorld.w);
return CastOutHalf4Color(PackHdr(float4(finalColour, 1.0)));
}
// ------------------------------------------------------------------------------------------------------------------//
OutHalf4Color ps_sky_plane_cubemap(VS_SKY_PLANE_OUTPUT IN)
{
float4 fogData = CalcFogData(IN.eyeToWorld.xyz);
float3 finalColour = lerp(IN.color.rgb, fogData.rgb, fogData.a * IN.eyeToWorld.w);
return CastOutHalf4Color(PackReflection(float4(finalColour, 1.0)));
}
// ------------------------------------------------------------------------------------------------------------------//
#if GS_INSTANCED_CUBEMAP
GEN_GSINST_TYPE(SkyPlane,VS_SKY_PLANE_OUTPUT,SV_RenderTargetArrayIndex)
GEN_GSINST_FUNC(SkyPlane,SkyPlane,VS_SKY_PLANE_INPUT,VS_SKY_PLANE_OUTPUT,VS_SKY_PLANE_OUTPUT,vs_sky_plane_common(IN,true),ps_sky_plane(IN))
#endif
technique sky_plane
{
pass p0_normal
{
VertexShader = compile VERTEXSHADER vs_sky_plane();
PixelShader = compile PIXELSHADER ps_sky_plane() OPTIMIZE;
}
#if GS_INSTANCED_CUBEMAP
GEN_GSINST_TECHPASS(SkyPlane,cubeinst)
#else
pass p2_cubemap
{
VertexShader = compile VERTEXSHADER vs_sky_plane();
PixelShader = compile PIXELSHADER ps_sky_plane_cubemap() OPTIMIZE;
}
#endif
}
// ------------------------------------------------------------------------------------------------------------------//
technique sun_visibility
{
pass p0
{
VertexShader = compile VERTEXSHADER vs_sun_visibility();
PixelShader = compile PIXELSHADER ps_sun_visibility() CGC_FLAGS(CGC_DEFAULTFLAGS);
}
}