ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • Dual-depth relief interior mapping
    Graphics/Graphics Study 자료 2022. 6. 11. 06:52

    Dual-depth relief interior mapping

     

    최초 작성 : 2022-06-11

    마지막 수정 : 2022-06-11

    최재호

     

    목차

    1. 목표
    2. 내용
      2.1. Relief mapping
        2.1.1. Linear and Binary tracing
        2.1.2. Dual-depth linear tracing
      2.2. Interior mapping
      2.3 Dual-depth + Interior mapping
    3. 구현 결과
    4. 실제 구현
    5. 레퍼런스

     

    1. 목표

    Interior mapping은 빌딩의 창문을 통해 건물 내부에 보이는 가구나 공간을 개별 드로우콜로 렌더링 하지 않고, 2D 평면에 텍스쳐 매핑을 통해서 렌더링 하는 기능입니다. 그림1를 참고해주세요.

     

    그림1. 스파이더맨에 사용된 Interior mapping 예제 (출처 : https://polycount.com/discussion/204601/interior-mapping-in-spider-man-ps4)



    UE5 CitySample의 Interior mapping에서 사용한 Dual-depth relief mapping, Interior mapping 에 대해서 알아봅시다. Dual-depth relief mapping 은 공간 내부의 가구들을 렌더링 하기 위해 사용되며, Interior mapping은 공간을 렌더링 하기 위해서 사용합니다.

     

     

    2. 내용

    2.1. Relief mapping

    Relief mapping은 이전에 알아본 Parallax mapping 이나 Horizon mapping 과 같이 텍스쳐 매핑을 사용하여 표면의 디테일을 더욱 풍부하게 만들어주는 기능입니다. Relief mapping의 경우 depth와 표면의 normal 을 사용하여 이런 디테일을 살려줍니다. 그림2에서 Relief mapping에 사용되는 normal, depth 맵을 볼 수 있습니다.

    그림2. Relief mapping 에 사용 되는 Normal과 Depth texture (출처 : 레퍼런스1)

    Relief mapping 의 구현은 텍스쳐 공간(탄젠트 공간)에서의 Ray marching 을 사용합니다. 아래 그림3를 봐주세요. 우측 상단 Viewing Ray 는 탄젠트 공간의 뷰벡터 입니다. 이 뷰벡터를 레이마칭의 방향으로 사용합니다. Ray의 시작 지점은 TexCoord.xy 가 xy 가 되고, z 값은 0 입니다. 즉, CameraStartPos = vec3(TexCoord.xy, 0.0). 시작 점과 방향이 정해졌으므로, 이제 레이마칭을 수행합니다. Ray는 z 축을 기준으로 0~1 범위 내에서 이동합니다. 

    레이마칭 중 렌더링 할 표면을 만나면, 해당 표면을 쉐이딩 하면 됩니다. 만약 렌더링 할 표면을 만나지 못했다면 계속해서 레이마칭을 수행합니다. 표면과 만나는 것을 판정하는 데에는 depth texture를 사용합니다. 레이마칭 중 현재 레이의 z와 depth texture에 있는 depth 값이 서로 교차하게 되면 여기가 쉐이딩 해야 할 표면입니다. 쉐이딩 할 표면을 찾은 경우 현재 Ray 위치의 xy 컴포넌트를 color texture와 normal texture 의 uv로 사용하여 텍스쳐 샘플링 후 쉐이딩을 수행하면 됩니다.

    셀프 쉐도잉을 위해서 레이마칭을 한번 더 수행합니다. 이번에는 이전 레이마칭 과정에서 샘플링 한 위치를 기반으로 라이트에 사용할 Ray의 시작점을 구합니다. 그리고 그 시작점과 라이트의 방향 정보를 사용하여 레이마칭을 수행합니다. 이전 과정처럼 depth texture를 사용하여 Ray와 표면이 교차하는 지점을 찾습니다. 그림3 을 보면 LightRay.z < ViewRay.z 인 경우 현재 쉐이딩 할 위치에 그림자가 드리운다는 것을 알 수 있습니다.

    그림3. Relief mapping 핵심 원리 (출처 : 레퍼런스1)

    Relief mapping 에 대한 핵심 알고리즘은 이것이 전부입니다. 여기서 추가로 알아볼 점은 어떤 방법으로 레이마칭을 수행하는가입니다. 이 방식에 따라서 최종 결과의 퀄리티나 성능이 달라집니다. 여기서는 레퍼런스1에 나오는 2가지 레이마칭 기법을 알아봅시다.


    2.1.1. Linear and Binary tracing

    Linear 방식은 단순하게 시작점에서 Ray의 방향으로 일정 거리만큼 이동하는 방식입니다. 이 방식의 단점으로는 두께가 얇은 부분은 그냥 통과할 수 있다는 점입니다. Ray 를 일정 거리만큼 전진시키기 때문에 이런 문제가 발생합니다.

    두 번째로 Binary 방식이 있습니다. Binary는 아래 그림4의 위쪽 그림처럼 1 번 -> 2 번 -> 3 번 순서로 이진 검색을 시도합니다. 하지만 이 방식은 점 P를 지나칠 수 있다는 단점이 있습니다. 그 결과 Binary tracing 은 점 Q를 렌더링 할 표면으로 선택할 것입니다.

    두 가지 방식을 같이 사용하여 최종적으로 다음과 같이 보완합니다. 먼저 첫 번째 충돌 지점을 만날 때 까지는 Linear tracing 을 수행합니다. 그리고 충돌 점이 발견되는 경우 그 점에서 Binary tracing 을 수행합니다. Binary tracing 을 수행하는 영역은 Ray의 시작 위치와 발견한 충돌 지점 사이 입니다. 이런 방식으로 두 방식은 보완합니다. 

    그림4. Binary 그리고 Linear tracing (출처 : 레퍼런스1)

    2.1.2. Dual-depth relief mapping

    Dual-depth relief mapping 은 Single-depth relief mapping 에서 발생하는 Skin 이라 불리는 Artifact를 완화 해줍니다. Skin 이슈가 발생하는 이유를 알아봅시다. 그림5를 봐주세요. 3D 모델을 depth texture에 렌더링 하면, 파란색 선을 기준으로 표면의 디테일이 저장됩니다. 하지만 일부 오브젝트는 초록색 선 부분의 디테일도 들어가야 3D 모델의 후면의 디테일을 표현할 수 있습니다. 초록색 부분의 표면 디테일을 잃게 되면서 그림6 처럼 디테일을 잃은 부분이 늘어져 보이게 됩니다. 논문에서는 이런 이슈를 Skin 이라고 부릅니다.

    그림5. Depth texture를 한장 사용하게 되면, 초록색 선과 같은 후면 부에 디테일을 잃을 수 있음. (출처 : 레퍼런스2)
    그림6. (a), (c) 에 Skin 이슈가 발생하고 있으며, Dual-depth relief mapping 을 사용한 (b), (d) 에서는 이 문제가 해결됨 (출처 : 레퍼런스2)

    이 부분을 완화하기 위해서 Dual-depth relief mapping을 사용합니다. 그림7 처럼 앞면과 뒷면에 대한 Depth texture를 모두 생성합니다. 그리고 이 두 개의 depth texture를 사용하여 레이마칭을 수행합니다.

    그림7. Dual-depth relief mapping 은 앞/뒤 두개의 depth texture를 만듬. (출처 : 레퍼런스2)

    물론 이 방식에도 단점이 있습니다. 그림8 의 빨간색 부분 처럼 양쪽 Depth 내부에 추가로 있는 디테일까지 커버 할 순 없습니다. 하지만 대부분의 경우 결과물이 괜찮으며 3D 물체를 충분히 잘 표현해줍니다.

    그림8. 붉은선이 표시된 표면 디테일은 Dual-depth relief mapping 이 커버할 수 없는 부분 (출처 : 직접그림)

    Dual-depth relief mapping 에서 레이마칭을 멈추는 시점은 현재 ray 의 위치가 두 depth texture 값의 사이에 있을 때입니다. 즉, front depth < ray.z < back depth 입니다. depth 값이 0~1 사이 값이라는 것을 생각해본다면 back depth 가 front depth 값 보다 항상 크도록 하기 위해서 적절히 값을 조정해줘야 하는 것을 알 수 있습니다.
    UE5 CitySample 에서 사용한 에셋에서는 아래와 같은 식을 통해 front depth < back depth 가 되도록 만들어 주었습니다.

    vec2 GetRelief(vec2 uv, int index) 
    { 
      vec2 dualdepth = texture(ReliefTexture[index], uv.xy).xy; 
      // This option is specialized for ue5 city sample's asset. 
      dualdepth.x = 1.0 - dualdepth.x;	// x는 카메라에서 가까울 수록 큼 
      dualdepth.y = dualdepth.y;			// y는 카메라에서 멀수록 큼 
      return dualdepth; 
    }

     

    2.2. Interior mapping

    Interior mapping 도 Relief mapping 과 같이 텍스쳐 매핑으로 지오메트리의 디테일을 살리는 기능입니다. 이것으로 2D 평면에서 3D 모델을 보는 것과 같은 효과를 주는 기술입니다. 이 기술은 환경맵을 사용하여 렌더링 될 공간을 표현하는 데 사용합니다. 

    그림9 를 봅시다. 검정색 사각형은 실제 렌더링 하는 지오메트리인 2D Quad 입니다. 회색으로 그어진 선은 우리가 가상으로 생각하는 육면체입니다. 그리고 현재 픽셀 쉐이더에서 처리하는 하는 지점을 빨간색 점이라고 둡시다. 만약 실제 육면체가 있어서 Ray 가 계속 진행된다면 육면체 내부에 파란점이 보일 것입니다. 즉, 빨간점 위치를 렌더링 할 때, 환경맵의 파란색 위치에 점을 렌더링 하면 됩니다. 

     파란색 점을 구하기 위해서는 필요한 몇 가지 준비물이 있습니다. 바로 Ray의 시작점과 방향입니다. 이 Ray는 Relief mapping과 같이 텍스쳐 공간(탄젠트 공간)에서 수행됩니다. 

    먼저 시작점을 구해봅시다. 빨간색 점은 환경맵의 가장 앞쪽면에 있는 한 점일 것입니다. 그래서 z값은 -1로 둘 수 있을 것입니다(구현 방식에 따라 1 일 수 있으며, 여기서는 -1이 앞쪽이라 가정합니다). 나머지 x, y 만 찾으면 시작점을 구할 수 있습니다 x, y는 바로 Texture UV 입니다. 2D Quad 자체가 육면체가 가진 하나의 면으로 볼 수 있기 때문에 xy는 Texture UV라 생각할 수 있습니다.

    두 번째로 방향의 구해봅시다. 방향은 (시작점 - 카메라 위치)를 통해 구할 수 있습니다. 이 방향은 정규화하여 사용할 것입니다.

    그림9. 현재 렌더링 하려는 빨간점을 Ray의 시작위치, 그리고 카메라에서 빨간점으로의 방향을 Ray의 방향으로 설정하여 레이마칭을 수행한 결과를 통해서 빨간점에 그려질 픽셀을 결정함. (출처 : 직접그림)

    이제 시작점과 방향을 사용하여, Ray 를 구성해 봅시다. 
    - 시작점을 S, 방향을 D 그리고 최종적으로 우리가 찾을 점을 T 라고 둡니다. 
    - T는 Ray 가 육면체에 가장 먼저 도달하는 지점입니다.
    - Ray 가 육면체에 도달했다는 것은 Ray의 x, y, z 중 어느 하나가 1이 된 경우입니다.

     

    이제 이 부분의 공식을 확인해봅시다.

    T = 1일 때를 알아봅시다. T=1인 Line의 매개변수 방정식은 다음과 같습니다.
    1 = S + kD
    이 식에서 S는 시작점, D는 방향, k는 D 방향으로 이동할 거리입니다. 이 중에서 우리가 모르는 것은 k 이기 때문에 이 부분을 구합니다. 식을 정리하여 (1 - S) / D = k 를 통해 k를 구할 수 있습니다. 

    여기서 기억할 점은 S와 D는 3D 벡터입니다. 그리고 k 또한 3D 벡터입니다. 그래서 벡터 연산을 하게 되면 x, y, z 각각 방향이 1이 되는 k 값을 한 번에 얻을 수 있습니다.

    얻어진 k값의 각각 컴포넌트 중 가장 작은 값을 선택합니다. 가장 작은 값이 가장 먼저 육면체의 면 중 하나에 도달했을 것이기 때문입니다. 이 k 값을 km 이라고 부르겠습니다. 그리고 최종적으로 S + km * D = T 식을 사용하여 환경맵에서 샘플링해야 할 위치 T를 얻어냅니다.

     

    아래 코드에서 AABB 교차 판정 전체 코드를 볼 수 있습니다.

    // 출처 : https://iquilezles.org/articles/intersectors/
    // axis aligned box centered at the origin, with size boxSize
    vec2 boxIntersection( in vec3 ro, in vec3 rd, vec3 boxSize, out vec3 outNormal ) 
    {
        vec3 m = 1.0/rd; // can precompute if traversing a set of aligned boxes
        vec3 n = m*ro;   // can precompute if traversing a set of aligned boxes
        vec3 k = abs(m)*boxSize;
        vec3 t1 = -n - k;
        vec3 t2 = -n + k;
        float tN = max( max( t1.x, t1.y ), t1.z );
        float tF = min( min( t2.x, t2.y ), t2.z );
        if( tN>tF || tF<0.0) return vec2(-1.0); // no intersection
        outNormal = -sign(rd)*step(t1.yzx,t1.xyz)*step(t1.zxy,t1.xyz);
        return vec2( tN, tF );
    }

     

    2.3 Dual-depth + Interior mapping

    앞에서 알아본 Dual depth relief mapping 과 interior mapping을 사용하여 최종 결과를 만들어 봅시다. 구현은 간단합니다. 아래의 코드에서 보듯 Dual-depth relief mapping을 실패하는 경우 Interior mapping 을 사용하는 것으로 두 기능을 함께 사용할 수 있습니다. 여기서 dual-depth-relief mapping 의 성공은 front depth < ray.z < back depth 인 표면을 만났는지 여부입니다.

    if (ray_intersect_dual_depth_relief(CurrentPosition, TangentSpace_ViewDir_ToSurface, IndexRelief)) 
    { 
      color = GetDiffuse(CurrentPosition.xy, IndexRelief); // Apply diffuse 
    } 
    else 
    { 
      color.xyz = GetEnvCube(uv, TangentSpace_ViewDir_ToSurface_, IndexEnv);	// Apply Env 
    }

    추가로 하나 더 알아볼 점이, Interior mapping의 경우 큰 빌딩을 구성하는 데 사용하기 때문에 여러 개의 방으로 구성될 수 있어야 합니다.  방의 개수를 스케일 하는 것은 아래의 코드로 처리합니다.

    vec2 texScale = TexCoord_ * RoomCount;  // TexCoord_ 를 0~1 에서 0~RoomCount 로 변환 
    vec2 uv = fract(texScale);   // texScale 의 소수점만 얻음. 계속해서 0~1 사이값이 반복되도록 해줌.

    이렇게 여러 개의 방으로 확장 가능하며, 각각의 방마다 사용하는 Dual-relief mapping 과 interior mapping 의 리소스와 기타 정보들을 다르게 하여 여러개의 방을 생성할 수 있습니다.

     

    이 외에도 블라인드 기능이나 창문 등을 추가하여 다양하게 응용할 수 있습니다. 이런 부분들도 한번 해보면 좋을 것 같습니다.

     

    3. 구현 결과

    그림10. Relief mapping 예제 (출처 : 직접 구현)
    그림11. Relief mapping 예제2 (출처 : 직접 구현)
    그림12. Dual depth Relief mapping, 복잡한 지오메트리의 경우 여전히 Skin 현상이 나타나는 것을 볼 수 있음. (Dual-depth Relief mapping에 사용한 리소스는 UE5 CitySample 사용함) (출처 : 직접 구현)
    그림13. Dual-depth relief interior mapping. (Dual-depth relief mapping과 Interior mapping 에 사용한 리소스는 UE5 CitySample 사용함) (출처 : 직접 구현)
    그림14. 초록/빨강 동그라미를 보면, Dual-depth relief mapping 은 각도를 다르게 해서 보면 3D 모델을 실제로 렌더링 한 것 처럼 정밀하게 표현해줌. 파란색 네모 부분을 보면 복잡한 모델의 경우 여전히 Skin 현상이 나타남을 알 수있음. (Dual-depth relief mapping과 Interior mapping 에 사용한 리소스는 UE5 CitySample 사용함) (출처 : 직접구현)

     

    그림15. Dual-depth relief interior mapping을 사용하여 내부 가구의 3D 모델과 방이 시점에 따라 적절하게 보임. (Dual-depth relief mapping과 Interior mapping 에 사용한 리소스는 UE5 CitySample 사용함) (출처 : 직접 구현)

     

    4. 실제 구현

    전체 코드는 https://github.com/scahp/Shadows/tree/ReliefMapping 에 있습니다.

    // [Vertex Shader] Dual-depth relief interior mapping
    // vs_reliefmap.glsl
    #version 330 core
    
    precision mediump float;
    
    layout(location = 0) in vec3 Pos;
    layout(location = 1) in vec4 Color;
    layout(location = 2) in vec3 Normal;
    layout(location = 3) in vec3 Tangent;
    layout(location = 4) in vec2 TexCoord;
    
    uniform mat4 M;
    uniform mat4 MVP;
    uniform vec3 WorldSpace_CameraPos;
    uniform vec3 WorldSpace_LightDir_ToSurface;
    
    out vec2 TexCoord_;
    out vec4 Color_;
    out mat3 TBN_;
    out vec3 TangentSpace_LightDir_ToSurface_;
    out vec3 WorldPos_;
    
    void main()
    {
      TexCoord_ = TexCoord;
      Color_ = Color;
      gl_Position = MVP * vec4(Pos, 1.0);
    
      vec3 T = normalize(vec3(M * vec4(Tangent, 0.0)));
      vec3 B = normalize(vec3(M * vec4(cross(Normal, Tangent), 0.0)));
      vec3 N = normalize(vec3(M * vec4(Normal, 0.0)));
      TBN_ = transpose(mat3(T, B, N));
    
      vec4 wpos = M * vec4(Pos, 1.0);
      wpos /= wpos.w;
      WorldPos_ = wpos.xyz;
    
      TangentSpace_LightDir_ToSurface_ = TBN_ * normalize(WorldSpace_LightDir_ToSurface);
    }
    // [Pixel shader]Dual-depth relief interior mapping
    // fs_dualdepthrelief_interiormap.glsl
    #version 330 core
    
    precision mediump float;
    
    uniform sampler2D ColorTexture[3];
    uniform sampler2D ReliefTexture[3];    // x : front relief depth, y : back relief depth
    uniform sampler2D EnvironmentTexture[3];
    
    uniform int TextureSRGB[1];
    uniform int UseTexture;
    uniform int DepthBias;
    uniform float DepthScale;
    uniform vec3 WorldSpace_CameraPos;
    uniform vec3 InteriorAmbientColor[3];
    uniform int RoomCount;
    
    in vec2 TexCoord_;
    in vec4 Color_;
    in mat3 TBN_;
    in vec3 WorldPos_;
    
    out vec4 color;
    
    vec4 GetDiffuse(vec2 uv, int index)
    {
      vec4 DiffuseColor;
      if (UseTexture > 0)
      {
        DiffuseColor = texture2D(ColorTexture[index], uv);
        if (TextureSRGB[0] > 0)
          DiffuseColor.xyz = pow(color.xyz, vec3(2.2));
      }
      else
      {
        DiffuseColor = Color_;
      }
      return DiffuseColor;
    }
    
    vec3 GetLightTracingStartPointFromCurrentPoint(vec3 CurrentPosition, vec3 LightDirectionToSurface)
    {
      // 텍스처의 접선 공간에서 z의 범위는 0에서 1입니다. 
      // 따라서 접선 공간에서 현재 위치와 빛의 방향을 모두 사용하여 '라이트의 레이마칭 시작점'을 찾을 수 있습니다. 
      
      // 선의 매개변수 방정식을 사용하여. 라인의 매개변수 ''를 얻을 수 있습니다. 
      // TargetZ = StartPointZ + t * DirectionZ, 그리고 'StartPointZ is 0'에서 't'를 찾고자 합니다. 
      // => t = TargetZ / DirectionZ
      float t = CurrentPosition.z / LightDirectionToSurface.z;
    
      // 't', 현재 위치 및 조명 방향을 사용하여 StartPoint를 가져옵니다.
      // Target = StartPosition + t * 방향;
      // => StartPosition = 대상 - t * 방향;
      vec3 StartPosition = CurrentPosition - t * LightDirectionToSurface;
    
      return StartPosition;
    }
    
    void ApplyDepthBiasScale(inout vec3 Direction)
    {
      if (DepthBias > 0)
      {
      float db = 1.0 - Direction.z;
      db *= db;
      db *= db;
      db = 1.0 - db * db;
      Direction.xy *= db;
      }
    
      Direction.xy *= DepthScale;
    }
    
    // http://filmicworlds.com/blog/filmic-tonemapping-operators/
    vec3 Uncharted2Tonemap(vec3 x)
    {
      float A = 0.15;  // Shoulder Strength
      float B = 0.50;  // Linear Strength
      float C = 0.10;  // Linear Angle
      float D = 0.20;  // Toe Strength
      float E = 0.02;  // Toe Numerator
      float F = 0.30;  // Toe Denominator
      float W = 11.2;  // Linear White Point Value
    
      return ((x * (A * x + C * B) + D * E) / (x * (A * x + B) + D * F)) - E / F;
    }
    
    vec2 GetRelief(vec2 uv, int index)
    {
      vec2 dualdepth = texture(ReliefTexture[index], uv.xy).xy;
    
      // This option is specialized for ue5 city sample's asset.
      dualdepth.x = 1.0 - dualdepth.x;  // x는 카메라에서 가까울 수록 큼
      dualdepth.y = dualdepth.y;    // y는 카메라에서 멀수록 큼
      return dualdepth;
    }
    
    bool ShouldContinue(vec2 dualdepth)
    {
      return (dot(dualdepth.x, dualdepth.y) <= 0);
    }
    
    bool IsInTexUV(vec2 uv)
    {
      return (uv.x > 0 && uv.x < 1 && uv.y > 0 && uv.y < 1);
    }
    
    bool CheckUV(vec3 p, vec2 tex)
    {
      return (p.z>tex.x && p.z<tex.y);
    }
    
    // https://learnopengl.com/PBR/IBL/Diffuse-irradiance
    // Equirectangular map
    const vec2 invAtan = vec2(0.1591, 0.3183);
    vec2 SampleSphericalMap(vec3 v)
    {
      vec2 uv = vec2(atan(v.z, v.x), asin(v.y));
      uv *= invAtan;
      uv += 0.5;
      return uv;
    }
    
    vec3 GetEnvCube(vec2 uv, vec3 TangentSpace_ViewDir_ToSurface_, int index)
    {
      // raytrace box from tangent view dir https://chulin28ho.tistory.com/521
      TangentSpace_ViewDir_ToSurface_.z = abs(TangentSpace_ViewDir_ToSurface_.z);
    
      vec3 pos = vec3(uv * 2.0 - 1.0, -1.0);
      vec3 id = 1.0 / (TangentSpace_ViewDir_ToSurface_+0.00001);
      vec3 k = abs(id) - pos * id;
      float kMin = min(min(k.x, k.y), k.z);
      pos += kMin * TangentSpace_ViewDir_ToSurface_;
    
      return texture(EnvironmentTexture[index], SampleSphericalMap(normalize(pos))).rgb;
    }
    
    // ray tracing dual depth relief until intersecting
    bool ray_intersect_dual_depth_relief(inout vec3 p, vec3 direction, int indexRelief)
    {
      //const int num_steps_lin=15;
      const int num_steps_lin = 128;
      const int num_steps_bin = 6;
      
      direction /= direction.z * num_steps_lin;
    
      bool found = false;
      for (int i = 0; i < num_steps_lin; i++)
      {
        vec2 tex = GetRelief(p.xy, indexRelief);
        if (CheckUV(p, tex) && IsInTexUV(p.xy))
        {
          found = true;
          break;
        }
        else
        {
          p += direction;
        }
      }
      
      return found;
    }
    
    void main()
    {
      vec2 texScale = TexCoord_ * RoomCount;
      vec2 uv = fract(texScale);
      vec2 indexUV = floor(texScale);
      int IndexRelief = int(indexUV.x + indexUV.y * 2) % 3;
      int IndexEnv = int(indexUV.y  + indexUV.x * 4) % 3;
      int IndexAmbient = int(indexUV.x * 2 + indexUV.y * 7) % 3;
    
      vec3 TangentSpace_ViewDir_ToSurface_ = TBN_ * normalize(WorldPos_ - WorldSpace_CameraPos);
      
      // 1. Tracing ray from camera postion
      vec3 CurrentPosition = vec3(uv,0.0);
      vec3 TangentSpace_ViewDir_ToSurface = normalize(TangentSpace_ViewDir_ToSurface_);
      TangentSpace_ViewDir_ToSurface.z = abs(TangentSpace_ViewDir_ToSurface.z);
    
      ApplyDepthBiasScale(TangentSpace_ViewDir_ToSurface);  // Apply DepthBias and DepthScale
    
      // 2. Tracing ray
      vec3 p = CurrentPosition;
      vec3 v = TangentSpace_ViewDir_ToSurface;
      if (ray_intersect_dual_depth_relief(CurrentPosition, TangentSpace_ViewDir_ToSurface, IndexRelief))
      {
        color = GetDiffuse(CurrentPosition.xy, IndexRelief); // Apply diffuse
      }
      else
      {
        color.xyz = GetEnvCube(uv, TangentSpace_ViewDir_ToSurface_, IndexEnv);  // Apply Env
      }
      color.xyz *= InteriorAmbientColor[IndexAmbient];
      color.xyz = Uncharted2Tonemap(color.xyz);
    }

     

    5. 레퍼런스

    1. https://developer.nvidia.com/gpugems/gpugems3/part-iii-rendering/chapter-18-relaxed-cone-stepping-relief-mapping

    2. Real-Time Relief Mapping on Arbitrary Polygonal Surfaces - F Policarpo, MM Oliveira, JLD Comba - Proceedings of the 2005

    3. https://chulin28ho.tistory.com/521

     

     

    댓글

Designed by Tistory & scahp.