I am attempting to implement a fisheye style lens.
Basically I project each vertex onto a unit sphere around the camera. Then I move the camera to the back of that unit sphere.
If every vertex was in front of the camera, it would get projected onto the forward hemisphere, and a 90° camera angle would render it onto a circle that touches the corners of the window.
Objects that would have been out of view will get squashed towards the centre.
Here is my shader code:
Shader "Pi shader"
{
Properties {
_Color ("Diffuse Material Color", Color ) = ( 0., 1.,0. ,1. )
_DidHit( "bool whether focalpoint exists", Int ) = 0
_Focus ( "focal point (worldSpace)" , Vector ) = ( 1., 0., 0. )
}
SubShader {
Pass {
Tags { "LightMode" = "ForwardBase" }
GLSLPROGRAM // here begins the part in Unity's GLSL
#include "UnityCG.glslinc"
varying vec4 v2f_color;
#ifdef VERTEX // here begins the vertex shader
uniform vec4 _Color;
uniform vec4 _Focus;
uniform int _DidHit;
uniform vec4 _LightColor0;
void main()
{
vec4 pos_camSpace = gl_ModelViewMatrix * gl_Vertex;
vec4 focus_camSpace = gl_ModelViewMatrix * _Focus;
vec4 X = pos_camSpace;
// hit-test unit sphere, i.e. normalize X
vec3 X_unitSphere = normalize( vec3(X) );
// now project from back of sphere, i.e. (0,0,+1) as camera looks down -ve z
// Moving the camera back by camera.z += 1.0 should be equivalent to keeping the at 0,
// and moving all the points away by v.z -= 1.0
vec3 X_proj = length(X) * normalize( vec3( X_unitSphere.x, X_unitSphere.y, X_unitSphere.z - 1.0 ) );
gl_Position = gl_ProjectionMatrix * vec4( X_proj, 1.0 );
// do light calc in world-space
vec4 normal_4 = vec4(gl_Normal, 0.0);
vec3 normal_ws = normalize( vec3( normal_4 * _World2Object ) );
vec3 object_to_cam_ws = normalize( vec3(pos_camSpace) );
vec3 diffuseReflection = vec3(_LightColor0) * vec3(_Color)
* max(0.0, dot(normal_ws, object_to_cam_ws));
v2f_color = vec4(diffuseReflection, 1.0);
}
#endif
#ifdef FRAGMENT
void main() { gl_FragColor = v2f_color; }
#endif
ENDGLSL
}
}
}
It seems to correctly warp all objects that would have been within the original 90° camera angle.
But all objects that would have been outside of this frustrum fail to render.
As I slide the camera’s FoV from the inspector, peripheral objects pop in and out of existence.
As you can see, FoV=95.8 → 95.9 makes one object at here. But no intermediate value makes part of that object appear.
I think that frustrum culling happens between the vertex and fragment shader… Also triangles partially offscreen get clipped.
Maybe there is a bounding box around the object, at this is checked by Unity against the camera’s FoV, and the render is just switched off it is determined to be off-screen…?
Is there anyway to get round this?
I guess I could have a 179° FoV camera, and then manually construct my own projection matrix.
Does this make sense?