Custom phong shading vs standard pbr(GGX) shading
내가 만들엇지만 나름 잘만든 것 같다.
(위사진은 왼쪽이 cook-torrance방식이고 가운데가 standard 왼쪽이 내가 만든 custom phong shading이다.)
회사 디자이너 분들에게 물어봤을때 오른쪽에 내가 만든 쉐이더가 제일 이쁘다고 했다 !
yeah~~ !
yeah~~ !
비용도 프로파일러로 GPU profiling했을때 standard의 절반정도 비용으로 나온다.
Nice~!
아래는 왼쪽이 standard pbr(GGX) shading 이고 오른쪽이 customize 한 phong shading으로 만든 것이다 퀄리티는 거의 흡사하지만 퍼포먼스는 확실히 많이 개선 됬으며 필요로 하게 되는 texture 의 수는 standard = 5/ custom = 2 로 확연히 줄었다.
Sample code 계속해서 발전 시켜보고 있다. (UTF-8 이 왜 풀렸는지.. 한글이 날라갔다 ㄷㄷ)
// Upgrade NOTE: replaced 'mul(UNITY_MATRIX_MVP,*)' with 'UnityObjectToClipPos(*)'
Shader "Custom/Phong"
{
Properties
{
_DiffuseSampler("DiffuseTexture", 2D) = "white"{}
_DiffuseColor("DiffuseColor", Color) = (0.5,0.5,0.5,1)
_DiffuseStr("Diffuse Strength", Float) = 1
_DiffusePow("Diffuse Power", Float) = 1
_BaseLerp("Base Lerp", 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
_HeightMap("Height Map", 2D) = "white"{}
_Parallax("Parallax", Float) = 0
}
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 float _DiffusePow;
uniform float _BaseLerp;
uniform float4 _ShadeColor;
uniform float _ShadeNormalStr;
uniform float4 _SpecColor;
uniform float _SpecDiffuseStr;
uniform float _ReflectionStr;
uniform float _Shininess;
uniform float _Metallic;
uniform float _BumpStr;
uniform float _Parallax;
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;
float fresnel : TEXCOORD7;
// float3 worldRefl;
};
sampler2D _DiffuseSampler;
float4 _DiffuseSampler_ST;
sampler2D _BumpTex;
float4 _BumpTex_ST;
sampler2D _HeightMap;
float4 _HeightMap_ST;
float3 customObjSpaceViewDir(float4 v)
{
float3 objSpaceCameraPos = mul(unity_WorldToObject, float4(_WorldSpaceCameraPos.xyz, 1)).xyz;
return objSpaceCameraPos - v.xyz;
}
vertexOutput vert(vertexInput v)
{
vertexOutput o;
//o.pos = UnityObjectToClipPos(v.vertex); //UNITY_MATRIX_MVP == gWorldViewProjectionMatrix
//o.color = v.color;
o.pos = UnityObjectToClipPos(v.vertex);
o.posWorld = mul(unity_ObjectToWorld, v.vertex);
o.lightDir = WorldSpaceLightDir(v.vertex);
o.viewDir = 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);
//fresnel equation
float3 i = normalize(customObjSpaceViewDir(v.vertex));
//o.fresnel = 1 - dot(i, v.normal);
o.fresnel = _FresnelBias + _FresnelScale * pow( 1 - dot(i, v.normal), _FresnelPower);
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
}
/*
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);
}
inline float2 customParallaxOffset(half h, half height, half3 viewDir)
{
h = h * height - height / 2.0;
float3 v = normalize(viewDir);
v.z += 0.42;
return h * (v.xy / v.z);
}
fixed4 frag(vertexOutput i) : COLOR
{...
}
ENDCG
}
}
Fallback "Diffuse"
}
댓글
댓글 쓰기