render head with random color triangles and no backface culling
This commit is contained in:
parent
10ac742f4f
commit
90420bdc72
2 changed files with 47 additions and 39 deletions
62
src/main.rs
62
src/main.rs
|
@ -36,11 +36,13 @@ const YELLOW: TGAColor = TGAColor {
|
||||||
};
|
};
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let w = 128;
|
let w = 800;
|
||||||
let h = 128;
|
let h = 800;
|
||||||
let mut fb = TGAImage::new(w, h, TGAFormat::RGB);
|
let mut fb = TGAImage::new(w, h, TGAFormat::RGB);
|
||||||
fill_triangles(&mut fb);
|
// fill_triangles(&mut fb);
|
||||||
fb.write_file("triangles.tga", true, true).unwrap();
|
// fb.write_file("triangles.tga", true, true).unwrap();
|
||||||
|
|
||||||
|
_render_head(&mut fb);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn fill_triangles(fb: &mut TGAImage) {
|
fn fill_triangles(fb: &mut TGAImage) {
|
||||||
|
@ -63,11 +65,17 @@ fn fill_triangles(fb: &mut TGAImage) {
|
||||||
t3.render_filled(GREEN, fb);
|
t3.render_filled(GREEN, fb);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn _render_diablo(model: Model, fb: &mut TGAImage) {
|
fn _render_diablo(fb: &mut TGAImage) {
|
||||||
|
let model = Model::from_obj("diablo3_pose.obj");
|
||||||
model.render_wireframe(fb);
|
model.render_wireframe(fb);
|
||||||
fb.write_file("diablo.tga", true, true).unwrap();
|
fb.write_file("diablo.tga", true, true).unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn _render_head(fb: &mut TGAImage) {
|
||||||
|
let model = Model::from_obj("head.obj");
|
||||||
|
model.render_triangles(fb);
|
||||||
|
fb.write_file("head.tga", true, true).unwrap();
|
||||||
|
}
|
||||||
fn _baseline(framebuffer: &mut TGAImage) {
|
fn _baseline(framebuffer: &mut TGAImage) {
|
||||||
let ax = 7;
|
let ax = 7;
|
||||||
let ay = 3;
|
let ay = 3;
|
||||||
|
@ -121,30 +129,17 @@ fn line(mut a: Point2i, mut b: Point2i, color: TGAColor, mut fb: &mut TGAImage)
|
||||||
std::mem::swap(&mut a, &mut b);
|
std::mem::swap(&mut a, &mut b);
|
||||||
}
|
}
|
||||||
|
|
||||||
let fb = Arc::new(Mutex::new(fb));
|
|
||||||
let y = Arc::new(Mutex::new(a.y as f32));
|
|
||||||
|
|
||||||
let step = (b.y - a.y) as f32 / (b.x - a.x) as f32;
|
let step = (b.y - a.y) as f32 / (b.x - a.x) as f32;
|
||||||
(a.x..b.x).into_par_iter().for_each(|x| {
|
let mut y = a.y as f32;
|
||||||
let ny = {
|
for x in a.x..b.x {
|
||||||
if let Ok(y) = y.lock() {
|
|
||||||
*y
|
|
||||||
} else {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
let (px, py) = if is_steep {
|
let (px, py) = if is_steep {
|
||||||
(ny.round_ties_even() as i32, x)
|
(y.round_ties_even() as i32, x)
|
||||||
} else {
|
} else {
|
||||||
(x, ny.round_ties_even() as i32)
|
(x, y.round_ties_even() as i32)
|
||||||
};
|
};
|
||||||
if let Ok(mut fb) = fb.lock() {
|
fb.set(px as u32, py as u32, color);
|
||||||
fb.set(px as u32, py as u32, color);
|
y += step;
|
||||||
}
|
}
|
||||||
if let Ok(mut y) = y.lock() {
|
|
||||||
*y += step;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
|
#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
|
||||||
|
@ -159,15 +154,6 @@ impl Triangle {
|
||||||
Self { a, b, c }
|
Self { a, b, c }
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn sort(&mut self) {
|
|
||||||
let mut sorted = [self.a, self.b, self.c];
|
|
||||||
sorted.sort_unstable_by(|a, b| a.y.cmp(&b.y));
|
|
||||||
let [a, b, c] = sorted;
|
|
||||||
self.a = a;
|
|
||||||
self.b = b;
|
|
||||||
self.c = c;
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn signed_area(&self) -> f32 {
|
pub fn signed_area(&self) -> f32 {
|
||||||
0.5 * ((self.b.y - self.a.y) * (self.a.x + self.b.x)
|
0.5 * ((self.b.y - self.a.y) * (self.a.x + self.b.x)
|
||||||
+ (self.c.y - self.b.y) * (self.c.x + self.b.x)
|
+ (self.c.y - self.b.y) * (self.c.x + self.b.x)
|
||||||
|
@ -189,13 +175,13 @@ impl Triangle {
|
||||||
pub fn render_filled(&self, color: TGAColor, fb: &mut TGAImage) {
|
pub fn render_filled(&self, color: TGAColor, fb: &mut TGAImage) {
|
||||||
let fb = Arc::new(Mutex::new(fb));
|
let fb = Arc::new(Mutex::new(fb));
|
||||||
let bb = self.bb();
|
let bb = self.bb();
|
||||||
let total_area = self.signed_area();
|
let total_area_sign = self.signed_area().signum();
|
||||||
(bb.ymin()..=bb.ymax()).into_par_iter().for_each(|y| {
|
(bb.ymin()..=bb.ymax()).into_par_iter().for_each(|y| {
|
||||||
(bb.xmin()..bb.xmax()).into_par_iter().for_each(|x| {
|
(bb.xmin()..bb.xmax()).into_par_iter().for_each(|x| {
|
||||||
let p = Point2i::new(x, y);
|
let p = Point2i::new(x, y);
|
||||||
let a = Triangle::new(p, self.a, self.b).signed_area() / total_area;
|
let a = Triangle::new(p, self.a, self.b).signed_area().signum() * total_area_sign;
|
||||||
let b = Triangle::new(p, self.b, self.c).signed_area() / total_area;
|
let b = Triangle::new(p, self.b, self.c).signed_area().signum() * total_area_sign;
|
||||||
let c = Triangle::new(p, self.c, self.a).signed_area() / total_area;
|
let c = Triangle::new(p, self.c, self.a).signed_area().signum() * total_area_sign;
|
||||||
|
|
||||||
if a.is_sign_positive()
|
if a.is_sign_positive()
|
||||||
&& b.is_sign_positive()
|
&& b.is_sign_positive()
|
||||||
|
|
24
src/model.rs
24
src/model.rs
|
@ -1,7 +1,9 @@
|
||||||
use std::ops::{Deref, DerefMut};
|
use std::ops::{Deref, DerefMut};
|
||||||
|
|
||||||
|
use rand::Rng;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
RED, line,
|
RED, Triangle, line,
|
||||||
point::{Point2i, Point3f},
|
point::{Point2i, Point3f},
|
||||||
tga::TGAImage,
|
tga::TGAImage,
|
||||||
};
|
};
|
||||||
|
@ -92,6 +94,26 @@ impl Model {
|
||||||
line(c, a, RED, framebuffer);
|
line(c, a, RED, framebuffer);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
pub fn render_triangles(&self, framebuffer: &mut TGAImage) {
|
||||||
|
let width = framebuffer.width;
|
||||||
|
let height = framebuffer.height;
|
||||||
|
|
||||||
|
let mut rng = rand::rng();
|
||||||
|
for face in self.faces.iter() {
|
||||||
|
let a = world2view(self.verts[face[0]], width, height);
|
||||||
|
let b = world2view(self.verts[face[1]], width, height);
|
||||||
|
let c = world2view(self.verts[face[2]], width, height);
|
||||||
|
let triangle = Triangle::new(a, b, c);
|
||||||
|
let color = [
|
||||||
|
rng.random_range(0..=255u8),
|
||||||
|
rng.random_range(0..=255u8),
|
||||||
|
rng.random_range(0..=255u8),
|
||||||
|
255,
|
||||||
|
]
|
||||||
|
.into();
|
||||||
|
triangle.render_filled(color, framebuffer);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn world2view(point: Point3f, width: u32, height: u32) -> Point2i {
|
fn world2view(point: Point3f, width: u32, height: u32) -> Point2i {
|
||||||
|
|
Loading…
Reference in a new issue