您可以根据vuforia目标图像创建飞机吗? [英] Can you create a plane from vuforia target images?
问题描述
如下图所示,我有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个坐标来创建平行图拐角A
,B
和C
,然后通过将向量B
→ C
添加到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 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();
}
}
修改
更改问题后:在这种情况下,您实际上并不需要可视平面,而是如前所述创建纯数学构造
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
和您的红色矢量(在target1
和target4
之间说).像
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屋!