|
@@ -1,73 +1,163 @@
|
|
|
<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 = 400
|
|
|
const numObjectsMax = 2000
|
|
|
const startTimeMS = ref(0)
|
|
|
-
|
|
|
+const width = 900
|
|
|
+const height = 600
|
|
|
const toggleCount = ref(0)
|
|
|
-const show = ref(false)
|
|
|
+const showTres = ref(false)
|
|
|
+const showVueThree = ref(false)
|
|
|
const msg = ref('Click Start Test to begin.')
|
|
|
const r = ref(null)
|
|
|
-const isStarted = ref(false)
|
|
|
-
|
|
|
let intervalId: ReturnType<typeof setInterval>
|
|
|
-
|
|
|
-const startTest = () => {
|
|
|
- isStarted.value = true
|
|
|
- startTimeMS.value = Date.now()
|
|
|
- msg.value = 'Test is running...'
|
|
|
- show.value = true // Start by showing the canvas
|
|
|
-
|
|
|
- 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) {
|
|
|
- if (r.value && show.value) {
|
|
|
- show.value = false
|
|
|
- toggleCount.value++
|
|
|
+ if (r.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 if (!show.value) {
|
|
|
- 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)
|
|
|
+ }
|
|
|
+ }
|
|
|
+ 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 = `Test completed in ${elapsedSec} seconds.`
|
|
|
+ msg.value = `Tres test completed in ${elapsedSec} seconds.`
|
|
|
+ clearInterval(intervalId)
|
|
|
}
|
|
|
- }, 1000 / 120)
|
|
|
+ }
|
|
|
+})()
|
|
|
+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...'
|
|
|
+}
|
|
|
+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(() => {
|
|
|
- if (intervalId) {
|
|
|
- clearInterval(intervalId)
|
|
|
- }
|
|
|
+ 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 test will create and remove {{ toggleMax }} TresCanvas instances with {{ numObjectsMax }} objects each.</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 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="startTest"
|
|
|
+ @click="startTestVueThree"
|
|
|
>
|
|
|
- Start Test
|
|
|
+ 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>
|