The particles look horrible in VR as they rotate when the head rotates. Has anyone been able to reduce the effect of this? I’ve tried setting Billboard Alignment to facing.
Workaround:
For ground based billboards (like trees) you can use a regular quad object or prefab with this optimized 1 dimension rotation script on it:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class vr_billboard : MonoBehaviour
{
static Transform tCam = null;
void Update ()
{
if(!tCam)
{
if(!Camera.main)
{
return;
}
tCam = Camera.main.transform;
}
transform.LookAt(tCam.position, Vector3.up);
}
}
For clouds up above like @eastes gif: Put them high enough and flat in XZ and no billboard needed or you could try swapping Vector3.up in above code for another axis if you want something above and fairly close.
Full and general quad faces camera solution would require 2 dimensional constrained quaternion rotation.
I just spent a week a little while ago tackling grass in Unity terrain, which does the same thing, and found some solutions. I have no experience with the particle billboards so I don’t know if it will transfer over but maybe you will find one useful.
as SiliconDroid said, for far away clouds don’t even bother billboarding them
you can rotate the objects themselves with a script as SiliconDroid said and not billboard in the shader, but if you have a lot of objects (like several thousand grass quads) this is really, really slow. But this is easiest.
You can write a new billboard shader with a vert shader that orients to camera position instead of camera.forward. This approach suffered from some weird problem where you’d have to disable batching in the shader or the vert shader would run incorrectly and all your different quads would end up transformed on top of each other. Turning off batching was OK for small numbers but bad for ~5000 grass cards.
The “best” solution I found which I’m using now for my grass was to copy the builtin unity grass shader and override it with my custom copy where I oriented to the camera position instead of camera forward. Again, I haven’t messed with the particle system at all, but I would guess you could do something similar.
Yup… I guess that’s gonna be the best solution for particles also.
I’m guessing the “broken” billboard shader was written to match camera rotation instead of lookat camera for some batching performance reason as all quads will have same worldspace vert matrix, not sure tho? Shaders to me at the moment are a black art.
Shaders are totally a black art to me too. I get the sl part but the hooks into unity and cg and pragma this and Tags that are totally confusing.
Weirdly enough my custom “face the camera instead of camera.forward” shader which overrides the builtin grass shader and is working in the builtin terrain system, although it does have a “DisableBatching” = “True” line in it, somehow results in very few draw calls - much fewer than if I added the same number of grass objects on my own. I don’t know how or what the Terrain system is doing but it actually works really well.
For Shuriken particles you can counter rotate the particles against the camera’s roll, but it is expensive. For billboard shaders, most do a trick to expand themselves in view space, but that means they feel “attached” to your face. @RibsNGibs comments are good ones. A side effect of using a billboard shader to orient towards the camera position rather than “camera forward” is you need a second vector to construct a full orientation, and the easiest world vector to use is world up, the result is a billboard that isn’t locked to the roll of the camera.
It does have one problem, which is if you look up or down close to 90 degrees your billboards will either start to spin or shrink depending on the implementation, but luckily people don’t usually rotate their heads that far.
I’m sure this isn’t the best way to do this, but this worked for me (I just copied the builtin shader and the functions it called to do the billboarding and changed some code in the TerrainBillboardGrass function. I don’t know if the naming matters, but if you put this in a file called WavingGrassBillboard.shader somewhere in your asset folder your grass should face the camera position instead of the camera view direction.
Thank you for sharing your shader. I understood it and tried to modify TerrainBillboardTree in same way but trees still rotate.
void TerrainBillboardTree( inout float4 pos, float2 offset, float offsetz )
{
float3 treePos = pos.xyz - _TreeBillboardCameraPos.xyz;
float treeDistanceSqr = dot(treePos, treePos);
if( treeDistanceSqr > _TreeBillboardDistances.x )
offset.xy = offsetz = 0.0;
float3 right = normalize(cross(float3(0, 1, 0), treePos));
float3 newup = normalize(cross(treePos, right));
// positioning of billboard vertices horizontally
// pos.xyz += _TreeBillboardCameraRight.xyz * offset.x;
pos.xyz += right * offset.x;
// tree billboards can have non-uniform scale,
// so when looking from above (or bellow) we must use
// billboard width as billboard height
// 1) non-compensating
//pos.xyz += _TreeBillboardCameraUp.xyz * offset.y;
// 2) correct compensating (?)
//float alpha = _TreeBillboardCameraPos.w;
//float a = offset.y;
//float b = offsetz;
// 2a) using elipse-radius formula
////float r = abs(a * b) / sqrt(sqr(a * sin(alpha)) + sqr(b * cos(alpha))) * sign(b);
//float r = abs(a) * b / sqrt(sqr(a * sin(alpha)) + sqr(b * cos(alpha)));
// 2b) sin-cos lerp
//float r = b * sin(alpha) + a * cos(alpha);
//pos.xyz += _TreeBillboardCameraUp.xyz * r;
// 3) incorrect compensating (using lerp)
// _TreeBillboardCameraPos.w contains ImposterRenderTexture::GetBillboardAngleFactor()
//float billboardAngleFactor = _TreeBillboardCameraPos.w;
//float r = lerp(offset.y, offsetz, billboardAngleFactor);
//pos.xyz += _TreeBillboardCameraUp.xyz * r;
// so now we take solution #3 and complicate it even further...
//
// case 49851: Flying trees
// The problem was that tree billboard was fixed on it's center, which means
// the root of the tree is not fixed and can float around. This can be quite visible
// on slopes (checkout the case on fogbugz for screenshots).
//
// We're fixing this by fixing billboards to the root of the tree.
// Note that root of the tree is not necessary the bottom of the tree -
// there might be significant part of the tree bellow terrain.
// This fixation mode doesn't work when looking from above/below, because
// billboard is so close to the ground, so we offset it by certain distance
// when viewing angle is bigger than certain treshold (40 deg at the moment)
// _TreeBillboardCameraPos.w contains ImposterRenderTexture::billboardAngleFactor
float billboardAngleFactor = _TreeBillboardCameraPos.w;
// The following line performs two things:
// 1) peform non-uniform scale, see "3) incorrect compensating (using lerp)" above
// 2) blend between vertical and horizontal billboard mode
float radius = lerp(offset.y, offsetz, billboardAngleFactor);
// positioning of billboard vertices veritally
// pos.xyz += _TreeBillboardCameraUp.xyz * radius;
pos.xyz += newup * offset.y;
// _TreeBillboardCameraUp.w contains ImposterRenderTexture::billboardOffsetFactor
float billboardOffsetFactor = _TreeBillboardCameraUp.w;
// Offsetting billboad from the ground, so it doesn't get clipped by ztest.
// In theory we should use billboardCenterOffsetY instead of offset.x,
// but we can't because offset.y is not the same for all 4 vertices, so
// we use offset.x which is the same for all 4 vertices (except sign).
// And it doesn't matter a lot how much we offset, we just need to offset
// it by some distance
pos.xyz += _TreeBillboardCameraFront.xyz * abs(offset.x) * billboardOffsetFactor;
}
Are you having problems with the actual billboarded trees - the ones really, really far away that are drawn with a single texture, or the trees with billboarded leaf and branch clusters - the trees up close that look mostly correct (trunk and branches and ~50% of the leaves look OK, and ~50% of the leaves rotate with camera)? I did an (awful) fix for geometry trees w/ billboarded leaf clusters that I could dig up later, but I haven’t looked at the full billboarded trees (I think my quality settings have an LOD bias that makes them never go to full billboard).
In any case, a cursory look of your code looks right. To be safe, I’d name the function something different (TerrainBillboardTreeAimino), and make sure that your shader calls that. I am unsure of the order of precedence if you have identically named functions.
I have problems with the full billboarded trees. I confirmed that my shader is called by changing some parameters. I don’t completely understand the mechanism of Unity’s billboard processing, but it seems to be rotated by another process.
I just tried out the billboarded trees and I was able to fix them by just going into Edit->ProjectSettings->Quality and toggling on the “Billboards Face Camera Position” button option.