Skip to content

Commit 8fa597d

Browse files
committed
Improve Screen mode handling
1 parent 977abca commit 8fa597d

12 files changed

+142
-60
lines changed

examples/knot.mjs

+1-1
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ scene.add(knotMesh);
3333

3434
// A slightly larger knot mesh, inside-out black - for outline
3535
const outlineGeometry = new THREE.TorusKnotGeometry(10, 2, 256, 20, 2, 7);
36-
const outlineMaterial = new THREE.MeshBasicMaterial({ color: 0, side: THREE.BackSide });;
36+
const outlineMaterial = new THREE.MeshBasicMaterial({ color: 0, side: THREE.BackSide });
3737
const outlineMesh = new THREE.Mesh(outlineGeometry, outlineMaterial);
3838
knotMesh.add(outlineMesh);
3939

examples/palette/palette.mjs

+21-6
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ import { createRenderTarget } from './utils/create-render-target.js';
1414
import { populateScene } from './utils/populate-scene.js';
1515

1616

17-
const IS_PERF_MODE = true;
17+
const IS_PERF_MODE = !true;
1818

1919
const hueModes = [
2020
'monochromatic', 'analagous', 'complementary', 'triadic', 'tetradic',
@@ -37,16 +37,16 @@ addThreeHelpers(THREE, gl);
3737
const icon = new Image('textures/icon.png');
3838
icon.on('load', () => { doc.icon = icon; });
3939

40-
const cameraPerspective = new THREE.PerspectiveCamera(50, doc.w / doc.h, 1, 1000);
41-
cameraPerspective.position.z = 9;
42-
const screen = new Screen({ three: THREE, camera: cameraPerspective });
40+
const screen = new Screen({ three: THREE, fov: 50, near: 1, far: 1000 });
41+
screen.renderer.shadowMap.enabled = true;
42+
screen.camera.position.z = 9;
4343

4444
const cameraOrtho = new THREE.OrthographicCamera(
4545
-doc.w * 0.5, doc.w * 0.5, doc.h * 0.5, -doc.h * 0.5, - 10, 10,
4646
);
4747
cameraOrtho.position.z = 5;
4848

49-
const controls = new OrbitControls(cameraPerspective, doc);
49+
const controls = new OrbitControls(screen.camera, doc);
5050
controls.update();
5151

5252
let mesh;
@@ -105,14 +105,29 @@ const setModeGrayscale = (newValue) => {
105105
newValue = 1;
106106
}
107107
modeGrayscale = newValue;
108+
109+
if (modeGrayscale == 1) {
110+
console.log('Grayscale mode: Luminosity.');
111+
} else if (modeGrayscale == 2) {
112+
console.log('Grayscale mode: Lightness.');
113+
} else if (modeGrayscale == 3) {
114+
console.log('Grayscale mode: Average.');
115+
} else {
116+
console.log('Grayscale mode: OFF.');
117+
}
118+
108119
materialPost.uniforms.modeGrayscale.value = modeGrayscale;
109120
};
110121

111122
const setIsSwap = (newValue) => {
123+
isSwap = newValue;
124+
112125
if (isSwap && !modeGrayscale) {
113126
setModeGrayscale(1);
127+
} else if (!isSwap) {
128+
setModeGrayscale(0);
114129
}
115-
isSwap = newValue;
130+
116131
materialPost.uniforms.isSwap.value = isSwap;
117132
palette.forEach((color, i) => {
118133
colorQuads[i].visible = isSwap;

examples/palette/post.glsl

+1-1
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ float toGrayscale(vec3 rgb) {
3434
}
3535

3636
void main() {
37-
vec4 rgba = texture(t, tc);
37+
vec4 rgba = sRGBTransferOETF(texture(t, tc));
3838
float gray = toGrayscale(rgba.rgb);
3939
vec3 finalColor = rgba.rgb;
4040
if (modeGrayscale > 0) {

examples/palette/profile.txt

Whitespace-only changes.

examples/palette/utils/create-render-target.js

+1
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ const createRenderTarget = (THREE, materialPost, w, h) => {
66
minFilter: THREE.LinearFilter,
77
magFilter: THREE.NearestFilter,
88
format: THREE.RGBAFormat,
9+
colorSpace: THREE.LinearSRGBColorSpace,
910
}
1011
);
1112

examples/palette/utils/palette.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -97,7 +97,7 @@ const createSettings = (colorCount) => {
9797
const generatePalette = (hueMode, colorCount) => {
9898
let paletteSettings = createSettings(colorCount);
9999
let lch = generateOKLCH(hueMode, paletteSettings);
100-
console.log('generated', hueMode, lch);
100+
console.log('New palette:', hueMode, lch);
101101
return lch;
102102
};
103103

examples/palette/utils/populate-scene.js

+31-8
Original file line numberDiff line numberDiff line change
@@ -30,20 +30,34 @@ const populateScene = (scene, cb) => {
3030
const { GLTFLoader } = await import('three/examples/jsm/loaders/GLTFLoader.js');
3131
const { DRACOLoader } = await import('./DRACOLoader.mjs');
3232

33-
const directionalLight1 = new THREE.DirectionalLight(0xffffff, 5);
34-
directionalLight1.position.set(0.5, 0.5, 0.5).normalize();
35-
directionalLight1.castShadow = true;
33+
const ambientLight = new THREE.AmbientLight(0xeeffee, 0.3);
34+
scene.add(ambientLight);
35+
36+
const directionalLight1 = new THREE.DirectionalLight(0xeeeeff, 2.4);
37+
directionalLight1.position.set(20, 20, 20);
3638
scene.add(directionalLight1);
3739

38-
const directionalLight2 = new THREE.DirectionalLight(0xffffff, 3);
39-
directionalLight2.position.set(-0.5, 0.5, 0.5).normalize();
40+
const d = 10;
41+
directionalLight1.castShadow = true;
42+
directionalLight1.shadow.camera.left = -d;
43+
directionalLight1.shadow.camera.right = d;
44+
directionalLight1.shadow.camera.top = d;
45+
directionalLight1.shadow.camera.bottom = -d;
46+
directionalLight1.shadow.camera.near = 5;
47+
directionalLight1.shadow.camera.far = 60;
48+
directionalLight1.shadow.mapSize.x = 2048;
49+
directionalLight1.shadow.mapSize.y = 2048;
50+
directionalLight1.shadow.intensity = 0.55;
51+
52+
const directionalLight2 = new THREE.DirectionalLight(0xffaaaa, 0.7);
53+
directionalLight2.position.set(-20, 5, 20).normalize();
4054
scene.add(directionalLight2);
4155

42-
const directionalLight3 = new THREE.DirectionalLight(0xffffff, 2);
43-
directionalLight3.position.set(0, -0.5, -0.5).normalize();
56+
const directionalLight3 = new THREE.DirectionalLight(0xffddaa, 0.5);
57+
directionalLight3.position.set(5, -20, -5).normalize();
4458
scene.add(directionalLight3);
4559

46-
scene.background = new THREE.Color(0xbfe3dd);
60+
scene.background = new THREE.Color(0x87ceeb);
4761

4862
const dracoLoader = new DRACOLoader();
4963
dracoLoader.setDecoderPath(`${__dirname}/../../../node_modules/three/examples/jsm/libs/draco/gltf/`);
@@ -57,13 +71,22 @@ const populateScene = (scene, cb) => {
5771
if (!node.isMesh) {
5872
return;
5973
}
74+
node.castShadow = true;
6075
flipUv(node.geometry.attributes.uv);
6176
flipUv(node.geometry.attributes.uv1);
6277
});
6378

6479
scene.add(gltf.scene);
6580
cb(gltf.scene);
6681
});
82+
83+
const floorMaterial = new THREE.MeshStandardMaterial({ color: 0xface8d });
84+
const geoFloor = new THREE.PlaneGeometry(100, 100, 4, 4);
85+
const meshFloor = new THREE.Mesh(geoFloor, floorMaterial);
86+
meshFloor.rotation.x = -Math.PI * 0.5;
87+
meshFloor.position.y = -2;
88+
meshFloor.receiveShadow = true;
89+
scene.add(meshFloor);
6790
})();
6891
};
6992

examples/srgb/package.json

+1
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
"name": "test",
33
"version": "0.0.0",
44
"type": "module",
5+
"private": true,
56
"scripts": {
67
"start": "node --experimental-strip-types main.ts"
78
},

index.d.ts

+13
Original file line numberDiff line numberDiff line change
@@ -224,6 +224,19 @@ declare module "3d-core-raub" {
224224
*/
225225
requestAnimationFrame: (cb: (dateNow: number) => void) => number,
226226

227+
/**
228+
* A wrapper for `document` that automates some common operations.
229+
*
230+
* * Pass `three`, or `THREE`. If not, it will refer to `global.THREE`
231+
* * Pass your own `camera`, or it will create a new one - with default parameters, or yours.
232+
* * Pass your `scene`, or it will create a new one.
233+
* * Pass a `renderer`, or don't - that's just fine.
234+
* * Call `screen.draw()` - equivalent of `renderer.render(scene, camera)`.
235+
*
236+
* It will also propagate the `document` input events and handle the `'mode'` event.
237+
* The latter is important to correctly update any VAO-based geometry. The `'mode'`
238+
* event will be propagated after necessary handling (re-creation of `renderer`).
239+
*/
227240
Screen: typeof Screen,
228241
};
229242

js/objects/screen.js

+69-40
Original file line numberDiff line numberDiff line change
@@ -19,15 +19,15 @@ class Screen extends EventEmitter {
1919
if (!opts.camera) {
2020
const { fov, near, far, z } = opts;
2121
if (fov === 0) {
22-
this._camera = new this.three.OrthographicCamera(
23-
-this.width * 0.5, this.width * 0.5,
24-
this.height * 0.5, -this.height * 0.5,
22+
this._camera = new this._three.OrthographicCamera(
23+
-this.w * 0.5, this.w * 0.5,
24+
this.h * 0.5, -this.h * 0.5,
2525
near ?? -10, far ?? 10,
2626
);
2727
this._camera.position.z = z ?? 5;
2828
} else {
29-
this._camera = new this.three.PerspectiveCamera(
30-
fov ?? 90, this.width / this.height, near ?? 0.1, far ?? 200,
29+
this._camera = new this._three.PerspectiveCamera(
30+
fov ?? 90, this.w / this.h, near ?? 0.1, far ?? 200,
3131
);
3232
this._camera.position.z = z ?? 10;
3333
}
@@ -36,40 +36,37 @@ class Screen extends EventEmitter {
3636
}
3737

3838
if (!opts.scene) {
39-
this._scene = new this.three.Scene();
39+
this._scene = new this._three.Scene();
4040
} else {
4141
this._scene = opts.scene;
4242
}
4343

44-
if (!opts.renderer) {
45-
this._reinitRenderer();
46-
} else {
44+
if (opts.renderer) {
4745
this._autoRenderer = false;
4846
this._renderer = opts.renderer;
49-
this.context.enable(0x8861); // GL_POINT_SPRITE 0x8861
50-
this.context.enable(0x8642); // GL_VERTEX_PROGRAM_POINT_SIZE
51-
this.context.enable(0x8862); // GL_COORD_REPLACE
5247
}
48+
this._reinitRenderer();
5349

54-
this.renderer.setSize(this._doc.width, this._doc.height, false);
50+
this._renderer.setSize(this._doc.width, this._doc.height, false);
5551

56-
this.document.on('mode', () => {
52+
this._doc.on('mode', (e) => {
5753
this._reinitRenderer();
54+
this.emit('mode', e);
5855
});
5956

60-
this.document.on('resize', ({ width, height }) => {
57+
this._doc.on('resize', ({ width, height }) => {
6158
width = width || 16;
6259
height = height || 16;
6360

64-
this.camera.aspect = width / height;
65-
this.camera.updateProjectionMatrix();
66-
this.renderer.setSize(width, height, false);
61+
this._camera.aspect = width / height;
62+
this._camera.updateProjectionMatrix();
63+
this._renderer.setSize(width, height, false);
6764

6865
this.emit('resize', { width, height });
6966
});
7067

7168
['keydown', 'keyup', 'mousedown', 'mouseup', 'mousemove','mousewheel'].forEach(
72-
(type) => this.document.on(type, (e) => this.emit(type, e))
69+
(type) => this._doc.on(type, (e) => this.emit(type, e))
7370
);
7471

7572
this.draw();
@@ -87,9 +84,9 @@ class Screen extends EventEmitter {
8784

8885
get width() { return this._doc.width; }
8986
get height() { return this._doc.height; }
90-
get w() { return this.width; }
91-
get h() { return this.height; }
92-
get size() { return new this.three.Vector2(this.width, this.height); }
87+
get w() { return this._doc.width; }
88+
get h() { return this._doc.height; }
89+
get size() { return new this._three.Vector2(this.w, this.h); }
9390

9491
get title() { return this._doc.title; }
9592
set title(v) { this._doc.title = v || 'Untitled'; }
@@ -103,50 +100,82 @@ class Screen extends EventEmitter {
103100
this._camera.updateProjectionMatrix();
104101
}
105102

106-
get mode() { return this._doc._mode; }
103+
get mode() { return this._doc.mode; }
107104
set mode(v) { this._doc.mode = v; }
108105

109106
draw() {
110-
this._renderer.render(this.scene, this.camera);
107+
this._renderer.render(this._scene, this._camera);
111108
}
112109

113110

114111
snapshot(name = `${Date.now()}.jpg`) {
115112
const memSize = this.w * this.h * 4; // estimated number of bytes
116113
const storage = { data: Buffer.allocUnsafeSlow(memSize) };
117114

118-
this.context.readPixels(
119-
0, 0, this.w, this.h, this.context.RGBA, this.context.UNSIGNED_BYTE, storage,
115+
this._gl.readPixels(
116+
0, 0, this.w, this.h, this._gl.RGBA, this._gl.UNSIGNED_BYTE, storage,
120117
);
121118

122119
const img = this._Image.fromPixels(this.w, this.h, 32, storage.data);
123120
img.save(name);
124121
}
125122

123+
static _deepAssign(src, dest) {
124+
Object.entries(src).forEach(([k, v]) => {
125+
if (v && typeof v === 'object') {
126+
Screen._deepAssign(v, dest[k]);
127+
return;
128+
}
129+
dest[k] = v;
130+
});
131+
}
132+
126133
// When switching from fullscreen and back, reset renderer to update VAO/FBO objects
127134
_reinitRenderer() {
135+
const old = this._renderer;
136+
137+
// Migrate renderer props
138+
const renderProps = !old ? null : {
139+
shadowMap: {
140+
enabled: old.shadowMap.enabled,
141+
type: old.shadowMap.type,
142+
},
143+
debug: {
144+
checkShaderErrors: old.debug_checkShaderErrors,
145+
onShaderError: old.debug_onShaderError,
146+
},
147+
autoClear: old.autoClear,
148+
autoClearColor: old.autoClearColor,
149+
autoClearDepth: old.autoClearDepth,
150+
autoClearStencil: old.autoClearStencil,
151+
clippingPlanes: old.clippingPlanes,
152+
outputColorSpace: old.outputColorSpace,
153+
sortObjects: old.sortObjects,
154+
toneMapping: old.toneMapping,
155+
toneMappingExposure: old.toneMappingExposure,
156+
transmissionResolutionScale: old.transmissionResolutionScale,
157+
};
128158
if (this._autoRenderer) {
129-
this._renderer.dispose();
159+
old.dispose();
130160
}
131161

132162
this._autoRenderer = true;
133-
this._renderer = new this.three.WebGLRenderer({
134-
context: this.context,
135-
antialias: true,
163+
this._renderer = new this._three.WebGLRenderer({
164+
context: this._gl,
136165
canvas: this.canvas,
137-
alpha: true,
138-
139-
premultipliedAlpha: true,
140-
preserveDrawingBuffer: true,
141-
logarithmicDepthBuffer: true,
142166
});
143167

144-
this._camera.aspect = this.width / this.height;
168+
this._camera.aspect = this.w / this.h;
145169
this._camera.updateProjectionMatrix();
146-
this._renderer.setSize(this.width, this.height, false);
147-
this.context.enable(0x8861); // GL_POINT_SPRITE 0x8861
148-
this.context.enable(0x8642); // GL_VERTEX_PROGRAM_POINT_SIZE
149-
this.context.enable(0x8862); // GL_COORD_REPLACE
170+
this._renderer.setSize(this.w, this.h, false);
171+
172+
if (renderProps) {
173+
Screen._deepAssign(renderProps, this._renderer);
174+
}
175+
176+
this._gl.enable(0x8861); // GL_POINT_SPRITE 0x8861
177+
this._gl.enable(0x8642); // GL_VERTEX_PROGRAM_POINT_SIZE
178+
this._gl.enable(0x8862); // GL_COORD_REPLACE
150179
}
151180
}
152181

package-lock.json

+2-2
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)