// 양면 종이 셰이더 (URP) // - 양면 렌더링: 얇은 종이 메시(Quad/Plane)의 앞뒤가 모두 보인다 // - _BaseColor: 앞뒤 공통 종이 색 // - _FrontTex: 앞면(메시의 노멀 방향 면)에만 표시되는 텍스처(인쇄물). 비우면 앞면도 종이 색 그대로 // - 하프-램버트 + 앰비언트 조명이라 그늘에서도 새까매지지 않음. 그림자 드리우기 포함 Shader "DinoLove/Paper" { Properties { _BaseColor ("Base Color (양면 종이 색)", Color) = (1, 1, 1, 1) _FrontTex ("Front Texture (앞면 인쇄물)", 2D) = "white" {} } SubShader { Tags { "RenderType" = "Opaque" "Queue" = "Geometry" "RenderPipeline" = "UniversalPipeline" } // 종이는 얇아서 뒷면도 그린다 Cull Off Pass { Name "ForwardLit" Tags { "LightMode" = "UniversalForward" } HLSLPROGRAM #pragma vertex vert #pragma fragment frag #pragma multi_compile_instancing #include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl" #include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Lighting.hlsl" struct Attributes { float4 positionOS : POSITION; float3 normalOS : NORMAL; float2 uv : TEXCOORD0; UNITY_VERTEX_INPUT_INSTANCE_ID }; struct Varyings { float4 positionCS : SV_POSITION; float2 uv : TEXCOORD0; float3 normalWS : TEXCOORD1; UNITY_VERTEX_INPUT_INSTANCE_ID UNITY_VERTEX_OUTPUT_STEREO }; TEXTURE2D(_FrontTex); SAMPLER(sampler_FrontTex); CBUFFER_START(UnityPerMaterial) float4 _BaseColor; float4 _FrontTex_ST; CBUFFER_END Varyings vert(Attributes input) { Varyings output; UNITY_SETUP_INSTANCE_ID(input); UNITY_TRANSFER_INSTANCE_ID(input, output); UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(output); output.positionCS = TransformObjectToHClip(input.positionOS.xyz); output.normalWS = TransformObjectToWorldNormal(input.normalOS); output.uv = TRANSFORM_TEX(input.uv, _FrontTex); return output; } half4 frag(Varyings input, bool isFrontFace : SV_IsFrontFace) : SV_Target { UNITY_SETUP_INSTANCE_ID(input); UNITY_SETUP_STEREO_EYE_INDEX_POST_VERTEX(input); // 양면 공통 종이 색. 앞면에만 텍스처를 곱한다 (기본 white 텍스처 = 종이 색 그대로) half3 albedo = _BaseColor.rgb; if (isFrontFace) albedo *= SAMPLE_TEXTURE2D(_FrontTex, sampler_FrontTex, input.uv).rgb; // 뒷면은 노멀을 뒤집어서 조명 계산 float3 normalWS = normalize(input.normalWS); if (!isFrontFace) normalWS = -normalWS; // 하프-램버트 + 앰비언트 — 부드러운 종이 음영 Light mainLight = GetMainLight(); half ndl = saturate(dot(normalWS, mainLight.direction)) * 0.5h + 0.5h; half3 lighting = mainLight.color * ndl + SampleSH(normalWS); return half4(albedo * lighting, 1); } ENDHLSL } // 그림자 드리우기 (없으면 종이가 공중에 뜬 것처럼 보임) Pass { Name "ShadowCaster" Tags { "LightMode" = "ShadowCaster" } ZWrite On ZTest LEqual ColorMask 0 Cull Off HLSLPROGRAM #pragma vertex shadowVert #pragma fragment shadowFrag #pragma multi_compile_instancing #include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl" #include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Shadows.hlsl" float3 _LightDirection; struct ShadowAttributes { float4 positionOS : POSITION; float3 normalOS : NORMAL; UNITY_VERTEX_INPUT_INSTANCE_ID }; float4 shadowVert(ShadowAttributes input) : SV_POSITION { UNITY_SETUP_INSTANCE_ID(input); float3 positionWS = TransformObjectToWorld(input.positionOS.xyz); float3 normalWS = TransformObjectToWorldNormal(input.normalOS); float4 positionCS = TransformWorldToHClip(ApplyShadowBias(positionWS, normalWS, _LightDirection)); #if UNITY_REVERSED_Z positionCS.z = min(positionCS.z, UNITY_NEAR_CLIP_VALUE); #else positionCS.z = max(positionCS.z, UNITY_NEAR_CLIP_VALUE); #endif return positionCS; } half4 shadowFrag() : SV_Target { return 0; } ENDHLSL } } FallBack "Hidden/Universal Render Pipeline/FallbackError" }