首页 > 其他分享 >0200-材质和散射

0200-材质和散射

时间:2024-07-19 14:42:44浏览次数:14  
标签:self material 散射 let 0200 new 材质 f64 ray

环境

  • Time 2022-11-16
  • WSL-Ubuntu 22.04
  • Rust 1.65.0

前言

说明

参考:https://raytracing.github.io/books/RayTracingInOneWeekend.html

目标

不同的材质有不同的散射光线和衰减,这一节将不同的材质进行抽象。

向量的乘法

impl Mul for Vector3 {
    type Output = Self;

    fn mul(self, other: Vector3) -> Self {
        Vector3 {
            x: self.x * other.x,
            y: self.y * other.y,
            z: self.z * other.z,
        }
    }
}

material.rs

use crate::{
    hittable::HitRecord,
    ray::Ray,
    vector3::{Color, Vector3},
};

// 材质
pub trait Material {
    fn scatter(&self, ray: &Ray, record: &HitRecord) -> Option<(Color, Ray)>;
}

pub struct Lambert {
    // 衰减
    pub albedo: Color,
}

impl Material for Lambert {
    fn scatter(&self, _: &Ray, record: &HitRecord) -> Option<(Color, Ray)> {
        let mut direction = record.normal + Vector3::random_unit();

        if direction.near_zero() {
            direction = record.normal;
        }
        let scattered = Ray::new(record.point, direction);

        Some((self.albedo, scattered))
    }
}

HitRecord

pub struct HitRecord {
    pub point: Point3,
    pub normal: Vector3,
    pub t: f64,
    pub material: Rc<dyn Material>,
}

Sphere

pub struct Sphere {
    center: Point3,
    radius: f64,
    material: Rc<dyn Material>,
}

impl Sphere {
    pub fn new(center: Point3, radius: f64, material: Rc<dyn Material>) -> Sphere {
        Sphere {
            center,
            radius,
            material,
        }
    }

    fn nearest(&self, ray: &Ray, temp: Temp) -> Option<HitRecord> {
        //  找到最近的点
        let a = ray.direction().dot(ray.direction());

        let mut t = (-temp.b - temp.sqrt) / a;
        if t < temp.min || temp.max < t {
            t = (-temp.b + temp.sqrt) / a;
            if t < temp.min || temp.max < t {
                return None;
            }
        }

        let point = ray.at(t);
        let normal = (point - self.center) / self.radius;
        Some(HitRecord {
            t,
            point,
            normal,
            material: Rc::clone(&self.material),
        })
    }
}

main.rs

use std::rc::Rc;

use camera::Camera;
use hittable::{Hit, World};
use material::{Lambert, Material};
use rand::Rng;
use ray::Ray;
use sphere::Sphere;
use vector3::{Color, Point3};

mod camera;
mod hittable;
mod material;
mod ray;
mod sphere;
mod vector3;

fn main() {
    // 图片的比例,和宽高
    const WIDTH: u64 = 400;
    const HEIGHT: u64 = (WIDTH as f64 / camera::RATIO) as u64;
    const SAMPLES_PER_PIXEL: u64 = 100;
    const MAX_DEPTH: u64 = 5;

    // 相机
    let camera = Camera::new();

    // 输出图片,第一行输出 P3,表示像素图
    let mut content = String::from("P3");
    // 输出宽和高,和最大颜色值
    content.push_str(&format!("\n{WIDTH} {HEIGHT}\n255\n"));

    let lambert: Rc<dyn Material> = Rc::new(Lambert {
        albedo: Color::new(0.5, 0.5, 0.5),
    });
    let world: World = vec![
        Box::new(Sphere::new(
            Point3::new(0.0, 0.0, -1.0),
            0.5,
            Rc::clone(&lambert),
        )),
        Box::new(Sphere::new(
            Point3::new(0.0, -100.5, -1.0),
            100.0,
            Rc::clone(&lambert),
        )),
    ];

    let mut rng = rand::thread_rng();
    for j in (0..HEIGHT).rev() {
        // 进度
        eprintln!("Scan lines remaining: {j}");
        for i in 0..WIDTH {
            let mut color = Color::default();
            for _ in 0..SAMPLES_PER_PIXEL {
                let random_u: f64 = rng.gen();
                let random_v: f64 = rng.gen();

                let u = ((i as f64) + random_u) / ((WIDTH - 1) as f64);
                let v = ((j as f64) + random_v) / ((HEIGHT - 1) as f64);

                color += ray_color(&camera.get_ray(u, v), &world, MAX_DEPTH);
            }
            content.push_str(&color.format_str(SAMPLES_PER_PIXEL as f64));
        }
    }
    println!("{}", content);
    eprintln!("Done.");
}

// 光线的颜色计算
fn ray_color(ray: &Ray, hittable: &dyn Hit, depth: u64) -> Color {
    // 超过最大深度,直接变成黑色
    if depth == 0 {
        return Color::new(0.0, 0.0, 0.0);
    }

    // 射线命中物体
    if let Some(record) = hittable.hit(ray, 0.001, f64::INFINITY) {
        // 命中物体根据材料散射光线
        return match record.material.scatter(ray, &record) {
            Some((attenuation, scattered)) => {
                attenuation * ray_color(&scattered, hittable, depth - 1)
            }
            None => Color::new(0.0, 0.0, 0.0),
        };
    }

    // 射线未命中,射线的单位向量
    let unit = ray.direction().unit();
    // 因为需要得到上下渐变的背景图,所以需要对 y 进行插值。
    let t = 0.5 * (unit.y + 1.0);
    // 线性插值,根据不同的光线得到在下面这个范围里的不同的颜色,并且是渐变色。
    (1.0 - t) * Color::new(1.0, 1.0, 1.0) + t * Color::new(0.5, 0.7, 1.0)
}

总结

抽象出了材质,下面可以基于材质的抽象,添加不同的材质。

附录

标签:self,material,散射,let,0200,new,材质,f64,ray
From: https://www.cnblogs.com/jiangbo4444/p/18311420

相关文章

  • MBR30200PT-ASEMI智能AI应用MBR30200PT
    编辑:llMBR30200PT-ASEMI智能AI应用MBR30200PT型号:MBR30200PT品牌:ASEMI封装:TO-247批号:最新恢复时间:35ns最大平均正向电流(IF):30A最大循环峰值反向电压(VRRM):200V最大正向电压(VF):0.70V~0.90V工作温度:-65°C~175°C芯片个数:2芯片尺寸:mil正向浪涌电流(IFMS):275AMBR30200PT特性:......
  • UE4材质笔记
    常用节点:添加贴图:TextureSample(贴图采样)常量数字:Constant(数字)Vector或长按数字并点击左键乘法:Multiply或长按M并点击左键常用插值:Lerp或长按L并点击左键加法:Add或者长按A键并点击左键减法:Subtract除法:Divide或者长按D键并点击左键1-x:搜索1-或者oneminus或者长按O键并点击左键绝......
  • MBR20200FCT-ASEMI无人机专用MBR20200FCT
    编辑:llMBR20200FCT-ASEMI无人机专用MBR20200FCT型号:MBR20200FCT品牌:ASEMI封装:TO-220F批号:最新最大平均正向电流(IF):20A最大循环峰值反向电压(VRRM):200V最大正向电压(VF):0..90V工作温度:-50°C~175°C反向恢复时间:35ns芯片个数:2芯片尺寸:74mil引脚数量:3正向浪涌电流(IFMS):200A......
  • MBR10200CT-ASEMI智能AI应用MBR10200CT
    编辑:llMBR10200CT-ASEMI智能AI应用MBR10200CT型号:MBR10200CT品牌:ASEMI封装:TO-220批号:最新恢复时间:35ns最大平均正向电流(IF):10A最大循环峰值反向电压(VRRM):200V最大正向电压(VF):0.70V~0.90V工作温度:-65°C~175°C芯片个数:2芯片尺寸:mil正向浪涌电流(IFMS):150AMBR10200CT特性:......
  • JMonkeyEngine——材质文件备注
    默认J3M编辑器不支持编辑纹理参数的Mag/Min滤波选项,只能配置Flip和Wrap模式,但是可以单独编辑J3M源码,如下: 添加你需要的Mag/Min滤波选项,参考源码的解析,就是Mag/Min+拼接对应的Filter值。虽然打开J3M编辑器会报错: 但实际进游戏时并不会报错,而且一切正常,如下: 所以可以正常......
  • blender常用材质参数
    Blender中材质的以下关键属性:基础色(BaseColor),金属度(Metallic),粗糙度(Roughness),IOR折射率(IOR),Alpha(Alpha),法向(Normal),次表面(Subsurface),高光(specular),透射(Transmission),涂层(Coat),边缘光泽(Sheen),自发光(Emission)请给出简约的白色T恤关于以上属性的各个值......
  • Cesium 实战 - 自定义纹理材质系列之 - 涟漪效果
    Cesium实战-自定义纹理材质系列之-涟漪效果核心代码完整代码在线示例Cesium给实体对象(Entity)提供了很多实用的样式,基本满足普通项目需求;但是作为WebGL引擎,肯定不够丰富,尤其是动态效果样式。对于实体对象(Entity),可以通过自定义材质,实现各种动态效果,虽......
  • Cesium 实战 - 自定义纹理材质系列之 - 动态扩散效果
    Cesium实战-自定义纹理材质系列之-动态扩散效果核心代码完整代码在线示例Cesium给实体对象(Entity)提供了很多实用的样式,基本满足普通项目需求;但是作为WebGL引擎,肯定不够丰富,尤其是动态效果样式。对于实体对象(Entity),可以通过自定义材质,实现各种动态效......
  • PixPlant.5.0.42_x64破解汉化版,创建平铺 3D 材质的更好方法
    PixPlant5是一款功能强大的贴图生成器,可用于快速生成高质量的纹理贴图,下面分享PixPlant5贴图生成器的使用方法。1、在网上找到需要的贴图类型,如丝绸,木板,砖块,纺织物等任意需要的贴图。2、找到贴图后打开PS,将贴图设置为长宽相同尺寸的图片,如以下设置为500×500像素,如贴图使......
  • 制作耳机壳的UV树脂和塑料材质相比优势有哪些?
    制作耳机壳的UV树脂和塑料材质相比优势有哪些?制作耳机壳的UV树脂相比塑料材质有以下优势:高强度与耐磨性:UV树脂具有高强度和耐磨性,能够更好地保护耳机内部零件,延长耳机使用寿命。相比之下,塑料材质可能较易磨损或刮伤。耐高温:UV树脂具有较好的耐高温性能,即使在炎热的环境中也......