94 lines
2.3 KiB
Plaintext
94 lines
2.3 KiB
Plaintext
static const float PI = 3.14159265358979323846;
|
|
static const float TWO_PI = 6.28318530717958647692;
|
|
|
|
float radiansFromDegrees(float degrees)
|
|
{
|
|
return degrees * (PI / 180.0);
|
|
}
|
|
|
|
float3 rotateX(float3 ray, float angle)
|
|
{
|
|
float s = sin(angle);
|
|
float c = cos(angle);
|
|
return float3(ray.x, c * ray.y - s * ray.z, s * ray.y + c * ray.z);
|
|
}
|
|
|
|
float3 rotateY(float3 ray, float angle)
|
|
{
|
|
float s = sin(angle);
|
|
float c = cos(angle);
|
|
return float3(c * ray.x + s * ray.z, ray.y, -s * ray.x + c * ray.z);
|
|
}
|
|
|
|
float3 rotateZ(float3 ray, float angle)
|
|
{
|
|
float s = sin(angle);
|
|
float c = cos(angle);
|
|
return float3(c * ray.x - s * ray.y, s * ray.x + c * ray.y, ray.z);
|
|
}
|
|
|
|
float normalizedFisheyeRadius(float theta, float halfFov)
|
|
{
|
|
float safeHalfFov = max(halfFov, 0.0001);
|
|
|
|
if (fisheyeModel == 1)
|
|
{
|
|
return sin(theta * 0.5) / max(sin(safeHalfFov * 0.5), 0.0001);
|
|
}
|
|
else if (fisheyeModel == 2)
|
|
{
|
|
return tan(theta * 0.5) / max(tan(safeHalfFov * 0.5), 0.0001);
|
|
}
|
|
else if (fisheyeModel == 3)
|
|
{
|
|
return sin(theta) / max(sin(safeHalfFov), 0.0001);
|
|
}
|
|
|
|
return theta / safeHalfFov;
|
|
}
|
|
|
|
float3 equirectangularRay(float2 uv)
|
|
{
|
|
float longitude = (uv.x - 0.5) * TWO_PI + radiansFromDegrees(seamAngleDegrees);
|
|
float latitude = (0.5 - uv.y) * PI;
|
|
float latitudeCos = cos(latitude);
|
|
|
|
return normalize(float3(
|
|
sin(longitude) * latitudeCos,
|
|
sin(latitude),
|
|
cos(longitude) * latitudeCos
|
|
));
|
|
}
|
|
|
|
float4 shadeVideo(ShaderContext context)
|
|
{
|
|
float3 ray = equirectangularRay(context.uv);
|
|
|
|
ray = rotateZ(ray, radiansFromDegrees(rollDegrees));
|
|
ray = rotateX(ray, radiansFromDegrees(-pitchDegrees));
|
|
ray = rotateY(ray, radiansFromDegrees(yawDegrees));
|
|
|
|
// Mirror the rear hemisphere into the front-facing fisheye image so one
|
|
// circular lens source fills both halves of the equirectangular output.
|
|
ray.z = abs(ray.z);
|
|
ray = normalize(ray);
|
|
|
|
float halfFov = radiansFromDegrees(clamp(lensFovDegrees, 1.0, 220.0) * 0.5);
|
|
float theta = acos(clamp(ray.z, -1.0, 1.0));
|
|
if (theta > halfFov)
|
|
return outsideColor;
|
|
|
|
float phi = atan2(ray.y, ray.x);
|
|
float fisheyeRadius = normalizedFisheyeRadius(theta, halfFov);
|
|
|
|
float2 sourceUv = float2(
|
|
center.x + cos(phi) * fisheyeRadius * radius.x,
|
|
center.y - sin(phi) * fisheyeRadius * radius.y
|
|
);
|
|
|
|
if (sourceUv.x < 0.0 || sourceUv.x > 1.0 || sourceUv.y < 0.0 || sourceUv.y > 1.0)
|
|
return outsideColor;
|
|
|
|
return sampleVideo(sourceUv);
|
|
}
|