-
-
Notifications
You must be signed in to change notification settings - Fork 120
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
chore(playground): add memory test comparing Tres and plain Vue/THREE…
… canvas performance (#917)
- Loading branch information
1 parent
db93014
commit 45f215c
Showing
1 changed file
with
133 additions
and
41 deletions.
There are no files selected for viewing
174 changes: 133 additions & 41 deletions
174
playground/vue/src/pages/advanced/MemoryTresObjects.vue
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,72 +1,164 @@ | ||
<script setup lang="ts"> | ||
import { TresCanvas } from '@tresjs/core' | ||
import type { Group, Material } from 'three' | ||
import { BoxGeometry, Color, Mesh, MeshBasicMaterial, PerspectiveCamera, Scene, Vector3, WebGLRenderer } from 'three' | ||
import { onUnmounted, ref } from 'vue' | ||
const toggleMax = 1000 | ||
const toggleMax = 400 | ||
const numObjectsMax = 2000 | ||
const startTimeMS = Date.now() | ||
const startTimeMS = ref(0) | ||
const width = 900 | ||
const height = 600 | ||
const toggleCount = ref(0) | ||
const show = ref(false) | ||
const msg = ref('Test is running.') | ||
const showTres = ref(false) | ||
const showVueThree = ref(false) | ||
const msg = ref('Click Start Test to begin.') | ||
const r = ref(null) | ||
const isPaused = ref(true) | ||
let intervalId: ReturnType<typeof setInterval> | ||
const startInterval = () => { | ||
intervalId = setInterval(() => { | ||
const testVueThree = (() => { | ||
let renderer: WebGLRenderer | null = null | ||
let scene: Scene | null = null | ||
let camera: PerspectiveCamera | null = null | ||
let frameCount = 0 | ||
function testVueThree() { | ||
if (toggleCount.value < toggleMax) { | ||
// NOTE: Make sure that objects are mounted by | ||
// checking `!!r.value`. | ||
if (r.value) { | ||
show.value = false | ||
toggleCount.value++ | ||
if (renderer) { | ||
if (frameCount < 2) { | ||
frameCount++ | ||
renderer.render(scene!, camera!) | ||
} | ||
else { | ||
camera?.removeFromParent() | ||
scene!.children.forEach((m) => { ((m as Mesh).material as Material).dispose(); (m as Mesh).geometry.dispose() }) | ||
renderer.dispose() | ||
frameCount = 0 | ||
camera = null | ||
scene = null | ||
renderer = null | ||
showVueThree.value = false | ||
toggleCount.value++ | ||
} | ||
} | ||
else { | ||
renderer = new WebGLRenderer({ canvas: r.value }) | ||
renderer.setSize(width, height) | ||
renderer.setClearColor(new Color('#EEE')) | ||
scene = new Scene() | ||
camera = new PerspectiveCamera() | ||
camera.position.x = 10 | ||
camera.position.y = 10 | ||
camera.lookAt(new Vector3(0, 0, 0)) | ||
for (let i = 0; i < numObjectsMax; i++) { | ||
scene.add(new Mesh(new BoxGeometry(), new MeshBasicMaterial())) | ||
} | ||
scene.add(camera) | ||
renderer.render(scene, camera) | ||
} | ||
} | ||
else { | ||
show.value = true | ||
else if (!showVueThree.value) { | ||
showVueThree.value = true | ||
} | ||
} | ||
else { | ||
const elapsedSec = (Date.now() - startTimeMS.value) / 1000 | ||
msg.value = `Plain Vue/THREE test completed in ${elapsedSec} seconds.` | ||
clearInterval(intervalId) | ||
const elapsedSec = (Date.now() - startTimeMS) / 1000 | ||
msg.value = `Test completed in ${elapsedSec} seconds.` | ||
} | ||
}, 1000 / 120) | ||
} | ||
const togglePause = () => { | ||
isPaused.value = !isPaused.value | ||
if (!isPaused.value) { | ||
startInterval() | ||
} | ||
else { | ||
clearInterval(intervalId) | ||
return testVueThree | ||
})() | ||
const testTres = (() => { | ||
let frameCount = 0 | ||
return () => { | ||
if (toggleCount.value < toggleMax) { | ||
if (r.value && frameCount < 2) { | ||
// NOTE: Wait until Tres has actually rendered before | ||
// removing the canvas. | ||
((r.value as Group).children[0] as Mesh).onAfterRender = () => { frameCount++ } | ||
} | ||
else { | ||
if (frameCount < 1) { | ||
showTres.value = true | ||
} | ||
else { | ||
toggleCount.value++ | ||
showTres.value = false | ||
frameCount = 0 | ||
} | ||
} | ||
} | ||
else { | ||
const elapsedSec = (Date.now() - startTimeMS.value) / 1000 | ||
msg.value = `Tres test completed in ${elapsedSec} seconds.` | ||
clearInterval(intervalId) | ||
} | ||
} | ||
})() | ||
const isStarted = ref(false) | ||
const startTestTres = () => { | ||
isStarted.value = true | ||
startTimeMS.value = Date.now() | ||
// NOTE: Using `setInterval`; it typically will keep | ||
// running in situations were `requestAnimationFrame` will pause. | ||
intervalId = setInterval(testTres, 1000 / 60) | ||
msg.value = 'Test is running...' | ||
} | ||
onUnmounted(() => clearInterval(intervalId)) | ||
const startTestVueThree = () => { | ||
isStarted.value = true | ||
startTimeMS.value = Date.now() | ||
// NOTE: Using `setInterval`; it typically will keep | ||
// running in situations were `requestAnimationFrame` will pause. | ||
intervalId = setInterval(testVueThree, 1000 / 60) | ||
msg.value = 'Test is running...' | ||
} | ||
onUnmounted(() => { | ||
clearInterval(intervalId) | ||
}) | ||
</script> | ||
|
||
<template> | ||
<OverlayInfo> | ||
<h1>Memory test: Tres Objects</h1> | ||
<h1>Memory test: Canvases with objects – Tres vs Plain Vue/THREE</h1> | ||
<p><span style="color: red">IMPORTANT</span> Epileptic warning: the tests run on this page cause the screen to flash rapidly.</p> | ||
<h2>Setup</h2> | ||
<p>This page will successively create and remove a TresCanvas containing a number of objects.</p> | ||
<p>This test will create and remove {{ toggleMax }} canvas instances with {{ numObjectsMax }} objects/materials/geometries each.</p> | ||
<h2>Note</h2> | ||
<ul> | ||
<li>These tests are intended to help spot memory leaks.</li> | ||
<li>Faster/slower test duration does not indicate a problem.</li> | ||
</ul> | ||
<h2>Status</h2> | ||
<p>{{ msg }}</p> | ||
<p>Number of TresCanvases created: {{ toggleCount }} / {{ toggleMax }}</p> | ||
<p>Number of Objects per TresCanvas: {{ numObjectsMax }}</p> | ||
<button style="padding: 8px 16px; margin-top: 10px;" @click="togglePause"> | ||
{{ isPaused ? 'Start Test' : 'Pause Test' }} | ||
<p>Number of canvases created: {{ toggleCount }} / {{ toggleMax }}</p> | ||
<button | ||
v-if="!isStarted" | ||
style="padding: 8px 16px; margin-top: 10px;" | ||
@click="startTestTres" | ||
> | ||
Start Tres test | ||
</button> | ||
|
||
<button | ||
v-if="!isStarted" | ||
style="padding: 8px 16px; margin-top: 10px;" | ||
@click="startTestVueThree" | ||
> | ||
Start plain Vue/THREE test | ||
</button> | ||
</OverlayInfo> | ||
<div v-if="show" style="width: 90%; height: 90%; border: 1px solid #F00"> | ||
<TresCanvas clear-color="black"> | ||
<TresGroup ref="r" /> | ||
<TresMesh v-for="_, i of Array.from({ length: numObjectsMax })" :key="i"> | ||
<TresMeshBasicMaterial /> | ||
<TresBoxGeometry /> | ||
</TresMesh> | ||
<div v-if="showTres" :style="{ width: `${width}px`, height: `${height}px` }"> | ||
<TresCanvas clear-color="#EEE"> | ||
<TresGroup ref="r"> | ||
<TresMesh v-for="_, i of Array.from({ length: numObjectsMax })" :key="i"> | ||
<TresMeshBasicMaterial /> | ||
<TresBoxGeometry /> | ||
</TresMesh> | ||
</TresGroup> | ||
</TresCanvas> | ||
</div> | ||
<div v-if="showVueThree"> | ||
<canvas ref="r" clear-color="black"></canvas> | ||
</div> | ||
</template> |