specular metallic materials
This commit is contained in:
parent
e1c61ef944
commit
1a355f81ca
15 changed files with 533 additions and 27 deletions
BIN
__output_image.png
Normal file
BIN
__output_image.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 658 KiB |
BIN
output_image.png
Normal file
BIN
output_image.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 58 KiB |
Binary file not shown.
Binary file not shown.
BIN
scenes/mirror.blend
Normal file
BIN
scenes/mirror.blend
Normal file
Binary file not shown.
BIN
scenes/mirror.blend1
Normal file
BIN
scenes/mirror.blend1
Normal file
Binary file not shown.
BIN
scenes/mirror.glb
Normal file
BIN
scenes/mirror.glb
Normal file
Binary file not shown.
BIN
scenes/reflective.bin
Normal file
BIN
scenes/reflective.bin
Normal file
Binary file not shown.
BIN
scenes/reflective.blend
Normal file
BIN
scenes/reflective.blend
Normal file
Binary file not shown.
BIN
scenes/reflective.blend1
Normal file
BIN
scenes/reflective.blend1
Normal file
Binary file not shown.
BIN
scenes/reflective.glb
Normal file
BIN
scenes/reflective.glb
Normal file
Binary file not shown.
452
scenes/reflective.gltf
Normal file
452
scenes/reflective.gltf
Normal file
|
|
@ -0,0 +1,452 @@
|
|||
{
|
||||
"asset":{
|
||||
"generator":"Khronos glTF Blender I/O v4.0.44",
|
||||
"version":"2.0"
|
||||
},
|
||||
"extensionsUsed":[
|
||||
"KHR_materials_emissive_strength"
|
||||
],
|
||||
"scene":0,
|
||||
"scenes":[
|
||||
{
|
||||
"name":"Scene",
|
||||
"nodes":[
|
||||
0,
|
||||
1,
|
||||
2,
|
||||
3,
|
||||
4
|
||||
]
|
||||
}
|
||||
],
|
||||
"nodes":[
|
||||
{
|
||||
"camera":0,
|
||||
"name":"Camera",
|
||||
"rotation":[
|
||||
-0.15949390828609467,
|
||||
0.662581741809845,
|
||||
0.1474284678697586,
|
||||
0.7168068289756775
|
||||
],
|
||||
"translation":[
|
||||
10.606247901916504,
|
||||
4.060349464416504,
|
||||
0.7527037858963013
|
||||
]
|
||||
},
|
||||
{
|
||||
"mesh":0,
|
||||
"name":"Plane",
|
||||
"scale":[
|
||||
7.545622825622559,
|
||||
7.545622825622559,
|
||||
7.545622825622559
|
||||
]
|
||||
},
|
||||
{
|
||||
"mesh":1,
|
||||
"name":"Plane.001",
|
||||
"rotation":[
|
||||
0,
|
||||
0,
|
||||
-0.7071068286895752,
|
||||
0.7071068286895752
|
||||
],
|
||||
"translation":[
|
||||
6.896522521972656,
|
||||
1.2417194843292236,
|
||||
-3.40067195892334
|
||||
]
|
||||
},
|
||||
{
|
||||
"mesh":2,
|
||||
"name":"Plane.002",
|
||||
"rotation":[
|
||||
0,
|
||||
0,
|
||||
-0.7071068286895752,
|
||||
0.7071068286895752
|
||||
],
|
||||
"scale":[
|
||||
3.870809316635132,
|
||||
1,
|
||||
5.133298873901367
|
||||
],
|
||||
"translation":[
|
||||
0,
|
||||
0,
|
||||
-1.2463083267211914
|
||||
]
|
||||
},
|
||||
{
|
||||
"mesh":3,
|
||||
"name":"Cube",
|
||||
"scale":[
|
||||
0.7817667722702026,
|
||||
0.7817667722702026,
|
||||
0.7817667722702026
|
||||
],
|
||||
"translation":[
|
||||
0.8038264513015747,
|
||||
0.7851558327674866,
|
||||
0
|
||||
]
|
||||
}
|
||||
],
|
||||
"cameras":[
|
||||
{
|
||||
"name":"Camera",
|
||||
"perspective":{
|
||||
"aspectRatio":1,
|
||||
"yfov":0.6911112070083618,
|
||||
"zfar":100,
|
||||
"znear":0.10000000149011612
|
||||
},
|
||||
"type":"perspective"
|
||||
}
|
||||
],
|
||||
"materials":[
|
||||
{
|
||||
"doubleSided":true,
|
||||
"name":"Specular_black",
|
||||
"pbrMetallicRoughness":{
|
||||
"baseColorFactor":[
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
1
|
||||
],
|
||||
"metallicFactor":0,
|
||||
"roughnessFactor":0
|
||||
}
|
||||
},
|
||||
{
|
||||
"doubleSided":true,
|
||||
"emissiveFactor":[
|
||||
1,
|
||||
1,
|
||||
1
|
||||
],
|
||||
"extensions":{
|
||||
"KHR_materials_emissive_strength":{
|
||||
"emissiveStrength":60
|
||||
}
|
||||
},
|
||||
"name":"Emissive",
|
||||
"pbrMetallicRoughness":{
|
||||
"baseColorFactor":[
|
||||
0.800000011920929,
|
||||
0.800000011920929,
|
||||
0.800000011920929,
|
||||
1
|
||||
],
|
||||
"metallicFactor":0,
|
||||
"roughnessFactor":0
|
||||
}
|
||||
},
|
||||
{
|
||||
"doubleSided":true,
|
||||
"name":"Specular_red",
|
||||
"pbrMetallicRoughness":{
|
||||
"baseColorFactor":[
|
||||
0.8001416921615601,
|
||||
0,
|
||||
0.004359794314950705,
|
||||
1
|
||||
],
|
||||
"metallicFactor":0,
|
||||
"roughnessFactor":0
|
||||
}
|
||||
},
|
||||
{
|
||||
"doubleSided":true,
|
||||
"name":"Rough_cube",
|
||||
"pbrMetallicRoughness":{
|
||||
"baseColorFactor":[
|
||||
0.009510930627584457,
|
||||
1,
|
||||
0,
|
||||
1
|
||||
],
|
||||
"metallicFactor":0
|
||||
}
|
||||
}
|
||||
],
|
||||
"meshes":[
|
||||
{
|
||||
"name":"Plane",
|
||||
"primitives":[
|
||||
{
|
||||
"attributes":{
|
||||
"POSITION":0,
|
||||
"NORMAL":1,
|
||||
"TEXCOORD_0":2
|
||||
},
|
||||
"indices":3,
|
||||
"material":0
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name":"Plane.001",
|
||||
"primitives":[
|
||||
{
|
||||
"attributes":{
|
||||
"POSITION":4,
|
||||
"NORMAL":5,
|
||||
"TEXCOORD_0":6
|
||||
},
|
||||
"indices":3,
|
||||
"material":1
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name":"Plane.002",
|
||||
"primitives":[
|
||||
{
|
||||
"attributes":{
|
||||
"POSITION":7,
|
||||
"NORMAL":8,
|
||||
"TEXCOORD_0":9
|
||||
},
|
||||
"indices":3,
|
||||
"material":2
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name":"Cube.001",
|
||||
"primitives":[
|
||||
{
|
||||
"attributes":{
|
||||
"POSITION":10,
|
||||
"NORMAL":11,
|
||||
"TEXCOORD_0":12
|
||||
},
|
||||
"indices":13,
|
||||
"material":3
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"accessors":[
|
||||
{
|
||||
"bufferView":0,
|
||||
"componentType":5126,
|
||||
"count":4,
|
||||
"max":[
|
||||
1,
|
||||
0,
|
||||
1
|
||||
],
|
||||
"min":[
|
||||
-1,
|
||||
0,
|
||||
-1
|
||||
],
|
||||
"type":"VEC3"
|
||||
},
|
||||
{
|
||||
"bufferView":1,
|
||||
"componentType":5126,
|
||||
"count":4,
|
||||
"type":"VEC3"
|
||||
},
|
||||
{
|
||||
"bufferView":2,
|
||||
"componentType":5126,
|
||||
"count":4,
|
||||
"type":"VEC2"
|
||||
},
|
||||
{
|
||||
"bufferView":3,
|
||||
"componentType":5123,
|
||||
"count":6,
|
||||
"type":"SCALAR"
|
||||
},
|
||||
{
|
||||
"bufferView":4,
|
||||
"componentType":5126,
|
||||
"count":4,
|
||||
"max":[
|
||||
1,
|
||||
0,
|
||||
1
|
||||
],
|
||||
"min":[
|
||||
-1,
|
||||
0,
|
||||
-1
|
||||
],
|
||||
"type":"VEC3"
|
||||
},
|
||||
{
|
||||
"bufferView":5,
|
||||
"componentType":5126,
|
||||
"count":4,
|
||||
"type":"VEC3"
|
||||
},
|
||||
{
|
||||
"bufferView":6,
|
||||
"componentType":5126,
|
||||
"count":4,
|
||||
"type":"VEC2"
|
||||
},
|
||||
{
|
||||
"bufferView":7,
|
||||
"componentType":5126,
|
||||
"count":4,
|
||||
"max":[
|
||||
1,
|
||||
0,
|
||||
1
|
||||
],
|
||||
"min":[
|
||||
-1,
|
||||
0,
|
||||
-1
|
||||
],
|
||||
"type":"VEC3"
|
||||
},
|
||||
{
|
||||
"bufferView":8,
|
||||
"componentType":5126,
|
||||
"count":4,
|
||||
"type":"VEC3"
|
||||
},
|
||||
{
|
||||
"bufferView":9,
|
||||
"componentType":5126,
|
||||
"count":4,
|
||||
"type":"VEC2"
|
||||
},
|
||||
{
|
||||
"bufferView":10,
|
||||
"componentType":5126,
|
||||
"count":24,
|
||||
"max":[
|
||||
1,
|
||||
1,
|
||||
1
|
||||
],
|
||||
"min":[
|
||||
-1,
|
||||
-1,
|
||||
-1
|
||||
],
|
||||
"type":"VEC3"
|
||||
},
|
||||
{
|
||||
"bufferView":11,
|
||||
"componentType":5126,
|
||||
"count":24,
|
||||
"type":"VEC3"
|
||||
},
|
||||
{
|
||||
"bufferView":12,
|
||||
"componentType":5126,
|
||||
"count":24,
|
||||
"type":"VEC2"
|
||||
},
|
||||
{
|
||||
"bufferView":13,
|
||||
"componentType":5123,
|
||||
"count":36,
|
||||
"type":"SCALAR"
|
||||
}
|
||||
],
|
||||
"bufferViews":[
|
||||
{
|
||||
"buffer":0,
|
||||
"byteLength":48,
|
||||
"byteOffset":0,
|
||||
"target":34962
|
||||
},
|
||||
{
|
||||
"buffer":0,
|
||||
"byteLength":48,
|
||||
"byteOffset":48,
|
||||
"target":34962
|
||||
},
|
||||
{
|
||||
"buffer":0,
|
||||
"byteLength":32,
|
||||
"byteOffset":96,
|
||||
"target":34962
|
||||
},
|
||||
{
|
||||
"buffer":0,
|
||||
"byteLength":12,
|
||||
"byteOffset":128,
|
||||
"target":34963
|
||||
},
|
||||
{
|
||||
"buffer":0,
|
||||
"byteLength":48,
|
||||
"byteOffset":140,
|
||||
"target":34962
|
||||
},
|
||||
{
|
||||
"buffer":0,
|
||||
"byteLength":48,
|
||||
"byteOffset":188,
|
||||
"target":34962
|
||||
},
|
||||
{
|
||||
"buffer":0,
|
||||
"byteLength":32,
|
||||
"byteOffset":236,
|
||||
"target":34962
|
||||
},
|
||||
{
|
||||
"buffer":0,
|
||||
"byteLength":48,
|
||||
"byteOffset":268,
|
||||
"target":34962
|
||||
},
|
||||
{
|
||||
"buffer":0,
|
||||
"byteLength":48,
|
||||
"byteOffset":316,
|
||||
"target":34962
|
||||
},
|
||||
{
|
||||
"buffer":0,
|
||||
"byteLength":32,
|
||||
"byteOffset":364,
|
||||
"target":34962
|
||||
},
|
||||
{
|
||||
"buffer":0,
|
||||
"byteLength":288,
|
||||
"byteOffset":396,
|
||||
"target":34962
|
||||
},
|
||||
{
|
||||
"buffer":0,
|
||||
"byteLength":288,
|
||||
"byteOffset":684,
|
||||
"target":34962
|
||||
},
|
||||
{
|
||||
"buffer":0,
|
||||
"byteLength":192,
|
||||
"byteOffset":972,
|
||||
"target":34962
|
||||
},
|
||||
{
|
||||
"buffer":0,
|
||||
"byteLength":72,
|
||||
"byteOffset":1164,
|
||||
"target":34963
|
||||
}
|
||||
],
|
||||
"buffers":[
|
||||
{
|
||||
"byteLength":1236,
|
||||
"uri":"reflective.bin"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
@ -5,6 +5,7 @@ mod geometry;
|
|||
mod ray;
|
||||
mod scene_data;
|
||||
mod colors;
|
||||
mod math_utils;
|
||||
|
||||
use std::string::String;
|
||||
use cgmath::Vector4;
|
||||
|
|
|
|||
37
src/math_utils.rs
Normal file
37
src/math_utils.rs
Normal file
|
|
@ -0,0 +1,37 @@
|
|||
use std::f32::consts::PI;
|
||||
use cgmath::{InnerSpace, Vector3};
|
||||
use easy_gltf::model::Triangle;
|
||||
use crate::ray::Ray;
|
||||
|
||||
/// return a uniform random angle in the hemisphere specified by the triangle
|
||||
pub fn uniform_random_angle_triangle_hemisphere(intersected_triangle: Triangle, ray: &Ray) -> Vector3<f32> {
|
||||
let tangent = (intersected_triangle[0].position -
|
||||
intersected_triangle[1].position).normalize();
|
||||
let mut face_normal: Vector3<f32> = tangent
|
||||
.cross(intersected_triangle[0].position -
|
||||
intersected_triangle[2].position).normalize();
|
||||
//flip normal if face is hit from behind
|
||||
if face_normal.dot(-ray.direction) < 0.0 {
|
||||
face_normal *= -1.0;
|
||||
}
|
||||
let bitangent = tangent.cross(face_normal).normalize();
|
||||
/*
|
||||
generate random direction on hemisphere
|
||||
*/
|
||||
let phi = rand::random::<f32>() * 2.0 * PI;
|
||||
//allow arbitrary angles
|
||||
let radius = rand::random::<f32>();
|
||||
let sqrt_radius = f32::sqrt(rand::random::<f32>());
|
||||
|
||||
(tangent * f32::cos(phi) * sqrt_radius +
|
||||
bitangent * f32::sin(phi) * sqrt_radius +
|
||||
face_normal * f32::sqrt(1.0 - radius)).normalize()
|
||||
}
|
||||
|
||||
/// Calculate a triangle from the three Vertices
|
||||
pub fn face_normal_for_triangle(triangle: &Triangle) -> Vector3<f32> {
|
||||
let tangent = (triangle[0].position -
|
||||
triangle[1].position).normalize();
|
||||
tangent.cross(triangle[0].position -
|
||||
triangle[2].position).normalize()
|
||||
}
|
||||
|
|
@ -8,6 +8,7 @@ use easy_gltf::{Camera, Projection, Scene};
|
|||
use indicatif::ParallelProgressIterator;
|
||||
use crate::Args;
|
||||
use crate::geometry::{Intersectable};
|
||||
use crate::math_utils::{face_normal_for_triangle, uniform_random_angle_triangle_hemisphere};
|
||||
use crate::ray::{construct_primary_rays, Ray};
|
||||
use crate::scene_data::IntersectionData;
|
||||
|
||||
|
|
@ -150,44 +151,47 @@ fn accumulate_colors(intersection_data: &IntersectionData,
|
|||
recursion_depth_left: usize) -> Vector4<f32> {
|
||||
let mut pixel_radiosity: Vector4<f32>
|
||||
= Vector4::new(0.0, 0.0, 0.0, 1.0);
|
||||
|
||||
//accumulate colors at point
|
||||
//emissive Component
|
||||
pixel_radiosity +=
|
||||
intersection_data.material().emissive.factor.extend(1.0)
|
||||
.mul_element_wise(
|
||||
intersection_data.material()
|
||||
//TODO: texture sampling!
|
||||
.get_base_color_alpha(Vector2::new(0.0, 0.0))
|
||||
);
|
||||
|
||||
|
||||
//get the intersected triangle and calculate the face normals
|
||||
let intersected_triangle = intersection_data.intersected_triangle();
|
||||
let tangent = (intersected_triangle[0].position -
|
||||
intersected_triangle[1].position).normalize();
|
||||
let mut face_normal: Vector3<f32> = tangent
|
||||
.cross(intersected_triangle[0].position -
|
||||
intersected_triangle[2].position).normalize();
|
||||
//flip normal if face is hit from behind
|
||||
if face_normal.dot(-intersection_data.ray().direction) < 0.0 {
|
||||
face_normal *= -1.0;
|
||||
|
||||
let decision_factor = rand::random::<f32>();
|
||||
let mut direction: Vector3<f32>;
|
||||
|
||||
let face_normal =
|
||||
face_normal_for_triangle(&intersection_data.intersected_triangle());
|
||||
|
||||
let rough_sampling: bool = decision_factor <= intersection_data.material().pbr.roughness_factor;
|
||||
|
||||
//do we trace rough or specular?
|
||||
if rough_sampling {
|
||||
//generate random direction (rough sampling)
|
||||
direction = uniform_random_angle_triangle_hemisphere(
|
||||
intersected_triangle,
|
||||
intersection_data.ray(),
|
||||
);
|
||||
} else {
|
||||
//mirror vector (specular sampling)
|
||||
direction = intersection_data.ray().direction -
|
||||
2.0 * (intersection_data.ray().direction.dot(face_normal)) * face_normal;
|
||||
}
|
||||
let bitangent = tangent.cross(face_normal).normalize();
|
||||
|
||||
/*
|
||||
generate random direction on hemisphere
|
||||
*/
|
||||
let phi = rand::random::<f32>() * 2.0 * PI;
|
||||
//allow arbitrary angles
|
||||
let radius = rand::random::<f32>();
|
||||
let sqrt_radius = f32::sqrt(rand::random::<f32>());
|
||||
|
||||
let direction = (tangent * f32::cos(phi) * sqrt_radius +
|
||||
bitangent * f32::sin(phi) * sqrt_radius +
|
||||
face_normal * f32::sqrt(1.0 - radius)).normalize();
|
||||
direction = direction.normalize();
|
||||
|
||||
let secondary_ray = Ray {
|
||||
//prevent self-intersection
|
||||
source: intersection_data.intersection_point() + RAY_EPSILON * face_normal,
|
||||
source: intersection_data.intersection_point() + RAY_EPSILON * direction,
|
||||
direction,
|
||||
};
|
||||
|
||||
|
|
@ -197,15 +201,27 @@ fn accumulate_colors(intersection_data: &IntersectionData,
|
|||
global_scene,
|
||||
recursion_depth_left - 1);
|
||||
|
||||
//weigh by cosine term depending on view angel
|
||||
let cos_weighting = direction.dot(
|
||||
face_normal
|
||||
);
|
||||
|
||||
let cos_weighting = direction.dot(face_normal);
|
||||
let brdf: Vector4<f32>;
|
||||
|
||||
let brdf = intersection_data.material()
|
||||
if rough_sampling {
|
||||
brdf = intersection_data.material()
|
||||
//TODO: texture sampling!
|
||||
.get_base_color_alpha(Vector2::new(0.0, 0.0));
|
||||
|
||||
//reflected component
|
||||
pixel_radiosity += brdf.mul_element_wise(incoming_radiosity) * cos_weighting * 2.0 * PI;
|
||||
} else {
|
||||
pixel_radiosity += incoming_radiosity * cos_weighting * 2.0 * PI +
|
||||
intersection_data.material()
|
||||
//TODO: texture sampling!
|
||||
.get_base_color_alpha(Vector2::new(0.0, 0.0));
|
||||
}
|
||||
|
||||
pixel_radiosity
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue