物体投影计算

 

以下为少量顶点(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。

 

posted @ 2025-05-12 18:54  盛沧海  阅读(3)  评论(0)    收藏  举报