首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >在“统一”中,计算圆角上与直线垂直的给定距离

在“统一”中,计算圆角上与直线垂直的给定距离
EN

Stack Overflow用户
提问于 2020-08-07 20:09:44
回答 2查看 1.4K关注 0票数 1

我制作了一个模型来说明我想要计算的内容。给定两个锚点之间的一条线(向量),我想将一个或多个游戏对象与该矢量的中点成一定距离的切线,并以指定的角度(弧度?)沿着一个垂直于向量的圆。

在这幅图中,一个虚圆位于中点,垂直于锚1和锚2之间的线。我要计算三个点(P1、P2和P3)的P1位置。其目的是将对象放置在每个点上。整个程序集将是一个可以在空间中旋转的游戏对象。(将有一个游戏对象,每个对象都是一个子对象。)

我已经搜索了StackOverflow和团结社区,找不到帮助我完成这三个位置的例子。

有什么想法吗?

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2020-08-07 20:37:24

考虑向量数学和四元数,而不是trig。使用交叉积找到0角偏移量,四元数根据角度旋转它。有关解释,请参见评论。

代码语言:javascript
复制
public void PlaceObjects(Transform anchor1, Transform anchor2, float r, 
        List<Transform> objs, List<float> angles)
{
    // lists must be non-null and same size
    Debug.Assert(objs != null);
    Debug.Assert(angles != null);
    Debug.Assert(objs.Count == angles.Count);
 
    // Find midpoint and axis of rotation   
    Vector3 midpoint = 0.5f * (anchor1.position + anchor2.position);
    Vector3 axis = (anchor2.position - anchor1.position).normalized;

    // What direction should the the "zero" offset be based on? 
    // Base it on the local up of the "assembly parent" this script is attached to?
    // or Vector3.up if "0 angle" should approximate world up?
    Vector3 upDirection = transform.up;

    // Of directions perpendicular to the axis find the closest to upDirection
    // See https://stackoverflow.com/a/57698547/1092820 for more information
    Vector3 axisRight = Vector3.Cross(upDirection, axis);

    if (axisRight == Vector3.zero) 
    {
        // upDirection & axis are colinear, no unique "up-ish" exists.
        // Just give up and don't move anything.
        return;
    }

    Vector3 zeroOffsetDir = Vector3.Cross(axis, axisRight);

    for (int i = 0 ; i < objs.Count ; i++)
    {
        Transform obj = objs[i];
        float angle = angles[i];
 
        // Find a rotation that describes how to rotate a "0 angle" offset into the one 
        // the current object needs
        Quaternion rot = Quaternion.AngleAxis(angle, axis); 
     
        // Find the offset by rotating the "zero" offset, then extending it by the radius
        Vector3 offset = r * (rot * zeroOffsetDir);

        // Set the object's position based on its offset and the location of the midpoint
        obj.position = midpoint + offset;

        // Optionally, set the object's rotation based on its current forward and the new up:
        // obj.rotation = Quaternion.LookRotation(obj.forward, offset);
    }
}
票数 1
EN

Stack Overflow用户

发布于 2020-08-08 00:44:30

对于那些感兴趣的人,这是我对@Ruzihm的解决方案的组件改编。PlaceObjectsOnCirclePerpendicularToVectorLine组件放置在一个空的游戏对象上。

代码语言:javascript
复制
using System.Collections.Generic;
using UnityEngine;

public class PlaceObjectsOnCirclePerpendicularToVectorLine : MonoBehaviour
{
    // Adapted from https://stackoverflow.com/a/63308834/13052746, by Ruzihm.

    public Transform anchor1;
    public Transform anchor2;
    public float radius;
    public List<Transform> objs;
    public List<float> angles;

    private Vector3 anchor1PriorPosition;
    private Vector3 anchor2PriorPosition;

    // Start is called before the first frame update
    void Start()
    {
        PlaceObjects(
            anchor1,
            anchor2,
            radius,
            objs,
            angles);
    }

    // Update is called once per frame
    void Update()
    {
        PlaceObjects(
            anchor1,
            anchor2,
            radius,
            objs,
            angles);
    }

    public void PlaceObjects(
        Transform anchor1, 
        Transform anchor2, 
        float radius,
        List<Transform> objs, 
        List<float> angles)
    {

        if (anchor1PriorPosition == anchor1.position &&
            anchor2PriorPosition == anchor2.position)
        {
            // The anchors haven't moved.
            return;
        } else
        {
            anchor1PriorPosition = anchor1.position;
            anchor2PriorPosition = anchor2.position;
        }

        // lists must be non-null and same size
        Debug.Assert(objs != null);
        Debug.Assert(angles != null);
        Debug.Assert(objs.Count == angles.Count);

        // Find midpoint and axis of rotation   
        Vector3 midpoint = 0.5f * (anchor1.position + anchor2.position);
        Vector3 axis = (anchor2.position - anchor1.position).normalized;

        // What direction should the the "zero" offset be based on? 
        // Base it on the local up of the "assembly parent" this script is attached to?
        // or Vector3.up if "0 angle" should approximate world up?
        Vector3 upDirection = transform.up;

        // Of directions perpendicular to the axis find the closest to upDirection
        // See https://stackoverflow.com/a/57698547/1092820 for more information
        Vector3 axisRight = Vector3.Cross(upDirection, axis);

        //if (axisRight == Vector3.zero)
        //{
        //    // upDirection & axis are colinear, no unique "up-ish" exists.
        //    // Just give up and don't move anything.
        //    return;
        //}

        Vector3 zeroOffsetDir = Vector3.Cross(axis, axisRight);

        for (int i = 0; i < objs.Count; i++)
        {
            Transform obj = objs[i];
            float angle = angles[i];

            // Find a rotation that describes how to rotate a "0 angle" offset into the one 
            // the current object needs
            Quaternion rot = Quaternion.AngleAxis(angle, axis);

            // Find the offset by rotating the "zero" offset, then extending it by the radius
            Vector3 offset = radius * (rot * zeroOffsetDir);

            // Set the object's position based on its offset and the location of the midpoint
            obj.position = midpoint + offset;
        }
    }
}

下面是场景视图中的样子:

下面是这个组件在检查器中的样子:

再来一次,聪明的,鲁兹姆!这正是我想要的!

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/63308574

复制
相关文章

相似问题

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