Skip to content

Instantly share code, notes, and snippets.

@tesu
Last active December 14, 2023 22:38
Show Gist options
  • Save tesu/196db5421559de3e9555d4f9da9d847d to your computer and use it in GitHub Desktop.
Save tesu/196db5421559de3e9555d4f9da9d847d to your computer and use it in GitHub Desktop.
mpv opengl shader for viewing 360 video
//!HOOK MAINPRESUB
//!BIND HOOKED
//!DESC un360
#define M_PI 3.1415926535897932384626433832795
const float fov = M_PI/2; // [0 to M_PI] horizontal field of view, range is exclusive
const float yaw = M_PI*1; // [any float] polar angle, one full revolution is 2*M_PI
const float pitch = M_PI*0; // [any float] vertical tilt, positive is up
const float roll = M_PI*0; // [any float] view rotation, positive is clockwise
const bool cubemap = false; // either cubemap or equirectangular
const float t = tan(fov/2);
const float c = cos(pitch);
const float s = sin(pitch);
float r = target_size.y/target_size.x;
const float sR = sin(roll);
const float cR = cos(roll);
mat3 m = mat3( 2*t*cR, 2*sR*t*r, -t*(cR+sR*r),
-2*sR*t*c, 2*cR*t*c*r, t*c*(sR-cR*r)-s,
-2*sR*t*s, 2*cR*t*s*r, t*s*(sR-cR*r)+c);
vec4 hook() {
vec3 p = vec3(HOOKED_pos, 1.0) * m;
float theta = atan(p.x, p.z) + yaw;
float phi = atan(p.y, length(p.xz)) + M_PI/2;
float x, y;
if (!cubemap) {
// equirectangular
x = fract(theta / (2*M_PI));
y = phi / M_PI;
} else {
// cubemap
float offset = mod(theta, M_PI/2)-M_PI/4;
float quadrant = mod(floor(theta*2/M_PI), 4);
float h = tan(phi)*cos(offset);
if (abs(h) > 1) { // side
if (quadrant == 3) { // back
x = .5/(tan(phi)*cos(offset))+.5;
y = .5*tan(offset)+.5;
x *= 1.0/3;
y *= 1.0/2;
x += 1.0/3;
y += 1.0/2;
} else {
x = .5*tan(offset)+.5;
y = -.5/(tan(phi)*cos(offset))+.5;
x *= 1.0/3;
y *= 1.0/2;
x += quadrant/3;
}
} else if (h > 0) { // top
x = .5*tan(M_PI-phi)*cos(theta+M_PI/4)+.5;
y = -.5*tan(M_PI-phi)*sin(theta+M_PI/4)+.5;
x *= 1.0/3;
y *= 1.0/2;
x += 2.0/3;
y += 1.0/2;
} else { // bottom
x = .5*tan(M_PI-phi)*cos(theta+M_PI/4)+.5;
y = .5*tan(M_PI-phi)*sin(theta+M_PI/4)+.5;
x *= 1.0/3;
y *= 1.0/2;
y += 1.0/2;
}
}
return HOOKED_tex(vec2(x,y));
}
@haasn
Copy link

haasn commented Aug 5, 2017

You don't have to do the edge clamping yourself, OpenGL implicitly does this.

@tesu
Copy link
Author

tesu commented Aug 5, 2017

I originally wasn't able to get the implicit edge clamping to work correctly because I didn't know how to change the HEIGHT and WIDTH of the texture, but now I've rewritten it to properly allow for rotating to values of theta greater than 2pi (also negative values), and so that extreme values of phi show some of what's "behind."

@b4zz4
Copy link

b4zz4 commented Nov 13, 2017

To my would like me use it for this type of video
https://www.youtube.com/watch?v=xCkqpGBMl8M

@ftoledo
Copy link

ftoledo commented Apr 30, 2019

how to use it?

@diimdeep
Copy link

To use add glsl-shaders-append="~/.config/mpv/un360.glsl" to ~/.config/mpv/mpv.conf and tweak parameters for video.

@haasn
Copy link

haasn commented Dec 22, 2022

With the recent addition of --glsl-shader-opts you could make this at least a bit more adjustable at runtime (maybe with an accompanying lua script to allow e.g. mouse dragging the view).

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