Skip to content

Instantly share code, notes, and snippets.

@fieldOfView
Last active November 4, 2017 16:43
Show Gist options
  • Star 3 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save fieldOfView/5097581 to your computer and use it in GitHub Desktop.
Save fieldOfView/5097581 to your computer and use it in GitHub Desktop.
Equirectangular viewer Pixel Bender filter
/**
* Equirectangular viewer
* Last update: 6 March 2013
*
* Changelog:
* 1.0 - Initial release
*
* 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 aldo@fieldofview.com
*
*/
#define TWOPI 6.283185307179586
#define PI 3.141592653589793
<languageVersion : 1.0;>
kernel EquirectangularViewer
< namespace : "com.fieldofview";
vendor : "Aldo Hoeben - www.fieldofview.com";
version : 1;
displayname: "Equirectangular Viewer";
description : "Unwraps an equirectangular panorama image.";
>
{
parameter float2 inputSize
<
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 yaw
<
minValue: -180.0;
maxValue: 180.0;
defaultValue: 0.0;
stepInterval: 0.5;
displayName: "Yaw";
aeDisplayName: "Yaw";
aeUIControl:"aeAngle";
>;
parameter float pitch
<
minValue: -90.0;
maxValue: 90.0;
defaultValue: 0.0;
stepInterval: 0.5;
displayName: "Pitch";
aeDisplayName: "Pitch";
aeUIControl:"aeAngle";
>;
parameter float hfov
<
minValue: 1.0;
maxValue: 170.0;
defaultValue: 80.0;
stepInterval: 1;
displayName: "Horizontal Field of View";
aeDisplayName: "Horizontal Field of View";
aeUIControl:"aeAngle";
>;
input image4 src;
output pixel4 dst;
#if !AIF_FLASH_TARGET
region needed(region outputRegion, imageRef inputRef)
{
return region(float4(0, 0, inputSize.x, inputSize.y));
}
region changed(region outputRegion, imageRef inputRef)
{
return region(float4(0, 0, outputSize.x, outputSize.y));
}
#endif
float3x3 rotationMatrix(const float2 euler)
{
float2 se = sin(euler);
float2 ce = cos(euler);
return float3x3(
ce.x, 0.,-se.x,
0., 1., 0.,
se.x, 0., ce.x
) * float3x3(
1., 0., 0.,
0., ce.y,-se.y,
0., se.y, ce.y
);
}
float3 toCartesian(float2 sphericalCoord)
{
return normalize(float3(sphericalCoord.x, sphericalCoord.y, 0.5 / tan(0.5 * radians(hfov))));
}
float2 toSpherical(float3 cartesianCoord)
{
float2 sphericalCoord = float2(
atan(cartesianCoord.x, cartesianCoord.z),
acos(cartesianCoord.y)
);
if(sphericalCoord.x < 0.0)
sphericalCoord.x += TWOPI;
return sphericalCoord;
}
void evaluatePixel()
{
float2 sphericalCoord = outCoord() / outputSize - float2(0.5);
sphericalCoord.y *= -outputSize.y / outputSize.x;
float3 cartesianCoord = rotationMatrix(float2(radians(yaw+180.), radians(pitch))) * toCartesian(sphericalCoord);
dst = sampleLinear(src, toSpherical(cartesianCoord) / float2(TWOPI, PI) * (inputSize-float2(1.0))+float2(0.5));
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment