用于Blinn-Phong光照模型的半角向量可视化工具
效果图
半角向量和法线重叠时,为最亮, 此时夹角为0, dot(normal, halfDir)=1
using UnityEngine; [RequireComponent(typeof(MeshFilter))] public class ShowHalfDirTool : MonoBehaviour { #if UNITY_EDITOR private static int s_InstIcr; private int m_InstId; public Transform m_Light; //光源 public Transform m_Viewer; //观察点 public float m_HalfDirLength = 2; public bool m_ShowLines = false; public int m_VertIndex; //442,490,497,494 public Color m_LightDirColor = Color.red; public Color m_ViewDirColor = Color.green; public Color m_HalfDirColor = Color.blue; public Color m_NormalColor = Color.yellow; public float m_HalfDirNormalAngle; public float m_HalfDirNormalPow; private Mesh m_Mesh; private MeshFilter m_MF; private Vector3[] m_Verts; private Vector3[] m_Normals; public ShowHalfDirTool() { m_InstId = s_InstIcr++; } private void Awake() { if (null == m_Light.GetComponent<Light>()) Debug.LogError("m_Light no Light Component"); if (null == m_Viewer.GetComponent<Camera>()) Debug.LogError("m_Viewer no Camera Component"); } private void Update() { if (!m_ShowLines || null == m_Light || null == m_Viewer) return; if (0 == m_InstId && Input.GetKeyDown(KeyCode.Alpha1)) { //与Viewr在同一个y-z平面的 Debug.Log($"----- y-z"); for (int i = 0; i < m_Mesh.vertexCount; i++) { var wPos = m_MF.transform.TransformPoint(m_Verts[i]); var viewDir = m_Viewer.position - wPos; if (Mathf.Abs(viewDir.x) <= 0.001f) Debug.Log($"{i}"); } Debug.Log($"-----"); Debug.Log($"----- x-z"); for (int i = 0; i < m_Mesh.vertexCount; i++) { var wPos = m_MF.transform.TransformPoint(m_Verts[i]); var viewDir = m_Viewer.position - wPos; if (Mathf.Abs(viewDir.y) <= 0.001f) Debug.Log($"{i}"); } Debug.Log($"-----"); } } private void CheckMFInit() { if (null == m_MF) { m_MF = GetComponent<MeshFilter>(); m_Mesh = m_MF.sharedMesh; m_Verts = m_Mesh.vertices; m_Normals = m_Mesh.normals; } } private void OnDrawGizmos() { if (!m_ShowLines || null == m_Light || null == m_Viewer) return; CheckMFInit(); //Gizmos.matrix = m_MF.transform.localToWorldMatrix; //Gizmos.matrix = m_MF.transform.worldToLocalMatrix; var colorBak = Gizmos.color; int len = m_Mesh.vertexCount; for (int i = 0; i < len; i++) { if (m_VertIndex == i) { DrawLines(i); } } Gizmos.color = colorBak; } void DrawLines(int i) { var wPos = m_MF.transform.TransformPoint(m_Verts[i]); var normalDir = m_Normals[i]; var lightDir = -m_Light.forward; lightDir.Normalize(); var lightDirLinePt2 = wPos + lightDir; Gizmos.color = m_LightDirColor; Gizmos.DrawLine(wPos, lightDirLinePt2); //光线方向 var viewDir = m_Viewer.position - wPos; viewDir.Normalize(); var viewDirLinePt2 = wPos + viewDir; Gizmos.color = m_ViewDirColor; Gizmos.DrawLine(wPos, viewDirLinePt2); //视角方向 Gizmos.color = Color.gray; Gizmos.DrawLine(viewDirLinePt2, viewDirLinePt2 + lightDir); //光线方向平行线 Gizmos.DrawLine(lightDirLinePt2, lightDirLinePt2 + viewDir); //视角方向平行线 var halfDir = lightDir + viewDir; halfDir.Normalize(); Gizmos.color = m_HalfDirColor; Gizmos.DrawLine(wPos, wPos + halfDir * m_HalfDirLength); //半角方向 Gizmos.color = m_NormalColor; Gizmos.DrawLine(wPos, wPos + normalDir); //法线 m_HalfDirNormalAngle = Vector3.Angle(normalDir, halfDir); m_HalfDirNormalPow = Mathf.Pow(Mathf.Max(0, Vector3.Dot(normalDir, halfDir)), 10); } #endif }
关于视角对齐菜单
选中相机, 菜单 -> GameObject -> Align View to Selected, 把Scene View的视角正向设置成和所选物体forward相同
Align With View, 把所选物体的forward设置成和Scene View的视角正向相同
参考