透視変換を修正するまでの道のり < 点からはじめるラスタライザ
from 座標変換と三次元空間のポリゴン(Rust製ラスタライザ)
透視変換を修正するまでの道のり < 点からはじめるラスタライザ
あ、同次座標を二次元座標にするときに$ wで割るの忘れてた
$ wで割ると$ w \simeq 0のときに死ぬな...
$ |w| < \varepsilonのときは$ \varepsilonで割るか?appbird.icon
code:rs
pub struct Vec4Screen(pub Vec4);
impl Vec4Screen {
/** このVec4のx, y要素をとった新たなPoint2を作る */
pub fn to_point2(&self) -> Point2 {
if self.0.w().abs() < 1e-6 { return Point2::new((self.0.x()* 1e6) as i32, (self.0.y()* 1e6) as i32) ; }
Point2::new((self.0.x() / self.0.w()) as i32, (self.0.y() / self.0.w()) as i32)
}
}
あはん
code:rs
thread 'main' panicked at src/canvas/line.rs:32:40:
attempt to multiply with overflow
note: run with RUST_BACKTRACE=1 environment variable to display a backtrace
オーバーフロー?
三角形面積の計算の際に外積を計算するよね(Rust で 三角形 を書く)
$ \varepsilon \simeq 10^{-6}に対して外積のオーダーは$ O(\varepsilon^{-2})になるわけで...
i64を使うべきか?appbird.icon
でも画面座標値にi64使ってもなあ、たかだか必要なのは$ 1024程度...。
Barycentric座標だと面積で困るのかappbird.icon
教えてチャッピー
---> 「これは「ラスタライズ自作勢あるある」ですね!途中結果だけi64にするとええんやで」
code:util/vec4.rs
pub fn cross(&self, rhs:&Self) -> i32 {
let r = (self.x as i64) * (rhs.y as i64) - (self.y as i64) * (rhs.x as i64);
r as i32
}
code:canvas/line.rs
pub fn across_y(&self, y:i32) -> ClosedInterval {
if self.p1.y == self.p2.y {
return
if self.p1.y == 0 { ClosedInterval::between(self.p1.x, self.p2.x) }
else { ClosedInterval::empty() }
}
let delta = self.delta();
let delta_x = delta.x as i64;
let delta_y = delta.y as i64;
let y_y1 = (y - self.p1.y) as i64;
let x0 = self.p1.x + round_div(delta_x*y_y1, delta_y);
let x1 = self.p1.x + round_div(delta_x*(y_y1+1), delta_y);
ClosedInterval::between(x0, x1)
}
なんか.....ビーム放ってますね....appbird.icon
https://gyazo.com/f97c14769768deae550ad39b34b093da
もしかして:カメラが近すぎる
code:rs
camera.position = Vec4::newpoint(f64::cos(k*t)*3., f64::sin(k*t)*3., 2.) ;
漆黒の闇になってしまったappbird.icon
$ z = 2
https://gyazo.com/bacf4daacd1e46debbd298545df2fdd6
$ z = 3
https://gyazo.com/e28865b89361b482fa9756be4628b09a
何この...何?
何がおかしいのか?appbird.icon
手順
1. 三角形のモデル座標を透視変換行列にかける
2. $ /wで割ってクリッピング座標系をローカル座標に
code:rs
snapshot projected = [
Vec4Project(Vec4 { e: -0.49912817523246633, 0.928240628968635, -2.400473380671401, -2.3333333333333335 }),
Vec4Project(Vec4 { e: -0.9991281752324664, -0.1828704821424762, -1.4002733606694002, -1.3333333333333333 }),
Vec4Project(Vec4 { e: -0.49912817523246633, 0.7060184067464128, 0.6001266793346001, 0.6666666666666666 })]
at src/camera.rs:50
これは平面上にあるのか?
o4くん「行列式を用いるとこれら 3 点は一直線上にはありません。」
ほならここは異常ではないね
3. ローカル座標をもとに三角形を描く
code:rs
snapshot points = Point2 { x: 0, y: -1 }, Point2 { x: 484315118, y: 442023437 }, Point2 { x: 2, y: 1 } at src/canvas/triangle.rs:19
なんか一点だけとんでもないことにappbird.icon
他の2点も0あたりの値に収束してるのは変だappbird.icon
2.と3.の間に異常がある?
あappbird.icon
code:canvas/camera.rs
pub fn transform_into_screen(&self, size:Point2, p: &Vec4Project) -> Vec4Screen {
let scale = size.y as f64 / 2.;
Vec4Screen(scale * &p.0 + size.to_vec4() / 2.)
}
よく考えたらここおかしいappbird.icon
scaleを直接かけてしまうとw成分にも影響してしまうな(scaleが意味をなしていない)
code:canvas/camera.rs
pub fn transform_into_screen(&self, size:Point2, p: &Vec4Project) -> Point2 {
let scale = size.y as f64 / 2.;
Vec4Screen(Mat4x4::scale_xyz(&scale) * &p.0 + size.to_vec4() / 2.).to_point2()
}
問題はなくなりつつあるけどまだだなあ
https://gyazo.com/6af3559f204df8d7193ce442079bc495
code:rs
snapshot points = Point2 { x: 16, y: -167 }, Point2 { x: 322417393, y: 325286930 }, Point2 { x: 303, y: 167 } at src/canvas/triangle.rs:19
なんで真ん中の一点だけ変なことになってるんだappbird.icon
多分真ん中の点のオーバーフローさえなんとかすればあるいは。
w値が変ということでもないappbird.icon
変換前の点を見てみよう。
code:rs
snapshot points = [
Vec4Project(Vec4 { e: 0.20661579061194416, 0.2818049077758217, -2.400473380671401, -2.3333333333333335 }),
Vec4Project(Vec4 { e: -0.293384209388056, -0.8293062033352895, -1.4002733606694002, -1.3333333333333333 }),
Vec4Project(Vec4 { e: 0.20661579061194416, 0.05958268555359947, 0.6001266793346001, 0.6666666666666666 })] at src/camera.rs:79
snapshot points = [
Vec4Project(Vec4 { e: 0.7160142132279991, -1.7574343149820502, -2.2004200420042004, -2.0 }),
Vec4Project(Vec4 { e: 0.7386714044093331, -0.36358921610512784, -0.0666733340000667, 0.0 }),
Vec4Project(Vec4 { e: 0.23867140440933302, -1.2524781049940168, 0.6001266793346001, 0.6666666666666666 })] at src/camera.rs:79
うーむappbird.icon
うん、なんか一個だけ0.0になってるやつがおるぞappbird.icon
これは何が原因?appbird.icon
カメラ位置をもっと遠くしないといけない?
$ z = 4
https://gyazo.com/e0331b98e0cb6ba30ab0194fde95a5bd
でもそうでもないな...
よくみるとワールドの点の置き方が変($ w/3されちゃってる)
code:main.rs
vertices: Vec4::newpoint(0., 0., 0.), Vec4::newpoint(3., 1., 2.)/3., Vec4::newpoint(0., -3., 4.)/3.,
code:main.rs
vertices: Vec4::newpoint(0., 0., 0.), Vec4::newpoint(3./3., 1./3., 2./3.), Vec4::newpoint(0./3., -3./3., 4./3.),
点とカメラが近すぎたんだなappbird.icon
どこいくねーんappbird.icon
左上にギリッギリ写ってるなappbird.icon
https://gyazo.com/93017c907163c3e2796f783fe2ad3c89
ええと、ということは割る側の$ wがデカすぎるという解釈でおk?
いやそれだと左側によるこたあないか
$ (\cos kt +10, \sin kt + 10, 5)にカメラを置いてみる
https://gyazo.com/87ecc18d678b48cd546b38260f425ecc
なんか遠くないです...??appbird.icon
一旦カメラ止めてみるか
これつまりは最初の三角形2枚写すやつはできていなかったということになるな....
$ (0, 0, 5)にカメラを置いてみる
スクリーン座標系に直す前の点はどうなっている?
code:rs
snapshot points = [
Vec4Project(Vec4 { e: 0.0, 0.0, -5.201020102010202, -5.0 }),
Vec4Project(Vec4 { e: 0.5000000000000001, 0.22222222222222224, -4.534220088675535, -4.333333333333333 }),
Vec4Project(Vec4 { e: 0.0, -0.6666666666666667, -3.8674200753408683, -3.666666666666667 })
] at src/camera.rs:79
snapshot points = [
Vec4Project(Vec4 { e: 0.0, 0.888888888888889, -6.868020135346869, -6.666666666666667 }),
Vec4Project(Vec4 { e: -0.5000000000000001, -0.22222222222222224, -5.867820115344869, -5.666666666666667 }),
Vec4Project(Vec4 { e: 0.0, 2.0, -3.8674200753408683, -3.666666666666667 })] at src/camera.rs:79
これをみると変な場所には置かれていなさそうappbird.icon
となると...appbird.icon
code:rs
pub fn transform_into_screen(&self, size:Point2, p: &Vec4Project) -> Point2 {
let scale = size.y as f64 / 2.;
let v = Mat4x4::scale_xyz(&scale) * &p.0 + size.to_vec4() / 2.;
snapshot!(&v / v.w());
Vec4Screen(&v / v.w()).to_point2()
}
お前か!
よく考えると後からw.割るの変だなappbird.icon
先にwを割らないとな
code:rs
pub fn transform_into_screen(&self, size:Point2, p: &Vec4Project) -> Point2 {
let scale = size.y as f64 / 2.;
let p = &p.0 / p.0.w();
let v = &p * scale + size.to_vec4() / 2.; // w値を気にしなくて良くなったので単純にscaleをスカラー倍するだけ
Vec4Screen(v).to_point2()
}
https://gyazo.com/0e153e96b5975cb35a17f947ad1748c9
ヨシャー!!!!!appbird.icon
と思ったけどなんか逆じゃないですか?appbird.icon
continue to 深度クリッピング < 点からはじめるラスタライザ