Interactive WebGL Goldberg polyhedron viewer and painter with PBR shading, adjustable environment lighting, paint tools (pen, brush, circle, fill, line, pick), undo/redo, colour palettes, and mesh relaxation. Added to the standalone experiments index. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
53 lines
2.1 KiB
JavaScript
53 lines
2.1 KiB
JavaScript
// Converts azimuth + elevation (degrees) to a normalised direction vector.
|
||
// Y = up, Z = towards camera. Azimuth is measured from +Z towards +X.
|
||
function _dir(azim_deg, elev_deg) {
|
||
const a = azim_deg * Math.PI / 180;
|
||
const e = elev_deg * Math.PI / 180;
|
||
return new Float32Array([Math.cos(e)*Math.sin(a), Math.sin(e), Math.cos(e)*Math.cos(a)]);
|
||
}
|
||
|
||
function _parse_hex(hex) {
|
||
return [parseInt(hex.slice(1,3),16)/255, parseInt(hex.slice(3,5),16)/255, parseInt(hex.slice(5,7),16)/255];
|
||
}
|
||
|
||
function _to_hex(c) {
|
||
const h = v => Math.round(Math.min(v,1)*255).toString(16).padStart(2,'0');
|
||
return `#${h(c[0])}${h(c[1])}${h(c[2])}`;
|
||
}
|
||
|
||
export class Env_State {
|
||
constructor() {
|
||
// Light 1 — warm key light (approximates the former hardcoded l1)
|
||
this.light1_azim = 27; // degrees
|
||
this.light1_elev = 34; // degrees
|
||
this.light1_color = [1.0, 0.98, 0.94]; // normalised hue
|
||
this.light1_intensity = 1.5;
|
||
|
||
// Light 2 — cool fill light (approximates former l2)
|
||
this.light2_azim = -58;
|
||
this.light2_elev = -28;
|
||
this.light2_color = [0.55, 0.65, 1.0];
|
||
this.light2_intensity = 0.5;
|
||
|
||
// Ambient — uniform baseline, no direction
|
||
this.ambient_color = [1.0, 1.0, 1.0];
|
||
this.ambient_intensity = 0.07;
|
||
}
|
||
|
||
light1_dir() { return _dir(this.light1_azim, this.light1_elev); }
|
||
light2_dir() { return _dir(this.light2_azim, this.light2_elev); }
|
||
|
||
// Final light colour = normalised hue × intensity (may exceed 1.0).
|
||
light1_col() { return new Float32Array(this.light1_color.map(v => v * this.light1_intensity)); }
|
||
light2_col() { return new Float32Array(this.light2_color.map(v => v * this.light2_intensity)); }
|
||
ambient_col() { return new Float32Array(this.ambient_color.map(v => v * this.ambient_intensity)); }
|
||
|
||
hex_light1() { return _to_hex(this.light1_color); }
|
||
hex_light2() { return _to_hex(this.light2_color); }
|
||
hex_ambient() { return _to_hex(this.ambient_color); }
|
||
|
||
set_hex_light1(hex) { this.light1_color = _parse_hex(hex); }
|
||
set_hex_light2(hex) { this.light2_color = _parse_hex(hex); }
|
||
set_hex_ambient(hex) { this.ambient_color = _parse_hex(hex); }
|
||
}
|