Browse Source

性能优化 InstanceMesh(Point) + BufferGeometry + Label

master
修宁 6 months ago
parent
commit
18669d9d10
  1. 98
      src/components/ThreePerfView.vue

98
src/components/ThreePerfView.vue

@ -7,7 +7,8 @@
<div class="demo-color-block"> <div class="demo-color-block">
<span class="demonstration">物体数:<el-text type="danger">{{ restate.objects }}</el-text></span> <span class="demonstration">物体数:<el-text type="danger">{{ restate.objects }}</el-text></span>
<span class="demonstration"> 顶点数:<el-text type="danger">{{ restate.vertices }}</el-text></span> <span class="demonstration"> 顶点数:<el-text type="danger">{{ restate.vertices }}</el-text></span>
<span class="demonstration"> 三角形数:<el-text type="danger">{{ restate.faces }}</el-text></span> <span class="demonstration"> 三角形:<el-text type="danger">{{ restate.faces }}</el-text></span>
<span class="demonstration"> 标签:<el-text type="danger">{{ restate.viewLabelCount }}</el-text></span>
</div> </div>
</el-space> </el-space>
<div class="main-content"> <div class="main-content">
@ -179,26 +180,58 @@ function test2() {
refreshCount() refreshCount()
} }
function isLabelInView(label, frustum, cameraPosition, maxDistance = 65) {
const pos = new THREE.Vector3()
label.getWorldPosition(pos)
//
if (frustum.containsPoint(pos)) {
//
if (shouldShowLabel(label)) {
return true
}
}
return false
}
const labels: Text[] = []
function getLabelPixelSize(fontSize, cameraZoom) {
const pixelRatio = renderer.getPixelRatio()
const referenceZoom = 1
const referenceFontSize = 0.2
const referencePixelSize = 16 // fontSize=0.2, zoom=1 16px
const scale = (fontSize / referenceFontSize) * (cameraZoom / referenceZoom)
return referencePixelSize * scale * pixelRatio
}
function shouldShowLabel(label, minPixelSize = 700) {
const pixelSize = getLabelPixelSize(label.fontSize, camera.zoom)
console.log(`pixel size: ${pixelSize}`)
return pixelSize >= minPixelSize
}
/** /**
* BufferGeometry + Label * InstanceMesh(Point) + BufferGeometry + Label
*/ */
function test3() { function test3() {
cleanupThree() cleanupThree() //
const xcount = 100 const xcount = 300
const zcount = 100 const zcount = 100
const dist = 1.25 const dist = 1.25
const spacing = dist const spacing = dist
const y = 0.1 const y = 0.1
const noShaderMaterial = new THREE.MeshBasicMaterial({ const noShaderMaterial = new THREE.MeshBasicMaterial({
color: 0xFFFF99, color: 0xFFFF99,
transparent: true, transparent: true,
depthWrite: false, depthWrite: false,
side: THREE.DoubleSide side: THREE.DoubleSide
}) })
const planeGeometry = new THREE.PlaneGeometry(0.25, 0.25) // const planeGeometry = new THREE.PlaneGeometry(0.25, 0.25)
// 使 InstancedMesh
const instancedMesh = new THREE.InstancedMesh(planeGeometry, noShaderMaterial, zcount * xcount) const instancedMesh = new THREE.InstancedMesh(planeGeometry, noShaderMaterial, zcount * xcount)
instancedMesh.instanceMatrix.setUsage(THREE.DynamicDrawUsage) instancedMesh.instanceMatrix.setUsage(THREE.DynamicDrawUsage)
const dummy = new THREE.Object3D() const dummy = new THREE.Object3D()
@ -212,7 +245,7 @@ function test3() {
const pz = z * dist const pz = z * dist
dummy.position.set(px, y, pz) dummy.position.set(px, y, pz)
dummy.rotation.set(-Math.PI / 2, 0, 0) // dummy.rotation.set(-Math.PI / 2, 0, 0)
dummy.updateMatrix() dummy.updateMatrix()
instancedMesh.setMatrixAt(z * xcount + x, dummy.matrix) instancedMesh.setMatrixAt(z * xcount + x, dummy.matrix)
@ -222,9 +255,9 @@ function test3() {
scene.add(instancedMesh) scene.add(instancedMesh)
const positions = [] const positions = []
const labels = [] labels.length = 0
function createTextLabel(text, position) { function createTextLabel(text, position): Text {
const label = new Text() const label = new Text()
label.text = text label.text = text
label.font = SimSunTTF label.font = SimSunTTF
@ -243,7 +276,8 @@ function test3() {
label.position.set(position.x, position.y + 0.3, position.z - 0.2) label.position.set(position.x, position.y + 0.3, position.z - 0.2)
label.quaternion.copy(camera.quaternion) label.quaternion.copy(camera.quaternion)
label.sync() label.visible = false
// label.sync()
return label return label
} }
@ -290,8 +324,9 @@ function test3() {
lineSegments.name = 'grid-lines' lineSegments.name = 'grid-lines'
scene.add(lineSegments) scene.add(lineSegments)
// labels.forEach(label => scene.add(label)) labels.forEach(label => scene.add(label))
//
refreshCount() refreshCount()
} }
@ -299,6 +334,7 @@ function test3() {
const restate = reactive({ const restate = reactive({
targetColor: '#ff0000', targetColor: '#ff0000',
loadScale: 1, loadScale: 1,
viewLabelCount: 0,
mode: 'translate', mode: 'translate',
objects: 0, objects: 0,
vertices: 0, vertices: 0,
@ -399,16 +435,52 @@ function initThree() {
statsControls.dom.style.left = 'auto' statsControls.dom.style.left = 'auto'
viewerDom.appendChild(statsControls.dom) viewerDom.appendChild(statsControls.dom)
renderer.setAnimationLoop(renderView) renderer.setAnimationLoop(animate)
renderer.setClearColor(0x000000, 0) renderer.setClearColor(0x000000, 0)
// animate() // animate()
} }
// //
let frameCount = 0
function animate() { function animate() {
animationFrameId = requestAnimationFrame(animate) // animationFrameId = requestAnimationFrame(animate)
renderView() renderView()
if (frameCount++ % 60 === 0) { // 60
const frustum = new THREE.Frustum()
const cameraCopy = camera.clone()
//
cameraCopy.updateMatrixWorld()
//
const projScreenMatrix = new THREE.Matrix4().multiplyMatrices(
cameraCopy.projectionMatrix,
cameraCopy.matrixWorldInverse
)
//
frustum.setFromProjectionMatrix(projScreenMatrix)
let viewLabelCount = 0
labels.forEach((label: Text) => {
// label.quaternion.copy(camera.quaternion) // billboard
const isvis = isLabelInView(label, frustum, camera.position)
if (isvis) {
viewLabelCount++
}
if (isvis && label.visible === false) {
label.visible = true
label.sync()
} else if (!isvis && label.visible === true) {
label.visible = false
label.sync()
}
})
restate.viewLabelCount = viewLabelCount
}
} }
function handleResize(entries) { function handleResize(entries) {

Loading…
Cancel
Save