NIM中的光线跟踪

2020-07-02 06:29:11

辐射跟踪是一周光线跟踪在NIM编程语言中的实现。

特别值得一提的是,我确信(显然有偏见),如果您想从头开始一个渲染项目(光线跟踪或其他),NIM是最适合使用的语言,特别是如果您专注于:

渲染是一项非常耗时的任务,NIM很快,非常快,有时甚至比C++还快。

在英特尔Skylake-X i9-9980XE上,超频为4.1SSE2全核涡轮。以x86-64模式编译(仅限 );384x216图像;每像素100射线:

单线程NIM比Cang C++快2.7%. %。多线程NIM通过编织比Cang C++快11.1 %。

以下是重现结果的步骤。请注意,如果您在不同的硬件上运行测试,结果可能与上面发布的结果略有不同。

git clone https://github.com/mratsim/weave CD weaven imble install-y#安装编织依赖项,此处为合成,如果要求则覆盖。nim-v#确保您的NIM 1.2.0或更高版本的#Threads on(默认情况下在此资源库中)nim c-d:danger-o:build/ray_threaded demos/raytracing/simpt.nim#threadoffnim c-d:danger-threads:off-o:build/ray_Single demos/ray tracing/mall pt.nimg++-O3-o build/ray_GCC_Single demos/ray tracacing/RayTracing/Smallpt.nimg++-O3-o build/ray_ray_Single Demos/RayTrac.。-o build/ray_clang_Single demos/ray Tracing/mall pt.cppclang++-O3-fopenmp-o build/ray_clang_omp demos/ray Tracing/mall pt.cpp。

NIM是少数几种可以正确建模物理单位并在编译时强制正确使用这些单位的语言之一。例如,向量和单位向量具有相同的表示形式,但类型不同。单位向量在传递给函数时可以自动转换为向量:

type Vector 3*=object x*,y*,z*:float64 UnitVector*{.borrow:`.`.}=DISTINCT Vec3#`.`注释确保可以将字段访问转换为Vec3*(UV:UnitVector):Vec3{.inlin.}=##UnitVector可无缝转换为Vec3(但不能反之亦然)Vec3(UV)。

Point3使用与Vec3相同的内部表示,并且可以借用(共享)公共运算符的实现(即没有代码大小影响):

type Point3*{.borrow:`.`.}=DISTINCT Vector 3#`.`注释确保可以访问字段func`*=`*(a:var Point3,标量:float64){.born.}func`*`*(a:Point3,标量:float64):Point3{.boror.}func`*`*(scalar:float64,a:Point3):Point3{.borrow.}。

不允许添加2个点,并带有一条漂亮的自定义错误消息,而不是编译器的默认错误。

函数`-`*(a,b:Point3):Point3{.inlin.}=##将一个点从另一个点减去,得到一个向量结果。x=a.x-b.x result t.y=a.y-b.y result t.z=a.z-b.zfunc`+`*(p:Point3,v:Vector 3):Point3{.inlin.}=##将向量加到一个点得到Point3(Vector 3(P)+v)funint3。v:Vector 3):Point3{.inlin.}=##从一个点减去一个向量得到一个点Point3(ve3(P)-v)函数`+`*(a,b:Point3):Point3{.error:";添加2个点3没有实际意义。}。

我还有两种类型的颜色及其衰减(按百分比表示),因此您不能将颜色相乘:

TYPE COLOR*{.BORROW:`.`.}=DISTINCT Vec3func`*`*(a,b:color):COLOR{.error:";将2种颜色相乘没有物理意义";.}类型衰减*{.借入:`.`.}=不同颜色函数`*=`*(a:VAR衰减,b:衰减){.inline}=#将颜色乘以每个通道的衰减因子A.X*=b.x A.Y*=b.y A.Z*=b.zfunc`*`*(a,b:衰减):衰减{.inlin.}=#将颜色乘以每个通道的衰减因子result。x=a.x*b.x result t.y=a.y*b.y result t.z=a.z*b.zfunc`*=`*(a:可变颜色,b:衰减){.inline}=#将颜色乘以每个通道的衰减因子a.x*=b.x A.Y*=b.y A.Z*=B.Z。

最后但并非最不重要的一点是,通过自动将弧度转换为浮动(并且度数将保持在较高水平),确保您不会混合和匹配度数和弧度:

类型度*=DISTINCT FLOAT64弧度*=DISTINCT FLOAT64模板deToRad*(deg:度):RADIANS=弧度(decToRad(float64(Deg)模板radToDeg*(rad:弧度):Degrees=Degrees(radToDeg(float64(Rad)#目前我们不会使用正确的cos/sin/tan弧度强制#和自动转换为浮点转换器创建完整的安全单元库#。

在使用值类型(堆栈对象、seq和字符串)时,NIM在传递参数或将参数赋值给变量时需要显式变量,因为参数是可变的。

此外,C和C++开发人员可能会感兴趣地了解,当传递大型对象时(32位平台上超过12字节,64位平台上超过24字节),NIM做正确的事情™,并且将默认通过引用传递(您可以在每个类型的基础上覆盖它,以始终通过复制传递或始终通过引用传递)。这意味着函数签名是出于易变性考虑,并且不受性能的影响(并且性能很好,正如基准测试所证明的那样)。

函数强制没有副作用,否则代码将无法编译。一些副作用示例:

如果你有一个Heisenbug,它很可能不在无副作用的函数中(除非你损坏了内存)。

这特别适合于物理学和光线追踪计算内核,因为物理方程是无副作用的。

尽管NIM具有所有功能,但它在C和C++目标下的编译速度都非常快,尤其是模板元编程的编译时间成本非常低。

这受到快速VM的支持,该VM在编译时为NIM提供Python的速度,并用于:

NIM可以编译成C和C++,并且可以无缝地调用用这两种语言编写的库,它甚至可以使用CUDA,只需稍加配置就可以调用NVCC。

虽然NIM提供了许多高级功能,但它不会强迫您先游泳或溺水。实际上,许多人报告说,NIM感觉像是一种经过编译的脚本语言。

并不是所有的事情都是小马和彩虹。NIM的主要问题是,它是一种非常年轻的语言,只有一个受支持的库的小生态系统。也就是说,您可以重用C和C++生态系统(也可以重用Javascript,因为Nim也可以编译到它)。例如,Trace of Radiance支持通过MP4从v0.2.0开始的视频输出,只需要60行的头C库包装。