Skip to content
This repository was archived by the owner on Nov 22, 2022. It is now read-only.

Commit cfb6851

Browse files
author
Lucas Crane
authored
Dynamic preview resolution (#73)
* scale preview res dynamically * don't render preview on first frame * add missing code * comments * rename class * actually average benchmark * improve benchmarking; get time from requestAnimationFrame * use renderer.time(), improvements * rename renderer.time to renderer.sync; tweak scaling values; update examples
1 parent 66e9cbc commit cfb6851

File tree

7 files changed

+192
-112
lines changed

7 files changed

+192
-112
lines changed

scenes/renderer-test/main.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,10 +38,11 @@ function resize() {
3838
window.addEventListener('resize', resize);
3939
resize();
4040

41-
const tick = () => {
41+
const tick = (time) => {
4242
controls.update();
4343
camera.focus = controls.target.distanceTo(camera.position);
4444
stats.begin();
45+
renderer.sync(time);
4546
renderer.render(scene, camera);
4647
stats.end();
4748
requestAnimationFrame(tick);

scenes/sample-models/main.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -85,10 +85,11 @@ function resize() {
8585

8686
let animationFrameId;
8787

88-
const tick = () => {
88+
const tick = (time) => {
8989
controls.update();
9090
camera.focus = controls.target.distanceTo(camera.position);
9191
stats.begin();
92+
renderer.sync(time);
9293
renderer.render(scene, camera);
9394
stats.end();
9495
animationFrameId = requestAnimationFrame(tick);

scenes/webgl-comparison/main.js

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -72,12 +72,18 @@ function resize() {
7272
}
7373
}
7474

75-
function tick() {
75+
function tick(time) {
7676
controls.update();
7777
camera.focus = controls.target.distanceTo(camera.position);
7878
stats.begin();
79+
80+
if (renderer.sync) {
81+
renderer.sync(time);
82+
}
83+
7984
renderer.render(scene, camera);
8085
stats.end();
86+
8187
requestAnimationFrame(tick);
8288
}
8389

src/RayTracingRenderer.js

Lines changed: 32 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,6 @@ export function RayTracingRenderer(params = {}) {
3737
needsUpdate: true,
3838
onSampleRendered: null,
3939
renderWhenOffFocus: true,
40-
renderToScreen: true,
4140
toneMapping: THREE.LinearToneMapping,
4241
toneMappingExposure: 1,
4342
toneMappingWhitePoint: 1,
@@ -66,12 +65,6 @@ export function RayTracingRenderer(params = {}) {
6665
module.needsUpdate = false;
6766
}
6867

69-
function restartTimer() {
70-
if (pipeline) {
71-
pipeline.restartTimer();
72-
}
73-
}
74-
7568
module.setSize = (width, height, updateStyle = true) => {
7669
size.set(width, height);
7770
canvas.width = size.width * pixelRatio;
@@ -111,13 +104,22 @@ export function RayTracingRenderer(params = {}) {
111104
}
112105
};
113106

114-
module.sendToScreen = () => {
115-
if (pipeline) {
116-
pipeline.hdrBufferToScreen();
117-
}
107+
let isValidTime = 1;
108+
let currentTime = NaN;
109+
let syncWarning = false;
110+
111+
function restartTimer() {
112+
isValidTime = NaN;
113+
}
114+
115+
module.sync = (t) => {
116+
// the first call to the callback of requestAnimationFrame does not have a time parameter
117+
// use performance.now() in this case
118+
currentTime = t || performance.now();
118119
};
119120

120121
let lastFocus = false;
122+
121123
module.render = (scene, camera) => {
122124
if (!module.renderWhenOffFocus) {
123125
const hasFocus = document.hasFocus();
@@ -134,19 +136,28 @@ export function RayTracingRenderer(params = {}) {
134136
initScene(scene);
135137
}
136138

137-
camera.updateMatrixWorld();
138-
139-
if (module.renderToScreen) {
140-
if(module.maxHardwareUsage) {
141-
// render new sample for the entire screen
142-
pipeline.drawFull(camera);
143-
} else {
144-
// render new sample for a tiled subset of the screen
145-
pipeline.draw(camera);
139+
if (isNaN(currentTime)) {
140+
if (!syncWarning) {
141+
console.warn('Ray Tracing Renderer warning: For improved performance, please call renderer.sync(time) before render.render(scene, camera), with the time parameter equalling the parameter passed to the callback of requestAnimationFrame');
142+
syncWarning = true;
146143
}
147144

145+
currentTime = performance.now(); // less accurate than requestAnimationFrame's time parameter
146+
}
147+
148+
pipeline.time(isValidTime * currentTime);
149+
150+
isValidTime = 1;
151+
currentTime = NaN;
152+
153+
camera.updateMatrixWorld();
154+
155+
if(module.maxHardwareUsage) {
156+
// render new sample for the entire screen
157+
pipeline.drawFull(camera);
148158
} else {
149-
pipeline.drawOffscreenTile(camera);
159+
// render new sample for a tiled subset of the screen
160+
pipeline.draw(camera);
150161
}
151162
};
152163

src/renderer/RenderSize.js

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
import { clamp } from './util';
2+
import { Vector2 } from 'three';
3+
4+
export function makeRenderSize(gl) {
5+
const desiredMsPerFrame = 20;
6+
7+
let fullWidth;
8+
let fullHeight;
9+
10+
let renderWidth;
11+
let renderHeight;
12+
let scale = new Vector2(1, 1);
13+
14+
let pixelsPerFrame = pixelsPerFrameEstimate(gl);
15+
16+
function setSize(w, h) {
17+
fullWidth = w;
18+
fullHeight = h;
19+
calcDimensions();
20+
}
21+
22+
function calcDimensions() {
23+
const aspectRatio = fullWidth / fullHeight;
24+
renderWidth = Math.round(clamp(Math.sqrt(pixelsPerFrame * aspectRatio), 1, fullWidth));
25+
renderHeight = Math.round(clamp(renderWidth / aspectRatio, 1, fullHeight));
26+
scale.set(renderWidth / fullWidth, renderHeight / fullHeight);
27+
}
28+
29+
function adjustSize(elapsedFrameMs) {
30+
if (!elapsedFrameMs) {
31+
return;
32+
}
33+
34+
// tweak to find balance. higher = faster convergence, lower = less fluctuations to microstutters
35+
const strength = 600;
36+
37+
const error = desiredMsPerFrame - elapsedFrameMs;
38+
39+
pixelsPerFrame += strength * error;
40+
pixelsPerFrame = clamp(pixelsPerFrame, 8192, fullWidth * fullHeight);
41+
calcDimensions();
42+
}
43+
44+
return {
45+
adjustSize,
46+
setSize,
47+
scale,
48+
get width() {
49+
return renderWidth;
50+
},
51+
get height() {
52+
return renderHeight;
53+
}
54+
};
55+
}
56+
57+
function pixelsPerFrameEstimate(gl) {
58+
const maxRenderbufferSize = gl.getParameter(gl.MAX_RENDERBUFFER_SIZE);
59+
60+
if (maxRenderbufferSize <= 8192) {
61+
return 80000;
62+
} else if (maxRenderbufferSize === 16384) {
63+
return 150000;
64+
} else if (maxRenderbufferSize >= 32768) {
65+
return 400000;
66+
}
67+
}

0 commit comments

Comments
 (0)