카테고리 없음

유니티로수학배우기_벡터의 내적

zelkova 2021. 4. 27. 10:15

<목차로 돌아가기>

 

내적

두 개의 벡터를 하나의 스칼라 양으로 변환하는 연산이다.

수식으로 표기하는 방법은 도트 연산자(·)를 이용하여 a·b로 표기할 수 있다.

내적이 추가된 벡터 공간은 내적공간이라고 한다.

 

내적이 추가된 벡터 공간은 내적공간이라고 한다.

두 변에 해당하는 벡터를 a, b라 하고 나머지 한변을 c라 할 때 다음과 같은 식이 성립한다.

c = a - b 이므로 아래의 공식을 도출할 수 있다.

 

여기에 삼각함수를 공식을 대입하면

 

다른 방식으로 생각할 수 있다.

위는 2D 벡터만 생각했으나 3D 벡터를 생각한다면.

 

유니티에서 사인과 코사인으로 대표되는 초월함수라 불리는 종류의 함수는 처리비용이 비싸므로 가능하면 성분표시를 사용해야한다.

 

백터의 직교 투영

직교투영이란 직관적으로 설명하면 빛이 닿았을 때 생기는 그림자 형태라고 생각하면 된다.

위으 그림을 아래와 같이 나타낼 수 있다.

 

a에서 b로 직교투영한 길이는 a와 단위벡터(정규화:normalize) b와의 내적으로 구해진다.

 

유니티는 Vector3에 정규화 프로퍼티 normalized와 직교투영을 구하는 Project메서드를 제공한다.

 

내적의 응용 COS 적용..

 

▷ a와 b가 완전히 같은 방향을 향할 때 

▷ θ가 90도보다 작을 때

▷수직일 때

θ가 90도와 180도 사이일 때

▷a와 b가 180도(반대)일 때

 

외적

두 개의 벡터에서 한 개의 스칼라를 생성하는 내적과 달리, 두 개의 벡터에서 새로운 한개의 벡터를 생성하는 연산이다.

 

2차원 벡터연산은 외적을 정의할 수  없고 3차원 이상의 벡터만 외적을 저의할 수 있다.

곱(wedge product)라는 개념을 도입하면 2차원 3차원 벡터의 외적을 다룰 수 있으나 이건 나중에 따로..

 

 

각도 θ를 이루는 벡터 a와 b의 외적과 그 크기는 크로스 연산자를 사용해 다음과 같이 정의할 수 있다.

u는 a와 b에 수직인 단위벡터다. 밑변이 길이가 ||b||이고 높이는 ||a||sinθ라 생각하면, 평행사변형 면적은 밑변의 길이에 높이를 곱해 구할 수 있다.

 

sinθ = 0 일 때, a xb는 영벡터가 딘다.

또한 a또는 b가 영벡터일 때도 a x b는 영벡터다.

 

외적과 내적과 다른 중요한 점은 교환법칙이 성립하지 앟는다는 점이다.

 

그대신 한쪽 벡터의 방향을 역으로 하면 교한할 수 있다.

외적에서는 곱하는 순서에 의미가 있다. 

외적의 정의에 나왔던 단위벡터 u가 그림에서는 위를 향하지만 b x a라는 연산을 하면 반대방향이 된다는 뜻이다.

그림에서는 위를 향하지만 b x a라는 연산을 하면 반대방햐이 된다는 뜻이다.

 

 

어느 좌표계를 사용하는지에 따라 방향이 바뀌는 벡터를 유사벡터 또는 축성벡터라 부르며 일반 벡터와는 구별된다.

좌표계가 변해도 방향이 변하지 않는 일반 벡터는 극성벡터라 한다.

 

외적에는 교환법칙 결합법칙은 성립하지 않지만, 스칼라를 이용한 곱셈과 분배법칙은 성립한다.

 

 

한편 벡터의 외적과 내적을 연관짓는 식은 벡터 삼중적이라고 한다.

 

이 식에서 a, b, c를 차례로 바꾼것을 더하면 다음 식을 얻을 수 있다.

이 식은 야코비 항등식으로 불리며 3차원 벡터의 외적의 성질을 나타낸다.

 

유니티에서는 Cross 메서드를 사용하면 외적을 계산할 수 있으므로 실제 손으로 외적을 계산하는 상황은 드물다.

 

외적의 응용

평만 바깥쪽에 있는지를 내적과 외적을 사용한다면 판정할 수 있다.

 

점 P가 삼각형 ABC 내부에 있는 경우, 각각의 변과 각 정점에서 점 P로 향한 직선과의 외적, 다시 말해 법선벡터는 같은 방향을 향한다.

 

점P가 삼각형 ABC 바깥쪽에 있으면, 안쪽에 있을 때와 달리 점 P에 근접한 변을 걸쳐서 점 P가 바깥쪽으로 나간 형태가 된다.

 

두 개의 벡터가 같은 방향인지 역방향인지는 내적을 이용하여 판정할 수 있다.

 

더보기
public class SINCOS_AroundCameraDrawLine : MonoBehaviour {

	public float rotateSpeed = 1f;
	public float scrollSpeed = 200f;

	public Transform pivot;

	[System.Serializable]
	public class SphericalCoordinates
	{
		public float _radius, _azimuth, _elevation;

		public float radius
		{ 
			get { return _radius; }
			private set
			{
				_radius = Mathf.Clamp( value, _minRadius, _maxRadius );
			}
		}

		public float azimuth
		{ 
			get { return _azimuth; }
			private set
			{ 
				_azimuth = Mathf.Repeat( value, _maxAzimuth - _minAzimuth ); 
			}
		}

		public float elevation
		{ 
			get{ return _elevation; }
			private set
			{ 
				_elevation = Mathf.Clamp( value, _minElevation, _maxElevation ); 
			}
		}

		public float _minRadius = 3f;
		public float _maxRadius = 20f;

		public float minAzimuth = 0f;
		private float _minAzimuth;

		public float maxAzimuth = 360f;
		private float _maxAzimuth;

		public float minElevation = 0f;
		private float _minElevation;

		public float maxElevation = 90f;
		private float _maxElevation;
		
		public SphericalCoordinates(){}
		
		public SphericalCoordinates(Vector3 cartesianCoordinate)
		{
			_minAzimuth = Mathf.Deg2Rad * minAzimuth;
			_maxAzimuth = Mathf.Deg2Rad * maxAzimuth;

			_minElevation = Mathf.Deg2Rad * minElevation;
			_maxElevation = Mathf.Deg2Rad * maxElevation;

			radius = cartesianCoordinate.magnitude;
			azimuth = Mathf.Atan2(cartesianCoordinate.z, cartesianCoordinate.x);
			elevation = Mathf.Asin(cartesianCoordinate.y / radius);
		}
		
		public Vector3 toCartesian
		{
			get
			{
				float t = radius * Mathf.Cos(elevation);
				return new Vector3(t * Mathf.Cos(azimuth), radius * Mathf.Sin(elevation), t * Mathf.Sin(azimuth));
			}
		}
		
		public SphericalCoordinates Rotate(float newAzimuth, float newElevation){
			azimuth += newAzimuth;
			elevation += newElevation;
			return this;
		}
		
		public SphericalCoordinates TranslateRadius(float x) {
			radius += x;
			return this;
		}
	}
	
	public SphericalCoordinates sphericalCoordinates;

	private List<Vector3> triangleVertices = new List<Vector3>();

	// Use this for initialization
	void Start () {
		sphericalCoordinates = new SphericalCoordinates(transform.position);
		transform.position = sphericalCoordinates.toCartesian + pivot.position;

		Mesh mesh = pivot.gameObject.GetComponent<MeshFilter>().mesh;
		for (int i = 0; i < mesh.vertices.Length; i++)
		{
			if (triangleVertices.Count < 3) {
				triangleVertices.Add(mesh.vertices[i]);
			}
		}
	}

	// Update is called once per frame
	void Update () {
		DrawCameraLine ();

		float kh, kv, mh, mv, h, v;
		kh = Input.GetAxis( "Horizontal" );
		kv = Input.GetAxis( "Vertical" );
		
		bool anyMouseButton = Input.GetMouseButton(0) | Input.GetMouseButton(1) | Input.GetMouseButton(2);
		mh = anyMouseButton ? Input.GetAxis( "Mouse X" ) : 0f;
		mv = anyMouseButton ? Input.GetAxis( "Mouse Y" ) : 0f;
		
		h = kh * kh > mh * mh ? kh : mh;
		v = kv * kv > mv * mv ? kv : mv;
		
		if (h * h > Mathf.Epsilon || v * v > Mathf.Epsilon) {
			transform.position
				= sphericalCoordinates.Rotate(h * rotateSpeed * Time.deltaTime, v * rotateSpeed * Time.deltaTime).toCartesian + pivot.position;
		}

		float sw = -Input.GetAxis("Mouse ScrollWheel");
		if (sw * sw > Mathf.Epsilon) {
			transform.position = sphericalCoordinates.TranslateRadius(sw * Time.deltaTime * scrollSpeed).toCartesian + pivot.position;
		}

		transform.LookAt(pivot.position);
	}

	void DrawCameraLine() {
		Debug.DrawLine(pivot.position, pivot.transform.forward * 2, Color.blue);
		
		Vector3 cameraPoint = transform.position + transform.forward * 5;
		
		Vector3 edge1 = triangleVertices [1] - triangleVertices [0];
		Vector3 edge2 = cameraPoint - triangleVertices [1];
		
		Vector3 edge3 = triangleVertices [2] - triangleVertices [1];
		Vector3 edge4 = cameraPoint - triangleVertices [2];
		
		Vector3 edge5 = triangleVertices [0] - triangleVertices [2];
		Vector3 edge6 = cameraPoint - triangleVertices [0];
		
		Vector3 cp1 = Vector3.Cross (edge1, edge2);
		Vector3 cp2 = Vector3.Cross (edge3, edge4);
		Vector3 cp3 = Vector3.Cross (edge5, edge6);

		if (Vector3.Dot (cp1, cp2) > 0 && Vector3.Dot (cp1, cp3) > 0) {
			Debug.DrawLine (transform.position, cameraPoint, Color.red);
		} else {
			Debug.DrawLine (transform.position, cameraPoint, Color.green);
		}
	}
}

 

 

 

 

 

 

 

내적의 증명 및 유도 2

 

삼각함수는 값이 비싸기 때문에 각각 곱해서 더한것으로 주로 사용하고

쉐이더와 같이 내적의 성질을 이용할 때는 COS θ를 이용한 방식을 사용

 

내적 = 벡터의 곱셈

 

내적(벡터곱셈)의 값은 스칼라

 

우선 분배법칙을 생각하고.

아래에 적용하면 ... 요렇게 도출됨.

 

어디에 사용되면..

한 지점과의 각도의 수치를 알아볼 수 있음

 

Vector3.Dot(Vector1, Vector2)

Vector1과 Vector2가 같은 방향이면 1

직각이면 0

반대 방향이면 -1 

 

2. Shaer계산할때 사용함.

이건 동영상 보는게 더 빠름 : 링크 

빛이 닿는 면적 

1 / cosθ

 

빛이 닿는 면적의 밝기

cosθ

 

내적의 증명 및 유도 3

 

내적의 증명 및 유도 4

 

 

반응형