middle of attempting to fix rotations
This commit is contained in:
parent
6cbd93aad0
commit
8657806aba
10 changed files with 692 additions and 78 deletions
BIN
result_image.png
BIN
result_image.png
Binary file not shown.
|
Before Width: | Height: | Size: 6.7 KiB After Width: | Height: | Size: 6.4 KiB |
BIN
scenes/cube_on_plane.bin
Normal file
BIN
scenes/cube_on_plane.bin
Normal file
Binary file not shown.
Binary file not shown.
BIN
scenes/cube_on_plane.blend1
Normal file
BIN
scenes/cube_on_plane.blend1
Normal file
Binary file not shown.
Binary file not shown.
538
scenes/cube_on_plane.gltf
Normal file
538
scenes/cube_on_plane.gltf
Normal file
|
|
@ -0,0 +1,538 @@
|
||||||
|
{
|
||||||
|
"asset":{
|
||||||
|
"generator":"Khronos glTF Blender I/O v4.1.34",
|
||||||
|
"version":"2.0"
|
||||||
|
},
|
||||||
|
"extensionsUsed":[
|
||||||
|
"KHR_lights_punctual"
|
||||||
|
],
|
||||||
|
"extensionsRequired":[
|
||||||
|
"KHR_lights_punctual"
|
||||||
|
],
|
||||||
|
"extensions":{
|
||||||
|
"KHR_lights_punctual":{
|
||||||
|
"lights":[
|
||||||
|
{
|
||||||
|
"color":[
|
||||||
|
1,
|
||||||
|
1,
|
||||||
|
1
|
||||||
|
],
|
||||||
|
"intensity":54351.41306588226,
|
||||||
|
"type":"point",
|
||||||
|
"name":"Light"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"scene":0,
|
||||||
|
"scenes":[
|
||||||
|
{
|
||||||
|
"name":"Scene",
|
||||||
|
"nodes":[
|
||||||
|
0,
|
||||||
|
1,
|
||||||
|
2,
|
||||||
|
3,
|
||||||
|
4,
|
||||||
|
5,
|
||||||
|
6
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"nodes":[
|
||||||
|
{
|
||||||
|
"mesh":0,
|
||||||
|
"name":"Cube"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"extensions":{
|
||||||
|
"KHR_lights_punctual":{
|
||||||
|
"light":0
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"name":"Light",
|
||||||
|
"rotation":[
|
||||||
|
-0.28416627645492554,
|
||||||
|
0.7269423007965088,
|
||||||
|
0.34203392267227173,
|
||||||
|
0.5232754945755005
|
||||||
|
],
|
||||||
|
"translation":[
|
||||||
|
4.076245307922363,
|
||||||
|
5.903861999511719,
|
||||||
|
-1.0054539442062378
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"camera":0,
|
||||||
|
"name":"Camera",
|
||||||
|
"rotation":[
|
||||||
|
0,
|
||||||
|
1,
|
||||||
|
0,
|
||||||
|
0
|
||||||
|
],
|
||||||
|
"translation":[
|
||||||
|
2,
|
||||||
|
10,
|
||||||
|
-1.9999992847442627
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"mesh":1,
|
||||||
|
"name":"Cube.001"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"mesh":2,
|
||||||
|
"name":"Cube.002",
|
||||||
|
"translation":[
|
||||||
|
2,
|
||||||
|
10,
|
||||||
|
-10
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"mesh":3,
|
||||||
|
"name":"Cube.003",
|
||||||
|
"rotation":[
|
||||||
|
0,
|
||||||
|
0.3826834559440613,
|
||||||
|
0,
|
||||||
|
0.9238795638084412
|
||||||
|
],
|
||||||
|
"translation":[
|
||||||
|
2,
|
||||||
|
10,
|
||||||
|
10
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"mesh":4,
|
||||||
|
"name":"Suzanne",
|
||||||
|
"translation":[
|
||||||
|
-10,
|
||||||
|
10,
|
||||||
|
0
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"cameras":[
|
||||||
|
{
|
||||||
|
"name":"Camera",
|
||||||
|
"perspective":{
|
||||||
|
"aspectRatio":1,
|
||||||
|
"yfov":0.7853981852531433,
|
||||||
|
"zfar":100,
|
||||||
|
"znear":0.0010000000474974513
|
||||||
|
},
|
||||||
|
"type":"perspective"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"materials":[
|
||||||
|
{
|
||||||
|
"doubleSided":true,
|
||||||
|
"name":"Material",
|
||||||
|
"pbrMetallicRoughness":{
|
||||||
|
"baseColorFactor":[
|
||||||
|
0.800000011920929,
|
||||||
|
0.800000011920929,
|
||||||
|
0.800000011920929,
|
||||||
|
1
|
||||||
|
],
|
||||||
|
"metallicFactor":0,
|
||||||
|
"roughnessFactor":0.5
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"doubleSided":true,
|
||||||
|
"name":"Material.001",
|
||||||
|
"pbrMetallicRoughness":{
|
||||||
|
"baseColorFactor":[
|
||||||
|
0.8002041578292847,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
1
|
||||||
|
],
|
||||||
|
"metallicFactor":0,
|
||||||
|
"roughnessFactor":0.5
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"doubleSided":true,
|
||||||
|
"name":"Material.003",
|
||||||
|
"pbrMetallicRoughness":{
|
||||||
|
"baseColorFactor":[
|
||||||
|
0.019036345183849335,
|
||||||
|
0,
|
||||||
|
0.8002663850784302,
|
||||||
|
1
|
||||||
|
],
|
||||||
|
"metallicFactor":0,
|
||||||
|
"roughnessFactor":0.5
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"doubleSided":true,
|
||||||
|
"name":"Material.002",
|
||||||
|
"pbrMetallicRoughness":{
|
||||||
|
"baseColorFactor":[
|
||||||
|
0.008347976952791214,
|
||||||
|
0.8001724481582642,
|
||||||
|
0,
|
||||||
|
1
|
||||||
|
],
|
||||||
|
"metallicFactor":0,
|
||||||
|
"roughnessFactor":0.5
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"meshes":[
|
||||||
|
{
|
||||||
|
"name":"Cube",
|
||||||
|
"primitives":[
|
||||||
|
{
|
||||||
|
"attributes":{
|
||||||
|
"POSITION":0,
|
||||||
|
"NORMAL":1,
|
||||||
|
"TEXCOORD_0":2
|
||||||
|
},
|
||||||
|
"indices":3,
|
||||||
|
"material":0
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name":"Cube.001",
|
||||||
|
"primitives":[
|
||||||
|
{
|
||||||
|
"attributes":{
|
||||||
|
"POSITION":4,
|
||||||
|
"NORMAL":5,
|
||||||
|
"TEXCOORD_0":6
|
||||||
|
},
|
||||||
|
"indices":3,
|
||||||
|
"material":0
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name":"Cube.002",
|
||||||
|
"primitives":[
|
||||||
|
{
|
||||||
|
"attributes":{
|
||||||
|
"POSITION":7,
|
||||||
|
"NORMAL":8,
|
||||||
|
"TEXCOORD_0":9
|
||||||
|
},
|
||||||
|
"indices":10,
|
||||||
|
"material":1
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name":"Cube.003",
|
||||||
|
"primitives":[
|
||||||
|
{
|
||||||
|
"attributes":{
|
||||||
|
"POSITION":11,
|
||||||
|
"NORMAL":12,
|
||||||
|
"TEXCOORD_0":13
|
||||||
|
},
|
||||||
|
"indices":10,
|
||||||
|
"material":2
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name":"Suzanne",
|
||||||
|
"primitives":[
|
||||||
|
{
|
||||||
|
"attributes":{
|
||||||
|
"POSITION":14,
|
||||||
|
"NORMAL":15,
|
||||||
|
"TEXCOORD_0":16
|
||||||
|
},
|
||||||
|
"indices":17,
|
||||||
|
"material":3
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"accessors":[
|
||||||
|
{
|
||||||
|
"bufferView":0,
|
||||||
|
"componentType":5126,
|
||||||
|
"count":14,
|
||||||
|
"max":[
|
||||||
|
1.4142135381698608,
|
||||||
|
2,
|
||||||
|
1.4142135381698608
|
||||||
|
],
|
||||||
|
"min":[
|
||||||
|
-1.4142135381698608,
|
||||||
|
0,
|
||||||
|
-1.4142135381698608
|
||||||
|
],
|
||||||
|
"type":"VEC3"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"bufferView":1,
|
||||||
|
"componentType":5126,
|
||||||
|
"count":14,
|
||||||
|
"type":"VEC3"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"bufferView":2,
|
||||||
|
"componentType":5126,
|
||||||
|
"count":14,
|
||||||
|
"type":"VEC2"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"bufferView":3,
|
||||||
|
"componentType":5123,
|
||||||
|
"count":36,
|
||||||
|
"type":"SCALAR"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"bufferView":4,
|
||||||
|
"componentType":5126,
|
||||||
|
"count":14,
|
||||||
|
"max":[
|
||||||
|
-0.5857864618301392,
|
||||||
|
2,
|
||||||
|
-0.5857864618301392
|
||||||
|
],
|
||||||
|
"min":[
|
||||||
|
-3.4142136573791504,
|
||||||
|
0,
|
||||||
|
-3.4142136573791504
|
||||||
|
],
|
||||||
|
"type":"VEC3"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"bufferView":5,
|
||||||
|
"componentType":5126,
|
||||||
|
"count":14,
|
||||||
|
"type":"VEC3"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"bufferView":6,
|
||||||
|
"componentType":5126,
|
||||||
|
"count":14,
|
||||||
|
"type":"VEC2"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"bufferView":7,
|
||||||
|
"componentType":5126,
|
||||||
|
"count":14,
|
||||||
|
"max":[
|
||||||
|
1,
|
||||||
|
1,
|
||||||
|
1
|
||||||
|
],
|
||||||
|
"min":[
|
||||||
|
-1,
|
||||||
|
-1,
|
||||||
|
-1
|
||||||
|
],
|
||||||
|
"type":"VEC3"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"bufferView":8,
|
||||||
|
"componentType":5126,
|
||||||
|
"count":14,
|
||||||
|
"type":"VEC3"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"bufferView":9,
|
||||||
|
"componentType":5126,
|
||||||
|
"count":14,
|
||||||
|
"type":"VEC2"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"bufferView":10,
|
||||||
|
"componentType":5123,
|
||||||
|
"count":36,
|
||||||
|
"type":"SCALAR"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"bufferView":11,
|
||||||
|
"componentType":5126,
|
||||||
|
"count":14,
|
||||||
|
"max":[
|
||||||
|
1,
|
||||||
|
1,
|
||||||
|
1
|
||||||
|
],
|
||||||
|
"min":[
|
||||||
|
-1,
|
||||||
|
-1,
|
||||||
|
-1
|
||||||
|
],
|
||||||
|
"type":"VEC3"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"bufferView":12,
|
||||||
|
"componentType":5126,
|
||||||
|
"count":14,
|
||||||
|
"type":"VEC3"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"bufferView":13,
|
||||||
|
"componentType":5126,
|
||||||
|
"count":14,
|
||||||
|
"type":"VEC2"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"bufferView":14,
|
||||||
|
"componentType":5126,
|
||||||
|
"count":555,
|
||||||
|
"max":[
|
||||||
|
1.3671875,
|
||||||
|
0.984375,
|
||||||
|
0.8515625
|
||||||
|
],
|
||||||
|
"min":[
|
||||||
|
-1.3671875,
|
||||||
|
-0.984375,
|
||||||
|
-0.8515625
|
||||||
|
],
|
||||||
|
"type":"VEC3"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"bufferView":15,
|
||||||
|
"componentType":5126,
|
||||||
|
"count":555,
|
||||||
|
"type":"VEC3"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"bufferView":16,
|
||||||
|
"componentType":5126,
|
||||||
|
"count":555,
|
||||||
|
"type":"VEC2"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"bufferView":17,
|
||||||
|
"componentType":5123,
|
||||||
|
"count":2904,
|
||||||
|
"type":"SCALAR"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"bufferViews":[
|
||||||
|
{
|
||||||
|
"buffer":0,
|
||||||
|
"byteLength":168,
|
||||||
|
"byteOffset":0,
|
||||||
|
"target":34962
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"buffer":0,
|
||||||
|
"byteLength":168,
|
||||||
|
"byteOffset":168,
|
||||||
|
"target":34962
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"buffer":0,
|
||||||
|
"byteLength":112,
|
||||||
|
"byteOffset":336,
|
||||||
|
"target":34962
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"buffer":0,
|
||||||
|
"byteLength":72,
|
||||||
|
"byteOffset":448,
|
||||||
|
"target":34963
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"buffer":0,
|
||||||
|
"byteLength":168,
|
||||||
|
"byteOffset":520,
|
||||||
|
"target":34962
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"buffer":0,
|
||||||
|
"byteLength":168,
|
||||||
|
"byteOffset":688,
|
||||||
|
"target":34962
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"buffer":0,
|
||||||
|
"byteLength":112,
|
||||||
|
"byteOffset":856,
|
||||||
|
"target":34962
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"buffer":0,
|
||||||
|
"byteLength":168,
|
||||||
|
"byteOffset":968,
|
||||||
|
"target":34962
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"buffer":0,
|
||||||
|
"byteLength":168,
|
||||||
|
"byteOffset":1136,
|
||||||
|
"target":34962
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"buffer":0,
|
||||||
|
"byteLength":112,
|
||||||
|
"byteOffset":1304,
|
||||||
|
"target":34962
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"buffer":0,
|
||||||
|
"byteLength":72,
|
||||||
|
"byteOffset":1416,
|
||||||
|
"target":34963
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"buffer":0,
|
||||||
|
"byteLength":168,
|
||||||
|
"byteOffset":1488,
|
||||||
|
"target":34962
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"buffer":0,
|
||||||
|
"byteLength":168,
|
||||||
|
"byteOffset":1656,
|
||||||
|
"target":34962
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"buffer":0,
|
||||||
|
"byteLength":112,
|
||||||
|
"byteOffset":1824,
|
||||||
|
"target":34962
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"buffer":0,
|
||||||
|
"byteLength":6660,
|
||||||
|
"byteOffset":1936,
|
||||||
|
"target":34962
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"buffer":0,
|
||||||
|
"byteLength":6660,
|
||||||
|
"byteOffset":8596,
|
||||||
|
"target":34962
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"buffer":0,
|
||||||
|
"byteLength":4440,
|
||||||
|
"byteOffset":15256,
|
||||||
|
"target":34962
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"buffer":0,
|
||||||
|
"byteLength":5808,
|
||||||
|
"byteOffset":19696,
|
||||||
|
"target":34963
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"buffers":[
|
||||||
|
{
|
||||||
|
"byteLength":25504,
|
||||||
|
"uri":"cube_on_plane.bin"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
122
src/geometry.rs
122
src/geometry.rs
|
|
@ -1,87 +1,69 @@
|
||||||
use cgmath::{Angle, InnerSpace, Matrix4, SquareMatrix, Vector3, Vector4};
|
use cgmath::{InnerSpace, Vector3};
|
||||||
use easy_gltf::{Camera, Projection};
|
use cgmath::num_traits::abs;
|
||||||
use easy_gltf::model::Triangle;
|
use easy_gltf::model::Triangle;
|
||||||
|
use crate::ray::Ray;
|
||||||
|
|
||||||
pub struct Ray {
|
const EPSILON: f32 = 0.000001;
|
||||||
source: Vector3<f32>,
|
|
||||||
direction: Vector3<f32>,
|
|
||||||
}
|
|
||||||
|
|
||||||
pub trait Intersectable {
|
pub trait Intersectable {
|
||||||
/*
|
/*
|
||||||
tests whether the ray intersects the Intersectable.
|
tests whether the ray intersects the Intersectable.
|
||||||
returns: The intersection point or empty if there is none
|
returns: The intersection point or empty if there is none
|
||||||
*/
|
*/
|
||||||
fn test_isec(&self, ray: &Ray) -> Option<Vector3<f32>>;
|
fn test_isec(&self, ray: &Ray) -> Option<(f32, Vector3<f32>)>;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Intersectable for Triangle {
|
impl Intersectable for Triangle {
|
||||||
//perform muller trumbore intersection
|
//perform muller trumbore intersection
|
||||||
fn test_isec(&self, ray: &Ray) -> Option<Vector3<f32>> {
|
fn test_isec(&self, ray: &Ray) -> Option<(f32, Vector3<f32>)> {
|
||||||
//TODO: implement correct intersection here
|
assert!(
|
||||||
if ray.direction.x > 0.5 &&
|
abs(ray.direction.dot(ray.direction) - 1.0) < EPSILON,
|
||||||
ray.direction.x < 0.6 &&
|
"Ray direction not normalized"
|
||||||
ray.direction.y > 0.1 &&
|
);
|
||||||
ray.direction.y < 0.6 {
|
|
||||||
return Some(Vector3::new(1.0, 1.0, 1.0));
|
//get triangle vertices
|
||||||
|
let p0 = self[0].position;
|
||||||
|
let p1 = self[1].position;
|
||||||
|
let p2 = self[2].position;
|
||||||
|
|
||||||
|
let edge1 = p1 - p0;
|
||||||
|
let edge2 = p2 - p0;
|
||||||
|
|
||||||
|
let ray_cross_e2 = ray.direction.cross(edge2);
|
||||||
|
let determinant = edge1.dot(ray_cross_e2);
|
||||||
|
|
||||||
|
//ray is parallel to triangle
|
||||||
|
if determinant > -EPSILON && determinant < EPSILON {
|
||||||
|
return None;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let inverse_determinant = 1.0 / determinant;
|
||||||
|
|
||||||
|
let s = ray.source - p0;
|
||||||
|
let u = s.dot(ray_cross_e2) * inverse_determinant;
|
||||||
|
|
||||||
|
//early out 2
|
||||||
|
if u < 0.0 || u > 1.0 {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
|
||||||
|
let s_cross_e1 = s.cross(edge1);
|
||||||
|
let v = ray.direction.dot(s_cross_e1) * inverse_determinant;
|
||||||
|
|
||||||
|
//early out 3
|
||||||
|
if v < 0.0 || u + v > 1.0 {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
|
||||||
|
//compute ray parameter t
|
||||||
|
|
||||||
|
let t = edge2.dot(s_cross_e1) * inverse_determinant;
|
||||||
|
|
||||||
|
if t > EPSILON {
|
||||||
|
return Option::from((t, ray.source + ray.direction * t));
|
||||||
|
}
|
||||||
|
// This means that there is a line intersection but not a ray intersection.
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn construct_primary_rays(camera: &Camera,
|
|
||||||
(width, height): (usize, usize),
|
|
||||||
(pixel_x_coord, pixel_y_coord): (usize, usize),
|
|
||||||
) -> Vec<Ray> {
|
|
||||||
//only allow perspective rendering
|
|
||||||
//TODO: ignoring aspect ratio here
|
|
||||||
let fovy = match camera.projection {
|
|
||||||
Projection::Perspective { yfov, aspect_ratio: _aspect_ratio } => { yfov }
|
|
||||||
Projection::Orthographic { .. } => { panic!("Orthographic rendering not supported.") }
|
|
||||||
};
|
|
||||||
|
|
||||||
//ray origin in world space
|
|
||||||
let origin_world_space = camera.position();
|
|
||||||
|
|
||||||
//seems to be the distance from the camera origin to the view plane
|
|
||||||
let z: f32 = height as f32 / fovy.tan();
|
|
||||||
|
|
||||||
//obtain the inverse transformation Matrix
|
|
||||||
let inverse_transform = camera.transform.invert().unwrap_or_else(||
|
|
||||||
panic!("Non invertible transform Matrix. giving up.")
|
|
||||||
);
|
|
||||||
|
|
||||||
//TODO: take ray multiplier per pixel into account here
|
|
||||||
let mut rays: Vec<Ray> = Vec::with_capacity(height * width);
|
|
||||||
|
|
||||||
//generate all rays for this pixel and add them to the rays vector
|
|
||||||
//TODO: use blue noise here to generate multiple rays per pixel
|
|
||||||
rays.push(generate_ray(
|
|
||||||
width,
|
|
||||||
height,
|
|
||||||
&inverse_transform,
|
|
||||||
z,
|
|
||||||
pixel_x_coord,
|
|
||||||
pixel_y_coord,
|
|
||||||
origin_world_space));
|
|
||||||
|
|
||||||
rays
|
|
||||||
}
|
|
||||||
|
|
||||||
fn generate_ray(image_width: usize,
|
|
||||||
image_height: usize,
|
|
||||||
inverse_transform: &Matrix4<f32>,
|
|
||||||
focal_length: f32,
|
|
||||||
u: usize,
|
|
||||||
v: usize,
|
|
||||||
ray_origin: Vector3<f32>) -> Ray {
|
|
||||||
//calculate the ray direction and translate it to world space
|
|
||||||
let direction_view_space: Vector4<f32> =
|
|
||||||
Vector4::new(u as f32 - (image_width as f32 / 2.0),
|
|
||||||
v as f32 - (image_height as f32 / 2.0),
|
|
||||||
-focal_length,
|
|
||||||
0.0);
|
|
||||||
let direction_world_space = inverse_transform * direction_view_space;
|
|
||||||
|
|
||||||
Ray { source: ray_origin, direction: direction_world_space.normalize().truncate() }
|
|
||||||
}
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
mod renderer;
|
mod renderer;
|
||||||
mod geometry;
|
mod geometry;
|
||||||
|
mod ray;
|
||||||
|
|
||||||
use std::string::String;
|
use std::string::String;
|
||||||
use std::sync::{Arc, Mutex};
|
use std::sync::{Arc, Mutex};
|
||||||
|
|
|
||||||
69
src/ray.rs
Normal file
69
src/ray.rs
Normal file
|
|
@ -0,0 +1,69 @@
|
||||||
|
use std::ops::Mul;
|
||||||
|
use cgmath::{Angle, InnerSpace, Matrix4, SquareMatrix, Vector3, Vector4};
|
||||||
|
use easy_gltf::{Camera, Projection};
|
||||||
|
|
||||||
|
pub struct Ray {
|
||||||
|
pub(crate) source: Vector3<f32>,
|
||||||
|
pub(crate) direction: Vector3<f32>,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn construct_primary_rays(camera: &Camera,
|
||||||
|
(width, height): (usize, usize),
|
||||||
|
(pixel_x_coord, pixel_y_coord): (usize, usize),
|
||||||
|
) -> Vec<Ray> {
|
||||||
|
//only allow perspective rendering
|
||||||
|
//TODO: ignoring aspect ratio here
|
||||||
|
let (fovy, aspect_ratio) = match camera.projection {
|
||||||
|
Projection::Perspective { yfov, aspect_ratio } => {
|
||||||
|
(yfov, aspect_ratio) }
|
||||||
|
Projection::Orthographic { .. } => { panic!("Orthographic rendering not supported.") }
|
||||||
|
};
|
||||||
|
|
||||||
|
//ray origin in world space
|
||||||
|
let origin_world_space = camera.position();
|
||||||
|
//dbg!(camera.transform);
|
||||||
|
|
||||||
|
// the distance from the camera origin to the view plane
|
||||||
|
let z: f32 = height as f32 / (2.0 * fovy.mul(0.5).tan());
|
||||||
|
|
||||||
|
//obtain the inverse transformation Matrix
|
||||||
|
let inverse_transform = camera.transform.invert().unwrap_or_else(||
|
||||||
|
panic!("Non invertible transform Matrix. giving up.")
|
||||||
|
);
|
||||||
|
|
||||||
|
//TODO: take ray multiplier per pixel into account here
|
||||||
|
let mut rays: Vec<Ray> = Vec::with_capacity(height * width);
|
||||||
|
|
||||||
|
//generate all rays for this pixel and add them to the rays vector
|
||||||
|
//TODO: use blue noise here to generate multiple rays per pixel
|
||||||
|
rays.push(generate_single_primary_ray(
|
||||||
|
width,
|
||||||
|
height,
|
||||||
|
&inverse_transform,
|
||||||
|
z,
|
||||||
|
pixel_x_coord,
|
||||||
|
pixel_y_coord,
|
||||||
|
origin_world_space));
|
||||||
|
|
||||||
|
rays
|
||||||
|
}
|
||||||
|
|
||||||
|
fn generate_single_primary_ray(image_width: usize,
|
||||||
|
image_height: usize,
|
||||||
|
inverse_transform: &Matrix4<f32>,
|
||||||
|
focal_length: f32,
|
||||||
|
u: usize,
|
||||||
|
v: usize,
|
||||||
|
ray_origin: Vector3<f32>) -> Ray {
|
||||||
|
//calculate the ray direction and translate it to world space
|
||||||
|
let direction_view_space: Vector4<f32> =
|
||||||
|
Vector4::new(u as f32 - (image_width as f32 / 2.0),
|
||||||
|
v as f32 - (image_height as f32 / 2.0),
|
||||||
|
-focal_length,
|
||||||
|
0.0);
|
||||||
|
//TODO: Rotation is fucked
|
||||||
|
//x rotation has sign wrong, y and z are flipped
|
||||||
|
let direction_world_space = inverse_transform * direction_view_space.normalize();
|
||||||
|
|
||||||
|
Ray { source: ray_origin, direction: direction_world_space.truncate().normalize() }
|
||||||
|
}
|
||||||
|
|
@ -1,11 +1,13 @@
|
||||||
|
use std::cmp::max;
|
||||||
use std::sync::{Arc, Mutex};
|
use std::sync::{Arc, Mutex};
|
||||||
|
use cgmath::{Vector2, Vector3, Vector4, Zero};
|
||||||
use rayon::iter::{IntoParallelIterator, ParallelIterator};
|
use rayon::iter::{IntoParallelIterator, ParallelIterator};
|
||||||
use easy_gltf::model::{Mode};
|
use easy_gltf::model::{Mode};
|
||||||
use easy_gltf::{Camera, Scene};
|
use easy_gltf::{Camera, Scene};
|
||||||
use image::{DynamicImage, GenericImage, Rgba};
|
use image::{DynamicImage, GenericImage, Rgba};
|
||||||
use crate::Args;
|
use crate::Args;
|
||||||
use crate::geometry::{construct_primary_rays, Intersectable, Ray};
|
use crate::geometry::{Intersectable};
|
||||||
|
use crate::ray::{construct_primary_rays, Ray};
|
||||||
|
|
||||||
pub fn render(scenes: &Vec<Scene>,
|
pub fn render(scenes: &Vec<Scene>,
|
||||||
cl_args: &Args,
|
cl_args: &Args,
|
||||||
|
|
@ -23,8 +25,8 @@ pub fn render(scenes: &Vec<Scene>,
|
||||||
(px, py),
|
(px, py),
|
||||||
);
|
);
|
||||||
|
|
||||||
//let the initial pixel color be white and opaque
|
//let the initial pixel color be black and transparent
|
||||||
let mut pixel_color: Rgba<u8> = Rgba([0, 0, 0, 255]);
|
let mut pixel_color: Rgba<u8> = Rgba::from([0, 0, 0, 255]);
|
||||||
|
|
||||||
//cast each ray and get the output color
|
//cast each ray and get the output color
|
||||||
//TODO: in the end we will want to average the colors out here
|
//TODO: in the end we will want to average the colors out here
|
||||||
|
|
@ -45,7 +47,12 @@ pub fn render(scenes: &Vec<Scene>,
|
||||||
|
|
||||||
|
|
||||||
fn raytrace(ray: &Ray, scene: &Scene) -> Rgba<u8> {
|
fn raytrace(ray: &Ray, scene: &Scene) -> Rgba<u8> {
|
||||||
let mut pixel_color: Rgba<u8> = Rgba([0, 0, 0, 255]);
|
let mut pixel_color: Rgba<u8> = Rgba::from([0, 0, 0, 255]);
|
||||||
|
|
||||||
|
|
||||||
|
let mut smallest_t: f32 = f32::MAX;
|
||||||
|
let mut clostest_intersection_point: Option<Vector3<f32>> = None;
|
||||||
|
let mut color_at_isec = [0, 0, 0, 0];
|
||||||
|
|
||||||
//test intersection with all models in the scene
|
//test intersection with all models in the scene
|
||||||
//TODO: Improve, to avoid iterating all models
|
//TODO: Improve, to avoid iterating all models
|
||||||
|
|
@ -64,12 +71,29 @@ fn raytrace(ray: &Ray, scene: &Scene) -> Rgba<u8> {
|
||||||
match triangle.test_isec(&ray) {
|
match triangle.test_isec(&ray) {
|
||||||
//boilerplate implementation to set pixel to red if any intersection happened
|
//boilerplate implementation to set pixel to red if any intersection happened
|
||||||
None => {}
|
None => {}
|
||||||
Some(point) => {
|
Some((t, isec)) => {
|
||||||
pixel_color.0 = [255, 255, 255, 255];
|
// a new closer Point is found
|
||||||
return
|
if t < smallest_t {
|
||||||
|
smallest_t = t;
|
||||||
|
clostest_intersection_point = Option::from(isec);
|
||||||
|
let color_vec = model.material().get_base_color_alpha(
|
||||||
|
Vector2::new(0.0, 0.0)
|
||||||
|
).map(|comp| comp * 255.0);
|
||||||
|
|
||||||
|
color_at_isec = [color_vec[0] as u8, color_vec[1] as u8, color_vec[2] as u8, color_vec[3] as u8]
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
//make pixel opaque if intersection is found
|
||||||
|
match clostest_intersection_point {
|
||||||
|
Some(_) => {
|
||||||
|
pixel_color = Rgba::from(color_at_isec);
|
||||||
|
}
|
||||||
|
None {} => {}
|
||||||
|
}
|
||||||
|
|
||||||
pixel_color
|
pixel_color
|
||||||
}
|
}
|
||||||
Loading…
Add table
Add a link
Reference in a new issue