ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • SphereMap TwoMirrorBall - 360도 방향 커버 됨
    Graphics/기본 2020. 12. 11. 20:31

    개요

    [번역+설명추가] Spherical Mapping 에서 알아본 SphereMap은 360도 방향을 모두 커버하지 못합니다. 이 부분을 완화한 SphereMap에 대해 알아봅니다.

     

    내용

    [번역+설명추가] Spherical Mapping에서 사용한 전통적인 Sphere Environment Map의 단점은 SphereMap을 전면에서만 촬영하므로 후면 정보가 없다는 점입니다. 그래서 SphereMap 360도의 환경맵 정보를 모두 커버하지 못합니다.

     

    Light Probe Image Gallery 에서 제공하는 SphereMap은 2번 촬영한 이미지를 붙여서 이런 문제를 해결하였습니다. 그래서 SphereMap의 연산 방식이 전통적인 SphereMap과는 다릅니다. (여기서 제공하는 이미지는 .hdr 형태로 제공됩니다. .hdr 파일은 HDR 컬러 범위를 가지며 Linear color space로 제공됩니다)

     

    이렇게 2개의 이미지를 붙여서 만든 SphereMap을 여기서는 SphereMap_TwoMirrorBall 으로 부를 예정입니다. (공식적인 명칭이 아님)

     

     

    그림1. SphereMap_TwoMirrorBall 모양

     

     

     

    그림2. SphereMap_TwoMirrorBall  (좌: 전면, 우: 후면), 360도 환경맵이 1장의 SphereMap으로 커버 됨. 후면의 경우 화질이 조금 떨어지는 것을 볼 수있음.

     

    후면이 전면에 비해서 해상도가 떨어지긴 하지만 360도 모두 잘 커버되는 것을 볼 수있습니다.

     

    3D Direction 정보로 부터 UV 값을 얻어오는 공식은 Light Probe Image Gallery에서 제공됩니다. 추가로 IrradianceMap 연산을 편하게 하기 위해서 UV에서 3D Direction 정보를 얻는 공식을 제가 만들어서 추가하였습니다. 공식은 아래와 같습니다.

    // https://www.pauldebevec.com/Probes/
    vec2 GetSphericalMap_TwoMirrorBall(vec3 InDir)
    {
        // Convert from Direction3D to UV[-1, 1]
        // - Direction : (Dx, Dy, Dz)
        // - r=(1/pi)*acos(Dz)/sqrt(Dx^2 + Dy^2)
        // - (Dx*r,Dy*r)
        //
        // To rerange UV from [-1, 1] to [0, 1] below explanation with code needed.
        // 0.159154943 == 1.0 / (2.0 * PI)
        // Original r is "r=(1/pi)*acos(Dz)/sqrt(Dx^2 + Dy^2)"
        // To adjust number's range from [-1.0, 1.0] to [0.0, 1.0] for TexCoord, we need this "[-1.0, 1.0] / 2.0 + 0.5"
        // - This is why we use (1.0 / 2.0 * PI) instead of (1.0 / PI) in "r".
        // - adding 0.5 execute next line. (here : "float u = 0.5 + InDir.x * r" and "float v = 0.5 + InDir.y * r")
        float d = sqrt(InDir.x * InDir.x + InDir.y * InDir.y);
        float r = (d > 0.0) ? (0.159154943 * acos(InDir.z) / d) : 0.0;
        float u = 0.5 + InDir.x * r;
        float v = 0.5 + InDir.y * r;
        return vec2(u, v);
    }
    
    vec3 GetNormalFromTexCoord_TwoMirrorBall(vec2 InTexCoord)
    {
        // Reverse transform from UV[0, 1] to Direction3D.
        // Explanation of equation. scahp(scahp@naver.com)
        // 1. x = ((u - 0.5) / r) from "float u = 0.5 + x * r;"
        // 2. y = ((v - 0.5) / r) from "float v = 0.5 + y * r;"
        // 3. d = sqrt(((u - 0.5) / r)^2 + ((v - 0.5) / r))
        // 4. z = cos(r * d / 0.159154943)
        //  -> r * d is "sqrt((u - 0.5)^2 + (v - 0.5)^2)"
        // 5. Now we get z from z = cos(sqrt((u - 0.5)^2 + (v - 0.5)^2) / 0.159154943)
        // 6. d is sqrt(1.0 - z^2), exaplanation is below.
        //  - r is length of direction. so r length is 1.0
        //  - so r^2 = (x)^2 + (y)^2 + (z)^2 = 1.0
        //  - r^2 = d^2 + (z)^2 = 1.0
        //  - so, d is sqrt(1.0 - z^2)
        // I substitute sqrt(1.0 - z^2) for d in "z = cos(r * d / 0.159154943)"
        //  - We already know z, so we can get r from "float r = 0.159154943 * acos(z) / sqrt(1.0 - z * z);"
        // 7. Now we can get x, y from "x = ((u - 0.5) / r)" and "y = ((v - 0.5) / r)"
    
        float u = InTexCoord.x;
        float v = InTexCoord.y;
    
        float z = cos(sqrt((u - 0.5) * (u - 0.5) + (v - 0.5) * (v - 0.5)) / 0.159154943);
        float r = 0.159154943 * acos(z) / sqrt(1.0 - z * z);
        float x = (u - 0.5) / r;
        float y = (v - 0.5) / r;
        return vec3(x, y, z);
    }

    SphereMap과 SphereMap_TwoMirrorBall 의 별도 구현 확인은 아래 링크에서 확인할 수 있습니다.

     

    구현 코드

    https://github.com/scahp/Shadows/tree/SphericalMapping

     

     

    레퍼런스

    1. Light Probe Image Gallery

    2. [번역+설명추가] Spherical Mapping

     

     

     

    댓글

Designed by Tistory & scahp.