Last active
November 4, 2017 16:43
-
-
Save fieldOfView/4031189 to your computer and use it in GitHub Desktop.
Equirectangular remapper Pixel Bender filter
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* Equirectangular remapper | |
* Last update: 7 November 2012 | |
* | |
* Changelog: | |
* 1.0 - Initial release | |
* 2.0 - Rewrite with polar<->carthesian instead of euler<->matrix math | |
* | |
* Licensed under the MIT License: | |
* http://www.opensource.org/licenses/mit-license.php | |
* | |
* | |
* Credits and references | |
* ====================== | |
* | |
* Inspired by LittlePlanets by subblue: | |
* http://www.subblue.com/blog/2010/6/17/little_planets | |
* | |
* A good selection of cosc-licensed equirectangular panorama source images can be found here: | |
* http://www.flickr.com/photos/sbprzd/sets/72057594100163739/ | |
* http://www.flickr.com/photos/heiwa4126/sets/72157601609820530/ | |
* http://www.flickr.com/search/?q=equirectangular&z=e&l=deriv&ss=2&ct=5&mt=all&adv=1 | |
* | |
* | |
* Contact | |
* ======= | |
* | |
* This plugin is free to use for personal or commercial projects. | |
* I'd love to hear how you are using it so email me at [email protected] | |
* | |
*/ | |
#define TWOPI 6.283185307179586 | |
#define PI 3.141592653589793 | |
<languageVersion : 1.0;> | |
kernel EquirectangularRemap2 | |
< namespace : "com.fieldofview"; | |
vendor : "Aldo Hoeben - www.fieldofview.com"; | |
version : 1; | |
displayname: "Equirectangular Remapper"; | |
description : "Rotates an equirectangular panorama image."; | |
> | |
{ | |
parameter float2 size | |
< | |
minValue: float2(8, 4); | |
maxValue: float2(4096, 4096); | |
defaultValue: float2(2000, 1000); | |
stepInterval: float2(1, 1); | |
displayName: "Input image size"; | |
componentName: "Width|Height"; | |
aeDisplayName: "Input image size"; | |
>; | |
parameter float2 outputSize | |
< | |
minValue: float2(8, 4); | |
maxValue: float2(4096, 4096); | |
defaultValue: float2(800, 400); | |
stepInterval: float2(1, 1); | |
displayName: "Output image size"; | |
componentName: "Width|Height"; | |
aeDisplayName: "Output image size"; | |
>; | |
parameter float longitude | |
< | |
minValue: -180.0; | |
maxValue: 180.0; | |
defaultValue: 0.0; | |
stepInterval: 0.5; | |
displayName: "Longitude offset"; | |
aeDisplayName: "Longitude offset"; | |
aeUIControl:"aeAngle"; | |
>; | |
parameter float latitude | |
< | |
minValue: -90.0; | |
maxValue: 90.0; | |
defaultValue: 0.0; | |
stepInterval: 0.5; | |
displayName: "Latitude offset"; | |
aeDisplayName: "Latitude offset"; | |
aeUIControl:"aeAngle"; | |
>; | |
parameter float rotate | |
< | |
minValue: -180.0; | |
maxValue: 180.0; | |
defaultValue: 0.0; | |
stepInterval: 0.5; | |
displayName: "Rotate"; | |
aeDisplayName: "Rotate"; | |
aeUIControl:"aeAngle"; | |
>; | |
input image4 src; | |
output pixel4 dst; | |
#if !AIF_FLASH_TARGET | |
region needed(region outputRegion, imageRef inputRef) | |
{ | |
return region(float4(0, 0, size.x, size.y)); | |
} | |
region changed(region outputRegion, imageRef inputRef) | |
{ | |
return region(float4(0, 0, outputSize.x, outputSize.y)); | |
} | |
#endif | |
// | |
// utility functions | |
// | |
float wrap(float angle) | |
{ | |
return (angle<0.)?angle+TWOPI:angle; | |
} | |
// | |
// polar <-> spherical conversion | |
// | |
float3 polarToSpherical(float2 polar) | |
{ | |
return float3( | |
sin(polar.y)*cos(polar.x), | |
sin(polar.y)*sin(polar.x), | |
cos(polar.y) | |
); | |
} | |
float2 sphericalToPolar(float3 spherical) | |
{ | |
return float2(wrap( | |
(spherical.x>0.)? | |
atan(spherical.y / spherical.x): | |
PI+atan(spherical.y / spherical.x) | |
), | |
acos(spherical.z) | |
); | |
} | |
// | |
// rotation of a 2d point around the origin | |
// | |
float2 rotate2d(float2 point, float angle) | |
{ | |
return float2( | |
point.x*cos(angle) - point.y*sin(angle), | |
point.x*sin(angle) + point.y*cos(angle) | |
); | |
} | |
// note: euler vectors are expressed in radians, | |
// axes: bank/roll around x-axis, attitude/pitch around y-axis, heading/yaw around z-axis | |
// http://en.wikipedia.org/wiki/Spherical_coordinate_system | |
// order: bank/roll, attitude/pitch, heading/yaw | |
// to match PTGUI | |
void evaluatePixel() | |
{ | |
float2 polar = float2(TWOPI,PI) * outCoord() / outputSize; | |
float3 spherical = polarToSpherical( polar ); | |
spherical.yx = rotate2d( spherical.yx, PI*longitude/180. ); | |
spherical.xz = rotate2d( spherical.xz, PI*latitude/180. ); | |
spherical.zy = rotate2d( spherical.zy, PI*rotate/180. ); | |
polar = size * sphericalToPolar( spherical ) / float2(TWOPI,PI); | |
dst = sampleNearest(src, polar); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment