Multi Viewer (#1518)
* Fixed an issue with HDRIs not generating proper PMREMs over multiple viewer instances * WIP on makign the world tree multiple instanced * The WorldTree is no longer static. Each viewer has it's own instance and it hands it over to whoever needs it. * Fixed an issue with filtering and the new non-static tree. Also removed the 'root' key from the NodeData structure since it's not needed * Added an guard when building batches for situations where all render views have invalid geometries. This generally means there is somethign wrong with the stream itself * multi-viewer css fixes --------- Co-authored-by: Dimitrie Stefanescu <didimitrie@gmail.com>
This commit is contained in:
committed by
GitHub
parent
90439d7d41
commit
4aef572a44
@@ -1,4 +1,4 @@
|
||||
import { Material, Object3D, WebGLRenderer } from 'three'
|
||||
import { Box3, Material, Object3D, WebGLRenderer } from 'three'
|
||||
import { MaterialOptions } from '../materials/Materials'
|
||||
import { NodeRenderView } from '../tree/NodeRenderView'
|
||||
|
||||
@@ -17,6 +17,8 @@ export interface Batch {
|
||||
renderObject: Object3D
|
||||
geometryType: GeometryType
|
||||
|
||||
get bounds(): Box3
|
||||
|
||||
getCount(): number
|
||||
setBatchMaterial(material: Material): void
|
||||
setVisibleRange(...range: BatchUpdateRange[])
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
import { generateUUID } from 'three/src/math/MathUtils'
|
||||
import MeshBatch from './MeshBatch'
|
||||
import { SpeckleType } from '../converter/GeometryConverter'
|
||||
import { WorldTree } from '../tree/WorldTree'
|
||||
import LineBatch from './LineBatch'
|
||||
import Materials from '../materials/Materials'
|
||||
import { NodeRenderView } from '../tree/NodeRenderView'
|
||||
@@ -18,6 +17,7 @@ import { Material, Mesh, WebGLRenderer } from 'three'
|
||||
import { FilterMaterial, FilterMaterialType } from '../filtering/FilteringManager'
|
||||
import Logger from 'js-logger'
|
||||
import { World } from '../World'
|
||||
import { RenderTree } from '../tree/RenderTree'
|
||||
import SpeckleMesh from '../objects/SpeckleMesh'
|
||||
|
||||
export enum TransformStorage {
|
||||
@@ -44,17 +44,15 @@ export default class Batcher {
|
||||
}
|
||||
|
||||
public makeBatches(
|
||||
subtreeId: string,
|
||||
renderTree: RenderTree,
|
||||
speckleType: SpeckleType[],
|
||||
batchType?: GeometryType
|
||||
) {
|
||||
const renderViews = WorldTree.getRenderTree(subtreeId)
|
||||
.getAtomicRenderViews(...speckleType)
|
||||
.sort((a, b) => {
|
||||
if (a.renderMaterialHash === 0) return -1
|
||||
if (b.renderMaterialHash === 0) return 1
|
||||
return a.renderMaterialHash - b.renderMaterialHash
|
||||
})
|
||||
const renderViews = renderTree.getAtomicRenderViews(...speckleType).sort((a, b) => {
|
||||
if (a.renderMaterialHash === 0) return -1
|
||||
if (b.renderMaterialHash === 0) return 1
|
||||
return a.renderMaterialHash - b.renderMaterialHash
|
||||
})
|
||||
const materialHashes = [
|
||||
...Array.from(new Set(renderViews.map((value) => value.renderMaterialHash)))
|
||||
]
|
||||
@@ -78,7 +76,7 @@ export default class Batcher {
|
||||
for (let k = 0; k < batches.length; k++) {
|
||||
const restrictedRvs = batches[k]
|
||||
const batch = this.buildBatch(
|
||||
subtreeId,
|
||||
renderTree,
|
||||
restrictedRvs,
|
||||
materialHashes[i],
|
||||
batchType
|
||||
@@ -89,20 +87,18 @@ export default class Batcher {
|
||||
}
|
||||
|
||||
public async *makeBatchesAsync(
|
||||
subtreeId: string,
|
||||
renderTree: RenderTree,
|
||||
speckleType: SpeckleType[],
|
||||
batchType?: GeometryType,
|
||||
priority?: number
|
||||
) {
|
||||
const pause = World.getPause(priority)
|
||||
|
||||
const renderViews = WorldTree.getRenderTree(subtreeId)
|
||||
.getAtomicRenderViews(...speckleType)
|
||||
.sort((a, b) => {
|
||||
if (a.renderMaterialHash === 0) return -1
|
||||
if (b.renderMaterialHash === 0) return 1
|
||||
return a.renderMaterialHash - b.renderMaterialHash
|
||||
})
|
||||
const renderViews = renderTree.getAtomicRenderViews(...speckleType).sort((a, b) => {
|
||||
if (a.renderMaterialHash === 0) return -1
|
||||
if (b.renderMaterialHash === 0) return 1
|
||||
return a.renderMaterialHash - b.renderMaterialHash
|
||||
})
|
||||
const materialHashes = [
|
||||
...Array.from(new Set(renderViews.map((value) => value.renderMaterialHash)))
|
||||
]
|
||||
@@ -129,7 +125,7 @@ export default class Batcher {
|
||||
for (let k = 0; k < batches.length; k++) {
|
||||
const restrictedRvs = batches[k]
|
||||
const batch = this.buildBatch(
|
||||
subtreeId,
|
||||
renderTree,
|
||||
restrictedRvs,
|
||||
materialHashes[i],
|
||||
batchType
|
||||
@@ -203,13 +199,27 @@ export default class Batcher {
|
||||
}
|
||||
|
||||
private buildBatch(
|
||||
subtreeId: string,
|
||||
renderTree: RenderTree,
|
||||
renderViews: NodeRenderView[],
|
||||
materialHash: number,
|
||||
batchType?: GeometryType
|
||||
): Batch {
|
||||
const geometryType =
|
||||
batchType !== undefined ? batchType : renderViews[0].geometryType
|
||||
let batch = renderViews.filter((value) => value.renderMaterialHash === materialHash)
|
||||
/** Prune any meshes with no geometry data */
|
||||
batch = batch.filter((value) => value.validGeometry)
|
||||
|
||||
if (!batch.length) {
|
||||
/** This is for the case when all renderviews have invalid geometries, and it generally
|
||||
* means there is something wrong with the stream
|
||||
*/
|
||||
Logger.warn(
|
||||
'All renderviews have invalid geometries. Skipping batch!',
|
||||
renderViews
|
||||
)
|
||||
return null
|
||||
}
|
||||
|
||||
const geometryType = batchType !== undefined ? batchType : batch[0].geometryType
|
||||
let matRef = null
|
||||
|
||||
if (geometryType === GeometryType.MESH) {
|
||||
@@ -230,21 +240,21 @@ export default class Batcher {
|
||||
case GeometryType.MESH:
|
||||
geometryBatch = new MeshBatch(
|
||||
batchID,
|
||||
subtreeId,
|
||||
renderViews,
|
||||
renderTree.id,
|
||||
batch,
|
||||
this.floatTextures
|
||||
? TransformStorage.VERTEX_TEXTURE
|
||||
: TransformStorage.UNIFORM_ARRAY
|
||||
)
|
||||
break
|
||||
case GeometryType.LINE:
|
||||
geometryBatch = new LineBatch(batchID, subtreeId, renderViews)
|
||||
geometryBatch = new LineBatch(batchID, renderTree.id, batch)
|
||||
break
|
||||
case GeometryType.POINT:
|
||||
geometryBatch = new PointBatch(batchID, subtreeId, renderViews)
|
||||
geometryBatch = new PointBatch(batchID, renderTree.id, batch)
|
||||
break
|
||||
case GeometryType.POINT_CLOUD:
|
||||
geometryBatch = new PointBatch(batchID, subtreeId, renderViews)
|
||||
geometryBatch = new PointBatch(batchID, renderTree.id, batch)
|
||||
break
|
||||
}
|
||||
|
||||
@@ -469,56 +479,9 @@ export default class Batcher {
|
||||
/**
|
||||
* Used for debuggin only
|
||||
*/
|
||||
public isolateRenderView(id: string) {
|
||||
const rvs = WorldTree.getRenderTree().getRenderViewsForNodeId(id)
|
||||
const batchIds = [...Array.from(new Set(rvs.map((value) => value.batchId)))]
|
||||
for (const k in this.batches) {
|
||||
if (!batchIds.includes(k)) {
|
||||
this.batches[k].setDrawRanges({
|
||||
offset: 0,
|
||||
count: Infinity,
|
||||
material: this.materials.getFilterMaterial(
|
||||
this.batches[k].renderViews[0],
|
||||
FilterMaterialType.GHOST
|
||||
)
|
||||
})
|
||||
this.batches[k].setVisibleRange(HideAllBatchUpdateRange)
|
||||
} else {
|
||||
const drawRanges = []
|
||||
for (let i = 0; i < this.batches[k].renderViews.length; i++) {
|
||||
if (!rvs.includes(this.batches[k].renderViews[i])) {
|
||||
drawRanges.push({
|
||||
offset: this.batches[k].renderViews[i].batchStart,
|
||||
count: this.batches[k].renderViews[i].batchCount,
|
||||
material: this.materials.getFilterMaterial(
|
||||
this.batches[k].renderViews[i],
|
||||
FilterMaterialType.GHOST
|
||||
)
|
||||
})
|
||||
} else {
|
||||
drawRanges.push({
|
||||
offset: this.batches[k].renderViews[i].batchStart,
|
||||
count: this.batches[k].renderViews[i].batchCount,
|
||||
material: this.materials.getFilterMaterial(
|
||||
this.batches[k].renderViews[i],
|
||||
FilterMaterialType.SELECT
|
||||
)
|
||||
})
|
||||
}
|
||||
}
|
||||
if (drawRanges.length > 0) {
|
||||
this.batches[k].setDrawRanges(...drawRanges)
|
||||
this.batches[k].autoFillDrawRanges()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Used for debuggin only
|
||||
*/
|
||||
public async isolateRenderViewBatch(id: string) {
|
||||
const rv = WorldTree.getRenderTree().getRenderViewForNodeId(id)
|
||||
public async isolateRenderViewBatch(id: string, renderTree: RenderTree) {
|
||||
const rv = renderTree.getRenderViewForNodeId(id)
|
||||
for (const k in this.batches) {
|
||||
if (k !== rv.batchId) {
|
||||
this.batches[k].setDrawRanges({
|
||||
|
||||
@@ -15,7 +15,6 @@ import { Geometry } from '../converter/Geometry'
|
||||
import SpeckleLineMaterial from '../materials/SpeckleLineMaterial'
|
||||
import { ObjectLayers } from '../SpeckleRenderer'
|
||||
import { NodeRenderView } from '../tree/NodeRenderView'
|
||||
import { Viewer } from '../Viewer'
|
||||
import {
|
||||
AllBatchUpdateRange,
|
||||
Batch,
|
||||
@@ -34,6 +33,11 @@ export default class LineBatch implements Batch {
|
||||
public colorBuffer: InstancedInterleavedBuffer
|
||||
private static readonly vector4Buffer: Vector4 = new Vector4()
|
||||
|
||||
public get bounds() {
|
||||
if (!this.geometry.boundingBox) this.geometry.computeBoundingBox()
|
||||
return this.geometry.boundingBox
|
||||
}
|
||||
|
||||
public constructor(id: string, subtreeId: string, renderViews: NodeRenderView[]) {
|
||||
this.id = id
|
||||
this.subtreeId = subtreeId
|
||||
@@ -221,7 +225,6 @@ export default class LineBatch implements Batch {
|
||||
private makeLineGeometry(position: Float64Array) {
|
||||
this.geometry = this.makeLineGeometryTriangle(new Float32Array(position))
|
||||
Geometry.updateRTEGeometry(this.geometry, position)
|
||||
Viewer.World.expandWorld(this.geometry.boundingBox)
|
||||
}
|
||||
|
||||
private makeLineGeometryTriangle(position: Float32Array): LineSegmentsGeometry {
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import {
|
||||
Box3,
|
||||
BufferAttribute,
|
||||
BufferGeometry,
|
||||
DynamicDrawUsage,
|
||||
@@ -13,7 +14,6 @@ import { Geometry } from '../converter/Geometry'
|
||||
import SpeckleStandardColoredMaterial from '../materials/SpeckleStandardColoredMaterial'
|
||||
import SpeckleMesh from '../objects/SpeckleMesh'
|
||||
import { NodeRenderView } from '../tree/NodeRenderView'
|
||||
import { Viewer } from '../Viewer'
|
||||
import {
|
||||
AllBatchUpdateRange,
|
||||
Batch,
|
||||
@@ -41,6 +41,10 @@ export default class MeshBatch implements Batch {
|
||||
private indexBuffer1: BufferAttribute
|
||||
private indexBufferIndex = 0
|
||||
|
||||
public get bounds(): Box3 {
|
||||
return this.mesh.BVH.getBoundingBox(new Box3())
|
||||
}
|
||||
|
||||
public constructor(
|
||||
id: string,
|
||||
subtreeId: string,
|
||||
@@ -548,8 +552,6 @@ export default class MeshBatch implements Batch {
|
||||
this.geometry.computeBoundingSphere()
|
||||
this.geometry.computeBoundingBox()
|
||||
|
||||
Viewer.World.expandWorld(this.geometry.boundingBox)
|
||||
|
||||
Geometry.updateRTEGeometry(this.geometry, position)
|
||||
|
||||
return this.geometry
|
||||
|
||||
@@ -8,7 +8,6 @@ import {
|
||||
} from 'three'
|
||||
import { Geometry } from '../converter/Geometry'
|
||||
import { NodeRenderView } from '../tree/NodeRenderView'
|
||||
import { Viewer } from '../Viewer'
|
||||
import {
|
||||
AllBatchUpdateRange,
|
||||
Batch,
|
||||
@@ -28,6 +27,11 @@ export default class PointBatch implements Batch {
|
||||
public batchMaterial: Material
|
||||
public mesh: Points
|
||||
|
||||
public get bounds() {
|
||||
if (!this.geometry.boundingBox) this.geometry.computeBoundingBox()
|
||||
return this.geometry.boundingBox
|
||||
}
|
||||
|
||||
public constructor(id: string, subtreeId: string, renderViews: NodeRenderView[]) {
|
||||
this.id = id
|
||||
this.subtreeId = subtreeId
|
||||
@@ -321,7 +325,6 @@ export default class PointBatch implements Batch {
|
||||
this.geometry.computeBoundingSphere()
|
||||
this.geometry.computeBoundingBox()
|
||||
|
||||
Viewer.World.expandWorld(this.geometry.boundingBox)
|
||||
Geometry.updateRTEGeometry(this.geometry, position)
|
||||
|
||||
return this.geometry
|
||||
|
||||
Reference in New Issue
Block a user