Watched an excellent GDC seminar on mobile optimization strategies. One trick mentioned was to use a 'pull to camera ' shader so that a Billboard render is pulled towards camera on z axis, effectively putting it in 'front' of the game object instead of slicing thru it. Haven't heard of this before. Is anyone aware of such a shader or how I might enable this on an existing fx shader?
I've done this many times and it's actually pretty simple to do. The easiest way to do this is in world space. So in the vertex shader: - Convert the input object space position to world space - Lerp the world space position between the original and the camera position - Convert the world space position to clip space So a lerp value of 0.5 would place the object halfway between the original position and the camera. You'll want to use a value that's as low as possible.
I have this that seems to be working: Code (CSharp): float4 pos = mul(_Object2World,v.vertex); pos.xyz = lerp(pos.xyz,_WorldSpaceCameraPos,_Pull); o.pos = mul(UNITY_MATRIX_MVP,mul(_World2Object,pos)); However I'm having some trouble making it work with my billboard code: Code (CSharp): float4 pos = mul(UNITY_MATRIX_P, mul(UNITY_MATRIX_MV, float4(0.0, 0.0, 0.0, 1.0)) - float4(v.vertex.x, v.vertex.y, 0.0, 0.0));
Change this: Code (csharp): o.pos = mul(UNITY_MATRIX_MVP,mul(_World2Object,pos)); To this for some simple optimization: Code (csharp): o.pos = mul(UNITY_MATRIX_VP,pos); And for the other one I'm also not that sure. You're taking a fixed base in camera/view space, then subtract the actual vertex positions there.
ok simple solution, using my billboard code, you can actually pull the z from the quad by changing it's z value like this. I use a variable _Pull to control it. Code (CSharp): float4 pos = mul(UNITY_MATRIX_P, mul(UNITY_MATRIX_MV, float4(0.0, 0.0, 0.0, 1.0)) - float4(v.vertex.x, v.vertex.y, _Pull, 0.0));
Depending on your needs, you might want to move a specific amount in world space towards the camera (we needed to for current project) - this should do the trick! Code (CSharp): // Convert to world space float3 pullPos = mul(unity_ObjectToWorld,v.vertex); // Determine cam direction (needs Normalize) float3 camDirection=normalize(_WorldSpaceCameraPos-pullPos); // Pull in the direction of the camera by a fixed amount pullPos+=camDirection*_PullDistance; // Convert to clip space o.pos=mul(UNITY_MATRIX_VP,float4(pullPos,1));
Hm, I think you're all putting a bit too much effort into it. I would just use the Offset feature of unity. From the documentation: Here is an example shader you can play around with: https://github.com/supyrb/ConfigurableShaders/wiki/Rendering By using an offset of -20 (well depends on the distance the camera is away from the object) you might just achieve what you want to achieve.
The problem with the Offset feature is it's potentially going to be different for every device it runs on as the implementation isn't defined in the spec. So a value of -20 not only changes with distance, but also per device. On some devices it might do nothing! The other problem with Offset is it is often (always?) implemented as a fragment shader depth write which has potential performance implications. Specifically that disables any early z rejection. Doing a manual offset in the vertex shader can potentially be much faster.
And what is the solution? I'm also interested in "pull to camera" / and uv distortion smoke shaders/technique.