首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >三维球体上的0-1缩放

三维球体上的0-1缩放
EN

Stack Overflow用户
提问于 2022-03-25 08:00:15
回答 1查看 130关注 0票数 1

我正在拍摄一个三维球面上的光线投射,我想要一种方法,它可以根据光线点(位置)从0(喷流中心)到1(圆周或球体轮廓)之间的浮点数。我怎样才能做到这一点。

我试着计算了球体位置和射线投落点之间的差异,虽然有点工作,但在代码中实现起来非常复杂。

还有其他方法吗?还是我遗漏了一些数学函数或向量函数,在这种情况下是有用的。

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2022-03-25 08:38:21

你可以取一个垂直于射线方向的Plane,穿过球体的起源,然后像这样使用Plane.Raycast将命中位置投射到球体上。

代码语言:javascript
复制
...
if(Physics.Raycast(ray, out var hit))
{
    if(hit.collider is SphereCollider hitSphere)
    {
        // This is assuming that your sphere is actually a sphere with uniform local scales
        var sphereRadius = hitSphere.radius * hitSphere.tranform.lossyScale.x;

        var hitObjectCenter = hit.collider.bounds.center;
        var plane = new Plane(-ray.diretcion, hitObjectCenter);
        if(plane.Raycast(ray, out var hitDistance))
        {
            var planeHitPoint = ray.GetPoint(hitDistance);

            var result = Vector3.Distance(hitObjectCenter, planeHitPoint) / sphereRadius;

            // now result should be your value between 0 (sphere center) and 1 (exactly on the sphere "edge" - probably never fully reached of course)
        }
    }
}

由于我们的平面使用的射线方向是正常的,你也可以用Plane.ClosestPointOnPlane近似。

代码语言:javascript
复制
var plane = new Plane(-ray.diretcion, hitObjectCenter);
var planeHitPoint = plane.ClosestPointOnPlane(hitDistance);
var result = Vector3.Distance(hitObjectCenter, planeHitPoint) / sphereRadius;

结果应该是几乎相同的,不确定哪一个更快,但我想光线投射是更精确的(我们说的差别有点像0.000001 ;)。

作为一个小演示,因为解释这是如何工作的有点复杂^^

代码语言:javascript
复制
public class Example : MonoBehaviour
{
    public Camera mainCamera;

    private float result;
    private Ray ray;
    private Vector3 hitPoint;
    private Vector3? hitObjectCenter;
    private Vector3 planeHitPoint;

    private void Awake()
    {
        if (!mainCamera) mainCamera = Camera.main;
    }

    private void Update()
    {
        ray = mainCamera.ScreenPointToRay(Input.mousePosition);

        if (Physics.Raycast(ray, out var hit) && hit.collider is SphereCollider hitSphere)
        {
            hitPoint = hit.point;

            // This is assuming that your sphere is actually a sphere with uniform local scales
            var sphereRadius = hitSphere.radius * hitSphere.transform.lossyScale.x;

            hitObjectCenter = hit.collider.bounds.center;
            var plane = new Plane(-ray.direction, hitObjectCenter.Value);
            if(plane.Raycast(ray, out var hitDistance))
            {
                var planeHitPoint = ray.GetPoint(hitDistance);

                var result = Vector3.Distance(hitObjectCenter, planeHitPoint) / sphereRadius;
            }
        }
        else
        {
            hitObjectCenter = null;
        }
    }

    private Mesh planeMesh;

    private void OnDrawGizmos()
    {
        // if not hitting a sphere do nothing
        if (!hitObjectCenter.HasValue)
        {
            return;
        }

        // lazy initialize plan visualization
        if (!planeMesh)
        {
            planeMesh = new Mesh
            {
                vertices = new Vector3[4]
                {
                    new Vector3(-1, -1),
                    new Vector3(-1, 1),
                    new Vector3(1, 1),
                    new Vector3(1, -1)
                },
                triangles = new[]
                {
                    0, 1, 2,
                    0, 2, 3,

                    // backfaces
                    0, 2, 1,
                    0, 3, 2
                },
                normals = new Vector3[4]
                {
                    Vector3.forward,
                    Vector3.forward,
                    Vector3.forward,
                    Vector3.forward,
                }
            };
        }

        // Visualize ray
        Gizmos.color = Color.green;
        Gizmos.DrawLine(ray.origin, hitPoint);

        // Visualize hit point on sphere
        Gizmos.DrawWireSphere(hitPoint, 0.05f);

        // Visualize Plane
        Gizmos.color = Color.cyan;
        Gizmos.DrawWireMesh(planeMesh, hitObjectCenter.Value, Quaternion.LookRotation(ray.direction));

        // visualize hit point on plane
        Gizmos.DrawWireSphere(planeHitPoint, 0.05f);

        // Visualize distance
        Gizmos.color = Color.red;
        Gizmos.DrawLine(planeHitPoint, hitObjectCenter.Value);

        // print result on screen
        Handles.Label((planeHitPoint + hitObjectCenter.Value) / 2f, $"RESULT: {result:0.000}", new GUIStyle(EditorStyles.boldLabel) { alignment = TextAnchor.MiddleCenter });
    }
}
票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/71613725

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档