Can you create a plane from vuforia target images? [closed]

不羁岁月 提交于 2019-12-24 12:44:23

问题


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:


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

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.

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.

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 B→C 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();
    }
}


Edit

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.

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.

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

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
}

Result using the LineRenderer

Result using the cube which looks almost the same



来源:https://stackoverflow.com/questions/57423931/can-you-create-a-plane-from-vuforia-target-images

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!