|
@@ -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>
|