summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authoryum <yum.food.vr@gmail.com>2023-01-29 18:33:10 -0800
committeryum <yum.food.vr@gmail.com>2023-01-29 18:34:02 -0800
commitc1019adc04e7ca10b1e42751224ff0e885d6bb34 (patch)
treebf0fe0e53a15a254e66189690939000a78ab20c4
parent3f4b2aa5548d1fb15cde1e8f83cda64637c55014 (diff)
Check in PBS, a very minimal physically-based shader
Strip out everything except the PBS bits from the TaSTT shader and put them into a standalone shader.
-rw-r--r--Shaders/PBS.shader62
-rw-r--r--Shaders/PBS_lighting.cginc311
2 files changed, 373 insertions, 0 deletions
diff --git a/Shaders/PBS.shader b/Shaders/PBS.shader
new file mode 100644
index 0000000..ddcfd1f
--- /dev/null
+++ b/Shaders/PBS.shader
@@ -0,0 +1,62 @@
+Shader "TaSTT/Simple_PBS"
+{
+ Properties
+ {
+ [MaterialToggle] BG_Enable("Enable custom background", float) = 0
+ BG_BaseColor("Background base color", 2D) = "black" {}
+ [NoScaleOffset] BG_NormalMap ("Background normal map", 2D) = "bump" {}
+ BG_NormalStrength ("Background normal strength", Float) = 1
+ BG_Smoothness("Background smoothness", 2D) = "black" {}
+ [MaterialToggle]BG_Smoothness_Invert("Invert background smoothness", float) = 1
+ BG_Metallic("Background metallic", 2D) = "black" {}
+ BG_Emission_Mask("Background emission mask", 2D) = "black" {}
+ BG_Emission_Color("Background emission color", Color) = (0, 0, 0)
+
+ // %TEMPLATE__UNITY_ROW_COL_PARAMS%
+ }
+ SubShader
+ {
+ Pass {
+ Tags {
+ "RenderType"="Opaque"
+ "Queue"="AlphaTest+499"
+ "LightMode" = "ForwardBase"
+ }
+ Blend SrcAlpha OneMinusSrcAlpha
+
+ CGPROGRAM
+ #pragma target 3.0
+
+ #pragma multi_compile _ VERTEXLIGHT_ON
+
+ #pragma vertex vert
+ #pragma fragment frag
+
+ #define FORWARD_BASE_PASS
+
+ #include "PBS_lighting.cginc"
+ ENDCG
+ }
+ Pass {
+ Tags {
+ "RenderType" = "Opaque"
+ "LightMode" = "ForwardAdd"
+ "Queue"="AlphaTest+499"
+ }
+ Blend One One
+ ZWrite Off
+
+ CGPROGRAM
+ #pragma target 3.0
+
+ #pragma multi_compile_fwdadd
+
+ #pragma vertex vert
+ #pragma fragment frag
+
+ #include "PBS_lighting.cginc"
+ ENDCG
+ }
+ }
+}
+
diff --git a/Shaders/PBS_lighting.cginc b/Shaders/PBS_lighting.cginc
new file mode 100644
index 0000000..d41d44b
--- /dev/null
+++ b/Shaders/PBS_lighting.cginc
@@ -0,0 +1,311 @@
+#ifndef PBS_LIGHTING
+#define PBS_LIGHTING
+
+#include "AutoLight.cginc"
+#include "UnityPBSLighting.cginc"
+
+struct appdata
+{
+ float4 position : POSITION;
+ float2 uv : TEXCOORD0;
+ float3 normal : NORMAL;
+};
+
+struct v2f
+{
+ float4 position : SV_POSITION;
+ float4 uv : TEXCOORD0;
+ float3 normal : TEXCOORD1;
+ float3 worldPos : TEXCOORD2;
+
+ #if defined(VERTEXLIGHT_ON)
+ float3 vertexLightColor : TEXCOORD3;
+ #endif
+};
+
+float BG_Enable;
+sampler2D BG_BaseColor;
+sampler2D BG_NormalMap;
+sampler2D BG_Metallic;
+sampler2D BG_Smoothness;
+sampler2D BG_Emission_Mask;
+float BG_Smoothness_Invert;
+float BG_NormalStrength;
+float3 BG_Emission_Color;
+float4 BG_BaseColor_ST;
+float4 BG_NormalMap_ST;
+float4 BG_Metallic_ST;
+float4 BG_Smoothness_ST;
+float4 BG_Emission_Mask_ST;
+
+void getVertexLightColor(inout v2f i)
+{
+ #if defined(VERTEXLIGHT_ON)
+ float3 light_pos = float3(unity_4LightPosX0.x, unity_4LightPosY0.x,
+ unity_4LightPosZ0.x);
+ float3 light_vec = light_pos - i.worldPos;
+ float3 light_dir = normalize(light_vec);
+ float ndotl = DotClamped(i.normal, light_dir);
+ // Light fills an expanding sphere with surface area 4 * pi * r^2.
+ // By conservation of energy, this means that at distance r, light intensity
+ // is proportional to 1/(r^2).
+ float attenuation = 1 / (1 + dot(light_vec, light_vec) * unity_4LightAtten0.x);
+ i.vertexLightColor = unity_LightColor[0].rgb * ndotl * attenuation;
+
+ i.vertexLightColor = Shade4PointLights(
+ unity_4LightPosX0, unity_4LightPosY0, unity_4LightPosZ0,
+ unity_LightColor[0].rgb,
+ unity_LightColor[1].rgb,
+ unity_LightColor[2].rgb,
+ unity_LightColor[3].rgb,
+ unity_4LightAtten0, i.worldPos, i.normal
+ );
+ #endif
+}
+
+v2f vert(appdata v)
+{
+ v2f o;
+ o.position = mul(UNITY_MATRIX_MVP, v.position);
+ o.worldPos = mul(unity_ObjectToWorld, v.position);
+ o.normal = UnityObjectToWorldNormal(v.normal);
+ o.uv.xy = TRANSFORM_TEX(v.uv, BG_BaseColor);
+ o.uv.zw = 1.0 - v.uv;
+ getVertexLightColor(o);
+ return o;
+}
+
+fixed sq_dist(fixed2 p0, fixed2 p1)
+{
+ fixed2 delta = p1 - p0;
+ return max(abs(delta.x), abs(delta.y));
+}
+
+float3 HUEtoRGB(in float H)
+{
+ float R = abs(H * 6 - 3) - 1;
+ float G = 2 - abs(H * 6 - 2);
+ float B = 2 - abs(H * 6 - 4);
+ return saturate(float3(R, G, B));
+}
+
+float3 HSVtoRGB(in float3 HSV)
+{
+ float3 RGB = HUEtoRGB(HSV.x);
+ return ((RGB - 1) * HSV.y + 1) * HSV.z;
+}
+
+fixed4 effect_squares (v2f i)
+{
+ float2 uv = i.uv.zw;
+ uv.y *= 2; // Text box has 2:1 aspect ratio
+ const fixed time = _Time.y;
+
+ #define PI 3.1415926535
+ fixed theta = PI/4 + sin(time / 4) * 0.1;
+ fixed2x2 rot =
+ fixed2x2(cos(theta), -1 * sin(theta),
+ sin(theta), cos(theta));
+
+ #define NSQ_X 9.0
+ #define NSQ_Y 5.0
+
+ // Map uv from [0, 1] to [-.5, .5].
+ fixed2 p = uv - 0.5;
+ p *= fixed2(NSQ_X, NSQ_Y);
+ p = mul(rot, p);
+ p -= 0.5;
+
+ // See how far we are from the nearest grid point
+ fixed2 intra_pos = frac(p);
+ fixed2 intra_center = fixed2(0.5, 0.5);
+ fixed intra_dist = sq_dist(intra_pos, intra_center);
+
+ fixed st0 = (sin(time) + 1) / 2;
+ fixed st1 = (sin(time + PI/8) + 1) / 2;
+ fixed st2 = (sin(time + PI/2) + 1) / 2;
+ fixed st3 = (sin(time + PI/2 + PI/8) + 1) / 2;
+
+ fixed2 center = fixed2(0, 0);
+ center = mul(rot, center);
+ center -= 0.5;
+ fixed2 rot_lim = fixed2(NSQ_X, NSQ_Y);
+ rot_lim = mul(rot, rot_lim);
+ rot_lim -= 0.5;
+
+ float v = 0;
+ float x = 0;
+
+ if (intra_dist > 0.5 * (0.5 + sin(time * 1.5) * 0.1)) {
+ v = intra_dist;
+ } else {
+ v = 0;
+ }
+
+ fixed extra_dist = sq_dist(p, center);
+ fixed check = max(rot_lim.x, rot_lim.y) / 2;
+ if (extra_dist > check * st0) {
+ v = 1.0 - v;
+ }
+ if (extra_dist > check * st1) {
+ v = 1.0 - v;
+ }
+ if (extra_dist > check * st2) {
+ v = 1.0 - v;
+ }
+ if (extra_dist > check * st3) {
+ v = 1.0 - v;
+ } else {
+ x = 0.50;
+ }
+
+ fixed3 hsv;
+ hsv[0] = (v * 0.2 * (1 - x * .8) + 0.55) - x;
+ hsv[1] = 0.7;
+ hsv[2] = 0.8;
+
+ fixed3 col = HSVtoRGB(hsv);
+
+ return fixed4(col, 1.0);
+}
+
+fixed4 margin_effect(v2f i)
+{
+ return effect_squares(i);
+}
+
+UnityLight GetLight(v2f i)
+{
+ UNITY_LIGHT_ATTENUATION(attenuation, 0, i.worldPos);
+ float3 light_color = _LightColor0.rgb * attenuation;
+
+ UnityLight light;
+ light.color = light_color;
+ #if defined(POINT) || defined(POINT_COOKIE) || defined(SPOT)
+ light.dir = normalize(_WorldSpaceLightPos0.xyz - i.worldPos);
+ #else
+ light.dir = _WorldSpaceLightPos0.xyz;
+ #endif
+ light.ndotl = DotClamped(i.normal, light.dir);
+
+ return light;
+}
+
+UnityIndirect GetIndirect(v2f i, float3 view_dir, float smoothness) {
+ UnityIndirect indirect;
+ indirect.diffuse = 0;
+ indirect.specular = 0;
+
+ #if defined(VERTEXLIGHT_ON)
+ indirect.diffuse = i.vertexLightColor;
+ #endif
+
+ #if defined(FORWARD_BASE_PASS)
+ indirect.diffuse += max(0, ShadeSH9(float4(i.normal, 1)));
+ float3 reflect_dir = reflect(-view_dir, i.normal);
+ // There's a nonlinear relationship between mipmap level and roughness.
+ float roughness = 1 - smoothness;
+ roughness *= 1.7 - .7 * roughness;
+ float3 env_sample = UNITY_SAMPLE_TEXCUBE_LOD(
+ unity_SpecCube0,
+ reflect_dir,
+ roughness * UNITY_SPECCUBE_LOD_STEPS);
+ indirect.specular = env_sample;
+ #endif
+
+ return indirect;
+}
+
+void initNormal(inout v2f i)
+{
+ if (BG_Enable) {
+ i.normal = UnpackScaleNormal(
+ tex2Dgrad(BG_NormalMap, i.uv.xy, ddx(i.uv.x), ddy(i.uv.y)),
+ BG_NormalStrength);
+ // Swap Y and Z
+ i.normal = i.normal.xzy;
+ }
+ i.normal = normalize(i.normal);
+}
+
+fixed4 light(v2f i,
+ sampler2D albedo_map,
+ sampler2D normal_map,
+ float normal_str,
+ sampler2D metallic_map,
+ sampler2D smoothness_map,
+ float invert_smoothness,
+ sampler2D emission_mask,
+ float3 emission_color)
+{
+ initNormal(i);
+
+ float2 iddx = ddx(i.uv.x);
+ float2 iddy = ddy(i.uv.y);
+ fixed4 albedo = tex2Dgrad(albedo_map, i.uv, iddx, iddy);
+
+ fixed3 normal = UnpackScaleNormal(
+ tex2Dgrad(normal_map, i.uv.xy, iddx, iddy),
+ normal_str);
+ // Swap Y and Z
+ normal = normal.xzy;
+
+ float3 view_dir = normalize(_WorldSpaceCameraPos - i.worldPos);
+
+ float metallic = tex2Dgrad(metallic_map, i.uv.xy, iddx, iddy);
+
+ float3 specular_tint;
+ float one_minus_reflectivity;
+ albedo.rgb = DiffuseAndSpecularFromMetallic(
+ albedo, metallic, specular_tint, one_minus_reflectivity);
+
+ UnityIndirect indirect_light;
+ indirect_light.diffuse = 0;
+ indirect_light.specular = 0;
+
+ float smoothness = tex2Dgrad(smoothness_map, i.uv.xy, iddx, iddy);
+ if (invert_smoothness) {
+ smoothness = 1 - smoothness;
+ }
+
+ fixed3 emission = tex2Dgrad(emission_mask, i.uv.xy, iddx, iddy) * emission_color;
+
+ fixed3 pbr = UNITY_BRDF_PBS(albedo, specular_tint,
+ one_minus_reflectivity, smoothness,
+ i.normal, view_dir, GetLight(i), GetIndirect(i, view_dir, smoothness)).rgb;
+ pbr.rgb += emission;
+
+ return fixed4(pbr, albedo.a);
+}
+
+fixed4 frag(v2f i) : SV_Target
+{
+ float2 uv = i.uv.zw;
+ // Fix text orientation
+ uv.y = 0.5 - uv.y;
+ uv.x = 1.0 - uv.x;
+ uv.y *= 2; // Text box has 2:1 aspect ratio
+
+ // Derived from github.com/pema99/shader-knowledge (MIT license).
+ if (unity_CameraProjection[2][0] != 0.0 ||
+ unity_CameraProjection[2][1] != 0.0) {
+ uv.x = 1.0 - uv.x;
+ }
+
+ if (BG_Enable) {
+ return light(i,
+ BG_BaseColor,
+ BG_NormalMap,
+ BG_NormalStrength,
+ BG_Metallic,
+ BG_Smoothness,
+ BG_Smoothness_Invert,
+ BG_Emission_Mask,
+ BG_Emission_Color);
+ } else {
+ return fixed4(1, 1, 1, 0);
+ }
+}
+
+#endif // PBS_LIGHTING
+