Skip to content

Commit 1d1e3bf

Browse files
committed
Added point lights
1 parent 694c72d commit 1d1e3bf

5 files changed

Lines changed: 327 additions & 60 deletions

File tree

src/rendering/types/node.ts

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import { mat4, vec3, vec4, type Line } from "../../math/types";
22
import { identity, translate, rotate, scale } from "../../math/transformations";
33
import type { Mesh } from "./mesh";
44
import { inverse_mat4, mul_mat4_vec4 } from "../../math/matrix_operators";
5+
import type { Light } from "./light";
56

67
export class Node {
78
mesh: Mesh;
@@ -10,12 +11,18 @@ export class Node {
1011
public scale_vec: vec3 = vec3(1, 1, 1);
1112
public radius:vec3 = vec3(1,1,1);
1213
public radius_reciprocal:vec3 = vec3(1,1,1);
14+
15+
public light: Light | null = null;
1316

1417
model: mat4 = identity();
1518
inverse_model: mat4 = identity();
1619

17-
constructor(mesh: Mesh) {
20+
constructor(mesh: Mesh, light:Light | null = null) {
1821
this.mesh = mesh;
22+
this.light = light;
23+
if(this.light){
24+
this.light.position = this.position;
25+
}
1926
this.update_matrix();
2027
this.determine_radius();
2128
}

src/ui/animation.ts

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
import type { Node } from "../rendering/types/node";
2+
3+
export interface Animation {
4+
name: string;
5+
apply(node: Node, t: number, dt: number): void;
6+
}
7+
8+
export class Rotator implements Animation {
9+
public name = "Rotator";
10+
11+
constructor(public axis: number, public speed: number) {}
12+
13+
apply(node: Node, t: number, dt: number) {
14+
node.rotation[this.axis] += this.speed * dt;
15+
}
16+
}
17+
18+
export class Oscillator implements Animation {
19+
public name = "Oscillator";
20+
21+
constructor(
22+
public axis: number,
23+
public speed: number,
24+
public amplitude: number,
25+
public base_val: number
26+
) {}
27+
28+
apply(node: Node, t: number, dt: number) {
29+
node.position[this.axis] = this.base_val + Math.sin(t * this.speed) * this.amplitude;
30+
}
31+
}
32+
33+
export class Orbit implements Animation {
34+
public name = "Orbit";
35+
36+
constructor(
37+
public speed: number,
38+
public radius: number,
39+
public center_x: number,
40+
public center_z: number
41+
) {}
42+
43+
apply(node: Node, t: number, dt: number) {
44+
node.position[0] = this.center_x + Math.cos(t * this.speed) * this.radius;
45+
node.position[2] = this.center_z + Math.sin(t * this.speed) * this.radius;
46+
}
47+
}

src/ui/inspector.ts

Lines changed: 93 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
1+
import type { ArrayType } from "../math/types";
12
import type { Node } from "../rendering/types/node";
23

34
export class Inspector {
45
private container: HTMLElement;
56
public current_node: Node | null = null;
67

78
private move_speed = 0.5;
8-
private rot_speed = 0.26;
99
private scale_factor = 0.1;
1010

1111
constructor(container_id: string) {
@@ -46,6 +46,7 @@ export class Inspector {
4646
table.setAttribute("border", "0");
4747
table.setAttribute("cellpadding", "2");
4848
this.container.appendChild(table);
49+
4950
this.create_action_row(table, "Move X",
5051
() => { node.position[0] -= this.move_speed; node.update_matrix(); },
5152
() => { node.position[0] += this.move_speed; node.update_matrix(); }
@@ -61,18 +62,18 @@ export class Inspector {
6162

6263
this.add_divider(table);
6364

64-
this.create_action_row(table, "Rotate X",
65-
() => { node.rotation[0] -= this.rot_speed; node.update_matrix(); },
66-
() => { node.rotation[0] += this.rot_speed; node.update_matrix(); }
67-
);
68-
this.create_action_row(table, "Rotate Y",
69-
() => { node.rotation[1] -= this.rot_speed; node.update_matrix(); },
70-
() => { node.rotation[1] += this.rot_speed; node.update_matrix(); }
71-
);
72-
this.create_action_row(table, "Rotate Z",
73-
() => { node.rotation[2] -= this.rot_speed; node.update_matrix(); },
74-
() => { node.rotation[2] += this.rot_speed; node.update_matrix(); }
75-
);
65+
this.create_slider_row(table, "Rotate X", "-3.14", "3.14", "0.01", node.rotation[0], (v) => {
66+
node.rotation[0] = v;
67+
node.update_matrix();
68+
});
69+
this.create_slider_row(table, "Rotate Y", "-3.14", "3.14", "0.01", node.rotation[1], (v) => {
70+
node.rotation[1] = v;
71+
node.update_matrix();
72+
});
73+
this.create_slider_row(table, "Rotate Z", "-3.14", "3.14", "0.01", node.rotation[2], (v) => {
74+
node.rotation[2] = v;
75+
node.update_matrix();
76+
});
7677

7778
this.add_divider(table);
7879

@@ -93,8 +94,44 @@ export class Inspector {
9394

9495
this.add_divider(table);
9596

96-
if (node.mesh && node.mesh.albedo) {
97-
this.create_color_row(table, "Color", node.mesh.albedo);
97+
if (node.mesh && node.mesh.albedo && !node.light) {
98+
this.create_color_row(table, "Color", node.mesh.albedo, node.mesh.albedo);
99+
}
100+
101+
if (node.light) {
102+
this.add_divider(table);
103+
104+
const tr_light = document.createElement("tr");
105+
const td_light = document.createElement("td");
106+
td_light.setAttribute("colspan", "3");
107+
const b_light = document.createElement("b");
108+
const font_light = document.createElement("font");
109+
font_light.setAttribute("face", "Arial");
110+
font_light.innerText = "Light Properties";
111+
b_light.appendChild(font_light);
112+
td_light.appendChild(b_light);
113+
tr_light.appendChild(td_light);
114+
table.appendChild(tr_light);
115+
116+
const light = node.light;
117+
118+
this.create_action_row(table, "Intensity",
119+
() => { light.intensity -= 0.1; },
120+
() => { light.intensity += 0.1; }
121+
);
122+
123+
this.create_action_row(table, "Radius",
124+
() => { light.radius -= 1.0; },
125+
() => { light.radius += 1.0; }
126+
);
127+
128+
this.create_color_row(table, "Emission", light.color, node.mesh.albedo);
129+
130+
if (false) {
131+
this.create_slider_row(table, "Cutoff", "0.0", "3.14", "0.01", Math.acos(light.cutoff || 1.0), (v) => {
132+
light.cutoff = Math.cos(v);
133+
});
134+
}
98135
}
99136
}
100137

@@ -138,7 +175,7 @@ export class Inspector {
138175
table.appendChild(tr);
139176
}
140177

141-
private create_color_row(table: HTMLElement, label: string, color_vec: Float32Array | number[]) {
178+
private create_slider_row(table: HTMLElement, label: string, min: string, max: string, step: string, value: number, on_change: (val: number) => void) {
142179
const tr = document.createElement("tr");
143180

144181
const td_label = document.createElement("td");
@@ -149,6 +186,42 @@ export class Inspector {
149186

150187
const td_input = document.createElement("td");
151188
td_input.setAttribute("colspan", "2");
189+
190+
const input = document.createElement("input");
191+
input.type = "range";
192+
input.min = min;
193+
input.max = max;
194+
input.step = step;
195+
input.value = value.toString();
196+
197+
const val_font = document.createElement("font");
198+
val_font.setAttribute("face", "monospace");
199+
val_font.innerText = " " + value.toFixed(2);
200+
201+
input.addEventListener("input", (e) => {
202+
const num = parseFloat((e.target as HTMLInputElement).value);
203+
val_font.innerText = " " + num.toFixed(2);
204+
on_change(num);
205+
});
206+
207+
td_input.appendChild(input);
208+
td_input.appendChild(val_font);
209+
tr.appendChild(td_label);
210+
tr.appendChild(td_input);
211+
table.appendChild(tr);
212+
}
213+
214+
private create_color_row(table: HTMLElement, label: string, color_vec: ArrayType | number[], albedo: ArrayType) {
215+
const tr = document.createElement("tr");
216+
217+
const td_label = document.createElement("td");
218+
const font = document.createElement("font");
219+
font.setAttribute("face", "Arial");
220+
font.innerText = `${label}: `;
221+
td_label.appendChild(font);
222+
223+
const td_input = document.createElement("td");
224+
td_input.setAttribute("colspan", "2");
152225

153226
const color_picker = document.createElement("input");
154227
color_picker.type = "color";
@@ -159,10 +232,13 @@ export class Inspector {
159232
color_picker.value = `#${r}${g}${b}`;
160233

161234
color_picker.addEventListener("input", (e) => {
162-
const hex = (e.target as HTMLInputElement).value;
235+
const hex = (e.target as HTMLInputElement).value;
163236
color_vec[0] = parseInt(hex.substring(1, 3), 16) / 255.0;
164237
color_vec[1] = parseInt(hex.substring(3, 5), 16) / 255.0;
165238
color_vec[2] = parseInt(hex.substring(5, 7), 16) / 255.0;
239+
albedo[0] = color_vec[0];
240+
albedo[1] = color_vec[1];
241+
albedo[2] = color_vec[2];
166242
});
167243

168244
td_input.appendChild(color_picker);

src/ui/scene_manager.ts

Lines changed: 18 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@ import type { EditorMode } from "./state_manager";
1717
import { EditorState } from "./state_manager";
1818

1919
import { parse_obj } from "../utils/parser";
20+
import * as primitives from "../rendering/utils/primitives";
21+
2022

2123
export class SceneManager {
2224
public scene: Scene;
@@ -71,7 +73,7 @@ export class SceneManager {
7173

7274
initialize_toolbar(toolbar_id, options_id, (geo: Geometry) => {
7375
this.add_node(geo);
74-
});
76+
}, () => this.add_point_light());
7577
}
7678

7779
private setup_lights() {
@@ -104,20 +106,28 @@ export class SceneManager {
104106
this.select_node(node);
105107
}
106108

109+
public add_point_light() {
110+
const new_light = new Light(vec3(0, 0, 0), vec3(1.0, 1.0, 1.0), 2.0, 50.0);
111+
this.scene.add_light(new_light);
112+
113+
const bulb_geo = primitives.create_sphere(0.2, 8, 8);
114+
115+
const mesh = this.scene.add_mesh(bulb_geo, vec3(1.0, 1.0, 0.0), 0.5);
116+
117+
const light_node = new Node(mesh, new_light);
118+
119+
this.nodes.push(light_node);
120+
this.select_node(light_node);
121+
}
122+
107123
private expand_capacity(required_triangles: number) {
108124
let new_capacity = this.current_capacity * 2;
109125
if (new_capacity < required_triangles) new_capacity = required_triangles;
110126
if (new_capacity > this.MAX_TRIANGLES) new_capacity = this.MAX_TRIANGLES;
111127

112128

113129
this.scene.resize_buffers(new_capacity);
114-
115-
if (typeof this.string_buffer.resize === 'function') {
116-
this.string_buffer.resize(new_capacity * 60);
117-
} else {
118-
console.warn("StringBuffer.resize() is not implemented yet!");
119-
}
120-
130+
this.string_buffer.resize(new_capacity * 60);
121131
this.current_capacity = new_capacity;
122132
}
123133

0 commit comments

Comments
 (0)