対面判定
https://youtu.be/NPCLKAvQ7bs
face1とface2にお互いの顔に相当するオブジェクトを配置し、お互いが向き合った(逸れた)タイミングでOnIntersectChangeイベントが発生する。
サンプルの動画ではMMDの顔部分に透明なCubeを後から配置している。
ロジックは以下の通り
相対距離が一定数値以下か
face1, face2で互いに以下を計算する
自分の位置から相手へのlook方向を計算
現在の向いている方向との差分を角度で出す
差分角度が一定数値以下なら「向いている」と判断する
code:c#
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Events;
public class GazeIntersectEvent : UnityEvent<bool>
{
}
public class GazeIntersectChecker : MonoBehaviour {
public Transform face1;
public Transform face2;
public float maxDintace = 1.30f;
public float maxAngle = 40.0f;
public GazeIntersectEvent OnIntersectChange;
private bool prevState = false;
// Use this for initialization
void Start () {
}
// Update is called once per frame
void Update () {
bool newState = false;
// お互いが一定距離内か確認
var pos1 = face1.position;
var pos2 = face2.position;
float magnitude = (pos1 - pos2).sqrMagnitude;
if( magnitude > maxDintace * maxDintace) {
if(newState != prevState){
Debug.Log("intersect change");
OnIntersectChange.Invoke(newState);
}
prevState = newState;
return;
}
//Debug.Log("near");
/*
それぞれのオブジェクトごとに
・相手に向かう時のdirectionを計算
・現在の向きとの差分を出す
・差分が一定数値以下なら「向いている」と判断する
*/
if (CheckFaceToFace(face1,face2)) {
if (CheckFaceToFace(face2,face1)) {
//Debug.Log("intersect");
newState = true;
}
}
if(newState != prevState){
Debug.Log("intersect change");
OnIntersectChange.Invoke(newState);
}
prevState = newState;
}
bool CheckFaceToFace(Transform f1, Transform f2)
{
var lookat = GetLookAt(f1.position, f2.position);
var rot = f1.rotation;
var angle = Quaternion.Angle(lookat, rot);
//Debug.Log("angle:" + angle);
//検証用:
//f1.rotation = lookat;
return angle < maxAngle;
}
private Quaternion GetLookAt(Vector3 myPos, Vector3 target)
{
Vector3 z = (target - myPos).normalized;
Vector3 x = Vector3.Cross(Vector3.up, z).normalized;
Vector3 y = Vector3.Cross(z, x).normalized;
Matrix4x4 m = Matrix4x4.identity;
Quaternion rot = GetRotation(m);
//transform.rotation = rot;
return rot;
}
private Quaternion GetRotation(Matrix4x4 m)
{
float[] elem = new float4; elem0 = m.m00 - m.m11 - m.m22 + 1.0f; elem1 = -m.m00 + m.m11 - m.m22 + 1.0f; elem2 = -m.m00 - m.m11 + m.m22 + 1.0f; elem3 = m.m00 + m.m11 + m.m22 + 1.0f; int biggestIdx = 0;
for (int i = 0; i < elem.Length; i++)
{
{
biggestIdx = i;
}
}
{
Debug.Log("Wrong matrix.");
return new Quaternion();
}
float mult = 0.25f / v;
switch (biggestIdx)
{
case 0:
q1 = (m.m10 + m.m01) * mult; q2 = (m.m02 + m.m20) * mult; q3 = (m.m21 - m.m12) * mult; break;
case 1:
q0 = (m.m10 + m.m01) * mult; q2 = (m.m21 + m.m12) * mult; q3 = (m.m02 - m.m20) * mult; break;
case 2:
q0 = (m.m02 + m.m20) * mult; q1 = (m.m21 + m.m12) * mult; q3 = (m.m10 - m.m01) * mult; break;
case 3:
q0 = (m.m21 - m.m12) * mult; q1 = (m.m02 - m.m20) * mult; q2 = (m.m10 - m.m01) * mult; break;
}
return new Quaternion(q0, q1, q2, q3); }
}