Skip to content

code for domemaster to equirectangular shader #2133

Description

@cbicari

whilst trialing the backwards approach of domemaster to equirectangular approach -- i got this beauty working :)
tested and functional as a shader --- Ubuntu 24 -- OSsia (bleeding edge as of 20 july 2026)

/*{
    "DESCRIPTION": "Generates an Equirectangular output by un-projecting a Domemaster (fisheye) input image. Rotations, input FOV, and horizontal flip are controllable.",
    "CREDIT": "Edu Meneses + AI Assistant",
    "CATEGORIES": [
        "GENERATOR",
        "3D",
        "DOME",
        "PANORAMIC"
    ],
    "INPUTS": [
        { "NAME": "domemasterImage", "TYPE": "image", "LABEL": "Domemaster (Fisheye) Input" },
        {
	      "NAME" :"XYZrotate",
	      "TYPE" : "point3D",
	      "DEFAULT" : [0.5, 0.5, 0.5],
	      "MAX" : [1.0, 1.0, 1.0],
	      "MIN" : [0.0, 0.0, 0.0]
	    },
        {
            "NAME": "domemaster_input_fov_degrees",
            "LABEL": "Domemaster Input FOV (degrees)",
            "TYPE": "float",
            "DEFAULT": 180.0,
            "MIN": 1.0,
            "MAX": 360.0
        },
        {
            "NAME": "flipHorizontal",
            "LABEL": "Flip Horizontally (Ext. Surface)",
            "TYPE": "bool",
            "DEFAULT": false
        }
    ]
}*/

#define M_PI 3.14159265359

mat3 makeRotationMatrix(vec3 a) // a = (yaw, pitch, roll)
{
    mat3 my = mat3(cos(a.x), 0, sin(a.x),  0, 1, 0,  -sin(a.x), 0, cos(a.x)); // Yaw
    mat3 mx = mat3(1, 0, 0,  0, cos(a.y), -sin(a.y),  0, sin(a.y), cos(a.y)); // Pitch
    mat3 mz = mat3(cos(a.z), -sin(a.z), 0,  sin(a.z), cos(a.z), 0,  0,0,1);    // Roll

    return my * mx * mz;
}

void main()
{
    // Output pixel -> equirectangular longitude/latitude
    vec2 p_norm_screen = vv_FragNormCoord; // [0,1]
    float u = p_norm_screen.x;
    float v = p_norm_screen.y;

    float longitude = (u - 0.5) * 2.0 * M_PI;
    float latitude  = (0.5 - v) * M_PI;

    // Longitude/latitude -> world-space ray direction (inverse of atan/asin in the other shader)
    vec3 norm_ray_dir_world;
    norm_ray_dir_world.x = cos(latitude) * sin(longitude);
    norm_ray_dir_world.y = sin(latitude);
    norm_ray_dir_world.z = cos(latitude) * cos(longitude);

    // Undo the world rotation to get back into "view" space
    float roll_angle  = (XYZrotate.z - 0.5) * 2.0 * M_PI;
    float yaw_angle   = XYZrotate.x * 2.0 * M_PI;
    float pitch_angle = XYZrotate.y * 2.0 * M_PI;

    vec3 rotation_euler_angles = vec3(yaw_angle, pitch_angle, roll_angle);
    mat3 camera_to_world_rotation_matrix = makeRotationMatrix(rotation_euler_angles);
    mat3 world_to_camera_rotation_matrix = transpose(camera_to_world_rotation_matrix); // rotation matrices are orthogonal

    vec3 ray_dir_view = world_to_camera_rotation_matrix * norm_ray_dir_world;

    // View-space ray direction -> fisheye polar coords (inverse of the sin/cos build in the other shader)
    float ray_polar_angle_view = acos(clamp(ray_dir_view.z, -1.0, 1.0));
    float ray_azimuth_angle_view = atan(ray_dir_view.y, ray_dir_view.x);

    float fisheye_half_fov_rad = (domemaster_input_fov_degrees / 2.0) * (M_PI / 180.0);
    float dist_from_center = ray_polar_angle_view / fisheye_half_fov_rad;

    if (dist_from_center > 1.0) {
        gl_FragColor = vec4(0.0, 0.0, 0.0, 0.0);
        return;
    }

    vec2 p_centered;
    p_centered.x = dist_from_center * cos(ray_azimuth_angle_view);
    p_centered.y = dist_from_center * sin(ray_azimuth_angle_view);

    // Undo the aspect-ratio correction applied in the forward shader
    float screen_aspect = RENDERSIZE.x / RENDERSIZE.y;
    if (screen_aspect > 1.0) { // Landscape or square
        p_centered.x /= screen_aspect;
    } else { // Portrait
        p_centered.y *= screen_aspect;
    }

    // Undo the horizontal flip
    if (flipHorizontal) {
        p_centered.x = -p_centered.x;
    }

    vec2 fisheye_uv = p_centered * 0.5 + 0.5;

    vec4 sampled_color = texture(domemasterImage, fisheye_uv);
    gl_FragColor = sampled_color;
}

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions