很多时候,我们需要根据对象距离摄像机的距离来设置属性,但是求距离往往是要计算开方的,这个运算量有点儿大,如果每帧对大量物体进行求距离运算,还是有一些负担的。但是,在很多情况下,实际上对象到摄像机的距离可以用对象相对于摄像机的“深度”来代替,这里所说的深度就是对象在摄像机坐标系下的Z轴的绝对值,不是0到1区间那个深度,是原始深度。使用对象相对于摄像机的深度来替代对象相对于摄像机的距离,不但运算量小很多,而且有时候效果更好,更符合直观感受。
下面是一个使用物体相对于摄像机“深度”控制物体缩放的代码示例:
using UnityEngine;
publicclassScaleByOpObjHover : MonoBehaviour
{
[SerializeField]
float hoverMulti = 1.5f;
[SerializeField]
float camMulti = 1;
OperationObject _obj;
OperationObject obj { get { if (!_obj) _obj = GetComponentInParent<OperationObject>(); return _obj; } }
Vector3 scaleInit;
voidStart()
{
scaleInit = transform.localScale;
}
voidUpdate()
{
Vector3 posCam = Camera.main.transform.InverseTransformPoint(obj.transform.position);
Vector3 scale = scaleInit * camMulti * (10f + Mathf.Abs(posCam.z)) ;
Vector3 scaleHovered = scale * hoverMulti;
transform.localScale = Vector3.Lerp(transform.localScale, obj.hovered ? scaleHovered : scale, Time.deltaTime * 10);
}
}
如果是在ShaderGraph中进行类似的控制,目前我知道的办法是两个:
一个是使用ScreenWorld节点,将其输出使用Split节点分离,使用分离后的A输出就是当前正在渲染的像素的基于真实坐标的“深度值”,或者说基于摄像机坐标系的Z轴的值的绝对值。这里需要注意的是不要使用SceneDepth的值,这个值是在渲染该像素之前生成的,不是当前渲染的像素的深度,经常用来与当前渲染的“深度”做对比。
另一个办法是使用Position节点,选择该节点的Eye选项输出的Z值应该就是基于摄像机坐标系的,这个Z值的绝对值应该就是相对于这个摄像机的“深度”,不过这个这个我没做过比较充分的测试,只是简单测试了一下。