Unity3D 연구원의 주역면이 일정한 구역 내 대상 각도로 계산(45)

10346 단어 그래픽스unity3

Unity3D 연구원의 주역면이 일정한 구역 내의 대상 각도를 향해 계산(45)...


2013-3-4 13:30|발표자:chino|보기:1263|평론:1|원작자:MOMO
요약: 앞에 쓰인 말, 엊그저께 어떤 친구가 QQ에서 주인공이 일정한 구역을 향해 있는 적의 대상을 어떻게 얻느냐고 물었다.이 명제는 보기에는 간단해 보이지만, 사실 그 안에는 수학 방면의 많은 것들이 포함되어 있다.오늘 마침 시간이 나서 나는 이 의문을 블로그에 철저히 썼다.그를 도울 수 있기를 바랍니다.... 에 있다
앞에 적힌 말, 엊그저께 한 친구가 QQ에서 주인공이 일정한 구역을 향해 있는 적의 대상을 어떻게 얻느냐고 물었다.이 명제는 보기에는 간단해 보이지만, 사실 그 안에는 수학 방면의 많은 것들이 포함되어 있다.오늘 마침 시간이 나서 나는 이 의문을 블로그에 철저히 썼다.그를 도울 수 있기를 바랍니다.코드를 올리기 전에 여러분은 저와 함께 간단한 연습문제를 몇 개 푸세요. 각도 벡터의 계산은 반드시 배워야 합니다. 그렇지 않으면 뒤에 있는 것은 이해하기 어려울 것입니다.1. 3D 좌표와 회전 각도, 그리고 거리를 알고 목표점의 3D 좌표를 구한다.현재 점은 Target인 것으로 알고 있으며 타겟 점은 Target의 Y 축을 따라 30도 회전하고 Target의 X 축을 따라 10미터 확장하여 타겟 점의 3D 좌표를 구합니까?

[코드]:

using UnityEngine;
using System.Collections;

public class Test : MonoBehaviour
{

	public Transform Target;

	void LateUpdate ()
	{
		Quaternion rotation = Quaternion.Euler(0f,30f,0f) * Target.rotation;
		Vector3  newPos = rotation * new Vector3(10f,0f,0f);
		Debug.DrawLine(newPos,Vector3.zero,Color.red);
		Debug.Log("newpos " + newPos +" nowpos " + Target.position + " distance " + Vector3.Distance(newPos,Target.position));
	}

}
출력 결과: 새 좌표(8.7,0.0,-5.0) 현재 좌표(0.0,0.0,0.0) 두 점 사이의 거리 10. 2.알려진 3D 모델의 각도는 벡터입니다.알려진 3D 모델 Target은 Y축이 30도 회전한 후 앞으로 변환됩니다.

[코드]:

using UnityEngine;
using System.Collections;

public class Test : MonoBehaviour
{

	public Transform Target;

	void LateUpdate ()
	{

		if(Input.GetMouseButton(0))
		{
			Quaternion rotation = Quaternion.Euler(0f,30f,0f) * Target.rotation;
			Vector3  newPos = rotation * Vector3.forward;
			Target.Translate(newPos.x,newPos.y,newPos.z);
		}
	}

}
 3.이미 알고 있는 목표점은 모델을 이 목표점을 향해 이동하게 한다.이것은 비교적 간단한 예로 모두가 분명히 볼 수 있을 것이다.

[코드]:

Target.transform.LookAt(new Vector3 (100f,200f,300f));
		Target.Translate(Vector3.forward);
여기서 내가 말하고자 하는 것은 바로 Vector3.forward, 그 등가는 new Vector3(0,0,1)과 같다.이것은 좌표가 아니라 Z축을 따라 앞으로 향하는 표준 벡터입니다.Vector 3.forward*100 그러면 한 번에 평이하게 이동하는 거리가 100미터입니다.다음 코드를 볼게요.

[코드]:

Vector3 vecn = (TargetCube.position - Target.position).normalized;

		Target.Translate(vecn *0.1f);
벡터로 벡터를 빼서 그것들의 차이를 구하면,normalized는 포맷 벡터로 그들 사이의 벡터를 1미터로 포맷하는 것을 의미한다.이렇게 하면 한 번의 평이 거리를 더욱 정확하게 계산할 수 있다.vecn*0.1f는 한 번의 평이 1분 미터, 조개를 표시한다.벡터는 X Y Z축뿐만 아니라 회전도 가능하며 다음 코드는 벡터를 Y축을 따라 30도 회전시키는 것입니다.

[코드]:

Vector3 vecn = (TargetCube.position - Target.position).normalized;

	vecn = Quaternion.Euler(0f,30f,0f) * vecn;

	Target.Translate(vecn *0.1f);
만약 상술한 세 개의 간단한 연습 문제를 네가 모두 이해할 수 있다면 본문의 가장 큰 난제는 어렵지 않을 거라고 나는 믿는다. 계속 읽어라.만약 우리가 주인공 앞에 있는 5미터 내의 모든 대상을 계산해야 한다고 가정할 때.주인공을 원심으로 앞의 5미터 밖의 점을 계산하여 여러분들이 똑똑히 볼 수 있도록 제가 지금 이 선을 그렸습니다.

[코드]:

private float distance = 5f;
void Update () 
{
	Quaternion r= transform.rotation;
	Vector3 f0 =  (transform.position  + (r *Vector3.forward) * distance);
	Debug.DrawLine(transform.position,f0,Color.red);
}
아래의 그림에서 우리는 이미 이 두 점을 계산해 냈다.이때 당신은 주인공 Y축의 좌표를 동태적으로 편집할 수 있습니다. 이 점은 영원히 주인공의 현재 각도 앞에서 5미터 떨어진 점입니다.이어서 우리는 주인공 앞에 있는 발산적인 각도를 계산해야 한다.주인공이 본 것이 왼쪽 30도, 오른쪽 30도라고 가정하면 이 구역에 있다.

[코드]:

private float distance = 5f;
void Update () 
{
	Quaternion r= transform.rotation;
	Vector3 f0 =  (transform.position  + (r *Vector3.forward) * distance);
	Debug.DrawLine(transform.position,f0,Color.red);

	Quaternion r0= Quaternion.Euler(transform.rotation.eulerAngles.x,transform.rotation.eulerAngles.y - 30f,transform.rotation.eulerAngles.z);
	Quaternion r1= Quaternion.Euler(transform.rotation.eulerAngles.x,transform.rotation.eulerAngles.y + 30f,transform.rotation.eulerAngles.z);

	Vector3 f1 =  (transform.position  + (r0 *Vector3.forward) * distance);
	Vector3 f2 =  (transform.position  + (r1 *Vector3.forward) * distance);

	Debug.DrawLine(transform.position,f1,Color.red);
	Debug.DrawLine(transform.position,f2,Color.red);

	Debug.DrawLine(f0,f1,Color.red);
	Debug.DrawLine(f0,f2,Color.red);
}
다음 그림에서 보듯이 이때 주인공 앞에 있는 구역이 계산되었다.보기에 두 삼각형 사이의 구역이다.마지막으로 간단한 공식을 적용하여 하나의 점이 삼각형 안에 있는지 계산하는 것이다. 본고에서 적의 점이 앞에 있는 두 삼각형 안에 있는지 계산하는 것이다.

[코드]:

using UnityEngine;
using System.Collections;

public class MyTest : MonoBehaviour {

	public Transform cube;

	private float distance = 5f;
	void Update () 
	{
		Quaternion r= transform.rotation;
		Vector3 f0 =  (transform.position  + (r *Vector3.forward) * distance);
		Debug.DrawLine(transform.position,f0,Color.red);

		Quaternion r0= Quaternion.Euler(transform.rotation.eulerAngles.x,transform.rotation.eulerAngles.y - 30f,transform.rotation.eulerAngles.z);
		Quaternion r1= Quaternion.Euler(transform.rotation.eulerAngles.x,transform.rotation.eulerAngles.y + 30f,transform.rotation.eulerAngles.z);

		Vector3 f1 =  (transform.position  + (r0 *Vector3.forward) * distance);
		Vector3 f2 =  (transform.position  + (r1 *Vector3.forward) * distance);

		Debug.DrawLine(transform.position,f1,Color.red);
		Debug.DrawLine(transform.position,f2,Color.red);

		Debug.DrawLine(f0,f1,Color.red);
		Debug.DrawLine(f0,f2,Color.red);

		Vector3 point = cube.position;

		if(isINTriangle(point,transform.position,f1,f0) || isINTriangle(point,transform.position,f2,f0) )
		{
			Debug.Log("cube in this !!!");
		}else 
		{
			Debug.Log("cube not in this !!!");
		}

	}

	private  float triangleArea(float v0x,float v0y,float v1x,float v1y,float v2x,float v2y) 
	{
        return Mathf.Abs((v0x * v1y + v1x * v2y + v2x * v0y
            - v1x * v0y - v2x * v1y - v0x * v2y) / 2f);
    }

	bool isINTriangle(Vector3 point,Vector3 v0,Vector3 v1,Vector3 v2)
	{
		float x = point.x;
		float y = point.z;

		float v0x = v0.x;
		float v0y = v0.z;

		float v1x = v1.x;
		float v1y = v1.z;

		float v2x = v2.x;
		float v2y = v2.z;

		float t = triangleArea(v0x,v0y,v1x,v1y,v2x,v2y);
		float a = triangleArea(v0x,v0y,v1x,v1y,x,y) + triangleArea(v0x,v0y,x,y,v2x,v2y) + triangleArea(x,y,v1x,v1y,v2x,v2y);

		if (Mathf.Abs(t - a) <= 0.01f) 
		{
			return true;
		}else 
		{
			return false;
		}
	}
}
아래 그림에서 보듯이 상자 대상이 주인공의 시야에서 검출된다.위의 그림에서 나의 시야는 두 개의 삼각형을 선택했다. 만약에 시야 목표점이 타원형이라면 삼각형을 많이 설정할 수 있다.그러나 이렇게 하면 효율을 매우 소모할 수 있다. 나는 이곳에서 삼각형 1개를 충분히 사용할 수 있다고 생각한다. 단지 옳은 목표점에 약간의 편차가 생길 뿐 영향은 크지 않을 것이다.아래 그림에서 보듯이 코드를 간단하게 수정하면 된다.

[코드]:

using UnityEngine;
using System.Collections;

public class MyTest : MonoBehaviour {

	public Transform cube;

	private float distance = 5f;
	void Update () 
	{
		Quaternion r= transform.rotation;
		Vector3 f0 =  (transform.position  + (r *Vector3.forward) * distance);
		Debug.DrawLine(transform.position,f0,Color.red);

		Quaternion r0= Quaternion.Euler(transform.rotation.eulerAngles.x,transform.rotation.eulerAngles.y - 30f,transform.rotation.eulerAngles.z);
		Quaternion r1= Quaternion.Euler(transform.rotation.eulerAngles.x,transform.rotation.eulerAngles.y + 30f,transform.rotation.eulerAngles.z);

		Vector3 f1 =  (transform.position  + (r0 *Vector3.forward) * distance);
		Vector3 f2 =  (transform.position  + (r1 *Vector3.forward) * distance);

		Debug.DrawLine(transform.position,f1,Color.red);
		Debug.DrawLine(transform.position,f2,Color.red);
		Debug.DrawLine(f1,f2,Color.red);

		Vector3 point = cube.position;

		if(isINTriangle(point,transform.position,f1,f2))
		{
			Debug.Log("cube in this !!!");
		}else 
		{
			Debug.Log("cube not in this !!!");
		}

	}

	private  float triangleArea(float v0x,float v0y,float v1x,float v1y,float v2x,float v2y) 
	{
        return Mathf.Abs((v0x * v1y + v1x * v2y + v2x * v0y
            - v1x * v0y - v2x * v1y - v0x * v2y) / 2f);
    }

	bool isINTriangle(Vector3 point,Vector3 v0,Vector3 v1,Vector3 v2)
	{
		float x = point.x;
		float y = point.z;

		float v0x = v0.x;
		float v0y = v0.z;

		float v1x = v1.x;
		float v1y = v1.z;

		float v2x = v2.x;
		float v2y = v2.z;

		float t = triangleArea(v0x,v0y,v1x,v1y,v2x,v2y);
		float a = triangleArea(v0x,v0y,v1x,v1y,x,y) + triangleArea(v0x,v0y,x,y,v2x,v2y) + triangleArea(x,y,v1x,v1y,v2x,v2y);

		if (Mathf.Abs(t - a) <= 0.01f) 
		{
			return true;
		}else 
		{
			return false;
		}
	}
}
위에서 우리가 삼각형 판단을 소개했는데 당연히 직사각형을 통해 교차 여부를 판단할 수 있다.코드:

[코드]:

using UnityEngine;
using System.Collections;

public class MyTest : MonoBehaviour {

	public Transform cube;

	private float distance = 5f;
	void Update () 
	{
		Quaternion r= transform.rotation;
		Vector3 left =  (transform.position  + (r *Vector3.left) * distance);
		Debug.DrawLine(transform.position,left,Color.red);

		Vector3 right =  (transform.position  + (r *Vector3.right) * distance);
		Debug.DrawLine(transform.position,right,Color.red);

		Vector3 leftEnd = (left  + (r *Vector3.forward) * distance);
		Debug.DrawLine(left,leftEnd,Color.red);

		Vector3 rightEnd = (right  + (r *Vector3.forward) * distance);
		Debug.DrawLine(right,rightEnd,Color.red);

		Debug.DrawLine(leftEnd,rightEnd,Color.red);

		Vector3 point = cube.position;

		if(isINRect(point,leftEnd,rightEnd,right,left))
		{
			Debug.Log("cube in this !!!");
		}else 
		{
			Debug.Log("cube not in this !!!");
		}

	}

     private float Multiply(float p1x , float p1y, float p2x,float p2y, float p0x,float p0y)
     {
        return ((p1x - p0x) * (p2y - p0y) - (p2x - p0x) * (p1y - p0y));
     }

	bool isINRect(Vector3 point,Vector3 v0,Vector3 v1,Vector3 v2,Vector3 v3)
	{
		float x = point.x;
		float y = point.z;

		float v0x = v0.x;
		float v0y = v0.z;

		float v1x = v1.x;
		float v1y = v1.z;

		float v2x = v2.x;
		float v2y = v2.z;

		float v3x = v3.x;
		float v3y = v3.z;

		if (Multiply(x,y, v0x,v0y, v1x,v1y) * Multiply(x,y, v3x,v3y, v2x,v2y) <= 0 && Multiply(x,y, v3x,v3y, v0x,v0y) * Multiply(x,y, v2x,v2y, v1x,v1y) <= 0)
             return true;
		else
            return false;

	}

}

좋은 웹페이지 즐겨찾기