CUSTOM shader : Phong shader base (light count : 1)
custom shader practice for light & good quality shaing
unpacking method and traspose of TBN edited in order to get better look
Shader "Custom/Phong"
{
Properties
{
_DiffuseSampler("DiffuseTexture", 2D) = "white"{}
_DiffuseColor("DiffuseColor", Color) = (0.5,0.5,0.5,1)
_DiffuseStr("Diffuse Strength", Float) = 1
_ShadeColor("ShadeColor", Color) = (0.5,0.5,0.5,1)
_ShadeNormalStr("Shade Normal Strength", Float) = 0.2
_SpecColor("SpecColor", Color) = (1,1,1,1)
_SpecDiffuseStr("Specular Diffuse Strength", Range(0,1)) = 0.5
_ReflectionStr("Refeflection strength", Float) = 0.2
_Shininess("Shininess", Float) = 0.5
_Metallic("Metallic", Range(0, 2)) = 0.5
_BumpTex("Bump Texture", 2D) = "bump"{}
_BumpStr("Bump Strength", Float) = 1
_FresnelBias("Fresnel Bias", Float) = 0
_FresnelScale("Fresnel Scale", Float) = 1
_FresnelPower("Fresnel Power", Float) = 1
}
SubShader
{
Tags {"Queue" = "Geometry" "RenderType" = "Opaque" }
Pass
{
CGPROGRAM
// Physically based Standard lighting model, and enable shadows on all light types
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
uniform float4 _LightColor0;
//uniform float4 _Color;
uniform float4 _DiffuseColor;
uniform float _DiffuseStr;
uniform float4 _ShadeColor;
uniform float _ShadeNormalStr;
uniform float4 _SpecColor;
uniform float _SpecDiffuseStr;
uniform float _ReflectionStr;
uniform float _Shininess;
uniform float _Metallic;
uniform float _BumpStr;
fixed _FresnelBias;
fixed _FresnelScale;
fixed _FresnelPower;
//float4x4 gWorldMatrix; //World space
//float4x4 gWorldViewProjectionMatrix;
//float4x4 gWorldLightPosition;
//float4x4 gWorldCameraPosition;
//float4x4 gViewMatrix; // View space
//float4x4 gProjectionMatrix; // resterize
// 입출력 과정
// Object space -> world space -> view space -> resterize
// 전역 변수 , 정점 데이터
// 전역 변수 -> 카메라 위치, world 좌표 ...
// 정점 데이터 -> vertex position ...
struct vertexInput // 정점 데이터 입력
{
float4 vertex : POSITION; //각 정점의 위치 (sementic)을 통해서 가져옴
float3 normal : NORMAL;
float4 tangent : TANGENT;
float4 texcoord :TEXCOORD0;
//float3 worldRefl; // Surface shader automatically calculate V2N world reflect vector
};
struct vertexOutput // 정점 데이터의 출력값
{
float4 pos : SV_POSITION;
float4 uv : TEXCOORD0;
float4 posWorld :TEXCOORD1;
float3 N :TEXCOORD2;
float3 T : TEXCOORD3;
float3 B : TEXCOORD4;
float3 lightDir : TEXCOORD5;
half3 viewDir : TEXCOORD6;
// float3 worldRefl;
};
sampler2D _DiffuseSampler;
float4 _DiffuseSampler_ST;
sampler2D _BumpTex;
float4 _BumpTex_ST;
vertexOutput vert(vertexInput v)
{
vertexOutput o;
//o.pos = UnityObjectToClipPos(v.vertex); //UNITY_MATRIX_MVP == gWorldViewProjectionMatrix
//o.color = v.color;
o.posWorld = mul(unity_ObjectToWorld, v.vertex);
o.pos = UnityObjectToClipPos(v.vertex);
o.lightDir = WorldSpaceLightDir(v.vertex);
o.viewDir = normalize(WorldSpaceViewDir(v.vertex));
half fTangentSign = v.tangent.w * unity_WorldTransformParams.w;
o.N = normalize(mul(float4(v.normal, 0.0), unity_WorldToObject).xyz); //normal direction converting
o.T = normalize(UnityObjectToWorldDir(v.tangent.xyz));//normalize(mul(float4(v.tangent, 0.0), modelMatrixInverse).xyz);
o.B = normalize(cross(o.N, o.T) * fTangentSign);
//o.worldRefl = v.worldRefl;
o.uv = float4(v.texcoord.xy, 0, 0);
return o;
}
fixed3 CustomUnpackNormal(fixed4 packednormal)
{ // convert [0~1] to [-1 ~ 1]
//xyzw
#if defined(UNITY_NO_DXT5nm)
// !!!! re calculation of this format needed !!!!
//fixed3 normal;
//normal.xy = packednormal.yw;
//normal.z = sqrt(1 - normal.x * normal.x - normal.y * normal.y);
return packednormal.xyz * 2 - 1;
#else
fixed3 normal;
normal.xy = packednormal.wy * 2 - 1;
normal.z = sqrt(1 - normal.x * normal.x - normal.y * normal.y);
return normal.xyz;
#endif
//#if defined(SHADER_API_GLES) defined(SHADER_API_MOBILE)
//#else
// fixed3 normal;
// normal.xy = packednormal.wy * 2 - 1;
// normal.z = sqrt(1 - normal.x * normal.x - normal.y * normal.y);
//
//
// return normal;
// #endif
}
/*
transpose :
[ 1, 2, 3 ] [ 1, 4, 7 ]
[ 4, 5 6 ] [ 2, 5, 8 ]
[ 7, 8, 9 ] [ 3, 6, 9 ]
*/
void CustomLocalNormal2TBN(half3 localnormal, float4 tangent, inout half3 T, inout half3 B, inout half3 N)
{
half fTangentSign = tangent.w * unity_WorldTransformParams.w;
N = normalize(UnityObjectToWorldNormal(localnormal));
T = normalize(UnityObjectToWorldDir(tangent.xyz));
B = normalize(cross(N, T) * fTangentSign);
}
half3 CustomTangentNormal2WorldNormal(half3 fTangentNormal, half3 T, half3 B, half3 N)
{
float3x3 TBN = float3x3(T, B, N);
TBN = transpose(TBN); // transpose(전치행렬) : MVP 좌표변환의 이동행렬(Translation)과 동일
return mul(TBN, fTangentNormal);
}
half3 CustomTangentNormal2TNB(half3 fTangentNormal, half3 T, half3 B, half3 N)
{
float3x3 TNB = float3x3(T, N, B);
TNB = transpose(TNB); // transpose(전치행렬) : MVP 좌표변환의 이동행렬(Translation)과 동일
return mul(TNB, fTangentNormal);
}
fixed4 frag(vertexOutput i) : COLOR
{
fixed4 o;
fixed4 diffuse = tex2D(_DiffuseSampler, i.uv * _DiffuseSampler_ST.xy) * _DiffuseColor * _DiffuseStr;
float3 viewDirection = normalize(_WorldSpaceCameraPos - i.posWorld.xyz); //view normal vector
float3 lightDirection;
float attenuation;
float4 ref_val = UNITY_SAMPLE_TEXCUBE(unity_SpecCube0, i.N);//texCUBE(_CubeMap, reflectDirection);//UNITY_SAMPLE_TEXCUBE(_CubeMap, i.worldRefl);//tex2D(_CubeMap, i.worlRefl.uv);
float3 ref_col = DecodeHDR(ref_val, unity_SpecCube0_HDR);
//Bump
half3 fTangentNormal = CustomUnpackNormal(tex2D(_BumpTex, i.uv * _BumpTex_ST.rg));
fTangentNormal.xy *= _BumpStr;
float3 worldNormal = CustomTangentNormal2WorldNormal(fTangentNormal, i.T, i.B, i.N);
float3 TNBNormal = CustomTangentNormal2TNB(fTangentNormal, i.T, i.B, i.N);
fixed fNdotL = dot(i.lightDir, worldNormal);
float3 fReflection = reflect(i.lightDir, worldNormal);
float3 fTNBRef = reflect(i.lightDir, TNBNormal);
if (0.0 == _WorldSpaceLightPos0.w)
{ // directional light
attenuation = 1.0;
lightDirection = normalize(_WorldSpaceLightPos0.xyz);
}
else
{
float3 vertexToLightSource = _WorldSpaceLightPos0.xyz - i.posWorld.xyz;
float distance = length(vertexToLightSource);
attenuation = 1.0 / distance;
lightDirection = normalize(vertexToLightSource);
}
float3 lightInverseDir = -lightDirection;
float3 ambientLighting = UNITY_LIGHTMODEL_AMBIENT.rgb * diffuse.rgb;
//get diffuse reflection on bright side
float3 diffuseReflection = attenuation * _LightColor0.rgb * diffuse.rgb * max(0.0, dot(i.N, lightDirection));
float3 diffuseShadeRef = attenuation * _ShadeColor.rgb * diffuse.rgb * max(0.0, dot(i.N, -lightDirection)) * 0.5; // +(ref_col - 0.4);
float3 specularReflection;
//if (dot(worldNormal, lightDirection) < 0.0)
//{
// specularReflection = float3(0.0, 0.0, 0.0);
//}
//else
//{
specularReflection = attenuation * _LightColor0.rgb * _SpecColor.rgb
* pow(max(0.0, dot(fReflection, -normalize(i.viewDir)) * _Metallic), _Shininess)
* ((1 - _SpecDiffuseStr) + diffuse.rgb * _SpecDiffuseStr) *ref_col + max(0, dot(fTNBRef, -normalize(i.viewDir) * _ShadeNormalStr));
//
// //attenuation * _LightColor0.rgb * _SpecColor.rgb *
// //pow(max(0.0, dot(-fReflection, normalize(i.viewDir)) * _Metallic), _Shininess)
// //* dot(i.lightDir, worldNormal); //*ref_col * ((1- _SpecDiffuseStr) + diffuse.rgb* _SpecDiffuseStr);
//}
float4 final = float4( ambientLighting +(diffuseReflection + diffuseShadeRef) + specularReflection, 1); //= float4(ambientLighting + diffuseReflection + specularReflection, 1.0);
//float4 final = float4(specularReflection, 1); //= float4(ambientLighting + diffuseReflection + specularReflection, 1.0);
return final;
}
ENDCG
}
}
Fallback "Diffuse"
}
.cs
CatDarkGame's Game Dev Story :: Unity Custom Light 5강 - Reflection (tistory.com)
CatDarkGame's Game Dev Story :: Unity Normal Map 구현 & 분석 (tistory.com)
Normal(법선) | 버텍스의 수직을 향하는 방향 |
Tangent(접선) | 버텍스의 수평을 향하는 방향 |
BiNormal(종법선) | Normal과 Tangent를 외적(Cross)하여 나온 방향 |
댓글
댓글 쓰기