Cubic to equirectangular projection algorithm

后端 未结 5 1954

I have a cube map texture which defines a surrounding, however I need to pass it to a program which only works with latitude/longitude maps. I am really at lost here on how to d

5条回答
  •  死守一世寂寞
    2021-02-03 16:30

    So, I found a solution mixing this article on spherical coordinates from wikipedia and the Section 3.8.10 from the OpenGL 4.1 specification (plus some hacks to make it work). So, assuming that the cubic image has a height h_o and width w_o, the equirectangular will have a height h = w_o / 3 and a width w = 2 * h. Now for each pixel (x, y) 0 <= x <= w, 0 <= y <= h in the equirectangular projection, we want to find the corresponding pixel in the cubic projection, I solve it using the following code in python (I hope I didn't make mistakes while translating it from C)

    import math
    
    # from wikipedia
    def spherical_coordinates(x, y):
        return (math.pi*((y/h) - 0.5), 2*math.pi*x/(2*h), 1.0)
    
    # from wikipedia
    def texture_coordinates(theta, phi, rho):
        return (rho * math.sin(theta) * math.cos(phi),
                rho * math.sin(theta) * math.sin(phi),
                rho * math.cos(theta))
    
    FACE_X_POS = 0
    FACE_X_NEG = 1
    FACE_Y_POS = 2
    FACE_Y_NEG = 3
    FACE_Z_POS = 4
    FACE_Z_NEG = 5
    
    # from opengl specification
    def get_face(x, y, z):
        largest_magnitude = max(x, y, z)
        if largest_magnitude - abs(x) < 0.00001:
            return FACE_X_POS if x < 0 else FACE_X_NEG
        elif largest_magnitude - abs(y) < 0.00001:
            return FACE_Y_POS if y < 0 else FACE_Y_NEG
        elif largest_magnitude - abs(z) < 0.00001:
            return FACE_Z_POS if z < 0 else FACE_Z_NEG
    
    # from opengl specification
    def raw_face_coordinates(face, x, y, z):
        if face == FACE_X_POS:
            return (-z, -y, x)
        elif face == FACE_X_NEG:
            return (-z, y, -x)
        elif face == FACE_Y_POS:
            return (-x, -z, -y)
        elif face == FACE_Y_NEG:
            return (-x, z, -y)
        elif face == FACE_Z_POS:
            return (-x, y, -z)
        elif face == FACE_Z_NEG:
            return (-x, -y, z)
    
    # computes the topmost leftmost coordinate of the face in the cube map
    def face_origin_coordinates(face):
        if face == FACE_X_POS:
            return (2*h, h)
        elif face == FACE_X_NEG:
            return (0, 2*h)
        elif face == FACE_Y_POS:
            return (h, h)
        elif face == FACE_Y_NEG:
            return (h, 3*h)
        elif face == FACE_Z_POS:
            return (h, 0)
        elif face == FACE_Z_NEG:
            return (h, 2*h)
    
    # from opengl specification
    def raw_coordinates(xc, yc, ma):
        return ((xc/abs(ma) + 1) / 2, (yc/abs(ma) + 1) / 2)
    
    
    def normalized_coordinates(face, x, y):
        face_coords = face_origin_coordinates(face)
        normalized_x = int(math.floor(x * h + 0.5))
        normalized_y = int(math.floor(y * h + 0.5))
        # eliminates black pixels
        if normalized_x == h:
          --normalized_x
        if normalized_y == h:
          --normalized_y
        return (face_coords[0] + normalized_x, face_coords[1] + normalized_y)
    
    def find_corresponding_pixel(x, y):
        spherical = spherical_coordinates(x, y)
        texture_coords = texture_coordinates(spherical[0], spherical[1], spherical[2])
        face = get_face(texture_coords[0], texture_coords[1], texture_coords[2])
    
        raw_face_coords = raw_face_coordinates(face, texture_coords[0], texture_coords[1], texture_coords[2])
        cube_coords = raw_coordinates(raw_face_coords[0], raw_face_coords[1], raw_face_coords[2])
        # this fixes some faces being rotated 90°
        if face in [FACE_X_NEG, FACE_X_POS]:
          cube_coords = (cube_coords[1], cube_coords[0])
        return normalized_coordinates(face, cube_coords[0], cube_coords[1])    
    

    at the end we just call find_corresponding_pixel for each pixel in the equirectangular projection

提交回复
热议问题