public OOModel(MannulDraw drawer) { Drawer = drawer; MeshFilter mf = drawer.gameObject.GetComponent <MeshFilter>(); Model = new OOMesh(mf); Box = new OOBox(Vector3.one * float.MaxValue, Vector3.one * float.MinValue); UpdateTransform(); Head = new OOItem(); Tail = new OOItem(); Tail.CNext = null; Head.CPrev = null; Head.CNext = Tail; Tail.CPrev = Head; CanOcclude = 1; // GeoDebugDrawUtils.DrawAABB(Box.Min, Box.Max); }
/// <summary> /// 绘制一个物体到缓冲区 /// </summary> /// <param name="obj">待绘制物体</param> private void DrawOccluder(OOModel obj) { // 获取物体的模型 OOMesh mdl = obj.Model; // 计算 ModelView 矩阵.注意:这里需要相机的变换矩阵的逆矩阵 // 另一问题:左手系和右手系问题。 Matrix4x4 modelViewMatrix = mView * obj.ModelWorldMatrix; // 变换mesh的顶点到 相机空间 和 裁剪空间 for (int i = 0; i < mdl.NumVert; i++) { // Vector3 p = obj.ModelWorldMatrix.MultiplyPoint3x4(mdl.Vertices[i]); Vector4 tmp = modelViewMatrix.MultiplyPoint3x4(mdl.Vertices[i]); mdl.CameraSpaceVertices[i] = tmp; tmp.w = 1; mdl.ClipSpaceVertices[i] = mProject * tmp; } int xmin = 100000; int xmax = 0; int ymin = 100000; int ymax = 0; // 遍历所有面 for (int i = 0; i < mdl.NumFace; i++) { // 面索引 int p1 = mdl.Faces[i][0]; int p2 = mdl.Faces[i][1]; int p3 = mdl.Faces[i][2]; // 计算法向量。此处可以优化成:初始化时计算,而后变换一下法向量即可。 // 构建右手坐标系 逆时针为正方向 Vector3 a = mdl.CameraSpaceVertices[p2] - mdl.CameraSpaceVertices[p1]; Vector3 b = mdl.CameraSpaceVertices[p3] - mdl.CameraSpaceVertices[p1]; Vector3 n = Vector3.Cross(a, b); // 背面剔除。可计算相机的朝向,然后与三角面的法线计算即可。 // 此处实际上计算 Camera 空间 原点到平面的距离是否小于0 if (Vector3.Dot(n, mdl.CameraSpaceVertices[p1]) < 0) { mClip.mClipSpaceVertices[0] = mdl.ClipSpaceVertices[p1]; mClip.mClipSpaceVertices[1] = mdl.ClipSpaceVertices[p2]; mClip.mClipSpaceVertices[2] = mdl.ClipSpaceVertices[p3]; // 裁剪计算 int nv = mClip.ClipAndProject(3); #if TEST_DRAW_ONE DebugUtils.Info("ClipAndProject", string.Format("world1({0}, {1})", mClip.mScreenSpaceVertices[0][0], mClip.mScreenSpaceVertices[0][1])); DebugUtils.Info("ClipAndProject", string.Format("world2({0}, {1})", mClip.mScreenSpaceVertices[1][0], mClip.mScreenSpaceVertices[1][1])); DebugUtils.Info("ClipAndProject", string.Format("world3({0}, {1})", mClip.mScreenSpaceVertices[2][0], mClip.mScreenSpaceVertices[2][1])); #endif // 裁剪判断 if (nv > 2) { // 裁剪后,计算屏幕区域的AABB for (int j = 0; j < nv; j++) { if (mClip.mScreenSpaceVertices[j][0] < xmin) { xmin = mClip.mScreenSpaceVertices[j][0]; } else { if (mClip.mScreenSpaceVertices[j][0] > xmax) { xmax = mClip.mScreenSpaceVertices[j][0]; } } if (mClip.mScreenSpaceVertices[j][1] < ymin) { ymin = mClip.mScreenSpaceVertices[j][1]; } else if (mClip.mScreenSpaceVertices[j][1] > ymax) { ymax = mClip.mScreenSpaceVertices[j][1]; } } // 绘制多边形到缓冲 Map.DrawPolygon(mClip.mScreenSpaceVertices, nv); } } } // 设置该区域内有被覆盖 Map.SetDirtyRectangle(xmin, ymin, xmax, ymax); }