Skip to content

Commit 1c48364

Browse files
committed
Lighting almost finished
1 parent b7ce605 commit 1c48364

8 files changed

Lines changed: 129 additions & 31 deletions

File tree

src/main.ts

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@ import { Mesh } from "./rendering/types/mesh";
77
import { Scene } from "./rendering/types/scene";
88
import { mul_mat4 } from "./math/matrix_operators";
99
import { build_scene } from "./to_html";
10+
import { process_world_coordinates } from "./rendering/process_lighting";
11+
import { Light } from "./rendering/types/light";
1012

1113

1214
export function main_3d() {
@@ -17,31 +19,45 @@ export function main_3d() {
1719
const sun_mesh = create_sphere(1.5, 32, 32);
1820
const planet_mesh = create_sphere(0.5, 16, 16);
1921

20-
const scene:Scene = new Scene([sun_mesh,planet_mesh]);
22+
const scene:Scene = new Scene([sun_mesh,planet_mesh],[vec3(1,0,0),vec3(0,0,1)]);
2123

2224
console.log(scene.draw_end)
2325

24-
2526
const y = vec3(0,1,0);
2627
const view:mat4 = look_at(vec3(0,2,6.5),vec3(0,0,0),y);
2728
const projection = perspective(60 * Math.PI / 180, 400/300, 0.1, 100);
2829
let time = 0;
2930
const string_buffer = new StringBuffer(scene.scene_buffer.length * 50);
3031
const vp = mul_mat4(projection,view);
32+
33+
const sun_light = new Light(
34+
vec3(10,10,10),
35+
vec3(1.0,0.95,0.9),
36+
8.0,
37+
200.0
38+
);
39+
40+
scene.add_light(sun_light);
41+
3142
const loop = () => {
3243
time += 0.01;
3344

3445
let frame_html = "";
3546
let sun_model = identity();
3647
sun_model = rotate(sun_model, time * 0.5, y);
3748
let planet_model = identity();
49+
3850
planet_model = rotate(planet_model, time, vec3(0, 1, 0));
3951
planet_model = translate(planet_model, vec3(3.5, 0, 0));
4052
planet_model = rotate(planet_model, time * 3, vec3(1, 0, 1));
4153

4254
const planet_mvp = mul_mat4(vp,planet_model);
4355
const sun_mvp = mul_mat4(vp,sun_model);
44-
56+
const ar = [sun_model,planet_model]
57+
for(let i = 0; i < 2; ++i){
58+
scene.meshes[i].update_normals(ar[i]);
59+
}
60+
process_world_coordinates(scene,ar);
4561
render_scene(scene,[sun_mvp,planet_mvp],true);
4662
frame_html = build_scene(scene,do_wireframe,string_buffer);
4763

src/rendering/screen_space/primitive_assembler.ts renamed to src/rendering/clip_space/primitive_assembler.ts

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,15 +9,22 @@ export function assemble_primitives(mesh:Mesh):void{
99
const projected = mesh.projected_buffer;
1010
const indices = mesh.indices;
1111

12-
const out = mesh.raster_buffer
12+
const out = mesh.raster_buffer;
13+
const out_color = mesh.raster_color;
1314
let out_index = 0;
15+
let out_color_index = 0;
1416
for(let i = 0; i < indices.length; ++i){
1517
const index = indices[i];
16-
const p_base = index * 4;
18+
const p_base = index * 4;
19+
const c_base = index * 3;
1720

1821
out[out_index++] = projected[p_base];
1922
out[out_index++] = projected[p_base + 1];
2023
out[out_index++] = projected[p_base + 2];
2124
out[out_index++] = projected[p_base + 3];
25+
26+
out_color[out_color_index++] = mesh.color_buffer[c_base];
27+
out_color[out_color_index++] = mesh.color_buffer[c_base + 1];
28+
out_color[out_color_index++] = mesh.color_buffer[c_base + 2];
2229
}
2330
}

src/rendering/process_lighting.ts

Lines changed: 35 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { length_vec3, mul_mat4_vec4, mul_mat4_vec4_mut, sub_vec3 } from "../math/matrix_operators";
1+
import { dot_vec3, length_vec3, mul_mat4_vec4, mul_mat4_vec4_mut, sub_vec3 } from "../math/matrix_operators";
22
import { ArrayType, mat4, vec3, vec4 } from "../math/types";
33
import type { Light } from "./types/light";
44
import type { Mesh } from "./types/mesh";
@@ -10,36 +10,59 @@ export function process_lighting(mesh:Mesh, scene:Scene){
1010
const lights = scene.lights;
1111
let vertex:vec3 = vec3(0,0,0);
1212
const k = 0.01;
13+
let index = 0;
1314
for(let i = 0; i < world_coordinates.length; i+=4){
1415
vertex[0] = world_coordinates[i];
1516
vertex[1] = world_coordinates[i+1];
1617
vertex[2] = world_coordinates[i+2];
17-
let color = vec3(0,0,0);
18+
const start = i/4*3;
19+
const nx = mesh.normals[start];
20+
const ny = mesh.normals[start+1];
21+
const nz = mesh.normals[start+2];
22+
23+
24+
let color = vec3(mesh.albedo[0],mesh.albedo[1],mesh.albedo[2]);
1825
for(const light of lights){
19-
const L = sub_vec3(vertex,light.position);
20-
const dist = length_vec3(L);
21-
if (dist > light.radius) continue;
22-
26+
const L = sub_vec3(light.position,vertex);
27+
const dist = length_vec3(L) || k;
28+
L[0]/=dist;
29+
L[1]/=dist;
30+
L[2]/=dist;
31+
if (dist > light.radius){
32+
continue;
33+
}
34+
const dot = L[0] * nx + L[1] * ny + L[2] * nz;
35+
const diffuse = Math.max(0,dot);
36+
const window = 1//*Math.pow(Math.max(0, 1 - Math.pow(dist / light.radius, 4)), 2)
37+
const attenuation = light.intensity/(1.0 + k*(dist*dist)) * window;
38+
const strength = diffuse * attenuation;
39+
color[0] += light.color[0] * strength;
40+
color[1] += light.color[1] * strength;
41+
color[2] += light.color[2] * strength;
2342
}
43+
mesh.color_buffer[index++] = Math.min(1.0, color[0]);
44+
mesh.color_buffer[index++] = Math.min(1.0, color[1]);
45+
mesh.color_buffer[index++] = Math.min(1.0, color[2]);
2446
}
2547
}
2648

2749
export function process_world_coordinates(scene:Scene, model:mat4[]){
2850
let v:vec4 = vec4(0,0,0,0);
2951
let mesh_index = 0;
3052
for(const mesh of scene.meshes){
53+
let out_index = 0 ;
3154
const mesh_model = model[mesh_index++];
3255
const vertices = mesh.vertices;
33-
for(let i = 0; i < vertices.length; i+=4){
56+
for(let i = 0; i < vertices.length; i+=3){
3457
v[0] = vertices[i];
3558
v[1] = vertices[i+1];
3659
v[2] = vertices[i+2];
37-
v[3] = vertices[i+3];
60+
v[3] = 1.0;
3861
mul_mat4_vec4_mut(mesh_model,v);
39-
mesh.projected_buffer[i] = v[0];
40-
mesh.projected_buffer[i+1] = v[1];
41-
mesh.projected_buffer[i+2] = v[2];
42-
mesh.projected_buffer[i+3] = v[3];
62+
mesh.projected_buffer[out_index++] = v[0];
63+
mesh.projected_buffer[out_index++] = v[1];
64+
mesh.projected_buffer[out_index++] = v[2];
65+
mesh.projected_buffer[out_index++] = v[3];
4366
}
4467
process_lighting(mesh,scene);
4568
}

src/rendering/render.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import type { Mesh } from "./types/mesh";
44
import { mul_mat4 } from "../math/matrix_operators";
55
import { ArrayType, type mat4 } from "../math/types";
66
import { transform_vertices } from "./clip_space/vertex";
7-
import { assemble_primitives } from "./screen_space/primitive_assembler";
7+
import { assemble_primitives } from "./clip_space/primitive_assembler";
88
import type { StringBuffer } from "../utils/string_buffer";
99
import type { Scene } from "./types/scene";
1010

src/rendering/screen_space/rasterizer.ts

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,9 @@ import { process_perspective_mutate} from "../clip_space/vertex";
1111
export function rasterize(mesh:Mesh, invert_y:boolean = true, stride:number = 4):void {
1212
const vertices = mesh.raster_buffer;
1313
const out = mesh.raster_buffer;
14+
const out_c = mesh.raster_color;
15+
const colors = mesh.raster_color;
16+
let out_color_index = 0;
1417
let out_index = 0;
1518
let c1:vec4, c2:vec4, c3:vec4;
1619
c1 = vec4(0,0,0,0);
@@ -64,6 +67,22 @@ export function rasterize(mesh:Mesh, invert_y:boolean = true, stride:number = 4)
6467
out[out_index++] = x3;
6568
out[out_index++] = y3;
6669
out[out_index++] = z3;
70+
71+
const color_base = i * 9;
72+
73+
const r = (colors[color_base] + colors[color_base + 3] + colors[color_base + 6]) / 3;
74+
const g = (colors[color_base + 1] + colors[color_base + 4] + colors[color_base + 7]) / 3;
75+
const b = (colors[color_base + 2] + colors[color_base + 5] + colors[color_base + 8]) / 3;
76+
77+
78+
if(isNaN(r) || isNaN(g) || isNaN(b)){
79+
console.log(`(${r},${g},${b}) in ${color_base}`)
80+
console.log(colors.subarray(color_base,color_base+9));
81+
}
82+
83+
out_c[out_color_index++] = r;
84+
out_c[out_color_index++] = g;
85+
out_c[out_color_index++] = b;
6786
}
6887
mesh.raster_end = out_index;
6988
}

src/rendering/types/mesh.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,16 +10,18 @@ export class Mesh{
1010
projected_buffer: ArrayType
1111
raster_buffer: ArrayType
1212
color_buffer: ArrayType
13+
raster_color: ArrayType
1314
normals: ArrayType;
1415
albedo: vec3;
1516
raster_end:number
1617
visible_triangles_count:number
1718

18-
constructor(geometry:Geometry, albedo:vec3 = vec3(0,0,0), raster_buffer:ArrayType | null = null, projected_buffer:ArrayType | null = null, color_buffer:ArrayType | null = null){
19+
constructor(geometry:Geometry, albedo:vec3 = vec3(0,0,0), raster_color:ArrayType, raster_buffer:ArrayType | null = null, projected_buffer:ArrayType | null = null, color_buffer:ArrayType | null = null){
1920
this.vertices = geometry.vertices;
2021
this.indices = geometry.indices;
22+
this.raster_color = raster_color;
2123
this.local_normals = geometry.normals;
22-
this.normals = new ArrayType(geometry.normals.length);
24+
this.normals = new ArrayType(geometry.indices.length*3);
2325
if(projected_buffer === null)
2426
this.projected_buffer = new ArrayType(this.vertices.length * 4 / 3);
2527
else

src/rendering/types/scene.ts

Lines changed: 19 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -8,20 +8,22 @@ export class Scene{
88
scene_buffer!:ArrayType;
99
color_buffer!:ArrayType
1010
draw_order!: IndexingType;
11+
raster_color!: ArrayType;
1112
draw_end!:number;
1213
meshes!:Mesh[];
1314
lights!:Light[];
1415

1516
private scene_cursor = 0;
1617
private projected_cursor = 0;
1718
private color_cursor = 0;
19+
private raster_color_cursor = 0;
1820

1921
/**
2022
* Initialize a Scene instance
2123
* @param geometry If you want a static scene, provide a list of Geometries of all present meshes. If you want a scene that grows to a dynamically large value, provide the maximum number of triangles Scene will store.
2224
* @returns Nothing
2325
*/
24-
constructor(geometry: Geometry[] | number) {
26+
constructor(geometry: Geometry[] | number, colors:vec3[] | null = null) {
2527
if (typeof geometry === "number") {
2628
this.reserve(geometry);
2729
return;
@@ -34,8 +36,13 @@ export class Scene{
3436
total_verts += g.vertices.length / 3;
3537
}
3638
this.reserve(total_tris);
37-
for (let g of geometry) {
38-
this.add_mesh(g);
39+
if(colors === null){
40+
colors = new Array(geometry.length);
41+
colors.fill(vec3(0.2,0.2,0.2));
42+
}
43+
for (let i = 0; i < geometry.length; ++i) {
44+
const g = geometry[i];
45+
this.add_mesh(g,colors[i]);
3946
}
4047
}
4148
/**
@@ -46,7 +53,8 @@ export class Scene{
4653
this.scene_buffer = new ArrayType(max_triangles * 12);
4754
this.projected_buffer = new ArrayType(max_triangles * 12);
4855
this.draw_order = new IndexingType(max_triangles);
49-
this.color_buffer = new ArrayType(max_triangles*3);
56+
this.color_buffer = new ArrayType(max_triangles * 9);
57+
this.raster_color = new ArrayType(max_triangles * 9);
5058
this.draw_end = 0;
5159
this.meshes = [];
5260
this.lights = [];
@@ -56,25 +64,28 @@ export class Scene{
5664
this.scene_cursor = 0;
5765
this.projected_cursor = 0;
5866
this.color_cursor = 0;
67+
this.raster_color_cursor = 0;
5968
this.meshes = [];
6069
this.lights = [];
6170
}
6271

63-
add_mesh(geometry:Geometry, color:vec3 = vec3(0,0,0)):Mesh{
72+
add_mesh(geometry:Geometry, color:vec3 = vec3(0.2,0.2,0.2)):Mesh{
6473
const scene_size = geometry.indices.length * 4;
6574
const proj_size = geometry.vertices.length/3*4;
66-
const color_size = geometry.vertices.length;
75+
const color_size = geometry.vertices.length * 3;
76+
const raster_color_size = geometry.indices.length * 3;
6777

6878
const scene_view = this.scene_buffer.subarray(this.scene_cursor, this.scene_cursor + scene_size);
6979
const proj_view = this.projected_buffer.subarray(this.projected_cursor,this.projected_cursor + proj_size);
7080
const color_view = this.color_buffer.subarray(this.color_cursor,this.color_cursor + color_size);
71-
81+
const raster_color = this.raster_color.subarray(this.raster_color_cursor,this.raster_color_cursor + raster_color_size);
7282

7383
this.scene_cursor += scene_size;
7484
this.projected_cursor += proj_size;
7585
this.color_cursor += color_size;
86+
this.raster_color_cursor += raster_color_size;
7687

77-
const mesh = new Mesh(geometry,color,scene_view,proj_view,color_view);
88+
const mesh = new Mesh(geometry,color,raster_color,scene_view,proj_view,color_view);
7889
this.meshes.push(mesh);
7990
return mesh;
8091
}

src/to_html.ts

Lines changed: 23 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -162,8 +162,11 @@ const PATH_TOKENS = {
162162
M: string_to_uint('M '),
163163
L: string_to_uint('L '),
164164
Z: string_to_uint('Z '),
165+
COLOR_HEAD: string_to_uint('"fill="rgb('),
166+
COMMA: character_to_uint(","),
167+
RPAREN: character_to_uint(")"),
165168
TAIL_WIREFRAME: string_to_uint('" fill="none" stroke = "black" stroke-width = "0.005"/>'),
166-
TAIL_SOLID: string_to_uint('" stroke="red" stroke-width = "0.005"/>')
169+
TAIL_SOLID: string_to_uint('"stroke-width = "0.005"/>')
167170
};
168171

169172
export function build_3d_svg(vertices:ArrayType, end:number, wireframe_mode:boolean,buffer:StringBuffer):string{
@@ -184,7 +187,7 @@ export function build_3d_svg(vertices:ArrayType, end:number, wireframe_mode:bool
184187
push_pair(x2,y2,buffer);
185188
buffer.write_chunk(PATH_TOKENS.L);
186189
push_pair(x3,y3,buffer);
187-
buffer.write_chunk(PATH_TOKENS.Z);
190+
buffer.write_chunk(PATH_TOKENS.Z);
188191
}
189192
if(wireframe_mode){
190193
buffer.write_chunk(PATH_TOKENS.TAIL_WIREFRAME);
@@ -204,8 +207,12 @@ export function build_scene(scene:Scene, wireframe_mode: boolean, buffer:StringB
204207
if(wireframe_mode)
205208
buffer.write_chunk(PATH_TOKENS.HEAD);
206209
const vertices = scene.scene_buffer;
210+
const colors = scene.raster_color;
207211
for(let i = 0; i < scene.draw_end; i++){
212+
if(!wireframe_mode)
213+
buffer.write_chunk(PATH_TOKENS.HEAD);
208214
const index = scene.draw_order[i];
215+
const c_index = index/3;
209216
const x1 = vertices[index];
210217
const y1 = vertices[index+1];
211218

@@ -214,16 +221,29 @@ export function build_scene(scene:Scene, wireframe_mode: boolean, buffer:StringB
214221

215222
const x3 = vertices[index+6];
216223
const y3 = vertices[index+7];
224+
225+
const r = Math.floor(colors[c_index] * 255) || 0;
226+
const g = Math.floor(colors[c_index + 1] * 255) || 0;
227+
const b = Math.floor(colors[c_index + 2] * 255) || 0;
217228

218229
if(!wireframe_mode)
219-
buffer.write_chunk(PATH_TOKENS.HEAD);
220230
buffer.write_chunk(PATH_TOKENS.M);
221231
push_pair(x1,y1,buffer);
222232
buffer.write_chunk(PATH_TOKENS.L);
223233
push_pair(x2,y2,buffer);
224234
buffer.write_chunk(PATH_TOKENS.L);
225235
push_pair(x3,y3,buffer);
226236
buffer.write_chunk(PATH_TOKENS.Z);
237+
238+
buffer.write_chunk(PATH_TOKENS.COLOR_HEAD);
239+
buffer.write_float(r);
240+
buffer.push(PATH_TOKENS.COMMA);
241+
buffer.write_float(g);
242+
buffer.push(PATH_TOKENS.COMMA);
243+
buffer.write_float(b);
244+
buffer.push(PATH_TOKENS.RPAREN);
245+
246+
227247
if(!wireframe_mode)
228248
buffer.write_chunk(PATH_TOKENS.TAIL_SOLID);
229249
}

0 commit comments

Comments
 (0)