解决Unity3D中ScreenPointToRay不准确的问题
————————————————————————
一、问题
1.我在场景里使用了两个相机。主相机渲染UGUI;另一个相机(透视)渲染模型,使用Render Texture将画面嵌入到UI中。
2.模型添加了Mesh Collider,使用射线检测点击事件。
3.实际点击位置和预计点击位置不一致。
————————————————————————
二、解决
展开相机的参数,逐个分析了一波,一个叫Sensor Size(传感器尺寸)的参数进入了我的视野。下面是关键代码:
float f = rayCamera.sensorSize.y == 0 ? 1 : rayCamera.sensorSize.x / rayCamera.sensorSize.y;
ray = rayCamera.ScreenPointToRay(Input.mousePosition * f);
三、话不多说,上代码
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Click3D : MonoBehaviour
{
[Header("发出射线的相机")]
public Camera rayCamera;
[Header("射线检测的层级")]
public string rayLayer = "Model";
[Header("被点击到的物体位移")]
public Vector3 colliderMove = Vector3.up;
[Header("是否为本地坐标")]
public bool isLocalCoordinate = false;
private bool isDirectRender = false;
private Collider[] colliders;
private Vector3[] collidersPosition;
private Ray ray;
private RaycastHit raycastHit;
private RaycastHit[] raycastHits;
private int currentColliderIndex = -1;
void Start()
{
isDirectRender = rayCamera.targetTexture == null;
colliders = GetComponentsInChildren<Collider>();
collidersPosition = new Vector3[colliders.Length];
for (int i = 0; i < colliders.Length; i++)
{
collidersPosition[i] = isLocalCoordinate ? colliders[i].transform.localPosition : colliders[i].transform.position;
}
}
void Update()
{
MouseClick();
}
private void MouseClick()
{
if (Input.GetMouseButtonDown(0))
{
GameObject go = RayCheckSingle();
if (go != null)
{
OnClick(go.name);
}
}
}
public void OnClick(string clickName)
{
for (int i = 0; i < colliders.Length; i++)
{
bool isClick = clickName.Equals(colliders[i].name);
if (isClick)
{
if (isLocalCoordinate)
{
colliders[i].transform.localPosition = currentColliderIndex != i ? collidersPosition[i] + colliderMove : collidersPosition[i];
}
else
{
colliders[i].transform.position = currentColliderIndex != i ? collidersPosition[i] + colliderMove : collidersPosition[i];
}
currentColliderIndex = i;
}
else
{
if (isLocalCoordinate)
{
colliders[i].transform.localPosition = collidersPosition[i];
}
else
{
colliders[i].transform.position = collidersPosition[i];
}
}
}
}
private GameObject RayCheckSingle()
{
if (isDirectRender)
{
ray = rayCamera.ScreenPointToRay(Input.mousePosition);
}
else
{
float f = rayCamera.sensorSize.y == 0 ? 1 : rayCamera.sensorSize.x / rayCamera.sensorSize.y;
ray = rayCamera.ScreenPointToRay(Input.mousePosition * f);
}
if (Physics.Raycast(ray,out raycastHit,rayCamera.farClipPlane,1 << LayerMask.NameToLayer(rayLayer)))
{
return raycastHit.collider.gameObject;
}
return null;
}
private GameObject[] RayCheckMulti()
{
if (isDirectRender)
{
ray = rayCamera.ScreenPointToRay(Input.mousePosition);
}
else
{
float f = rayCamera.sensorSize.y == 0 ? 1 : rayCamera.sensorSize.x / rayCamera.sensorSize.y;
ray = rayCamera.ScreenPointToRay(Input.mousePosition * f);
}
raycastHits = Physics.RaycastAll(ray, rayCamera.farClipPlane, 1 << LayerMask.NameToLayer(rayLayer));
if (raycastHits.Length > 0)
{
GameObject[] hitGOs = new GameObject[raycastHits.Length];
for (int i = 0; i < raycastHits.Length; i++)
{
hitGOs[i] = raycastHits[i].collider.gameObject;
}
return hitGOs;
}
return null;
}
}
|