🙆♀️
Rust wgpuで球(Sphere)を描く
はじめに
wgpuになれるために立体を描こうと思った。まずはsphereから。
以下ソースコード。
Examplesの改変
公式examplesのcubeを参考にしています。
cubeでは面をlineで表示するものと、面上にテクスチャを表示する2つのdrawで構成されている。
このうち、lineで表示する部分だけを流用することにする。
基本的な動き
大雑把な流れは以下の通り。
- 頂点データをバッファにセットする。
- 面を構成する3頂点のindexの配列をバッファにセットする。
- drawする。
球の頂点の計算
半径
ただし
シンプルに
インデックス(i, j)
の頂点を計算する関数はこんな感じ。
fn vert(&self, i: i32, j: i32) -> Array1<f32> {
let i = i as f32;
let j = j as f32;
let n = self.n as f32;
let m = self.m as f32;
let r = 1.;
let xy = f32::sin(PI*i/n);
let z = r * f32::cos(PI*i/n);
let x = r * xy * f32::cos(2.*PI*j/m);
let y = r * xy * f32::sin(2.*PI*j/m);
let p = Array1::from_vec(vec![x, y, z]);
p
}
球の部分的な面(四角形)を構成する頂点
まずは部分面を構成する4頂点ごとにまとめていく。
部分面を構成する4頂点のインデックスのセットを、反時計回りにならべると:
(i, j)
, (i+1, j)
, (i+1, j+1)
, (i, j+1)
となる。
pub fn verts(&self) -> Vec<Vec<Array1<f32>>> {
let mut vvs:Vec<Vec<Array1<f32>>> = vec![];
for i in 0..self.n {
for j in 0..self.m {
let i2 = i+1 % self.n;
let j2 = j+1 % self.m;
let mut vs: Vec<Array1<f32>> = vec![];
vs.push(self.vert(i, j));
vs.push(self.vert(i2, j));
vs.push(self.vert(i2, j2));
vs.push(self.vert(i, j2));
vvs.push(vs);
}
}
vvs
}
四角形を2つの三角形に分割する。
wgpuでdrawするときは三角形の組み合わせで描画する。
4つの頂点のインデックスを0, 1, 2, 3
として、それぞれ反時計回りで三角形になるように0, 1, 2
と2, 3, 0
に分ける。
pub fn indices0(&self) -> Vec<u16> {
let mut ids = vec![];
for i in 0..self.n {
for j in 0..self.m {
// i*m + jが進むごとに4進む
let i = i as u16;
let j = j as u16;
let m = self.m as u16;
let offset = (i*m + j)*4;
// 0 1 2 / 2 3 0
ids.push(0+offset);
ids.push(1+offset);
ids.push(2+offset);
ids.push(2+offset);
ids.push(3+offset);
ids.push(0+offset);
}
}
ids
}
Discussion