美文网首页MetalKit专题
[MetalKit]Ray tracing in a Swift

[MetalKit]Ray tracing in a Swift

作者: 苹果API搬运工 | 来源:发表于2017-07-21 19:53 被阅读19次

    本系列文章是对 http://metalkit.org 上面MetalKit内容的全面翻译和学习.

    MetalKit系统文章目录


    让我们继续上周的工作完成ray tracer射线追踪器.现在我们知道如何生成不同材料的球体,也知道了如何从不同角度来观察它们,让我们再看看如何生成更多的球体.

    pixel.swift中创建一个random_scene()方法:

    func random_scene() -> Hitable_list {
        var objects = [Hitable]()
        objects.append(Sphere(c: float3(0, -1000, 0), r: 1000, m: Lambertian(albedo: float3(0.5, 0.5, 0.5))))
        for a in -2..<3 {
            for b in -2..<3 {
                let materialChoice = drand48()
                let center = float3(Float(a) + 0.9 * Float(drand48()), 0.2, Float(b) + 0.9 * Float(drand48()))
                if length(center - float3(4, 0.2, 0)) > 0.9 {
                    if materialChoice < 0.8 {   // diffuse
    
                        let albedo = float3(Float(drand48()) * Float(drand48()), Float(drand48()) * Float(drand48()), Float(drand48()) * Float(drand48()))
                        objects.append(Sphere(c: center, r: 0.2, m: Lambertian(albedo: albedo)))
                    } else if materialChoice < 0.95 {   // metal
    
                        let albedo = float3(0.5 * (1 + Float(drand48())), 0.5 * (1 + Float(drand48())), 0.5 * (1 + Float(drand48())))
                        objects.append(Sphere(c: center, r: 0.2, m: Metal(albedo: albedo, fuzz: Float(0.5 * drand48()))))
                    } else {    // glass
    
                        objects.append(Sphere(c: center, r: 0.2, m: Dielectric()))
                    }
                }
            }
        }
        objects.append(Sphere(c: float3(0, 0.7, 0), r: 0.7, m: Dielectric()))
        objects.append(Sphere(c: float3(-3, 0.7, 0), r: 0.7, m: Lambertian(albedo: float3(0.4, 0.2, 0.1))))
        objects.append(Sphere(c: float3(3, 0.7, 0), r: 0.7, m: Metal(albedo: float3(0.7, 0.6, 0.5), fuzz: 0.0)))
        return Hitable_list(list: objects)
    }
    

    这个方法生成了25个小球体,并用随机值给它们赋上不同材料,lambertian, metalglass.然后把这些球体添加到一个列表里,作为返回值.我们还添加一个大球体,还有我们初始的3个小球体.

    然后在imageFromPixels()方法里,我们将以前添加球体的代码:

    var objects = [Hitable]()
    var object = Sphere(c: float3(0, -100.5, -1), r: 100, m: Lambertian(albedo: float3(0.7, 0.23, 0.12)))
    objects.append(object)
    object = Sphere(c: float3(1, 0, -1), r: 0.5, m: Metal(albedo: float3(0.8, 0.6, 0.2), fuzz: 0.1))
    objects.append(object)
    object = Sphere(c: float3(-1, 0, -1), r: 0.5, m: Dielectric())
    objects.append(object)
    object = Sphere(c: float3(-1, 0, -1), r: -0.49, m: Dielectric())
    objects.append(object)
    object = Sphere(c: float3(0, 0, -1), r: 0.5, m: Lambertian(albedo: float3(0.24, 0.5, 0.15)))
    objects.append(object)
    let world = Hitable_list(list: objects)
    

    替换为一行,创建随机场景:

    let world = random_scene()
    

    一般情况下,现在我会告诉你可以渲染场景了,但是我从 hyperjeff那里学到了一点加速的方法,可以让我们更快得到更好的质量的图片.还是在imageFromPixels()方法里,将外层循环的第一行:

    for i in 0..<width {
    

    替换为下面的代码:

    let queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)
    dispatch_apply(width, queue) { i in
    

    通过使用GCD多线程,渲染速度提高了3倍!在playground主页面中,看看新生成的图像:

    raytracing.png

    这张图片创建参数是:ns=50,球体产生器范围-7..<7,图片分辨率800 x 400.整个渲染花费752秒,如果你想要快一些,5秒渲染的话,我建议使用参数:ns=10,球体产生器范围-2..<3,图片分辨率400 x 200.
    源代码source code 已发布在Github上.
    下次见!

    相关文章

      网友评论

        本文标题:[MetalKit]Ray tracing in a Swift

        本文链接:https://www.haomeiwen.com/subject/ntbekxtx.html