Top
e5c7fbaa2dafc2b400691075194f45c4

Devlog 3 / Sphere Projected Cubemap Reflections

sphereProjectedReflection

For Trials of Asphodel we are aiming to build with Unity Indie, which has a few restrictions, and probably the biggest restriction for us is the lack of render to textures.

(If you just want the code skip the next 5 of paragraphs of backstory)

In the temple level Martin wanted shallow reflective water, to do this a few of options spring to mind, one would be realtime render to texture reflection using something like the Mirror Reflection Script on the Unity wiki. This re-renders the scene from a second camera flipped on the Y axis and looks great, BUT requires Unity Pro so that was out.

Another option would be to mask off the water and render a second camera from the flipped Y axis reflection position, maybe Cull None on all the shaders to fix reversed triangle winding, but this wouldn’t have allowed any texture distortion so wouldn’t have looked very watery.

That leaves cubemap reflection. Generating cubemaps can be done in Indie using this handy script. Here’s the cubemap I generated.
templeCubemap

The standard cubemap shaders work great on curvy objects but on planar surfaces the illusion is broken, the view direction doesn’t change so reflections seem magnified and appear not to move correctly. An increasingly common solution is Box Projected Cubemaps, where the reflection vector is corrected to appear to mapped to a cube. Box Projection works great for cuboid rooms, and is used on every object in VRoom, but the arenas in Trials are circular and not a good fit for Box Projection.

So final solution, Spherical Projection Mapping, correcting the refection vector to map onto the inside of a sphere. I couldn’t find any shader snippets online to do it, but there were a couple of resources on the theory and many resources on the maths principles. Theory wise this blog post by S├ębastien Lagarde is a great resource. And for the actual maths this page on lighthouse3d.com is useful. I jotted it all down at 2am when the idea popped into my head.

unnamed

The result looks like this;

167db68ffa37b8a455fbc93063d81898

a890418519bd4843a7256207fb8e6535

(CODE STARTS HERE)

Anyway, the Shader, this is for a surface shader but could be easily translated to vert/frag I think. I’ve only included the bit relevant to the reflection, skipping out normal mapping and transparancy etc.

_Center is the centre of the sphere
_Radius is the radius of the sphere
IN. and o. properties are built in surface shader values

//get the vector direction from the center of the sphere to the origin of the ray
float3 centerToPosition = IN.worldPos - _Center.xyz;
float3 worldRefl = WorldReflectionVector (IN, o.Normal);
//normalize the reflection vector
float3 reflection = normalize(worldRefl);
//get directional vector to the closest point on the ray to the center of the circle
float3 proj = (dot(centerToPosition, reflection)/length(reflection))* reflection;
//get the position of the closest point
float3 projCoord = IN.worldPos - proj;
//get vector direction between the center of the sphere and the closest point
projCoord -= _Center.xyz;
//cache the magnitude (saves on an instruction)
float projCoordMag = length(projCoord);
//use pythagoras to length of the remaining side
float distanceToP = sqrt((_Radius * _Radius) - (projCoordMag * projCoordMag));
//get the position of the intersection
float3 P = projCoord + (reflection * distanceToP);
//the final
float3 correctedReflection = normalize(P - _Center.xyz);
fixed3 reflcol = texCUBE (_Cube, correctedReflection);

Resolution artifacts due to the arena being 80m wide can be disguised with a normal map.

e5c7fbaa2dafc2b400691075194f45c4

e1400b505470dec8a22f216f898f1c24

I think the result is passable and especially with the normal map distortion is a worthwhile Indie alternative to render to texture reflections.

For the Trials of Asphodel indiedb page go to http://www.indiedb.com/games/trials-of-asphodel

Leave a comment

Your email address will not be published.

//