Skip to content

Commit 896e42d

Browse files
committed
refactor some codes
1 parent 889c426 commit 896e42d

File tree

5 files changed

+138
-276
lines changed

5 files changed

+138
-276
lines changed

src/cubemap.ts

Lines changed: 11 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -2,39 +2,34 @@ import type { CubemapURLs } from './types';
22

33
export class Cubemap {
44
private device: GPUDevice;
5-
private texture: GPUTexture | null;
65

76
constructor(device: GPUDevice) {
87
this.device = device;
9-
this.texture = null;
108
}
119

1210
async load(urls: CubemapURLs): Promise<GPUTexture> {
13-
const order: (keyof CubemapURLs)[] = ['xpos', 'xneg', 'ypos', 'yneg', 'zpos', 'zneg'];
11+
const faces: (keyof CubemapURLs)[] = ['xpos', 'xneg', 'ypos', 'yneg', 'zpos', 'zneg'];
1412

15-
// Load all images first to get dimensions
16-
const images = await Promise.all(order.map(name =>
17-
fetch(urls[name]).then(res => res.blob()).then(blob => createImageBitmap(blob))
18-
));
13+
const images = await Promise.all(
14+
faces.map(face => fetch(urls[face]).then(r => r.blob()).then(b => createImageBitmap(b)))
15+
);
1916

20-
const width = images[0].width;
21-
const height = images[0].height;
17+
const { width, height } = images[0];
2218

23-
this.texture = this.device.createTexture({
19+
const texture = this.device.createTexture({
2420
size: [width, height, 6],
2521
format: 'rgba8unorm',
2622
usage: GPUTextureUsage.TEXTURE_BINDING | GPUTextureUsage.COPY_DST | GPUTextureUsage.RENDER_ATTACHMENT,
27-
viewFormats: ['rgba8unorm'],
2823
});
2924

30-
for (let i = 0; i < 6; i++) {
25+
images.forEach((image, i) => {
3126
this.device.queue.copyExternalImageToTexture(
32-
{ source: images[i], flipY: true },
33-
{ texture: this.texture, origin: [0, 0, i] },
27+
{ source: image, flipY: true },
28+
{ texture, origin: [0, 0, i] },
3429
{ width, height }
3530
);
36-
}
31+
});
3732

38-
return this.texture;
33+
return texture;
3934
}
4035
}

src/lightgl.ts

Lines changed: 67 additions & 160 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
1-
// Ported from lightgl.js and adapted for wgpu-matrix
2-
// http://github.com/evanw/lightgl.js/
1+
// Ported from lightgl.js - http://github.com/evanw/lightgl.js/
32

43
import { mat4, vec3 } from 'wgpu-matrix';
54
import type { Mat4 } from 'wgpu-matrix';
@@ -10,38 +9,42 @@ export class Vector {
109
y: number;
1110
z: number;
1211

13-
constructor(x?: number, y?: number, z?: number) {
14-
this.x = x || 0;
15-
this.y = y || 0;
16-
this.z = z || 0;
12+
constructor(x = 0, y = 0, z = 0) {
13+
this.x = x;
14+
this.y = y;
15+
this.z = z;
1716
}
1817

1918
negative(): Vector {
2019
return new Vector(-this.x, -this.y, -this.z);
2120
}
2221

2322
add(v: Vector | number): Vector {
24-
if (v instanceof Vector) return new Vector(this.x + v.x, this.y + v.y, this.z + v.z);
25-
else return new Vector(this.x + v, this.y + v, this.z + v);
23+
if (v instanceof Vector) {
24+
return new Vector(this.x + v.x, this.y + v.y, this.z + v.z);
25+
}
26+
return new Vector(this.x + v, this.y + v, this.z + v);
2627
}
2728

2829
subtract(v: Vector | number): Vector {
29-
if (v instanceof Vector) return new Vector(this.x - v.x, this.y - v.y, this.z - v.z);
30-
else return new Vector(this.x - v, this.y - v, this.z - v);
30+
if (v instanceof Vector) {
31+
return new Vector(this.x - v.x, this.y - v.y, this.z - v.z);
32+
}
33+
return new Vector(this.x - v, this.y - v, this.z - v);
3134
}
3235

3336
multiply(v: Vector | number): Vector {
34-
if (v instanceof Vector) return new Vector(this.x * v.x, this.y * v.y, this.z * v.z);
35-
else return new Vector(this.x * v, this.y * v, this.z * v);
37+
if (v instanceof Vector) {
38+
return new Vector(this.x * v.x, this.y * v.y, this.z * v.z);
39+
}
40+
return new Vector(this.x * v, this.y * v, this.z * v);
3641
}
3742

3843
divide(v: Vector | number): Vector {
39-
if (v instanceof Vector) return new Vector(this.x / v.x, this.y / v.y, this.z / v.z);
40-
else return new Vector(this.x / v, this.y / v, this.z / v);
41-
}
42-
43-
equals(v: Vector): boolean {
44-
return this.x == v.x && this.y == v.y && this.z == v.z;
44+
if (v instanceof Vector) {
45+
return new Vector(this.x / v.x, this.y / v.y, this.z / v.z);
46+
}
47+
return new Vector(this.x / v, this.y / v, this.z / v);
4548
}
4649

4750
dot(v: Vector): number {
@@ -65,39 +68,27 @@ export class Vector {
6568
}
6669

6770
min(): number {
68-
return Math.min(Math.min(this.x, this.y), this.z);
71+
return Math.min(this.x, this.y, this.z);
6972
}
7073

7174
max(): number {
72-
return Math.max(Math.max(this.x, this.y), this.z);
73-
}
74-
75-
toAngles(): { theta: number; phi: number } {
76-
return {
77-
theta: Math.atan2(this.z, this.x),
78-
phi: Math.asin(this.y / this.length())
79-
};
75+
return Math.max(this.x, this.y, this.z);
8076
}
8177

82-
angleTo(a: Vector): number {
83-
return Math.acos(this.dot(a) / (this.length() * a.length()));
84-
}
85-
86-
toArray(n?: number): number[] {
87-
return [this.x, this.y, this.z].slice(0, n || 3);
78+
toArray(): number[] {
79+
return [this.x, this.y, this.z];
8880
}
8981

9082
clone(): Vector {
9183
return new Vector(this.x, this.y, this.z);
9284
}
9385

94-
init(x: number, y: number, z: number): Vector {
95-
this.x = x; this.y = y; this.z = z;
96-
return this;
97-
}
98-
99-
static fromArray(a: number[]): Vector {
100-
return new Vector(a[0], a[1], a[2]);
86+
static fromAngles(theta: number, phi: number): Vector {
87+
return new Vector(
88+
Math.cos(phi) * Math.cos(theta),
89+
Math.sin(phi),
90+
Math.cos(phi) * Math.sin(theta)
91+
);
10192
}
10293

10394
static lerp(a: Vector, b: Vector, t: number): Vector {
@@ -111,167 +102,83 @@ export class Vector {
111102
static max(a: Vector, b: Vector): Vector {
112103
return new Vector(Math.max(a.x, b.x), Math.max(a.y, b.y), Math.max(a.z, b.z));
113104
}
114-
115-
static fromAngles(theta: number, phi: number): Vector {
116-
return new Vector(Math.cos(phi) * Math.cos(theta), Math.sin(phi), Math.cos(phi) * Math.sin(theta));
117-
}
118105
}
119106

120107
export class HitTest {
121108
t: number;
122109
hit: Vector;
123110
normal: Vector;
124111

125-
constructor(t?: number, hit?: Vector, normal?: Vector) {
126-
this.t = arguments.length ? (t ?? Number.MAX_VALUE) : Number.MAX_VALUE;
127-
this.hit = hit!;
128-
this.normal = normal!;
129-
}
130-
131-
mergeWith(other: HitTest): void {
132-
if (other.t > 0 && other.t < this.t) {
133-
this.t = other.t;
134-
this.hit = other.hit;
135-
this.normal = other.normal;
136-
}
112+
constructor(t: number, hit: Vector, normal: Vector) {
113+
this.t = t;
114+
this.hit = hit;
115+
this.normal = normal;
137116
}
138117
}
139118

140119
export class Raytracer {
141-
viewport: Viewport;
142120
eye: Vector;
143-
invViewProj: Mat4;
144-
ray00: Vector;
145-
ray10: Vector;
146-
ray01: Vector;
147-
ray11: Vector;
121+
private viewport: Viewport;
122+
private invViewProj: Mat4;
123+
private ray00: Vector;
124+
private ray10: Vector;
125+
private ray01: Vector;
126+
private ray11: Vector;
148127

149128
constructor(viewMatrix: Mat4, projectionMatrix: Mat4, viewport: Viewport) {
150-
// viewMatrix and projectionMatrix are Float32Array (wgpu-matrix)
151129
this.viewport = viewport;
152130

153-
// Calculate Eye Position from View Matrix
154-
// Eye is origin (0,0,0) in Camera space, transformed to World.
155-
// World = View^-1 * Camera.
156-
// Eye = View^-1 * [0,0,0,1].
131+
// Calculate eye position from inverse view matrix
157132
const invView = mat4.invert(viewMatrix);
158133
const eyeVec = vec3.transformMat4([0, 0, 0], invView);
159134
this.eye = new Vector(eyeVec[0], eyeVec[1], eyeVec[2]);
160135

161-
// Calculate View-Projection Inverse for unProject
136+
// Calculate view-projection inverse for unprojection
162137
this.invViewProj = mat4.invert(mat4.multiply(projectionMatrix, viewMatrix));
163138

164-
// Precalculate Corner Rays
165-
const minX = viewport[0], maxX = minX + viewport[2];
166-
const minY = viewport[1], maxY = minY + viewport[3];
167-
168-
// unProject corners. Z=1 (Far).
169-
// Note: WebGPU Clip Z is 0..1.
170-
// For ray direction, we can unproject a point on Far plane.
171-
this.ray00 = this.unProject(minX, minY, 1).subtract(this.eye) as Vector;
172-
this.ray10 = this.unProject(maxX, minY, 1).subtract(this.eye) as Vector;
173-
this.ray01 = this.unProject(minX, maxY, 1).subtract(this.eye) as Vector;
174-
this.ray11 = this.unProject(maxX, maxY, 1).subtract(this.eye) as Vector;
139+
// Precalculate corner rays
140+
const [minX, minY, width, height] = viewport;
141+
const maxX = minX + width;
142+
const maxY = minY + height;
143+
144+
this.ray00 = this.unProject(minX, minY, 1).subtract(this.eye);
145+
this.ray10 = this.unProject(maxX, minY, 1).subtract(this.eye);
146+
this.ray01 = this.unProject(minX, maxY, 1).subtract(this.eye);
147+
this.ray11 = this.unProject(maxX, maxY, 1).subtract(this.eye);
175148
}
176149

177-
unProject(winX: number, winY: number, winZ: number): Vector {
178-
const v = this.viewport;
179-
// Map window (0..W, 0..H) to NDC (-1..1, -1..1)
180-
// Note: wgpu-matrix assumes Y-down for some things?
181-
// But standard projection logic usually maps:
182-
// Bottom (-1) to Top (1) if Y-up.
183-
// Top (-1) to Bottom (1) if Y-down.
184-
// Let's assume standard GL behavior for now:
185-
// x: -1 to 1
186-
// y: -1 (bottom) to 1 (top)
187-
// But winY 0 is top. So we flip Y.
188-
189-
const x = (winX - v[0]) / v[2] * 2 - 1;
190-
const y = (1 - (winY - v[1]) / v[3]) * 2 - 1; // Flip Y: 0->1, H->-1.
191-
const z = winZ; // 0..1
192-
193-
const ndc: [number, number, number] = [x, y, z];
194-
const world = vec3.transformMat4(ndc, this.invViewProj);
150+
private unProject(winX: number, winY: number, winZ: number): Vector {
151+
const [vx, vy, vw, vh] = this.viewport;
152+
const x = ((winX - vx) / vw) * 2 - 1;
153+
const y = (1 - (winY - vy) / vh) * 2 - 1;
154+
155+
const world = vec3.transformMat4([x, y, winZ], this.invViewProj);
195156
return new Vector(world[0], world[1], world[2]);
196157
}
197158

198159
getRayForPixel(x: number, y: number): Vector {
199-
// Interpolate precalculated rays
200-
// x, y are window coordinates
201-
const u = (x - this.viewport[0]) / this.viewport[2];
202-
const v = (y - this.viewport[1]) / this.viewport[3]; // 0 top, 1 bottom
203-
204-
// ray00 is Top-Left?
205-
// In constructor: minY (0) -> unProject(..., 0).
206-
// unProject(..., 0) uses `y = (1 - 0) * 2 - 1 = 1` -> Top.
207-
// So ray00 is Top-Left (minX, minY).
208-
// ray01 is Bottom-Left (minX, maxY).
209-
// ray10 is Top-Right.
210-
// ray11 is Bottom-Right.
211-
212-
// v goes 0 (Top) to 1 (Bottom).
213-
// Lerp(rayTop, rayBottom, v).
160+
const [vx, vy, vw, vh] = this.viewport;
161+
const u = (x - vx) / vw;
162+
const v = (y - vy) / vh;
163+
214164
const rayTop = Vector.lerp(this.ray00, this.ray10, u);
215165
const rayBottom = Vector.lerp(this.ray01, this.ray11, u);
216166

217167
return Vector.lerp(rayTop, rayBottom, v).unit();
218168
}
219169

220-
static hitTestBox(origin: Vector, ray: Vector, min: Vector, max: Vector): HitTest | null {
221-
const tMin = min.subtract(origin).divide(ray) as Vector;
222-
const tMax = max.subtract(origin).divide(ray) as Vector;
223-
const t1 = Vector.min(tMin, tMax);
224-
const t2 = Vector.max(tMin, tMax);
225-
const tNear = t1.max();
226-
const tFar = t2.min();
227-
228-
if (tNear > 0 && tNear < tFar) {
229-
const epsilon = 1.0e-6, hit = origin.add(ray.multiply(tNear)) as Vector;
230-
min = min.add(epsilon) as Vector;
231-
max = max.subtract(epsilon) as Vector;
232-
return new HitTest(tNear, hit, new Vector(
233-
Number(hit.x > max.x) - Number(hit.x < min.x),
234-
Number(hit.y > max.y) - Number(hit.y < min.y),
235-
Number(hit.z > max.z) - Number(hit.z < min.z)
236-
));
237-
}
238-
239-
return null;
240-
}
241-
242170
static hitTestSphere(origin: Vector, ray: Vector, center: Vector, radius: number): HitTest | null {
243-
const offset = origin.subtract(center) as Vector;
171+
const offset = origin.subtract(center);
244172
const a = ray.dot(ray);
245173
const b = 2 * ray.dot(offset);
246174
const c = offset.dot(offset) - radius * radius;
247175
const discriminant = b * b - 4 * a * c;
248176

249177
if (discriminant > 0) {
250-
const t = (-b - Math.sqrt(discriminant)) / (2 * a), hit = origin.add(ray.multiply(t)) as Vector;
251-
return new HitTest(t, hit, (hit.subtract(center) as Vector).divide(radius) as Vector);
252-
}
253-
254-
return null;
255-
}
256-
257-
static hitTestTriangle(origin: Vector, ray: Vector, a: Vector, b: Vector, c: Vector): HitTest | null {
258-
const ab = b.subtract(a) as Vector;
259-
const ac = c.subtract(a) as Vector;
260-
const normal = ab.cross(ac).unit();
261-
const t = normal.dot((a.subtract(origin) as Vector)) / normal.dot(ray);
262-
263-
if (t > 0) {
264-
const hit = origin.add(ray.multiply(t)) as Vector;
265-
const toHit = hit.subtract(a) as Vector;
266-
const dot00 = ac.dot(ac);
267-
const dot01 = ac.dot(ab);
268-
const dot02 = ac.dot(toHit);
269-
const dot11 = ab.dot(ab);
270-
const dot12 = ab.dot(toHit);
271-
const divide = dot00 * dot11 - dot01 * dot01;
272-
const u = (dot11 * dot02 - dot01 * dot12) / divide;
273-
const v = (dot00 * dot12 - dot01 * dot02) / divide;
274-
if (u >= 0 && v >= 0 && u + v <= 1) return new HitTest(t, hit, normal);
178+
const t = (-b - Math.sqrt(discriminant)) / (2 * a);
179+
const hit = origin.add(ray.multiply(t));
180+
const normal = hit.subtract(center).divide(radius);
181+
return new HitTest(t, hit, normal);
275182
}
276183

277184
return null;

0 commit comments

Comments
 (0)