Shader "ryoo/RyooSpecularShaderForwardAddooo"
{
Properties
{
_DiffuseTex ("Texture", 2D) = "white" {}
_Color ("Color", Color) = (1,0,0,1)
_Ambient ("Ambient", Range (0, 1)) = 0.25
_SpecColor ("Specular Material Color", Color) = (1,1,1,1) // 스페큘러 컬러
_Shininess ( "Shininess", Float) = 10 // 스페큘러 강도
}
SubShader
{
Tags { "LightMode" = "ForwardBase" }
LOD 100
Pass
{
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
#pragma multi_compile_fwdbase
#include "UnityLightingCommon.cginc"
struct appdata
{
float4 vertex : POSITION;
float3 normal : NORMAL;
float2 uv : TEXCOORD0;
};
struct v2f // v2f struct(구조체)에 변수를 추가하고, v2f를 통해 프레그먼트 셰이더에 전달
{
float2 uv : TEXCOORD0;
float4 vertexClip : SV_POSITION;
float4 vertexWorld : TEXCOORD2; // 프레그먼트 셰이더에서 광원 방향 벡터 계산
float3 worldNormal : TEXCOORD1;
};
sampler2D _DiffuseTex;
float4 _DiffuseTex_ST;
float4 _Color;
float _Ambient;
float _Shininess;
v2f vert (appdata v) //정점 셰이더 부분
{
v2f o;
o.vertexClip = UnityObjectToClipPos(v.vertex);
//o.vertexWorld = mul(unity_ObjectToWorld, v.vertex);
o.vertexWorld = UnityObjectToClipPos(v.vertex);
o.uv = TRANSFORM_TEX(v.uv, _DiffuseTex); //텍스쳐 영역
float3 worldNormal = UnityObjectToWorldNormal(v.normal);
o.worldNormal = worldNormal;
return o;
}
float4 frag (v2f i) : SV_Target //프레그먼트 셰이더 부분
{
//정규화된 월드 공간의 노멀 벡터
float3 normalDirection = normalize( i.worldNormal);
// 정규화된 뷰 방향 벡터
float3 viewDirection = normalize(UnityWorldSpaceViewDir(i. vertexWorld));
// 정규화된 광원 방향 벡터
float3 lightDirection = normalize(UnityWorldSpaceLightDir(i. vertexWorld));
//텍스쳐 영역
float4 tex =tex2D(_DiffuseTex, i.uv);
// 디퓨즈(람버트) 구현
float nl = max(_Ambient, dot(normalDirection, lightDirection));
float4 diffuseTerm = nl * _Color * tex * _LightColor0;
//스페큘러(퐁) 구현
float3 reflectionDirection = reflect(-lightDirection, normalDirection);
float3 specularDot = max(0.0, dot(viewDirection, reflectionDirection));
float3 specular = pow(specularDot, _Shininess);
float4 specularTerm = float4( specular, 1) * _SpecColor * _LightColor0;
float4 finalColor = diffuseTerm + specularTerm;
return finalColor;
}
ENDCG
}
Pass // 추가 광원을 지원하기 위해서 같은걸 복사하고 몇가지만 수정
{
Tags { "LightMode" = "ForwardAdd" } // 추가 광원을 지원하기 위함.
Blend One One
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#pragma multi_compile_fwdadd
#include "UnityCG.cginc"
#include "UnityLightingCommon.cginc"
struct appdata
{
float4 vertex : POSITION;
float3 normal : NORMAL;
float2 uv : TEXCOORD0;
};
struct v2f
{
float2 uv : TEXCOORD0;
float4 vertexClip : SV_POSITION;
float4 vertexWorld : TEXCOORD2;
float3 worldNormal : TEXCOORD1;
};
sampler2D _DiffuseTex;
float4 _DiffuseTex_ST;
float4 _Color;
float _Ambient;
float _Shininess;
v2f vert (appdata v)
{
v2f o;
o.vertexClip = UnityObjectToClipPos(v.vertex);
o.vertexWorld = mul(unity_ObjectToWorld, v.vertex);
o.uv = TRANSFORM_TEX(v.uv, _DiffuseTex);
float3 worldNormal = UnityObjectToWorldNormal(v.normal);
o.worldNormal = worldNormal;
return o;
}
float4 frag (v2f i) : SV_Target
{
float3 normalDirection = normalize( i.worldNormal);
// 정규화된 뷰 방향 벡터
float3 viewDirection = normalize( UnityWorldSpaceViewDir(i.vertexWorld));
// 정규화된 광원 방향 벡터
float3 lightDirection = normalize(UnityWorldSpaceLightDir(i.vertexWorld));
//텍스쳐 영역
float4 tex = tex2D(_DiffuseTex, i.uv);
// 디퓨즈(람버트) 구현
float nl = max(0.0, dot(normalDirection, lightDirection)); // Ambient를 제외시킨다. 포함시키면 빛이 더해져서 너무 밝게 나오기 때문에 0으로 셋팅한다.
float4 diffuseTerm = nl * _Color * tex * _LightColor0;
//스페큘러(퐁) 구현
float3 reflectionDirection = reflect(-lightDirection, normalDirection);
float3 specularDot = max(0.0, dot(viewDirection, reflectionDirection));
float3 specular = pow( specularDot, _Shininess);
//여기까지 퐁
float4 specularTerm = float4( specular, 1) *_SpecColor * _LightColor0;
float4 finalColor = diffuseTerm + specularTerm;
return finalColor;
}
ENDCG
}
}
}
참고서적: 유니티 물리 기반 셰이더 개발