物体投影计算
以下为少量顶点(100万顶点内,太多不建议使用),以XoY为前后面,绕Z轴旋转,从顶部投影到ZoX的投影实现。
/// <summary> /// 旋转顶点,得到投影区域 /// </summary> /// <param name="vertices">所有顶点</param> /// <param name="angleDegrees">旋转角度</param> /// <param name="translation">平移位置(旋转前需要将旋转中心置于原点)</param> /// <returns>返回旋转后的投影区域内的所有点位置</returns> internal unsafe static HashSet<Point> RotateVerticesAndGetSection3(float[] vertices, double angleDegrees, double translation) { Stopwatch stopwatch = Stopwatch.StartNew(); stopwatch.Start(); HashSet<Point> points = new(vertices.Length / 3); var angleRadiants = angleDegrees * Math.PI / 180; float cos = (float)Math.Cos(angleRadiants); float sin = (float)Math.Sin(angleRadiants); Vector256<float> targetVector = Vector256.Create(cos, -sin, 0f, 0f, cos, -sin, 0f, 0f); Vector128<float> targetVector2 = Vector128.Create(cos, -sin, 0f, 0f); fixed (float* verPtr = vertices) { int limit = vertices.Length - vertices.Length % 8; int i = 0; for (; i < limit; i += 8) { float* temp = verPtr + i; var v = *(Vector256<float>*)temp; var result = Avx2.Multiply(v, targetVector); var a = Avx2.ExtractVector128(result, 0); var b = Avx2.ExtractVector128(result, 1); Point p1 = new Point((int)(Sum(a) + translation), (int)*(temp + 2)); if (!points.Contains(p1)) { points.Add(p1); } Point p2 = new Point((int)(Sum(b) + translation), (int)*(temp + 6)); if (!points.Contains(p2)) { points.Add(p2); } } for (; i < vertices.Length; i += 4) { float* temp = verPtr + i; var v = *(Vector128<float>*)temp; var result = Sse2.Multiply(v, targetVector2); Point p = new((int)(Sum(result) + translation), (int)*(temp + 2)); if (!points.Contains(p)) { points.Add(p); } } } stopwatch.Stop(); Debug.WriteLine("RotateVerticesAndGetSeciton3 cost times:" + stopwatch.ElapsedMilliseconds); return points; }
上述涉及到的Sum方法,在.net8中,C#中已经有相应实现,.net6中没有,不得不自行实现。
static unsafe float Sum(Vector128<float> vector) { float sum = 0f; var ptr = (float*)&vector; for (int index = 0; index < Vector128<float>.Count; index++) { sum += *(ptr + index); } return sum; }
以上代码基于SMID指令加速计算,目前主流的CPU都支持。
实测来看,顶点在100w以内时,生成相应的投影区域不会超过10ms。
*****有道无术,术尚可求;有术无道,止于术。*****