You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
401 lines
11 KiB
401 lines
11 KiB
2 years ago
|
// Marmoset Skyshop
|
||
|
// Copyright 2013 Marmoset LLC
|
||
|
// http://marmoset.co
|
||
|
|
||
|
#ifndef MARMOSET_CORE_CGINC
|
||
|
#define MARMOSET_CORE_CGINC
|
||
|
|
||
|
#define INV_2PI 0.15915494309189533576888376337251
|
||
|
#define INV_2PIx2 0.31830988618379067153776752674502
|
||
|
|
||
|
//Linear - unity_ColorSpaceGrey.r is 0.19
|
||
|
//Gamma - unity_ColorSpaceGrey.r is 0.5
|
||
|
//linear ? 1 : 0 = (Grey - 0.5) / (0.19 - 0.5) = one clever MAD instruction
|
||
|
#define IS_LINEAR ((-3.22581*unity_ColorSpaceGrey.r) + 1.6129)
|
||
|
#define IS_GAMMA (( 3.22581*unity_ColorSpaceGrey.r) - 0.6129)
|
||
|
|
||
|
#ifdef MARMO_SPECULAR_IBL
|
||
|
uniform samplerCUBE _SpecCubeIBL;
|
||
|
#endif
|
||
|
|
||
|
uniform half4 _ExposureIBL; //IBL intensities
|
||
|
uniform half2 _ExposureLM; //IBL intensities when lightmapping
|
||
|
uniform half2 _UniformOcclusion; //Uniform diffuse and specular IBL occlusion terms
|
||
|
|
||
|
uniform float4x4 _SkyMatrix;
|
||
|
uniform float4x4 _InvSkyMatrix;
|
||
|
uniform float3 _SkySize;
|
||
|
uniform float3 _SkyMin;
|
||
|
uniform float3 _SkyMax;
|
||
|
|
||
|
uniform float3 _SH0;
|
||
|
uniform float3 _SH1;
|
||
|
uniform float3 _SH2;
|
||
|
uniform float3 _SH3;
|
||
|
uniform float3 _SH4;
|
||
|
uniform float3 _SH5;
|
||
|
uniform float3 _SH6;
|
||
|
uniform float3 _SH7;
|
||
|
uniform float3 _SH8;
|
||
|
|
||
|
#ifdef MARMO_SKY_BLEND
|
||
|
uniform float _BlendWeightIBL;
|
||
|
|
||
|
uniform half4 _ExposureIBL1; //IBL intensities
|
||
|
uniform half2 _ExposureLM1; //IBL intensities when lightmapping
|
||
|
|
||
|
uniform float4x4 _SkyMatrix1;
|
||
|
uniform float4x4 _InvSkyMatrix1;
|
||
|
uniform float3 _SkySize1;
|
||
|
uniform float3 _SkyMin1;
|
||
|
uniform float3 _SkyMax1;
|
||
|
|
||
|
#ifdef MARMO_SPECULAR_IBL
|
||
|
uniform samplerCUBE _SpecCubeIBL1;
|
||
|
#endif
|
||
|
|
||
|
uniform float3 _SH01;
|
||
|
uniform float3 _SH11;
|
||
|
uniform float3 _SH21;
|
||
|
uniform float3 _SH31;
|
||
|
uniform float3 _SH41;
|
||
|
uniform float3 _SH51;
|
||
|
uniform float3 _SH61;
|
||
|
uniform float3 _SH71;
|
||
|
uniform float3 _SH81;
|
||
|
#endif
|
||
|
|
||
|
//Color-correction
|
||
|
half3 toLinearApprox3(half3 c){ return c*c; }
|
||
|
half3 toLinear3(half3 c) { return pow(c,2.2); }
|
||
|
half toLinearFast1(half c) { half c2 = c*c; return dot(half2(0.7532,0.2468),half2(c2,c*c2)); }
|
||
|
half3 toLinearFast3(half3 c) { half3 c2 = c*c; return 0.7532*c2 + 0.2468*c*c2; }
|
||
|
|
||
|
half toGammaApprox1(half c) { return sqrt(c); }
|
||
|
half3 toGammaApprox3(half3 c) { return sqrt(c); }
|
||
|
half toGamma1(half c) { return pow(c,0.454545); }
|
||
|
half3 toGamma3(half3 c) { return pow(c,0.454545); }
|
||
|
half toGammaFast1(half c) {
|
||
|
c = 1.0 - c;
|
||
|
half c2 = c*c;
|
||
|
half3 c16 = half3(c2*c2,c2,c); //^4
|
||
|
c16.x *= c16.x; //^8
|
||
|
c16.x *= c16.x; //^16
|
||
|
c16 = half3(1.0,1.0,1.0)-c16;
|
||
|
return dot(half3(0.326999,0.249006,0.423995),c16);
|
||
|
}
|
||
|
half3 toGammaFast3(half3 c) {
|
||
|
half3 one = half3(1.0,1.0,1.0);
|
||
|
c = one - c;
|
||
|
half3 c2 = c*c;
|
||
|
half3 c16 = c2*c2; //^4
|
||
|
c16 *= c16; //^8
|
||
|
c16 *= c16; //^16
|
||
|
return 0.326999*(one-c16) + 0.249006*(one-c2) + 0.423995*(one-c);
|
||
|
}
|
||
|
|
||
|
//(1-t)a + t*a*a;
|
||
|
//a - t*a + t*a*a;
|
||
|
//a( 1-t + t*a);
|
||
|
//mul(a, mad(t,a,1-t)); //4 inst, 2 inst if t and 1-t are constants
|
||
|
//lerp(a, a*a, t); //4 inst, 3 inst if constant t
|
||
|
half toGammaAuto1(half a) { return a * ((a * IS_LINEAR) + IS_GAMMA); }
|
||
|
half3 toGammaAuto3(half3 a) { return a * ((a * IS_LINEAR.xxx) + IS_GAMMA.xxx); }
|
||
|
|
||
|
//(1-t)*sqrt(a) + t*a
|
||
|
//(1-s)*a + s*sqrt(a)
|
||
|
//a - s*a + s*sqrt(a)
|
||
|
//a - s*a + s*a/sqrt(a)
|
||
|
//a*(1-s+s*invsqrt(a))
|
||
|
//mul(a,mad(s,invsqrt(a),1-s))
|
||
|
//mul(a,mad(s,invsqrt(a),t)) //5 inst, 3 inst if constant t
|
||
|
//lerp(a*invsqrt(a), a, t) //5 inst, 4 if constant t
|
||
|
half toLinearAuto1(half a) { return a*(IS_GAMMA*rsqrt(a) + IS_LINEAR); }
|
||
|
half3 toLinearAuto3(half3 a) { return a*(IS_GAMMA.xxx*rsqrt(a) + IS_LINEAR.xxx); }
|
||
|
|
||
|
//approximations for the true, step-wise gamma curve used in sRGB compression
|
||
|
float linearTosRGB1( float c ) {
|
||
|
float sqrtc = sqrt( c ); //SQRT/MAD/MAD/MAD (accurate)
|
||
|
return (sqrtc - sqrtc*c) + c*(0.4672*c + 0.5328);
|
||
|
}
|
||
|
float3 linearTosRGB3( float3 c ) {
|
||
|
float3 sqrtc = sqrt( c ); //SQRT/MAD/MAD/MAD (accurate)
|
||
|
return (sqrtc - sqrtc*c) + c*(float3(0.4672,0.4672,0.4672)*c + float3(0.5328,0.5328,0.5328));
|
||
|
}
|
||
|
float4 linearTosRGB4( float4 c ) {
|
||
|
float4 sqrtc = sqrt( c ); //SQRT/MAD/MAD/MAD (accurate)
|
||
|
return (sqrtc - sqrtc*c) + c*(float4(0.4672,0.4672,0.4672,0.4672)*c + float4(0.5328,0.5328,0.5328,0.5328));
|
||
|
}
|
||
|
|
||
|
float sRGBToLinear1( float c ) {
|
||
|
return (c*c)*(c*0.2848 + 0.7152); //MAD/MUL/MUL (accurate)
|
||
|
}
|
||
|
float3 sRGBToLinear3( float3 c ) {
|
||
|
return (c*c)*(c*float3(0.2848,0.2848,0.2848) + float3(0.7152,0.7152,0.7152)); //MAD/MUL/MUL (accurate)
|
||
|
}
|
||
|
float4 sRGBToLinear4( float4 c ) {
|
||
|
return (c*c)*(c*float4(0.2848,0.2848,0.2848,0.2848) + float4(0.7152,0.7152,0.7152,0.7152)); //MAD/MUL/MUL (accurate)
|
||
|
}
|
||
|
|
||
|
float3 mulVec3( float4x4 m, float3 v ) {
|
||
|
return float3(dot(m[0].xyz,v.xyz),
|
||
|
dot(m[1].xyz,v.xyz),
|
||
|
dot(m[2].xyz,v.xyz));
|
||
|
}
|
||
|
|
||
|
float3 mulPoint3( float4x4 m, float3 p ) {
|
||
|
float4 v = float4(p.x,p.y,p.z,1.0);
|
||
|
return float3(dot(m[0],v),
|
||
|
dot(m[1],v),
|
||
|
dot(m[2],v));
|
||
|
}
|
||
|
|
||
|
float3 transposeMulVec3( float4x4 m, float3 v ) {
|
||
|
return m[0].xyz*v.x + (m[1].xyz*v.y + (m[2].xyz*v.z));
|
||
|
}
|
||
|
|
||
|
float3 transposeMulVec3( float3x3 m, float3 v ) {
|
||
|
return m[0].xyz*v.x + (m[1].xyz*v.y + (m[2].xyz*v.z));
|
||
|
}
|
||
|
|
||
|
float3 transposePoint3( float4x4 m, float3 p ) {
|
||
|
return m[0].xyz*p.x + (m[1].xyz*p.y + (m[2].xyz*p.z + m[3].xyz));
|
||
|
}
|
||
|
|
||
|
half3 fromRGBM(half4 c) {
|
||
|
c.a *= 6.0;
|
||
|
return c.rgb * lerp(c.a, toLinearFast1(c.a), IS_LINEAR);
|
||
|
}
|
||
|
|
||
|
half3 diffCubeLookup(samplerCUBE diffCube, float3 worldNormal) {
|
||
|
half4 diff = texCUBE(diffCube, worldNormal);
|
||
|
return fromRGBM(diff);
|
||
|
}
|
||
|
|
||
|
half3 specCubeLookup(samplerCUBE specCube, float3 worldRefl) {
|
||
|
half4 spec = texCUBE(specCube, worldRefl);
|
||
|
return fromRGBM(spec);
|
||
|
}
|
||
|
|
||
|
half3 glossCubeLookup(samplerCUBE specCube, float3 worldRefl, float glossLod) {
|
||
|
#ifdef MARMO_BIAS_GLOSS
|
||
|
half4 lookup = half4(worldRefl,glossLod);
|
||
|
half4 spec = texCUBEbias(specCube, lookup);
|
||
|
#else
|
||
|
half4 lookup = half4(worldRefl,glossLod);
|
||
|
half4 spec = texCUBElod(specCube, lookup);
|
||
|
#endif
|
||
|
return fromRGBM(spec);
|
||
|
}
|
||
|
|
||
|
half glossLOD(half glossMap, half shininess) {
|
||
|
glossMap = 1.0-glossMap;
|
||
|
glossMap = 1.0-(glossMap*glossMap);
|
||
|
return 7.0 + glossMap - (shininess*glossMap);
|
||
|
}
|
||
|
|
||
|
half glossExponent(half glossLod) {
|
||
|
return exp2(8.0-glossLod);
|
||
|
}
|
||
|
|
||
|
//returns 1/spec. function integral
|
||
|
float specEnergyScalar(float gloss) {
|
||
|
return (gloss*INV_2PI) + INV_2PIx2;
|
||
|
}
|
||
|
|
||
|
half splineFresnel(float3 N, float3 E, half specIntensity, half fresnel) {
|
||
|
half factor = 1.0-saturate(dot(N,E));
|
||
|
half factor3 = factor*factor*factor;
|
||
|
|
||
|
//a spline between 1, factor, and factor^3
|
||
|
half3 p = half3(1.0, factor, factor3);
|
||
|
half2 t = half2(1.0-fresnel,fresnel);
|
||
|
p.x = dot(p.xy,t);
|
||
|
p.y = dot(p.yz,t);
|
||
|
factor = 0.05 + 0.95 * dot(p.xy,t);
|
||
|
factor *= specIntensity;
|
||
|
|
||
|
//The math above is performed in linear space. If rendering in gamma space,
|
||
|
//fresnel*specInt needs to be applied in gamma-space.
|
||
|
// Note: specInt is also a linear value, it comes from a slider.
|
||
|
factor = lerp(sqrt(factor), factor, IS_LINEAR);
|
||
|
return factor;
|
||
|
}
|
||
|
|
||
|
|
||
|
half fastFresnel(float3 N, float3 E, half specIntensity, half fresnel) {
|
||
|
//fresnel math performed in gamma space
|
||
|
half factor = 1.0-saturate(dot(N,E));
|
||
|
factor *= 0.5 + 0.5*factor;
|
||
|
factor = 0.15 + factor*0.85;
|
||
|
factor = lerp(1.0, factor, fresnel);
|
||
|
factor = specIntensity * factor;
|
||
|
factor = lerp(factor, factor*factor, IS_LINEAR);
|
||
|
return factor;
|
||
|
}
|
||
|
|
||
|
float3 skyRotate(uniform float4x4 skyMatrix, float3 R) {
|
||
|
#ifdef MARMO_SKY_ROTATION
|
||
|
R = transposeMulVec3(skyMatrix,R);
|
||
|
#endif
|
||
|
return R;
|
||
|
}
|
||
|
|
||
|
float3 skyProject(uniform float4x4 skyMatrix, uniform float4x4 invSkyMatrix, uniform float3 skyMin, uniform float3 skyMax, float3 worldPos, float3 R) {
|
||
|
#ifdef MARMO_BOX_PROJECTION
|
||
|
//box projection happens in sky-space
|
||
|
#ifdef MARMO_SKY_ROTATION
|
||
|
R = transposeMulVec3(skyMatrix,R).xyz; //HACK: mulVec3 is mul(transpose(_sky))
|
||
|
#endif
|
||
|
float3 invR = 1.0/R;
|
||
|
#ifdef MARMO_SKY_ROTATION
|
||
|
float3 P = mulPoint3(invSkyMatrix,worldPos);
|
||
|
#else
|
||
|
float3 P = worldPos - skyMatrix[3].xyz;
|
||
|
#endif
|
||
|
float3 rbminmax = lerp(skyMin, skyMax, saturate(R*1000000.0));
|
||
|
rbminmax = (rbminmax - P.xyz) * invR;
|
||
|
float fa = min(min(rbminmax.x, rbminmax.y), rbminmax.z);
|
||
|
//R in projected sky space
|
||
|
return (R*fa) + P.xyz;
|
||
|
#else
|
||
|
#ifdef MARMO_SKY_ROTATION
|
||
|
R = transposeMulVec3(skyMatrix,R);
|
||
|
#endif
|
||
|
return R;
|
||
|
#endif
|
||
|
}
|
||
|
|
||
|
//converts linear, HDR color to RGBM encoded data, ready for screen output
|
||
|
float4 HDRtoRGBM(float4 color) {
|
||
|
float toLinear = 2.2;
|
||
|
float toGamma = 1.0/2.2;
|
||
|
color.rgb = pow(color.rgb, toGamma); //RGBM gamma compression is 1/2.2
|
||
|
color *= 1.0/6.0;
|
||
|
float m = max(max(color.r,color.g),color.b);
|
||
|
m = saturate(m);
|
||
|
m = ceil(m*255.0)/255.0;
|
||
|
|
||
|
if( m > 0.0 ) {
|
||
|
float inv_m = 1.0/m;
|
||
|
color.rgb = saturate(color.rgb*inv_m);
|
||
|
color.a = m;
|
||
|
} else {
|
||
|
color = half4(0.0,0.0,0.0,0.0);
|
||
|
}
|
||
|
return color;
|
||
|
}
|
||
|
|
||
|
float3 SHLookup(float3 dir) {
|
||
|
//l = 0 band (constant)
|
||
|
float3 result = _SH0.xyz;
|
||
|
|
||
|
//l = 1 band
|
||
|
result += _SH1.xyz * dir.y;
|
||
|
result += _SH2.xyz * dir.z;
|
||
|
result += _SH3.xyz * dir.x;
|
||
|
|
||
|
//l = 2 band
|
||
|
float3 swz = dir.yyz * dir.xzx;
|
||
|
result += _SH4.xyz * swz.x;
|
||
|
result += _SH5.xyz * swz.y;
|
||
|
result += _SH7.xyz * swz.z;
|
||
|
float3 sqr = dir * dir;
|
||
|
result += _SH6.xyz * ( 3.0*sqr.z - 1.0 );
|
||
|
result += _SH8.xyz * ( sqr.x - sqr.y );
|
||
|
|
||
|
return abs(result);
|
||
|
}
|
||
|
|
||
|
void SHLookup(float3 dir, out float3 band0, out float3 band1, out float3 band2) {
|
||
|
//l = 0 band (constant)
|
||
|
band0 = _SH0.xyz;
|
||
|
|
||
|
//l = 1 band
|
||
|
band1 = _SH1.xyz * dir.y;
|
||
|
band1 += _SH2.xyz * dir.z;
|
||
|
band1 += _SH3.xyz * dir.x;
|
||
|
|
||
|
//l = 2 band
|
||
|
float3 swz = dir.yyz * dir.xzx;
|
||
|
band2 = _SH4.xyz * swz.x;
|
||
|
band2 += _SH5.xyz * swz.y;
|
||
|
band2 += _SH7.xyz * swz.z;
|
||
|
float3 sqr = dir * dir;
|
||
|
band2 += _SH6.xyz * ( 3.0*sqr.z - 1.0 );
|
||
|
band2 += _SH8.xyz * ( sqr.x - sqr.y );
|
||
|
}
|
||
|
|
||
|
#ifdef MARMO_SKY_BLEND
|
||
|
float3 SHLookup1(float3 dir) {
|
||
|
//l = 0 band (constant)
|
||
|
float3 result = _SH01.xyz;
|
||
|
|
||
|
//l = 1 band
|
||
|
result += _SH11.xyz * dir.y;
|
||
|
result += _SH21.xyz * dir.z;
|
||
|
result += _SH31.xyz * dir.x;
|
||
|
|
||
|
//l = 2 band
|
||
|
float3 swz = dir.yyz * dir.xzx;
|
||
|
result += _SH41.xyz * swz.x;
|
||
|
result += _SH51.xyz * swz.y;
|
||
|
result += _SH71.xyz * swz.z;
|
||
|
float3 sqr = dir * dir;
|
||
|
result += _SH61.xyz * ( 3.0*sqr.z - 1.0 );
|
||
|
result += _SH81.xyz * ( sqr.x - sqr.y );
|
||
|
|
||
|
return abs(result);
|
||
|
}
|
||
|
void SHLookup1(float3 dir, out float3 band0, out float3 band1, out float3 band2) {
|
||
|
//l = 0 band (constant)
|
||
|
band0 = _SH01.xyz;
|
||
|
|
||
|
//l = 1 band
|
||
|
band1 = _SH11.xyz * dir.y;
|
||
|
band1 += _SH21.xyz * dir.z;
|
||
|
band1 += _SH31.xyz * dir.x;
|
||
|
|
||
|
//l = 2 band
|
||
|
float3 swz = dir.yyz * dir.xzx;
|
||
|
band2 = _SH41.xyz * swz.x;
|
||
|
band2 += _SH51.xyz * swz.y;
|
||
|
band2 += _SH71.xyz * swz.z;
|
||
|
float3 sqr = dir * dir;
|
||
|
band2 += _SH61.xyz * ( 3.0*sqr.z - 1.0 );
|
||
|
band2 += _SH81.xyz * ( sqr.x - sqr.y );
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
float3 SHLookupUnity(float3 dir) {
|
||
|
return ShadeSH9(half4(dir.x, dir.y, dir.z,1.0));
|
||
|
}
|
||
|
void SHLookupUnity(float3 dir, out float3 band0, out float3 band1, out float3 band2) {
|
||
|
//constant term
|
||
|
band0 = float3(unity_SHAr.w, unity_SHAg.w, unity_SHAb.w);
|
||
|
|
||
|
// Linear term
|
||
|
band1.r = dot(unity_SHAr.xyz, dir.xyz);
|
||
|
band1.g = dot(unity_SHAg.xyz, dir.xyz);
|
||
|
band1.b = dot(unity_SHAb.xyz, dir.xyz);
|
||
|
|
||
|
// 4 of the quadratic polynomials
|
||
|
half4 vB = dir.xyzz * dir.yzzx;
|
||
|
band2.r = dot(unity_SHBr,vB);
|
||
|
band2.g = dot(unity_SHBg,vB);
|
||
|
band2.b = dot(unity_SHBb,vB);
|
||
|
|
||
|
// Final quadratic polynomial
|
||
|
float vC = dir.x*dir.x - dir.y*dir.y;
|
||
|
band2 += unity_SHC.rgb * vC;
|
||
|
}
|
||
|
|
||
|
float3 SHConvolve(float3 band0, float3 band1, float3 band2, float3 weight) {
|
||
|
float3 conv1 = lerp( float3(1.0,1.0,1.0), float3(0.6667,0.6667,0.6667), weight);
|
||
|
float3 conv2 = lerp( float3(1.0,1.0,1.0), float3(0.25,0.25,0.25), weight);
|
||
|
conv1 = lerp(conv1, conv1*conv1, weight);
|
||
|
conv2 = lerp(conv2, conv2*conv2, weight);
|
||
|
return abs(band0 + band1*conv1 + band2*conv2);
|
||
|
}
|
||
|
|
||
|
#endif
|