您可以根据vuforia目标图像创建飞机吗? [英] Can you create a plane from vuforia target images?

查看:95
本文介绍了您可以根据vuforia目标图像创建飞机吗?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

如下图所示,我有4个vuforia目标图像.我想要实现的是测量连接两个目标图像的红轴相对于我要使用绿线连接的三个目标图像生成的平面的角度.希望这是可以理解的.我将如何使用这三个目标图像生成该平面?

As seen in the photo below i have 4 vuforia target images. What i want to achieve is to measure the angle of the red axis joining two target images, against a plane which i want to generate using the three target images connected by the green line. Hopefully this is more understandable. How would i go about generating that plane with those three target images?

[![] [1]] [1]

[![][1]][1]

推荐答案

您的问题非常广泛!不过,我会试一试:

You question is extremely broad! However I'll give it a shot:

我假设平面"是指实际上可见的3D网格.否则,您可以直接使用给定的3个坐标来创建数学 Plane

I'm assuming by "Plane" you mean an actually visible 3D mesh. Otherwise you could directly use the 3 given coordinates to create a mathematical Plane.

首先,对于飞机,通常使用矩形网格..在您的问题中,尚不清楚您要如何精确地从3个坐标中建立坐标.

First of all for a plane you usually use a rectangular mesh .. it is unclear in your question how exactly you want to built that from the 3 coordinates you get.

我只是假设您在此处直接使用3个坐标来创建平行图拐角ABC,然后通过将向量BC添加到A

I'm simply assuming here you create a Parallelogram directly using the 3 coordinates for the corners A, B andC and then adding a 4th one D by adding the vector BC to A

using UnityEngine;

[RequireComponent(typeof(MeshFilter))]
[RequireComponent(typeof(MeshRenderer))]
public class PlaneController : MonoBehaviour
{
    public Transform target1;
    public Transform target2;
    public Transform target3;

    private MeshFilter meshFilter;
    private Mesh mesh;
    private Vector3[] vertices;

    private void Awake()
    {
        meshFilter = GetComponent<MeshFilter>();
        mesh = meshFilter.mesh;

        vertices = new Vector3[4];

        // Set the 4 triangles (front and backside)
        // using the 4 vertices
        var triangles = new int[3 * 4];

        // triangle 1 - ABC
        triangles[0] = 0;
        triangles[1] = 1;
        triangles[2] = 2;
        // triangle 2 - ACD
        triangles[3] = 0;
        triangles[4] = 2;
        triangles[5] = 3;

        // triangle 3 - BAC
        triangles[6] = 1;
        triangles[7] = 0;
        triangles[8] = 2;
        // triangle 4 - ADC
        triangles[9] = 0;
        triangles[10] = 3;
        triangles[11] = 2;

        mesh.vertices = vertices;
        mesh.triangles = triangles;
    }

    // Update is called once per frame
    void Update()
    {
        // build triangles according to target positions
        vertices[0] = target1.position - transform.position; // A
        vertices[1] = target2.position - transform.position; // B
        vertices[2] = target3.position - transform.position; // C

        // D = A  + B->C
        vertices[3] = vertices[0] + (vertices[2] - vertices[1]);

        // update the mesh vertex positions
        mesh.vertices = vertices;

        // Has to be done in order to update the bounding box culling
        mesh.RecalculateBounds();
    }
}

修改

更改问题后:在这种情况下,您实际上并不需要可视平面,而是如前所述创建纯数学构造

After you changed the question: In this case you don't really need the visual plane but as mentioned before create the purely mathematical construct Plane.

平面法线是始终与平面成90°的向量.然后,您可以使用 Vector3.Angle ,以获取 normal 和您的红色矢量(在target1target4之间说).像

The planes normal is a vector standing always 90° to the plane. You then can use e.g. Vector3.Angle in order to get the angular difference between the normal and your red vector (lets say between target1 and target4). Something like

#if UNITY_EDITOR
using UnityEditor;
#endif
using UnityEngine;

public class AngleChecker : MonoBehaviour
{
    [Header("Input")]

    public Transform target1;
    public Transform target2;
    public Transform target3;
    public Transform target4;

    [Header("Output")]
    public float AngleOnPlane;

    private void Update()
    {
        AngleOnPlane = GetAngle();
    }

    private float GetAngle()
    {
        // get the plane (green line/area)
        var plane = new Plane(target1.position, target2.position, target3.position);

        // get the red vector
        var vector = target4.position - target1.position;

        // get difference
        var angle = Vector3.Angle(plane.normal, vector);

        // since the normal itself stands 90° on the plane
        return 90 - angle;
    }

#if UNITY_EDITOR
    // ONLY FOR VISUALIZATION
    private void OnDrawGizmos()
    {
        // draw the plane
        var mesh = new Mesh
        {
            vertices = new[]
            {
                target1.position,
                target2.position,
                target3.position,
                target3.position + (target1.position - target2.position)
            },
            triangles = new[] {
                0, 1, 2,
                0, 2, 3,
                1, 0, 2,
                0, 3, 2
            }
        };
        mesh.RecalculateNormals();
        Gizmos.color = Color.white;
        Gizmos.DrawMesh(mesh);

        // draw the normal at target1
        var plane = new Plane(target1.position, target2.position, target3.position);
        Gizmos.color = Color.blue;
        Gizmos.DrawRay(target1.position, plane.normal);

        Handles.Label(target1.position + plane.normal, "plane normal");

        // draw the red vector
        Gizmos.color = Color.red;
        Gizmos.DrawLine(target1.position, target4.position);

        Handles.Label(target4.position , $"Angle to plane: {90 - Vector3.Angle(plane.normal, target4.position - target1.position)}");
    }
#endif
}

发表评论后,我想要看到您,使其也可以在场景中看到. 因此,我们也回到了答案的第一部分中.

After your comment I see you want to make it also visible in the scene. So we are back to also the first part of my answer where exactly this was done.

通过合并前面提到的脚本,只需将可见平面也添加到场景中.

Simply add the visible plane to the scene as well by merging both before mentioned scripts.

为了使文本可视化,我建议您阅读 Unity UI手册.

For making the text visual I recommend to go through the Unity UI Manual.

要使该行显示,有两个选项.您可以使用 LineRenderer (

For making the line appear there are two options. You can either use a LineRenderer (API) or simply use a cube your rotate and scale accordingly:

// ! UNCOMMENT THIS IF YOU RATHER WANT TO USE THE LINERENDERER !
//#define USE_LINERENDERER

using UnityEngine;
using UnityEngine.UI;

[RequireComponent(typeof(MeshFilter))]
[RequireComponent(typeof(MeshRenderer))]
public class PlaneController : MonoBehaviour
{
    [Header("Input")]

    // Reference these in the Inspector
    public Transform target1;
    public Transform target2;
    public Transform target3;
    public Transform target4;

    [Space]

    public MeshFilter meshFilter;

    [Header("Output")]
    public float AngleOnPlane;

    public Text angleText;
    public float lineWith = 0.05f;

#if USE_LINERENDERER
    public LineRenderer lineRenderer;
#else
    public MeshRenderer cubeLine;
#endif

    private Mesh mesh;
    private Vector3[] vertices;
    private Vector3 redLineDirection;

    // if using line renderer
    private Vector3[] positions = new Vector3[2];

    private void Start()
    {
        InitializePlaneMesh();

#if USE_LINERENDERER
        InitializeLineRenderer();
#endif
    }

    // Update is called once per frame
    private void Update()
    {
        // update the plane mesh
        UpdatePlaneMesh();

        // update the angle value
        UpdateAngle();
#if USE_LINERENDERER
        // update the line either using the line renderer
        UpdateLineUsingLineRenderer();
#else
        // update the line rather using a simple scaled cube instead
        UpdateLineUsingCube();
#endif
    }

    private void InitializePlaneMesh()
    {
        if (!meshFilter) meshFilter = GetComponent<MeshFilter>();

        mesh = meshFilter.mesh;

        vertices = new Vector3[4];

        // Set the 4 triangles (front and backside)
        // using the 4 vertices
        var triangles = new int[3 * 4];

        // triangle 1 - ABC
        triangles[0] = 0;
        triangles[1] = 1;
        triangles[2] = 2;
        // triangle 2 - ACD
        triangles[3] = 0;
        triangles[4] = 2;
        triangles[5] = 3;

        // triangle 3 - BAC
        triangles[6] = 1;
        triangles[7] = 0;
        triangles[8] = 2;
        // triangle 4 - ADC
        triangles[9] = 0;
        triangles[10] = 3;
        triangles[11] = 2;

        mesh.vertices = vertices;
        mesh.triangles = triangles;
    }

#if USE_LINERENDERER
    private void InitializeLineRenderer()
    {
        lineRenderer.positionCount = 2;
        lineRenderer.startWidth = lineWith;
        lineRenderer.endWidth = lineWith;
        lineRenderer.loop = false;
        lineRenderer.alignment = LineAlignment.View;
        lineRenderer.useWorldSpace = true;
    }
#endif

    private void UpdatePlaneMesh()
    {
        // build triangles according to target positions
        vertices[0] = target1.position - transform.position; // A
        vertices[1] = target2.position - transform.position; // B
        vertices[2] = target3.position - transform.position; // C

        // D = A  + B->C
        vertices[3] = vertices[0] + (vertices[2] - vertices[1]);

        // update the mesh vertex positions
        mesh.vertices = vertices;

        // Has to be done in order to update the bounding box culling
        mesh.RecalculateBounds();
    }

    private void UpdateAngle()
    {
        // get the plane (green line/area)
        var plane = new Plane(target1.position, target2.position, target3.position);

        // get the red vector
        redLineDirection = target4.position - target1.position;

        // get difference
        var angle = Vector3.Angle(plane.normal, redLineDirection);

        // since the normal itself stands 90° on the plane
        AngleOnPlane = Mathf.Abs(90 - angle);

        // write the angle value to a UI Text element
        angleText.text = $"Impact Angle = {AngleOnPlane:F1}°";

        // move text to center of red line and a bit above it
        angleText.transform.position = (target1.position + target4.position) / 2f + Vector3.up * 0.1f;

        // make text always face the user (Billboard)
        // using Camera.main here is not efficient! Just for the demo
        angleText.transform.forward = Camera.main.transform.forward;
    }

#if USE_LINERENDERER
    private void UpdateLineUsingLineRenderer()
    {
        positions[0] = target1.position;
        positions[1] = target4.position;

        lineRenderer.SetPositions(positions);
    }
#else
    private void UpdateLineUsingCube()
    {
        // simply rotate the cube so it is facing in the line direction
        cubeLine.transform.forward = redLineDirection.normalized;

        // scale it to match both target positions with its ends
        cubeLine.transform.localScale = new Vector3(lineWith, lineWith, redLineDirection.magnitude);

        // and move it to the center between both targets
        cubeLine.transform.position = (target1.position + target4.position) / 2f;
    }
#endif
}

使用LineRenderer的结果

Result using the LineRenderer

使用看起来几乎相同的立方体的结果

Result using the cube which looks almost the same

这篇关于您可以根据vuforia目标图像创建飞机吗?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆