Fake Interior Shader

Shader 2019.01.27 02:31


가짜로 실내를 만들때 쓰는 셰이더. 

언리얼에서는 로보리콜에서 예제를 볼 수 있고, 

스파이더맨 PS4 게임에서도 볼 수 있는 건물 표현 방식입니다. 그 외에도 오버워치라던가 여러 군데에서 씀. 

실내에 직접 모델링을 할 수도 있지만 아무래도 그게 좀 많아지면 이게 훨씬 더 가벼운 방법 


참고할 수 있는 부분은 


심시티나 스파이더맨에서도 사용함 

http://www.andrewwillmott.com/talks/from-aaa-to-indie


유니티 포럼에서 이 내용에 대해 토의

https://forum.unity.com/threads/interior-mapping.424676/#post-2751518


알란주코니의 모음 

https://www.alanzucconi.com/2018/09/10/shader-showcase-9/




등이 되겠습니다. 


핵심적인 내용은 이전 게시물인 AABB 레이 충돌공식에서 썼으므로 (Thanks to @Hybrid) 여기에는 코드만. 







큐브맵을 이용해야 합니다 




큐브맵은 6 direction 쪽이 좋아요 



주의사항은 normal을 직접 탄젠트 좌표로 입력하거나 텍스쳐를 받아야 한다는 것. 

안 그렇게 하면 서피스 셰이더 코드 내의 연산이 월드 좌표계로 연산되기 때문입니다. 

굳이 o.Normal로 구현시켜 줘야 탄젠트 좌표계로 움직어요. 


현재 위의 그림에서 벽은 구현만 해놓고 켜놓질 않았습니다만, 


이걸[각주:1] 넣고 아래처럼 활성화 시키면 [각주:2]




1
2
3
4
5
o.Normal = float3(001); //using normal for tangent calculation 
                o.Albedo = tex.rgb;
                o.Smoothness = 1 - tex.a ;
                o.Emission = room.rgb * (1- tex.a);
                o.Alpha = 1;
cs




이렇게도 됩니다.




풀 코드는 다음과 같습니다. 



1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
Shader "FakeInterior"
{
    Properties
    {
        [NoScaleOffset]_MainTex("MainTex",2D) = "white"{}
        _Color ("Color", Color) = (1,1,1,1)
        _RoomCube("Albedo (RGB)",CUBE) = "" {}
 
    }
    SubShader
        {
            Tags { "RenderType" = "Opaque" }
            LOD 200
 
            CGPROGRAM
            #pragma surface surf Standard fullforwardshadows 
            #pragma target 3.0
 
 
            sampler2D _MainTex;
            samplerCUBE _RoomCube;
            float4 _RoomCube_ST;
            fixed4 _Color;
 
 
            struct Input
            {
                float2 uv_MainTex;
                float3 viewDir;
                INTERNAL_DATA
            };                       
 
            // psuedo random
            float2 rand2(float co) {
                return frac(sin(co * float2(12.989878.233)) * 43758.5453);
            }
 
            void surf(Input IN, inout SurfaceOutputStandard o)
            {
                
                //room UV and index UV 
                float2 roomUV = frac(IN.uv_MainTex*_RoomCube_ST.xy );                
                float2 roomIndexUV = floor(IN.uv_MainTex*_RoomCube_ST.xy )+1;
 
                // randomize the room
                float2 n = (rand2(roomIndexUV.x + roomIndexUV.y * (roomIndexUV.x + 1)) * _RoomCube_ST.xy);
                roomIndexUV += n;
                roomIndexUV = frac(roomIndexUV) ;
 
 
                //raytrance box from tangent view dir . aabb 
                float3 viewD = normalize(-IN.viewDir);
                float3 pos = float3(roomUV * 2.0 - 1.01.1 - roomIndexUV.x  );
                float3 id = 1.0 / (viewD+0.00001);
                float3 k = abs(id) - pos * id;
                float kMin = min(min(k.x, k.y),k.z);
                pos += kMin * viewD;
                
                //Random Room Left and Right riversal 
                pos.x = roomIndexUV > 0.5 ? pos.x : -pos.x;
 
                //room Tex
                fixed4 room = texCUBE(_RoomCube, pos.xyz);
                //room random color
                room.rgb *= clamp(roomIndexUV.yyx, 0.21);
                
                //window and outwall texture
                float4 tex = tex2D(_MainTex, roomUV);
 
                
                o.Normal = float3(001); //using normal for tangent calculation 
                o.Albedo = tex.rgb;
                o.Smoothness = 1 - tex.a ;
                o.Emission = room.rgb * (1- tex.a);
                o.Alpha = 1;
                
            }
            ENDCG
        }
    FallBack "Diffuse"
}
cs




  1. 위 그림은 알파도 있습니다 [본문으로]
  2. 밉맵 때문에 경계선이 날 수 있는데다가 어차피 따로 건물 외각을 만드는게 나을테니.. 사실상 필요는 별로 없습니다 [본문으로]