You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

寻求更高效的Raycasting实现方案(基于.NET C# CPU环境)

高效Raycasting实现优化与学习建议

问题背景

我想涉足图形编程,但觉得OpenGL语法晦涩,于是用.NET C#开发了一个可将图像保存为位图的渲染器。由于找不到Raycasting的相关实现资料,自行设计了一种方案:通过for循环让一个点从相机向近平面上的点移动,直至碰撞到物体或到达远平面。当前的问题是:当远平面设置得很远且未碰撞到任何物体时,Raycasting会显著变慢,且只能使用.NET默认命名空间,无法借助GPU API优化。

当前代码片段

// Go through every point on the near plane, divided by the resolution
for (int y = 0; y < nearPlanePoints.GetLength(1); y++)
{
    for (int x = 0; x < nearPlanePoints.GetLength(0); x++)
    {
        bool doBreak = false;
        // Get the direction from the camera towards the current pixel on the near plane
        Vector3 rayDirection = new Vector3(nearPlanePoints[x,y], nearPlane).Normalized;
        // Move the point by rayStep amount until reaching the far plane
        for (float z = 0; z <= farPlane; z+=rayStep)
        {
            Vector3 point = position + rayDirection * z;
            // Check for collision with object in the "scene" (since I use radius, I can only render spheres) 
            for (int i = 0; i < sceneObjects.Length; i++)
            {
                if (Vector3.Distance(point, sceneObjects[i].position) <= sceneObjects[i].radius)
                {
                    // When collides, paint the corresponding pixel to the color of the object
                    renderedImage[(y * Program.image_width) + x] = sceneObjects[i].color;
                    // Don't continue to search for collision
                    doBreak = true;
                    break;
                }
            }

            if (doBreak)
                break;
            else
                // If the search ended without a collision, paint the corresponding pixel to a predefined background color
                renderedImage[(y * Program.image_width) + x] = backgroundColor;
        }
    }
}

return renderedImage;

优化方案

1. 替换步进式检测为数学交点计算(核心优化)

当前的逐点步进是效率瓶颈,对于球体这类规则几何体,完全可以通过二次方程求解直接计算射线与球体的交点,无需循环采样:

  • 射线定义:origin + t * direction(t为射线长度,仅取t≥0的有效解)
  • 球体方程:(P - C)·(P - C) = r²(P为射线上的点,C为球心,r为半径)
  • 代入后得到二次方程,求解后取最小的正t值,即为最近的交点位置

这种方式可以彻底消除步进循环,速度提升极其明显。

2. CPU层面的辅助优化

  • 并行化像素处理:用.NET自带的Parallel.For替代外层的y循环,利用多核CPU的并行计算能力
  • 预计算重复值:提前计算射线方向的点积、球心到射线原点的向量等,避免重复计算
  • 提前剔除不可能的碰撞:计算球心到射线的最短距离,若大于半径则直接跳过该球体

优化后的简化代码

// 并行处理像素,充分利用多核CPU
Parallel.For(0, nearPlanePoints.GetLength(1), y =>
{
    for (int x = 0; x < nearPlanePoints.GetLength(0); x++)
    {
        Vector3 rayDirection = new Vector3(nearPlanePoints[x,y], nearPlane).Normalized;
        Vector3 rayOrigin = position;
        float closestT = float.MaxValue;
        Color pixelColor = backgroundColor;

        foreach (var sphere in sceneObjects)
        {
            Vector3 oc = rayOrigin - sphere.position;
            float a = Vector3.Dot(rayDirection, rayDirection);
            float b = 2.0f * Vector3.Dot(oc, rayDirection);
            float c = Vector3.Dot(oc, oc) - sphere.radius * sphere.radius;
            float discriminant = b * b - 4 * a * c;

            // 存在有效交点
            if (discriminant >= 0)
            {
                // 计算两个解,取更近的正t值
                float t = (-b - (float)Math.Sqrt(discriminant)) / (2 * a);
                if (t > 0 && t < closestT && t <= farPlane)
                {
                    closestT = t;
                    pixelColor = sphere.color;
                }
                
                // 检查另一个解(可能在更远位置,仅保留最近的交点)
                t = (-b + (float)Math.Sqrt(discriminant)) / (2 * a);
                if (t > 0 && t < closestT && t <= farPlane)
                {
                    closestT = t;
                    pixelColor = sphere.color;
                }
            }
        }

        renderedImage[(y * Program.image_width) + x] = pixelColor;
    }
});

return renderedImage;

图形编程学习资源

  • 《Ray Tracing in One Weekend》系列:入门光线追踪的经典教程,用极简代码逐步实现从球体渲染到复杂材质、光照的完整流程,非常适合从零开始摸索的开发者
  • 基础图形学原理教程:专注于射线与几何体交点计算、相机变换、光照模型等核心知识点,可系统学习图形编程的底层逻辑
  • .NET图形编程社区讨论:在技术论坛中搜索C#图形编程相关内容,能找到很多开发者分享的实现经验与优化技巧

内容的提问来源于stack exchange,提问作者3DartBlade

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.30 23:06:35