411 lines
13 KiB
HLSL
411 lines
13 KiB
HLSL
|
// Upgrade NOTE: replaced '_Object2World' with 'unity_ObjectToWorld'
|
||
|
|
||
|
// Unity built-in shader source. Copyright (c) 2016 Unity Technologies. MIT license (see license.txt)
|
||
|
// This code in no way belongs to BrainFailProductions. I have just made a small change to make
|
||
|
// it work with texture arrays
|
||
|
|
||
|
|
||
|
#ifndef UNITY_STANDARD_INPUT_INCLUDED
|
||
|
#define UNITY_STANDARD_INPUT_INCLUDED
|
||
|
|
||
|
#include "UnityCG.cginc"
|
||
|
#include "Includes/BatchFewStandardConfig.cginc"
|
||
|
#include "UnityPBSLighting.cginc" // TBD: remove
|
||
|
#include "Includes/BatchFewStandardUtils.cginc"
|
||
|
|
||
|
//---------------------------------------
|
||
|
// Directional lightmaps & Parallax require tangent space too
|
||
|
#if (_NORMALMAP || DIRLIGHTMAP_COMBINED || defined(_PARALLAXMAP) || defined(_POM))
|
||
|
#define _TANGENT_TO_WORLD 1
|
||
|
#endif
|
||
|
|
||
|
#if (_DETAIL_MULX2 || _DETAIL_MUL || _DETAIL_ADD || _DETAIL_LERP)
|
||
|
#define _DETAIL 1
|
||
|
#endif
|
||
|
|
||
|
//---------------------------------------
|
||
|
half _Cutoff;
|
||
|
|
||
|
UNITY_DECLARE_TEX2DARRAY(_MainTex);
|
||
|
float4 _MainTex_ST;
|
||
|
|
||
|
sampler2D _AttrImg;
|
||
|
float4 _AttrImg_TexelSize;
|
||
|
|
||
|
UNITY_DECLARE_TEX2DARRAY(_DetailAlbedoMap);
|
||
|
float4 _DetailAlbedoMap_ST;
|
||
|
|
||
|
UNITY_DECLARE_TEX2DARRAY(_BumpMap);
|
||
|
|
||
|
UNITY_DECLARE_TEX2DARRAY(_DetailMask);
|
||
|
UNITY_DECLARE_TEX2DARRAY(_DetailNormalMap);
|
||
|
|
||
|
UNITY_DECLARE_TEX2DARRAY(_SpecGlossMap);
|
||
|
UNITY_DECLARE_TEX2DARRAY(_MetallicGlossMap);
|
||
|
|
||
|
UNITY_DECLARE_TEX2DARRAY(_OcclusionMap);
|
||
|
|
||
|
UNITY_DECLARE_TEX2DARRAY(_ParallaxMap);
|
||
|
half _Parallax;
|
||
|
half _UVSec;
|
||
|
|
||
|
UNITY_DECLARE_TEX2DARRAY(_EmissionMap);
|
||
|
|
||
|
sampler2D _DetailAlbedoSingle;
|
||
|
sampler2D _DetailNormalSingle;
|
||
|
|
||
|
//-------------------------------------------------------------------------------------
|
||
|
// Input functions
|
||
|
|
||
|
struct VertexInput
|
||
|
{
|
||
|
float4 vertex : POSITION;
|
||
|
half4 color : COLOR;
|
||
|
half3 normal : NORMAL;
|
||
|
float4 uv0 : TEXCOORD0;
|
||
|
float2 uv1 : TEXCOORD1;
|
||
|
#if defined(DYNAMICLIGHTMAP_ON) || defined(UNITY_PASS_META)
|
||
|
float2 uv2 : TEXCOORD2;
|
||
|
#endif
|
||
|
#ifdef _TANGENT_TO_WORLD
|
||
|
half4 tangent : TANGENT;
|
||
|
#endif
|
||
|
UNITY_VERTEX_INPUT_INSTANCE_ID
|
||
|
|
||
|
};
|
||
|
|
||
|
float4 SampleAttrImg(float prop, float index)
|
||
|
{
|
||
|
return tex2Dlod(_AttrImg, float4((prop + 0.5) * _AttrImg_TexelSize.x, (index + 0.5) * _AttrImg_TexelSize.y, 0, 0));
|
||
|
}
|
||
|
|
||
|
float4 TexCoords(VertexInput v)
|
||
|
{
|
||
|
|
||
|
float4 uvScaleOffset = SampleAttrImg(0, v.color.r * 255);
|
||
|
|
||
|
float4 texcoord;
|
||
|
texcoord.z = v.color.a * 255;
|
||
|
texcoord.w = v.color.r * 255;
|
||
|
texcoord.xy = v.uv0.xy * (uvScaleOffset.xy+1) + uvScaleOffset.zw;
|
||
|
|
||
|
return texcoord;
|
||
|
}
|
||
|
|
||
|
half DetailMask(float3 uv)
|
||
|
{
|
||
|
return UNITY_SAMPLE_TEX2DARRAY(_DetailMask, uv).a;
|
||
|
}
|
||
|
|
||
|
|
||
|
half3 Albedo(float4 texcoords, half4 attribs)
|
||
|
{
|
||
|
half3 albedo = UNITY_SAMPLE_TEX2DARRAY (_MainTex, texcoords.xyz).rgb * SampleAttrImg(2, texcoords.w).rgb;
|
||
|
#if _DETAIL
|
||
|
#if (SHADER_TARGET < 30)
|
||
|
// SM20: instruction count limitation
|
||
|
// SM20: no detail mask
|
||
|
half mask = 1;
|
||
|
#else
|
||
|
half mask = DetailMask(texcoords);
|
||
|
#endif
|
||
|
//float4 uvmod = SampleAttrImg(5, texcoords.w);
|
||
|
texcoords.xy = texcoords.xy * SampleAttrImg(5, texcoords.w).xy + SampleAttrImg(5, texcoords.w).zw;
|
||
|
half3 detailAlbedo = UNITY_SAMPLE_TEX2DARRAY (_DetailAlbedoMap, texcoords.xyz).rgb;
|
||
|
#if _DETAIL_MULX2
|
||
|
albedo *= LerpWhiteTo (detailAlbedo * unity_ColorSpaceDouble.rgb, mask);
|
||
|
#elif _DETAIL_MUL
|
||
|
albedo *= LerpWhiteTo (detailAlbedo, mask);
|
||
|
#elif _DETAIL_ADD
|
||
|
albedo += detailAlbedo * mask;
|
||
|
#elif _DETAIL_LERP
|
||
|
albedo = lerp (albedo, detailAlbedo, mask);
|
||
|
#endif
|
||
|
#elif _DETAIL_SINGLE
|
||
|
#if (SHADER_TARGET < 30)
|
||
|
// SM20: instruction count limitation
|
||
|
// SM20: no detail mask
|
||
|
half mask = 1;
|
||
|
#else
|
||
|
half mask = DetailMask(texcoords);
|
||
|
#endif
|
||
|
|
||
|
//float4 uvmod = SampleAttrImg(5, texcoords.w);
|
||
|
|
||
|
texcoords.xy = texcoords.xy * SampleAttrImg(5, texcoords.w).xy + SampleAttrImg(5, texcoords.w).zw;
|
||
|
half3 detailAlbedo = tex2D (_DetailAlbedoSingle, texcoords.xy).rgb;
|
||
|
albedo *= LerpWhiteTo (detailAlbedo * unity_ColorSpaceDouble.rgb, mask);
|
||
|
|
||
|
#endif
|
||
|
return albedo;
|
||
|
}
|
||
|
|
||
|
half Alpha(float4 uv)
|
||
|
{
|
||
|
return UNITY_SAMPLE_TEX2DARRAY(_MainTex, uv.xyz).a;
|
||
|
}
|
||
|
|
||
|
half Occlusion(float4 uv, half4 attribs)
|
||
|
{
|
||
|
return UNITY_SAMPLE_TEX2DARRAY(_OcclusionMap, uv.xyz).g * attribs.y;
|
||
|
}
|
||
|
|
||
|
half4 SpecularGloss(float4 uv, half4 attribs)
|
||
|
{
|
||
|
half4 sg = attribs.wwzz;
|
||
|
#ifdef _SPECGLOSSMAP
|
||
|
#if defined(_SMOOTHNESS_TEXTURE_ALBEDO_CHANNEL_A)
|
||
|
sg.rgb = UNITY_SAMPLE_TEX2DARRAY(_SpecGlossMap, uv.xyz).rgb;
|
||
|
sg.a = UNITY_SAMPLE_TEX2DARRAY(_MainTex, uv.xyz).a * attribs.z;
|
||
|
#else
|
||
|
sg = UNITY_SAMPLE_TEX2DARRAY(_SpecGlossMap, uv.xyz);
|
||
|
#endif
|
||
|
sg.a *= SampleAttrImg(4, uv.w).a;
|
||
|
#else
|
||
|
sg.rgb = SampleAttrImg(4, uv.w).rgb;
|
||
|
#ifdef _SMOOTHNESS_TEXTURE_ALBEDO_CHANNEL_A
|
||
|
sg.a = UNITY_SAMPLE_TEX2DARRAY(_MainTex, uv.xyz).a * attribs.z;
|
||
|
#else
|
||
|
sg.a = SampleAttrImg(1, uv.w).b;
|
||
|
#endif
|
||
|
#endif
|
||
|
|
||
|
return sg;
|
||
|
}
|
||
|
|
||
|
|
||
|
half2 MetallicGloss(float4 uv, half4 attribs)
|
||
|
{
|
||
|
half2 mg = attribs.wz;
|
||
|
|
||
|
#ifdef _METALLICGLOSSMAP
|
||
|
#ifdef _SMOOTHNESS_TEXTURE_ALBEDO_CHANNEL_A
|
||
|
mg.r = UNITY_SAMPLE_TEX2DARRAY(_MetallicGlossMap, uv.xyz).r;
|
||
|
mg.g = UNITY_SAMPLE_TEX2DARRAY(_MainTex, uv.xyz).a * attribs.z;
|
||
|
#else
|
||
|
mg = UNITY_SAMPLE_TEX2DARRAY(_MetallicGlossMap, uv.xyz).ra;
|
||
|
mg.g *= attribs.z;
|
||
|
#endif
|
||
|
#else
|
||
|
mg.r = attribs.w;
|
||
|
#ifdef _SMOOTHNESS_TEXTURE_ALBEDO_CHANNEL_A
|
||
|
mg.g = UNITY_SAMPLE_TEX2DARRAY(_MainTex, uv.xyz).a;
|
||
|
#else
|
||
|
mg.g = attribs.z;
|
||
|
#endif
|
||
|
#endif
|
||
|
|
||
|
return mg;
|
||
|
}
|
||
|
|
||
|
half3 Emission(float4 uv)
|
||
|
{
|
||
|
#if _EMISSION
|
||
|
return UNITY_SAMPLE_TEX2DARRAY(_EmissionMap, uv.xyz).rgb;
|
||
|
#endif
|
||
|
#if _EMISSION_COLOR
|
||
|
return SampleAttrImg(3, uv.w).xyz;
|
||
|
#endif
|
||
|
return half3(0,0,0);
|
||
|
}
|
||
|
|
||
|
#ifdef _NORMALMAP
|
||
|
half3 NormalInTangentSpace(float4 texcoords, half4 attribs)
|
||
|
{
|
||
|
half3 normalTangent = UnpackScaleNormal(UNITY_SAMPLE_TEX2DARRAY (_BumpMap, texcoords.xyz), attribs.r);
|
||
|
|
||
|
#if _DETAIL && defined(UNITY_ENABLE_DETAIL_NORMALMAP)
|
||
|
half mask = DetailMask(texcoords);
|
||
|
|
||
|
texcoords.xy = texcoords.xy * SampleAttrImg(5, texcoords.w).xy + SampleAttrImg(5, texcoords.w).zw;
|
||
|
half3 detailNormalTangent = UnpackScaleNormal(UNITY_SAMPLE_TEX2DARRAY (_DetailNormalMap, texcoords.xyz), SampleAttrImg(6, texcoords.w).r);
|
||
|
#if _DETAIL_LERP
|
||
|
normalTangent = lerp(
|
||
|
normalTangent,
|
||
|
detailNormalTangent,
|
||
|
mask);
|
||
|
#else
|
||
|
normalTangent = lerp(
|
||
|
normalTangent,
|
||
|
BlendNormals(normalTangent, detailNormalTangent),
|
||
|
mask);
|
||
|
#endif
|
||
|
#endif
|
||
|
|
||
|
#if _DETAIL_SINGLE && defined(UNITY_ENABLE_DETAIL_NORMALMAP)
|
||
|
half mask = DetailMask(texcoords);
|
||
|
//float uvmod = SampleAttrImg(5, texcoords.w);
|
||
|
texcoords.xy = texcoords.xy * SampleAttrImg(5, texcoords.w).xy + SampleAttrImg(5, texcoords.w).zw;
|
||
|
half3 detailNormalTangent = UnpackScaleNormal(tex2D (_DetailNormalSingle, texcoords.xy), SampleAttrImg(6, texcoords.w).r);
|
||
|
#if _DETAIL_LERP
|
||
|
normalTangent = lerp(
|
||
|
normalTangent,
|
||
|
detailNormalTangent,
|
||
|
mask);
|
||
|
#else
|
||
|
normalTangent = lerp(
|
||
|
normalTangent,
|
||
|
BlendNormals(normalTangent, detailNormalTangent),
|
||
|
mask);
|
||
|
#endif
|
||
|
#endif
|
||
|
|
||
|
return normalTangent;
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
|
||
|
#if (UNITY_VERSION >= 201810 && (defined(SHADER_API_D3D11) || defined(SHADER_API_XBOXONE) || defined(UNITY_COMPILER_HLSLCC) || defined(SHADER_API_PSSL) || (SHADER_TARGET_SURFACE_ANALYSIS && !SHADER_TARGET_SURFACE_ANALYSIS_MOJOSHADER))) || (UNITY_VERSION < 201810 && (defined(SHADER_API_D3D11) || defined(SHADER_API_XBOXONE) || defined(UNITY_COMPILER_HLSLCC) || defined(SHADER_API_PSSL)))
|
||
|
#define BACTHFEW_SAMPLE_TEX2D_GRAD(tex,coord,dx,dy) tex.SampleGrad (sampler##tex,coord,dx,dy)
|
||
|
#elif defined(SHADER_API_D3D9)
|
||
|
#define BACTHFEW_SAMPLE_TEX2D_GRAD(tex,coord,dx,dy) half4(0,1,0,0)
|
||
|
#elif defined(UNITY_COMPILER_HLSL2GLSL) || defined(SHADER_TARGET_SURFACE_ANALYSIS)
|
||
|
#define BACTHFEW_SAMPLE_TEX2D_GRAD(tex,coord,dx,dy) texCUBEgrad (tex,coord,float3(dx.x,dx.y,0),float3(dy.x,dy.y,0))
|
||
|
#elif defined(SHADER_API_GLES)
|
||
|
#define BACTHFEW_SAMPLE_TEX2D_GRAD(tex,coord,dx,dy) half4(1,1,0,0)
|
||
|
#elif defined(SHADER_API_D3D11_9X)
|
||
|
#define BACTHFEW_SAMPLE_TEX2D_GRAD(tex,coord,dx,dy) half4(0,1,1,0)
|
||
|
#else
|
||
|
#define BACTHFEW_SAMPLE_TEX2D_GRAD(tex,coord,dx,dy) half4(0,0,1,0)
|
||
|
#endif
|
||
|
|
||
|
|
||
|
#if (UNITY_VERSION >= 201810 && (defined(SHADER_API_D3D11) || defined(SHADER_API_XBOXONE) || defined(UNITY_COMPILER_HLSLCC) || defined(SHADER_API_PSSL) || (SHADER_TARGET_SURFACE_ANALYSIS && !SHADER_TARGET_SURFACE_ANALYSIS_MOJOSHADER))) || (UNITY_VERSION < 201810 && (defined(SHADER_API_D3D11) || defined(SHADER_API_XBOXONE) || defined(UNITY_COMPILER_HLSLCC) || defined(SHADER_API_PSSL)))
|
||
|
#define BATCHFEW_SAMPLE_TEX2D_LOD(tex,coord, lod) tex.SampleLevel (sampler##tex,coord, lod)
|
||
|
#define BATCHFEW_SAMPLE_TEX2D_SAMPLER_LOD(tex,samplertex,coord, lod) tex.SampleLevel (sampler##samplertex,coord, lod)
|
||
|
#else
|
||
|
#define BATCHFEW_SAMPLE_TEX2D_LOD(tex,coord,lod) tex2D (tex,coord,0,lod)
|
||
|
#define BATCHFEW_SAMPLE_TEX2D_SAMPLER_LOD(tex,samplertex,coord,lod) tex2D (tex,coord,0,lod)
|
||
|
#endif
|
||
|
|
||
|
|
||
|
float ComputeMipLevel(float2 uv, float2 textureSize)
|
||
|
{
|
||
|
uv *= textureSize;
|
||
|
float2 dx_vtc = ddx(uv);
|
||
|
float2 dy_vtc = ddy(uv);
|
||
|
float delta_max_sqr = max(dot(dx_vtc, dx_vtc), dot(dy_vtc, dy_vtc));
|
||
|
return 0.5 * log2(delta_max_sqr);
|
||
|
}
|
||
|
|
||
|
int _ParallaxSteps;
|
||
|
|
||
|
float4 _ParallaxMap_TexelSize;
|
||
|
|
||
|
inline float2 POM( float2 uvs,
|
||
|
float3 normalWorld, float3 viewWorld, float3 viewDirTan,
|
||
|
float parallax, float texIndex)
|
||
|
{
|
||
|
float curvFix = 1.0;
|
||
|
|
||
|
float2 curv = float2(0, 0);
|
||
|
float refPlane = 0;
|
||
|
|
||
|
float3 result = 0;
|
||
|
int stepIndex = 0;
|
||
|
//int numSteps = ( int )lerp( maxSamples, minSamples, dot( normalWorld, viewWorld ) );
|
||
|
int numSteps = _ParallaxSteps; // artifacts when using variable step slope above
|
||
|
float layerHeight = 1.0 / numSteps;
|
||
|
float2 plane = parallax * ( viewDirTan.xy / viewDirTan.z );
|
||
|
uvs += refPlane * plane;
|
||
|
float2 deltaTex = -plane * layerHeight;
|
||
|
float2 prevTexOffset = 0;
|
||
|
float prevRayZ = 1.0f;
|
||
|
float prevHeight = 0.0f;
|
||
|
float2 currTexOffset = deltaTex;
|
||
|
float currRayZ = 1.0f - layerHeight;
|
||
|
float currHeight = 0.0f;
|
||
|
float intersection = 0;
|
||
|
float2 finalTexOffset = 0;
|
||
|
float mipLevel = ComputeMipLevel(uvs, _ParallaxMap_TexelSize.zw);
|
||
|
|
||
|
|
||
|
while ( stepIndex < numSteps + 1 )
|
||
|
{
|
||
|
result.z = dot( curv, currTexOffset * currTexOffset );
|
||
|
|
||
|
currHeight = BATCHFEW_SAMPLE_TEX2D_LOD(_ParallaxMap, float3(uvs + currTexOffset, texIndex), mipLevel ).r * ( 1 - result.z );
|
||
|
|
||
|
if ( currHeight > currRayZ )
|
||
|
{
|
||
|
stepIndex = numSteps + 1;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
stepIndex++;
|
||
|
prevTexOffset = currTexOffset;
|
||
|
prevRayZ = currRayZ;
|
||
|
prevHeight = currHeight;
|
||
|
currTexOffset += deltaTex;
|
||
|
currRayZ -= layerHeight * ( 1 - result.z ) * (1+curvFix);
|
||
|
}
|
||
|
}
|
||
|
int sectionSteps = 10;
|
||
|
int sectionIndex = 0;
|
||
|
float newZ = 0;
|
||
|
float newHeight = 0;
|
||
|
while ( sectionIndex < sectionSteps )
|
||
|
{
|
||
|
intersection = ( prevHeight - prevRayZ ) / ( prevHeight - currHeight + currRayZ - prevRayZ );
|
||
|
finalTexOffset = prevTexOffset + intersection * deltaTex;
|
||
|
newZ = prevRayZ - intersection * layerHeight;
|
||
|
|
||
|
newHeight = BATCHFEW_SAMPLE_TEX2D_LOD(_ParallaxMap, float3(uvs + finalTexOffset, texIndex), mipLevel ).r * ( 1 - result.z );
|
||
|
|
||
|
|
||
|
if ( newHeight > newZ )
|
||
|
{
|
||
|
currTexOffset = finalTexOffset;
|
||
|
currHeight = newHeight;
|
||
|
currRayZ = newZ;
|
||
|
deltaTex = intersection * deltaTex;
|
||
|
layerHeight = intersection * layerHeight;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
prevTexOffset = finalTexOffset;
|
||
|
prevHeight = newHeight;
|
||
|
prevRayZ = newZ;
|
||
|
deltaTex = ( 1 - intersection ) * deltaTex;
|
||
|
layerHeight = ( 1 - intersection ) * layerHeight;
|
||
|
}
|
||
|
sectionIndex++;
|
||
|
}
|
||
|
#ifdef UNITY_PASS_SHADOWCASTER
|
||
|
if ( unity_LightShadowBias.z == 0.0 )
|
||
|
{
|
||
|
#endif
|
||
|
if ( result.z > 1 )
|
||
|
clip( -1 );
|
||
|
#ifdef UNITY_PASS_SHADOWCASTER
|
||
|
}
|
||
|
#endif
|
||
|
return uvs + finalTexOffset;
|
||
|
}
|
||
|
|
||
|
|
||
|
float4 Parallax (float4 texcoords, half3 i_viewDirForParallax, float3 i_eyeVec, float4 tangentToWorld[3])
|
||
|
{
|
||
|
#if defined(_PARALLAXMAP)
|
||
|
|
||
|
half h = UNITY_SAMPLE_TEX2DARRAY (_ParallaxMap, texcoords.xyz).g;
|
||
|
|
||
|
float2 offset = ParallaxOffset1Step (h, SampleAttrImg(6, texcoords.w).b, i_viewDirForParallax);
|
||
|
return float4(texcoords.xy + offset, texcoords.zw);
|
||
|
#endif
|
||
|
#if defined(_POM)
|
||
|
float parallax = SampleAttrImg(6, texcoords.w).b;
|
||
|
half3 normal = (0,0,1);
|
||
|
|
||
|
|
||
|
half3 worldNormal = half3(dot(tangentToWorld[0], normal), dot(tangentToWorld[1],normal), dot(tangentToWorld[2],normal));
|
||
|
|
||
|
float2 offset = POM(texcoords.xy, worldNormal, i_eyeVec, i_viewDirForParallax, parallax, texcoords.z);
|
||
|
return float4(offset, texcoords.zw);
|
||
|
#endif
|
||
|
return texcoords;
|
||
|
}
|
||
|
|
||
|
|
||
|
#endif // UNITY_STANDARD_INPUT_INCLUDED
|