我試圖找到向量或角度,以計算兩條“粗”線相交的點。最終目標是為粗線渲染器繪制簡單的平面。
盡管我正在使用 Unity 并且正在使用 Vector3,但出于我的目的,假設 Z 值始終為 0。這是一個二維問題。這不是Unity 特定的問題,我不確定為什么我很難找到我能理解的解決方案。獲得繪制“粗”線的分數肯定不是什么新鮮事。但是對于我的生活,我找不到解決方案。
我最接近的是找出垂直于我想要的線的點。我知道這是“反彈”線。換句話說,假設中間點是臺球桌側面的撞擊點,我可以通過 3 個點獲得表示臺球桌側面的線的向量。我想要的是垂直于那條邊的向量。我根據這里的帖子計算出下面的代碼:

uj5u.com熱心網友回復:
不是 100% 確定這里的預期邏輯,但在你的代碼中對我來說似乎很棘手的部分是這樣的:
Vector3 n1 = (p2 - p1).normalized;
Vector3 n2 = (p3 - p2).normalized;
在這里,您將獲得一條線的法線和另一條線的反轉法線,然后將它們相加。這會導致您描述的“彈跳墻”線,因為您在交叉點上鏡像了一個法線。你不是說:
Vector3 n1 = (p3 - p2).normalized;
Vector3 n2 = (p1 - p2).normalized;
當您通過解決該問題使標志相同時,兩條法線都位于交點的一側。將它們加在一起會導致 y 分量在某種程度上相互抵消,并且 x 分量位于交點的正確一側。繪制的藍線然后采用您想要的角度(紅色固定法線):

我用來做這個的代碼的完整修改版本:
using UnityEngine;
public class ThickLineRenderer : MonoBehaviour {
public Vector3 line1Start = new Vector3(-1, -1);
public Vector3 intersect = new Vector3(0, 0);
public Vector3 line2Start = new Vector3(-1, 1);
private void OnDrawGizmos() {
Vector3[] points = new Vector3[] { line1Start, intersect, line2Start };
Vector3 p1 = points[0];
Vector3 p2 = points[1];
Vector3 p3 = points[2];
Gizmos.color = Color.white;
Gizmos.DrawLine(p1, p2);
Gizmos.DrawLine(p2, p3);
Vector3 n1 = (p3 - p2).normalized;
Vector3 n2 = (p1 - p2).normalized;
Gizmos.color = Color.red;
Gizmos.DrawLine(p2, n1);
Gizmos.DrawLine(p2, n2);
Vector3 n = (n1 n2).normalized;
Vector3 d = p2 n;
Vector3 d2 = p2 - n;
Gizmos.color = Color.blue;
Gizmos.DrawLine(p2, d);
Gizmos.DrawLine(p2, d2);
}
}
(對不起,我沒有完全正確的詞匯來描述這個問題,距三角學已經很長時間了。希望這是有道理的。)
uj5u.com熱心網友回復:
您好,我不確定我是否真的理解您要完成的任務,但對我而言,您的問題看起來像這樣,您得到了三個點 P1、P2、P3,并且您希望準確找到“法線角度”,即 P12 之間的黃色角度和 P23 線。
一種方法是計算絕對角度,這意味著 x 軸和每個線段之間形成的角度。在下圖中,它們是橙色和紫色的角度。然后減法會告訴你 P12 和 P23 之間形成的角度,這是綠色角度。最后,為了獲得我認為的所謂的“法線角”,它恰好位于綠色角的中間,在這種情況下,您只需要從較大的角減去綠色角的一半,即紫色角。

我做了一個簡單的控制臺程式來進行計算here'sthe code
using System;
namespace ConsoleApp1
{
class Program
{
public static double GetAbsAngle(double x, double y)
{
double radsAbsAngle;
//Get the absolute angle from respect to the x axis given a podouble x,y
if (y > 0)
{
radsAbsAngle = Math.Atan2(y, x);
return radsAbsAngle;
}
//Here Math.Atan2(y, x) will always result negative
radsAbsAngle = 2*Math.PI Math.Atan2(y, x);
return radsAbsAngle;
}
public static double AngleBetweenPoints(double x1, double y1, double x2, double y2)
{
double absAngleP1 = Program.GetAbsAngle(x1, y1);
Console.WriteLine("Abs angle P1 in degrees: {0}", Program.RadiansToDegrees(absAngleP1));
double absAngleP2 = Program.GetAbsAngle(x2, y2);
Console.WriteLine("Abs angle P2 in degrees: {0}", Program.RadiansToDegrees(absAngleP2));
double angleBetween;
angleBetween = (x1 > x2) ? absAngleP1 - absAngleP2 : absAngleP2 - absAngleP1;
return angleBetween;
}
public static double RadiansToDegrees(double radians)
{
double degrees = (180 / Math.PI) * radians;
return (degrees);
}
static void Main(string[] args)
{
//P1 with
double x1 = -4;
double y1 = 4;
//Assuming that P2 is always at 0,0
//P3 with
double x3 = -4;
double y3 = -4;
double angleBetween = Program.AngleBetweenPoints(x1, y1, x3, y3);
Console.WriteLine("Angle between P1 and P3 in degrees: {0}",Program.RadiansToDegrees(angleBetween));
double p1Angle = Program.GetAbsAngle(x1, y1);
double p3Angle = Program.GetAbsAngle(x3, y3);
double absNormalAngle = (p1Angle > p3Angle) ? p1Angle - (angleBetween/ 2) : p3Angle - (angleBetween / 2);
Console.WriteLine("The normal abs angle between P1 and P3 in degrees: {0}", Program.RadiansToDegrees(absNormalAngle));
}
}
}
結果如下
Abs angle P1 in degrees: 135
Abs angle P2 in degrees: 225
Angle between P1 and P3 in degrees: 90
The normal abs angle between P1 and P3 in degrees: 180
uj5u.com熱心網友回復:
我為 nonce 提出了一個解決方案,該解決方案依賴于使用平行線和線交點來找到繪制“粗”線所需的角點。
我并不完全相信這是正確的方法,并且愿意接受更好的答案(或編輯這個答案)。然而,我希望一個有效的答案將有助于產生更好的答案。
下圖顯示了我的最終結果。是的,如果 p1 == p3 有明顯的問題。銳角同樣會引起問題。但是,目前這適用于我的用例。
using System;
using System.Collections.Generic;
using UnityEngine;
[RequireComponent(typeof(MeshRenderer))]
[RequireComponent(typeof(MeshFilter))]
public class OutlineRenderer : MonoBehaviour {
//Add 5 GameObjects as children to this one at:
//0, 0, 0
//12, 4.5, 0
//10, -0.5, 0
//15, -6, 0
//2, -6, 0
public GameObject[] points;
private void OnDrawGizmos() {
//Hold a list of corner vertices alternating by left-right as the line progresses.
List<Vector2> corners = new List<Vector2>();
//For now, thickness is an inverse-multiplier.
//With a little extra math, it can be converted to a scalar unit.
float thickness = 1.5f;
//This logic is going to connect the line into a loop (which is my end use-case).
//For a straight line, modify the logic for the starting and ending vertices.
for (int i = 0; i < points.Length; i ) {
//The prev point. If p2 is index 0, then p1 is the last point in the list.
Vector3 p1 = i > 0 ? points[i - 1].transform.position : points[points.Length - 1].transform.position;
//The current point.
Vector3 p2 = points[i].transform.position;
float dist = Vector2.Distance(p1, p2);
float dx = p2.x - p1.x;
float dy = p2.y - p1.y;
dx /= dist * thickness;
dy /= dist * thickness;
Vector3 a = new Vector3(-dy p1.x, dx p1.y);
Vector3 b = new Vector3(dy p1.x, -dx p1.y);
Vector3 a2 = a new Vector3(dx, dy);
Vector3 b2 = b new Vector3(dx, dy);
//----------------------------------------
//The next point. If p2 is the last index, then p3 is the first point in the list.
Vector3 p3 = i < points.Length - 1 ? points[i 1].transform.position : points[0].transform.position;
dist = Vector2.Distance(p3, p2);
dx = p2.x - p3.x;
dy = p2.y - p3.y;
dx /= dist * thickness;
dy /= dist * thickness;
Vector3 c = new Vector3(dy p3.x, -dx p3.y);
Vector3 d = new Vector3(-dy p3.x, dx p3.y);
Vector3 c2 = c new Vector3(dx, dy);
Vector3 d2 = d new Vector3(dx, dy);
Vector2 i1 = findSegmentIntersection(a, a2, c, c2);
Vector2 i2 = findSegmentIntersection(b, b2, d, d2);
corners.Add(i1);
corners.Add(i2);
}
//Corners are the actual vertices I'm going to need.
//Draw logic (for Gizmos only).
//Mesh rendering is completely separate.
int n = corners.Count;
for (int i = 0; i < n - 2; i = 2) {
Vector3 p = points[i / 2].transform.position;
Gizmos.color = Color.blue;
Gizmos.DrawLine(p, corners[i]);
Gizmos.DrawLine(p, corners[i 1]);
Gizmos.color = Color.red;
Gizmos.DrawLine(corners[i], corners[i 2]);
Gizmos.DrawLine(corners[i 1], corners[i 3]);
}
Gizmos.color = Color.blue;
Gizmos.DrawLine(points[points.Length - 1].transform.position, corners[n - 2]);
Gizmos.DrawLine(points[points.Length - 1].transform.position, corners[n - 1]);
Gizmos.color = Color.red;
Gizmos.DrawLine(corners[n - 2], corners[0]);
Gizmos.DrawLine(corners[n - 1], corners[1]);
}
//A utility method I converted from ActionScript.
//There's probably something in the Unity library that can also do it.
public Vector2 findSegmentIntersection(Vector2 p1, Vector2 p2, Vector2 p3, Vector2 p4) {
var x1 = p1.x;
var x2 = p2.x;
var x3 = p3.x;
var x4 = p4.x;
var y1 = p1.y;
var y2 = p2.y;
var y3 = p3.y;
var y4 = p4.y;
var z1 = x1 - x2;
var z2 = x3 - x4;
var z3 = y1 - y2;
var z4 = y3 - y4;
var d = z1 * z4 - z3 * z2;
//If d is zero, there is no intersection.
if (d == 0) {
throw new Exception("Lines do not intersect!");
}
//Get the x and y.
var pre = x1 * y2 - y1 * x2;
var post = x3 * y4 - y3 * x4;
var x = (pre * z2 - z1 * post) / d;
var y = (pre * z4 - z3 * post) / d;
//Return the point of intersection.
return new Vector2(x, y);
}
}

轉載請註明出處,本文鏈接:https://www.uj5u.com/qiye/316210.html
上一篇:Unity2D-如何檢查我的游戲物件/精靈是否低于ceratinYlvl?
下一篇:Unity碰撞時受到傷害
