Text support and limited Dimensions support (#1604)

* Font loading (hidden under a .png for now). Simple experiments with rendering text

* Added some text rendering tests. WIP on billboarding

* Added tests using troika-text-three library which uses sdf font textures instead of generating text geometry

* WIP on supporting speckle text objects

* Some more work on speckle text object integration. Worked on text materials, text batch and text object. We're now rendering basic text

* We're now rendering the text for various dimension types. Changed text to use display style first, since that's the one that contains it's color.

* Implemented text selection. Text can now be selected and works the same way every other speckle objects works when selecting

* Implemented the rest of the filtering features for text.

* Batch building can now be async. Building text batches needs to be async because that's how the troika libary works. Fixed an issue with the section box not clippin text properly

* Removed dummy text geometry data from it's RenderData. Enabled render views with metadata to count as valid. getRenderableRenderViews now returns nodes with metadata as well. Text now supports proper unit conversion. Text now is being displayed correctly(-ish) when inside blocks. Autocad text is now being displayed
This commit is contained in:
Alexandru Popovici
2023-06-06 14:49:47 +02:00
committed by GitHub
parent 5361d64e99
commit b3d8c5d28c
24 changed files with 2277 additions and 58 deletions
+3 -2
View File
@@ -377,7 +377,8 @@ export default class Sandbox {
title: 'Screenshot'
})
screenshot.on('click', async () => {
console.warn(await this.viewer.screenshot())
// console.warn(await this.viewer.screenshot())
this.viewer.getRenderer().adnotate()
})
const rotate = this.tabs.pages[0].addButton({
@@ -882,7 +883,7 @@ export default class Sandbox {
filteringFolder.addInput(this.filterParams, 'filterBy', {
options: {
Volume: 'parameters.HOST_VOLUME_COMPUTED.value',
Area: 'parameters.HOST_AREA_COMPUTED.value',
Area: 'area',
Elevation: 'Elevation',
SpeckleType: 'speckle_type',
DisplayName: 'DisplayName',
+7 -2
View File
@@ -109,7 +109,7 @@ const getStream = () => {
// prettier-ignore
// 'https://speckle.xyz/streams/da9e320dad/commits/5388ef24b8?c=%5B-7.66134,10.82932,6.41935,-0.07739,-13.88552,1.8697,0,1%5D'
// Revit sample house (good for bim-like stuff with many display meshes)
// 'https://speckle.xyz/streams/da9e320dad/commits/5388ef24b8'
'https://speckle.xyz/streams/da9e320dad/commits/5388ef24b8'
// 'https://latest.speckle.dev/streams/c1faab5c62/commits/6c6e43e5f3'
// 'https://latest.speckle.dev/streams/58b5648c4d/commits/60371ecb2d'
// 'Super' heavy revit shit
@@ -263,10 +263,15 @@ const getStream = () => {
// 'https://speckle.xyz/streams/be0f962efb/objects/37639741c363a123100eda8044f2fe3f'
// 'https://latest.speckle.dev/streams/92b620fb17/objects/a4e2fad01e69cd886ecbfedf221f5301'
// 'https://latest.speckle.dev/streams/3f895e614f/commits/7e16d2ab71'
// 'https://latest.speckle.dev/streams/55cc1cbf0a/commits/aa72674507'
// 'https://latest.speckle.dev/streams/55cc1cbf0a/objects/44aa4bad23591f90484a9a63814b9dc9'
// 'https://latest.speckle.dev/streams/55cc1cbf0a/objects/3a21694b533826cf551d4e2ff9963397'
// 'https://latest.speckle.dev/streams/55cc1cbf0a/commits/a7f74b6524'
// 'https://latest.speckle.dev/streams/c1faab5c62/objects/d3466547df9df86397eb4dff7ac9713f'
// 'https://latest.speckle.dev/streams/c1faab5c62/commits/140c443886'
// 'https://latest.speckle.dev/streams/e258b0e8db/commits/108971810d'
'https://latest.speckle.dev/streams/e258b0e8db/objects/3fcd63d80cf791c3f554a795846e62f6'
// 'https://latest.speckle.dev/streams/55cc1cbf0a/objects/d7ae178fb6a7b1f599a177486e14f9a6'
// 'https://latest.speckle.dev/streams/e258b0e8db/objects/3fcd63d80cf791c3f554a795846e62f6'
)
}
+2 -1
View File
@@ -51,7 +51,8 @@
"string-to-color": "^2.2.2",
"three": "^0.140.0",
"three-mesh-bvh": "0.5.17",
"tree-model": "1.0.7"
"tree-model": "1.0.7",
"troika-three-text": "0.47.2"
},
"devDependencies": {
"@babel/core": "^7.18.2",
+2 -1
View File
@@ -19,7 +19,8 @@ export interface ViewerParams {
export enum AssetType {
TEXTURE_8BPP = 'png', // For now
TEXTURE_HDR = 'hdr',
TEXTURE_EXR = 'exr'
TEXTURE_EXR = 'exr',
FONT_JSON = 'font-json'
}
export interface Asset {
File diff suppressed because it is too large Load Diff
+32 -5
View File
@@ -8,11 +8,12 @@ import {
} from 'three'
import { EXRLoader } from 'three/examples/jsm/loaders/EXRLoader.js'
import { RGBELoader } from 'three/examples/jsm/loaders/RGBELoader.js'
import { FontLoader, Font } from 'three/examples/jsm/loaders/FontLoader.js'
import { Asset, AssetType } from '../IViewer'
import Logger from 'js-logger'
export class Assets {
private static _cache: { [name: string]: Texture } = {}
private static _cache: { [name: string]: Texture | Font } = {}
private static getLoader(src: string, assetType: AssetType): TextureLoader {
if (assetType === undefined) assetType = src.split('.').pop() as AssetType
@@ -43,7 +44,7 @@ export class Assets {
srcUrl = asset as string
}
if (this._cache[srcUrl]) {
return Promise.resolve(this._cache[srcUrl])
return Promise.resolve(this._cache[srcUrl] as Texture)
}
return new Promise<Texture>((resolve, reject) => {
@@ -58,7 +59,7 @@ export class Assets {
this._cache[srcUrl] = pmremRT.texture
texture.dispose()
generator.dispose()
resolve(this._cache[srcUrl])
resolve(this._cache[srcUrl] as Texture)
},
undefined,
(error: ErrorEvent) => {
@@ -83,7 +84,7 @@ export class Assets {
}
if (this._cache[srcUrl]) {
return Promise.resolve(this._cache[srcUrl])
return Promise.resolve(this._cache[srcUrl] as Texture)
}
return new Promise<Texture>((resolve, reject) => {
// Hack to load 'data:image's - for some reason, the frontend receives the default
@@ -107,7 +108,7 @@ export class Assets {
srcUrl,
(texture) => {
this._cache[srcUrl] = texture
resolve(this._cache[srcUrl])
resolve(this._cache[srcUrl] as Texture)
},
undefined,
(error: ErrorEvent) => {
@@ -121,6 +122,32 @@ export class Assets {
})
}
public static getFont(asset: Asset | string): Promise<Font> {
let srcUrl: string = null
if ((<Asset>asset).src) {
srcUrl = (asset as Asset).src
} else {
srcUrl = asset as string
}
if (this._cache[srcUrl]) {
return Promise.resolve(this._cache[srcUrl] as Font)
}
return new Promise<Font>((resolve, reject) => {
new FontLoader().load(
srcUrl,
(font: Font) => {
resolve(font)
},
undefined,
(error: ErrorEvent) => {
reject(`Loading asset ${srcUrl} failed ${error.message}`)
}
)
})
}
/** To be used wisely */
public static async getTextureData(asset: Asset | string): Promise<ImageData> {
const texture = await Assets.getTexture(asset)
@@ -65,6 +65,7 @@ export enum ObjectLayers {
STREAM_CONTENT_MESH = 10,
STREAM_CONTENT_LINE = 11,
STREAM_CONTENT_POINT = 12,
STREAM_CONTENT_TEXT = 13,
STREAM_CONTENT = 1,
PROPS = 2,
@@ -1420,4 +1421,34 @@ export default class SpeckleRenderer {
public markTransformsDirty(batchId: string) {
;(this.batcher.batches[batchId] as MeshBatch).mesh.transformsDirty = true
}
public async adnotate() {
// const batches: Batch[] = Object.values(this.batcher.batches)
// let accumulator = 0
// let tris = 0
// let count = 0
// for (let k = 0; k < batches.length; k++) {
// const rvs = batches[k].renderViews
// for (let i = 0; i < rvs.length; i++) {
// const speckleObject = this.viewer.getWorldTree().findId(rvs[i].renderData.id)
// .model.raw
// const text = new SpeckleText()
// const start = performance.now()
// await text.setText(speckleObject.speckle_type.split('.').reverse()[0], 1)
// tris += text.triCount
// accumulator += performance.now() - start
// const objSize = rvs[i].aabb.getSize(new Vector3())
// const objCenter = rvs[i].aabb.getCenter(new Vector3())
// text.setPosition(
// new Vector3(objCenter.x, objCenter.y + objSize.y * 0.5, objCenter.z)
// )
// this.rootGroup.add(text.text)
// this.rootGroup.add(text.background)
// count++
// }
// }
// console.warn(accumulator)
// console.warn(tris / 3)
// console.warn(count)
}
}
@@ -6,7 +6,8 @@ export enum GeometryType {
MESH,
LINE,
POINT,
POINT_CLOUD
POINT_CLOUD,
TEXT
}
export interface Batch {
+17 -11
View File
@@ -19,6 +19,7 @@ import Logger from 'js-logger'
import { World } from '../World'
import { RenderTree } from '../tree/RenderTree'
import SpeckleMesh from '../objects/SpeckleMesh'
import TextBatch from './TextBatch'
export enum TransformStorage {
VERTEX_TEXTURE = 0,
@@ -43,7 +44,7 @@ export default class Batcher {
this.materials.createDefaultMaterials()
}
public makeBatches(
public async makeBatches(
renderTree: RenderTree,
speckleType: SpeckleType[],
batchType?: GeometryType
@@ -72,12 +73,12 @@ export default class Batcher {
if (valid) {
vertCount += value.renderData.geometry.attributes.POSITION.length / 3
}
return valid
return valid || value.hasMetadata
})
const batches = this.splitBatch(renderViewsBatch, vertCount)
for (let k = 0; k < batches.length; k++) {
const restrictedRvs = batches[k]
const batch = this.buildBatch(
const batch = await this.buildBatch(
renderTree,
restrictedRvs,
materialHashes[i],
@@ -123,12 +124,12 @@ export default class Batcher {
if (valid) {
vertCount += value.renderData.geometry.attributes.POSITION.length / 3
}
return valid
return valid || value.hasMetadata
})
const batches = this.splitBatch(renderViewsBatch, vertCount)
for (let k = 0; k < batches.length; k++) {
const restrictedRvs = batches[k]
const batch = this.buildBatch(
const batch = await this.buildBatch(
renderTree,
restrictedRvs,
materialHashes[i],
@@ -202,15 +203,15 @@ export default class Batcher {
return vSplit
}
private buildBatch(
private async buildBatch(
renderTree: RenderTree,
renderViews: NodeRenderView[],
materialHash: number,
batchType?: GeometryType
): Batch {
let batch = renderViews.filter((value) => value.renderMaterialHash === materialHash)
/** Prune any meshes with no geometry data */
batch = batch.filter((value) => value.validGeometry)
): Promise<Batch> {
const batch = renderViews.filter(
(value) => value.renderMaterialHash === materialHash
)
if (!batch.length) {
/** This is for the case when all renderviews have invalid geometries, and it generally
@@ -234,6 +235,8 @@ export default class Batcher {
matRef = renderViews[0].renderData.renderMaterial
} else if (geometryType === GeometryType.POINT_CLOUD) {
matRef = renderViews[0].renderData.renderMaterial
} else if (geometryType === GeometryType.TEXT) {
matRef = renderViews[0].renderData.displayStyle
}
const material = this.materials.getMaterial(materialHash, matRef, geometryType)
@@ -260,10 +263,13 @@ export default class Batcher {
case GeometryType.POINT_CLOUD:
geometryBatch = new PointBatch(batchID, renderTree.id, batch)
break
case GeometryType.TEXT:
geometryBatch = new TextBatch(batchID, renderTree.id, batch)
break
}
geometryBatch.setBatchMaterial(material)
geometryBatch.buildBatch()
await geometryBatch.buildBatch()
return geometryBatch
}
@@ -0,0 +1,111 @@
/* eslint-disable @typescript-eslint/no-unused-vars */
/* eslint-disable @typescript-eslint/no-empty-function */
import { Box3, Material, Object3D, WebGLRenderer } from 'three'
import { NodeRenderView } from '../tree/NodeRenderView'
import { AllBatchUpdateRange, Batch, BatchUpdateRange, GeometryType } from './Batch'
import { SpeckleText } from '../objects/SpeckleText'
import { GlyphGeometry } from 'troika-three-text'
import { ObjectLayers } from '../SpeckleRenderer'
export default class TextBatch implements Batch {
public id: string
public subtreeId: string
public renderViews: NodeRenderView[]
private geometry: GlyphGeometry
public batchMaterial: Material
public mesh: SpeckleText
public get bounds(): Box3 {
return new Box3() //this.mesh.BVH.getBoundingBox(new Box3())
}
public constructor(id: string, subtreeId: string, renderViews: NodeRenderView[]) {
this.id = id
this.subtreeId = subtreeId
this.renderViews = renderViews
}
public get geometryType(): GeometryType {
return GeometryType.TEXT
}
public get renderObject(): Object3D {
return this.mesh
}
public getCount(): number {
return this.geometry.index.count
}
public setBatchMaterial(material: Material) {
this.batchMaterial = material
}
public onUpdate(deltaTime: number) {
deltaTime
}
public onRender(renderer: WebGLRenderer) {
renderer
}
public setVisibleRange(...ranges: BatchUpdateRange[]) {}
public getVisibleRange(): BatchUpdateRange {
return AllBatchUpdateRange
}
public setDrawRanges(...ranges: BatchUpdateRange[]) {
this.mesh.textMesh.material = ranges[0].material
if (ranges[0].materialOptions && ranges[0].materialOptions.rampIndexColor) {
this.mesh.textMesh.material.color.copy(ranges[0].materialOptions.rampIndexColor)
}
}
public autoFillDrawRanges() {}
public resetDrawRanges() {
this.mesh.textMesh.material = this.batchMaterial
this.mesh.textMesh.visible = true
// this.geometry.clearGroups()
// this.geometry.setDrawRange(0, Infinity)
}
public async buildBatch() {
this.mesh = new SpeckleText(this.id)
this.mesh.matrixAutoUpdate = false
await this.mesh.update(
SpeckleText.SpeckleTextParamsFromMetadata(
this.renderViews[0].renderData.geometry.metaData
)
)
this.mesh.matrix.copy(this.renderViews[0].renderData.geometry.bakeTransform)
this.renderViews[0].setBatchData(
this.id,
0,
this.mesh.textMesh.geometry.index.length / 3
)
this.mesh.textMesh.material = this.batchMaterial
this.mesh.layers.set(ObjectLayers.STREAM_CONTENT_TEXT)
this.mesh.textMesh.layers.set(ObjectLayers.STREAM_CONTENT_TEXT)
}
public getRenderView(index: number): NodeRenderView {
return this.renderViews[0]
}
public getMaterialAtIndex(index: number): Material {
index
console.warn('Deprecated! Do not call this anymore')
return null
}
public purge() {
this.renderViews.length = 0
this.geometry.dispose()
this.batchMaterial.dispose()
this.mesh = null
}
}
@@ -35,7 +35,9 @@ export default class Coverter {
Circle: this.CircleToNode.bind(this),
Arc: this.ArcToNode.bind(this),
Ellipse: this.EllipseToNode.bind(this),
RevitInstance: this.RevitInstanceToNode.bind(this)
RevitInstance: this.RevitInstanceToNode.bind(this),
Text: this.TextToNode.bind(this),
Dimension: this.DimensionToNode.bind(this)
}
constructor(objectLoader: unknown, tree: WorldTree) {
@@ -487,6 +489,53 @@ export default class Coverter {
node.model.raw.colors = await this.dechunk(obj.colors)
}
private async TextToNode(obj, node) {
return
}
private async DimensionToNode(obj, node) {
const displayValues = [...this.getDisplayValue(obj)]
for (const displayValue of displayValues) {
const childNode: TreeNode = this.tree.parse({
id: this.getNodeId(displayValue),
raw: Object.assign({}, displayValue),
atomic: false,
children: []
})
this.tree.addNode(childNode, node)
await this.convertToNode(displayValue, childNode)
}
/**
* YOLO
* - Dimensions of all types do not have information about text size
* - Positioning of the text is not consistent across dimension types
* - Angular Dimensions are broken
*/
const textObj = JSON.parse(JSON.stringify(obj))
textObj.plane = textObj.RhinoProps.plane
const derivedType = this.getSpeckleTypeChain(textObj)[0]
switch (derivedType) {
case 'LengthDimension':
textObj.plane.origin = textObj.position
break
case 'DistanceDimension':
textObj.plane.origin = textObj.textPosition
break
case 'AngleDimension':
textObj.plane.origin = textObj.textPosition
break
}
textObj['speckle_type'] = 'Objects.Other.Text'
const textNode: TreeNode = this.tree.parse({
id: this.getNodeId(textObj),
raw: textObj,
atomic: false,
children: []
})
this.tree.addNode(textNode, node)
await this.convertToNode(textObj, textNode)
}
private async PointToNode(obj, node) {
return
}
@@ -8,6 +8,7 @@ import {
Matrix4,
Vector3
} from 'three'
import { SpeckleObject } from '../tree/DataTree'
export enum GeometryAttributes {
POSITION = 'POSITION',
@@ -22,6 +23,7 @@ export interface GeometryData {
attributes: Partial<Record<GeometryAttributes, number[]>>
bakeTransform: Matrix4
transform: Matrix4
metaData?: SpeckleObject
}
export class Geometry {
@@ -21,6 +21,7 @@ export enum SpeckleType {
Arc = 'Arc',
Ellipse = 'Ellipse',
RevitInstance = 'RevitInstance',
Text = 'Text',
Unknown = 'Unknown'
}
@@ -36,7 +37,8 @@ export const SpeckleTypeAllRenderables: SpeckleType[] = [
SpeckleType.Curve,
SpeckleType.Circle,
SpeckleType.Arc,
SpeckleType.Ellipse
SpeckleType.Ellipse,
SpeckleType.Text
]
export class GeometryConverter {
@@ -94,7 +96,9 @@ export class GeometryConverter {
return GeometryConverter.View3DToGeometryData(node)
case SpeckleType.RevitInstance:
return GeometryConverter.RevitInstanceToGeometryData(node)
default:
case SpeckleType.Text:
return GeometryConverter.TextToGeometryData(node)
case SpeckleType.Unknown:
// console.warn(`Skipping geometry conversion for ${type}`)
return null
}
@@ -337,6 +341,29 @@ export class GeometryConverter {
} as GeometryData
}
/**
* TEXT
*/
private static TextToGeometryData(node: NodeData): GeometryData {
const conversionFactor = getConversionFactor(node.raw.units)
const plane = node.raw.plane
const position = new Vector3(plane.origin.x, plane.origin.y, plane.origin.z)
const scale = new Matrix4().makeScale(
conversionFactor,
conversionFactor,
conversionFactor
)
const mat = new Matrix4().makeBasis(plane.xdir, plane.ydir, plane.normal)
mat.setPosition(position)
mat.premultiply(scale)
return {
attributes: null,
bakeTransform: mat,
transform: null,
metaData: node.raw
} as GeometryData
}
/**
* POINT
*/
@@ -22,6 +22,7 @@ import { Assets } from '../Assets'
import { getConversionFactor } from '../converter/Units'
import SpeckleGhostMaterial from './SpeckleGhostMaterial'
import Logger from 'js-logger'
import SpeckleTextMaterial from './SpeckleTextMaterial'
export interface MaterialOptions {
rampIndex?: number
@@ -56,6 +57,12 @@ export default class Materials {
private pointOverlayMaterial: Material = null
private pointCloudOverlayMaterial: Material = null
private textHighlightMaterial: Material = null
private textGhostMaterial: Material = null
private textColoredMaterial: Material = null
private textOverlayMaterial: Material = null
private textHiddenMaterial: Material = null
private defaultGradientTextureData: ImageData = null
public static renderMaterialFromNode(node: TreeNode): RenderMaterial {
@@ -430,6 +437,104 @@ export default class Materials {
;(this.pointGhostMaterial as SpecklePointMaterial).toneMapped = false
}
private async createDefaultTextMaterials() {
this.textHighlightMaterial = new SpeckleTextMaterial(
{
color: 0x047efb,
opacity: 1,
side: DoubleSide
},
['USE_RTE']
)
this.textHighlightMaterial.transparent =
this.textHighlightMaterial.opacity < 1 ? true : false
this.textHighlightMaterial.depthWrite = this.textHighlightMaterial.transparent
? false
: true
this.textHighlightMaterial.toneMapped = false
;(this.textHighlightMaterial as SpeckleTextMaterial).color.convertSRGBToLinear()
this.textHighlightMaterial = (
this.textHighlightMaterial as SpeckleTextMaterial
).getDerivedMaterial()
this.textGhostMaterial = new SpeckleTextMaterial(
{
color: 0xffffff,
opacity: 0.1,
side: DoubleSide
},
['USE_RTE']
)
this.textGhostMaterial.transparent =
this.textGhostMaterial.opacity < 1 ? true : false
this.textGhostMaterial.depthWrite = this.textGhostMaterial.transparent
? false
: true
this.textGhostMaterial.toneMapped = false
;(this.textGhostMaterial as SpeckleTextMaterial).color.convertSRGBToLinear()
this.textGhostMaterial = (
this.textGhostMaterial as SpeckleTextMaterial
).getDerivedMaterial()
this.textColoredMaterial = new SpeckleTextMaterial(
{
color: 0xffffff,
opacity: 1,
side: DoubleSide
},
['USE_RTE']
)
this.textColoredMaterial.transparent =
this.textColoredMaterial.opacity < 1 ? true : false
this.textColoredMaterial.depthWrite = this.textColoredMaterial.transparent
? false
: true
this.textColoredMaterial.toneMapped = false
;(this.textColoredMaterial as SpeckleTextMaterial).color.convertSRGBToLinear()
this.textColoredMaterial = (
this.textColoredMaterial as SpeckleTextMaterial
).getDerivedMaterial()
this.textOverlayMaterial = new SpeckleTextMaterial(
{
color: 0x04cbfb,
opacity: 1,
side: DoubleSide
},
['USE_RTE']
)
this.textOverlayMaterial.transparent =
this.textOverlayMaterial.opacity < 1 ? true : false
this.textOverlayMaterial.depthWrite = this.textOverlayMaterial.transparent
? false
: true
this.textOverlayMaterial.toneMapped = false
;(this.textOverlayMaterial as SpeckleTextMaterial).color.convertSRGBToLinear()
this.textOverlayMaterial = (
this.textOverlayMaterial as SpeckleTextMaterial
).getDerivedMaterial()
this.textHiddenMaterial = new SpeckleTextMaterial(
{
color: 0xffffff,
opacity: 1,
side: DoubleSide
},
['USE_RTE']
)
this.textHiddenMaterial.visible = false
this.textHiddenMaterial.toneMapped = false
;(this.textHiddenMaterial as SpeckleTextMaterial).color.convertSRGBToLinear()
this.textHiddenMaterial = (
this.textHiddenMaterial as SpeckleTextMaterial
).getDerivedMaterial()
}
private async createDefaultNullMaterials() {
this.materialMap[NodeRenderView.NullRenderMaterialHash] =
new SpeckleStandardMaterial(
@@ -523,6 +628,7 @@ export default class Materials {
await this.createDefaultMeshMaterials()
await this.createLineDefaultMaterials()
await this.createDefaultPointMaterials()
await this.createDefaultTextMaterials()
await this.createDefaultNullMaterials()
this.defaultGradientTextureData = await Assets.getTextureData(defaultGradient)
}
@@ -600,6 +706,23 @@ export default class Materials {
return mat
}
private makeTextMaterial(materialData: DisplayStyle): Material {
const mat = new SpeckleTextMaterial(
{
color: materialData.color,
opacity: 1,
side: DoubleSide
},
['USE_RTE']
)
mat.transparent = mat.opacity < 1 ? true : false
mat.depthWrite = mat.transparent ? false : true
mat.toneMapped = false
mat.color.convertSRGBToLinear()
return mat.getDerivedMaterial()
}
public getMaterial(
hash: number,
material: RenderMaterial | DisplayStyle,
@@ -619,6 +742,9 @@ export default class Materials {
case GeometryType.POINT_CLOUD:
mat = this.getPointCloudMaterial(hash, material as RenderMaterial)
break
case GeometryType.TEXT:
mat = this.getTextMaterial(hash, material)
break
}
// }
/** There's a bug in three.js where it checks for the length of the planes without checking if they exist first
@@ -659,6 +785,10 @@ export default class Materials {
return this.getPointMaterial(hash, material)
}
private getTextMaterial(hash: number, material: RenderMaterial | DisplayStyle) {
return this.makeTextMaterial(material as DisplayStyle)
}
public getHighlightMaterial(renderView: NodeRenderView): Material {
switch (renderView.geometryType) {
case GeometryType.MESH:
@@ -671,6 +801,8 @@ export default class Materials {
return this.pointHighlightMaterial
case GeometryType.POINT_CLOUD:
return this.pointCloudHighlightMaterial
case GeometryType.TEXT:
return this.textHighlightMaterial
}
}
@@ -684,6 +816,8 @@ export default class Materials {
return this.pointGhostMaterial
case GeometryType.POINT_CLOUD:
return this.pointGhostMaterial
case GeometryType.TEXT:
return this.textGhostMaterial
}
}
@@ -699,6 +833,8 @@ export default class Materials {
return this.pointGhostMaterial
case GeometryType.POINT_CLOUD:
return this.pointGhostMaterial
case GeometryType.TEXT:
return this.textColoredMaterial
}
}
@@ -714,6 +850,8 @@ export default class Materials {
return this.pointGhostMaterial
case GeometryType.POINT_CLOUD:
return this.pointGhostMaterial
case GeometryType.TEXT:
return this.textColoredMaterial
}
}
@@ -729,6 +867,8 @@ export default class Materials {
return this.pointOverlayMaterial
case GeometryType.POINT_CLOUD:
return this.pointCloudOverlayMaterial
case GeometryType.TEXT:
return this.textOverlayMaterial
}
}
@@ -742,6 +882,8 @@ export default class Materials {
return this.meshHiddenMaterial
case GeometryType.POINT_CLOUD:
return this.meshHiddenMaterial
case GeometryType.TEXT:
return this.textHiddenMaterial
}
}
@@ -799,6 +941,20 @@ export default class Materials {
},
['USE_RTE']
)
case GeometryType.TEXT: {
const mat = new SpeckleTextMaterial(
{
color,
opacity: 1,
side: DoubleSide
},
['USE_RTE']
)
mat.toneMapped = false
mat.color.convertSRGBToLinear()
return mat.getDerivedMaterial()
}
}
}
@@ -42,7 +42,8 @@ class SpeckleBasicMaterial extends ExtendedMeshBasicMaterial {
uViewer_low: new Vector3(),
uTransforms: [new Matrix4()],
tTransforms: null,
objCount: 1
objCount: 1,
billboardPos: new Vector3()
}
}
@@ -0,0 +1,101 @@
/* eslint-disable @typescript-eslint/no-unused-vars */
/* eslint-disable @typescript-eslint/no-explicit-any */
/* eslint-disable camelcase */
import { speckleTextVert } from './shaders/speckle-text-vert'
import { speckleTextFrag } from './shaders/speckle-text-frag'
import {
UniformsUtils,
ShaderLib,
Vector3,
MeshBasicMaterial,
Material,
IUniform
} from 'three'
import { Matrix4 } from 'three'
import { Geometry } from '../converter/Geometry'
import SpeckleMesh from '../objects/SpeckleMesh'
import { Uniforms } from './SpeckleStandardMaterial'
import { ExtendedMeshBasicMaterial } from './SpeckleMaterial'
import { createTextDerivedMaterial } from 'troika-three-text'
class SpeckleTextMaterial extends ExtendedMeshBasicMaterial {
protected static readonly matBuff: Matrix4 = new Matrix4()
protected static readonly vecBuff0: Vector3 = new Vector3()
protected static readonly vecBuff1: Vector3 = new Vector3()
protected static readonly vecBuff2: Vector3 = new Vector3()
protected get vertexShader(): string {
return speckleTextVert
}
protected get fragmentShader(): string {
return speckleTextFrag
}
protected get baseUniforms(): { [uniform: string]: IUniform } {
return ShaderLib.basic.uniforms
}
protected get uniformsDef(): Uniforms {
return {
uViewer_high: new Vector3(),
uViewer_low: new Vector3(),
uTransforms: [new Matrix4()],
tTransforms: null,
objCount: 1,
billboardPos: new Vector3()
}
}
constructor(parameters, defines = []) {
super(parameters)
this.init(defines)
}
/** We need a unique key per program */
public customProgramCacheKey() {
return this.constructor.name
}
public copy(source) {
super.copy(source)
this.copyFrom(source)
return this
}
public getDerivedMaterial() {
const derived = createTextDerivedMaterial(this)
/** We rebind the uniforms */
for (const k in this.userData) {
derived.uniforms[k] = this.userData[k]
}
return derived
}
/** Called by three.js render loop */
public onBeforeRender(_this, scene, camera, geometry, object, group) {
/** TO ENABLE */
// SpeckleTextMaterial.matBuff.copy(camera.matrixWorldInverse)
// SpeckleTextMaterial.matBuff.elements[12] = 0
// SpeckleTextMaterial.matBuff.elements[13] = 0
// SpeckleTextMaterial.matBuff.elements[14] = 0
// object.modelViewMatrix.copy(SpeckleTextMaterial.matBuff)
// SpeckleTextMaterial.vecBuff0.set(
// camera.matrixWorld.elements[12],
// camera.matrixWorld.elements[13],
// camera.matrixWorld.elements[14]
// )
// Geometry.DoubleToHighLowVector(
// SpeckleTextMaterial.vecBuff0,
// SpeckleTextMaterial.vecBuff1,
// SpeckleTextMaterial.vecBuff2
// )
// this.userData.uViewer_low.value.copy(SpeckleTextMaterial.vecBuff1)
// this.userData.uViewer_high.value.copy(SpeckleTextMaterial.vecBuff2)
// this.needsUpdate = true
}
}
export default SpeckleTextMaterial
@@ -0,0 +1,53 @@
export const speckleTextFrag = /* glsl */ `
uniform vec3 diffuse;
uniform float opacity;
#ifndef FLAT_SHADED
varying vec3 vNormal;
#endif
#include <common>
#include <dithering_pars_fragment>
#include <color_pars_fragment>
#include <uv_pars_fragment>
#include <uv2_pars_fragment>
#include <map_pars_fragment>
#include <alphamap_pars_fragment>
#include <alphatest_pars_fragment>
#include <aomap_pars_fragment>
#include <lightmap_pars_fragment>
#include <envmap_common_pars_fragment>
#include <envmap_pars_fragment>
#include <cube_uv_reflection_fragment>
#include <fog_pars_fragment>
#include <specularmap_pars_fragment>
#include <logdepthbuf_pars_fragment>
#include <clipping_planes_pars_fragment>
void main() {
#include <clipping_planes_fragment>
vec4 diffuseColor = vec4( diffuse, opacity );
#include <logdepthbuf_fragment>
#include <map_fragment>
#include <color_fragment>
#include <alphamap_fragment>
#include <alphatest_fragment>
#include <specularmap_fragment>
ReflectedLight reflectedLight = ReflectedLight( vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ) );
// accumulation (baked indirect lighting only)
#ifdef USE_LIGHTMAP
vec4 lightMapTexel = texture2D( lightMap, vUv2 );
reflectedLight.indirectDiffuse += lightMapTexel.rgb * lightMapIntensity * RECIPROCAL_PI;
#else
reflectedLight.indirectDiffuse += vec3( 1.0 );
#endif
// modulation
#include <aomap_fragment>
reflectedLight.indirectDiffuse *= diffuseColor.rgb;
vec3 outgoingLight = reflectedLight.indirectDiffuse;
#include <envmap_fragment>
#include <output_fragment>
#include <tonemapping_fragment>
#include <encodings_fragment>
#include <fog_fragment>
#include <premultiplied_alpha_fragment>
#include <dithering_fragment>
}
`
@@ -0,0 +1,184 @@
export const speckleTextVert = /* glsl */ `
#include <common>
#ifdef USE_RTE
// The high component is stored as the default 'position' attribute buffer
attribute vec3 position_low;
uniform vec3 uViewer_high;
uniform vec3 uViewer_low;
#endif
#ifdef TRANSFORM_STORAGE
attribute float objIndex;
#if TRANSFORM_STORAGE == 0
#if __VERSION__ == 300
#define TRANSFORM_STRIDE 4
#else
#define TRANSFORM_STRIDE 4.
#endif
uniform sampler2D tTransforms;
uniform float objCount;
#elif TRANSFORM_STORAGE == 1
uniform mat4 uTransforms[OBJ_COUNT];
#endif
#endif
#include <uv_pars_vertex>
#include <uv2_pars_vertex>
#include <envmap_pars_vertex>
#include <color_pars_vertex>
#include <fog_pars_vertex>
#include <morphtarget_pars_vertex>
#include <skinning_pars_vertex>
#include <logdepthbuf_pars_vertex>
#include <clipping_planes_pars_vertex>
#ifdef USE_RTE
vec4 computeRelativePositionSeparate(in vec3 position_low, in vec3 position_high, in vec3 relativeTo_low, in vec3 relativeTo_high){
/*
Vector calculation for the high and low differences works on everything
*BESIDES* Apple Silicon (or whatever they call it) GPUs
It would seem that when this code gets compiled, vector types get a lower precision(?)
which completely brakes the 2 float -> double reconstructio. Doing it separately for each
vector component using floats works fine.
*/
vec3 highDifference;
vec3 lowDifference;
float t1 = position_low.x - relativeTo_low.x;
float e = t1 - position_low.x;
float t2 = ((-relativeTo_low.x - e) + (position_low.x - (t1 - e))) + position_high.x - relativeTo_high.x;
highDifference.x = t1 + t2;
lowDifference.x = t2 - (highDifference.x - t1);
t1 = position_low.y - relativeTo_low.y;
e = t1 - position_low.y;
t2 = ((-relativeTo_low.y - e) + (position_low.y - (t1 - e))) + position_high.y - relativeTo_high.y;
highDifference.y = t1 + t2;
lowDifference.y = t2 - (highDifference.y - t1);
t1 = position_low.z - relativeTo_low.z;
e = t1 - position_low.z;
t2 = ((-relativeTo_low.z - e) + (position_low.z - (t1 - e))) + position_high.z - relativeTo_high.z;
highDifference.z = t1 + t2;
lowDifference.z = t2 - (highDifference.z - t1);
vec3 position = highDifference.xyz + lowDifference.xyz;
return vec4(position, 1.);
}
vec4 computeRelativePosition(in vec3 position_low, in vec3 position_high, in vec3 relativeTo_low, in vec3 relativeTo_high){
/*
Source https://github.com/virtualglobebook/OpenGlobe/blob/master/Source/Examples/Chapter05/Jitter/GPURelativeToEyeDSFUN90/Shaders/VS.glsl
Note here, we're storing the high part of the position encoding inside three's default 'position' attribute buffer so we avoid redundancy
*/
vec3 t1 = position_low.xyz - relativeTo_low;
vec3 e = t1 - position_low.xyz;
vec3 t2 = ((-relativeTo_low - e) + (position_low.xyz - (t1 - e))) + position_high.xyz - relativeTo_high;
vec3 highDifference = t1 + t2;
vec3 lowDifference = t2 - (highDifference - t1);
vec3 position = highDifference.xyz + lowDifference.xyz;
return vec4(position, 1.);
}
#endif
#ifdef TRANSFORM_STORAGE
void objectTransform(out vec4 quaternion, out vec4 pivotLow, out vec4 pivotHigh, out vec4 translation, out vec4 scale){
#if TRANSFORM_STORAGE == 0
#if __VERSION__ == 300
ivec2 uv = ivec2(int(objIndex) * TRANSFORM_STRIDE, 0);
vec4 v0 = texelFetch( tTransforms, uv, 0 );
vec4 v1 = texelFetch( tTransforms, uv + ivec2(1, 0), 0);
vec4 v2 = texelFetch( tTransforms, uv + ivec2(2, 0), 0);
vec4 v3 = texelFetch( tTransforms, uv + ivec2(3, 0), 0);
quaternion = v0;
pivotLow = vec4(v1.xyz, 1.);
pivotHigh = vec4(v2.xyz, 1.);
translation = vec4(v3.xyz, 1.);
scale = vec4(v1.w, v2.w, v3.w, 1.);
#elif
float size = objCount * TRANSFORM_STRIDE;
vec2 cUv = vec2(0.5/size, 0.5);
vec2 dUv = vec2(1./size, 0.);
vec2 uv = vec2((objIndex * TRANSFORM_STRIDE)/size + cUv.x, cUv.y);
vec4 v0 = texture2D( tTransforms, uv);
vec4 v1 = texture2D( tTransforms, uv + dUv);
vec4 v2 = texture2D( tTransforms, uv + 2. * dUv);
vec4 v3 = texture2D( tTransforms, uv + 3. * dUv);
quaternion = v0;
pivotLow = vec4(v1.xyz, 1.);
pivotHigh = vec4(v2.xyz, 1.);
translation = vec4(v3.xyz, 1.);
scale = vec4(v1.w, v2.w, v3.w, 1.);
#endif
#elif TRANSFORM_STORAGE == 1
mat4 tMatrix = uTransforms[int(objIndex)];
quaternion = tMatrix[0];
pivotLow = vec4(tMatrix[1].xyz, 1.);
pivotHigh = vec4(tMatrix[2].xyz, 1.);
translation = vec4(tMatrix[3].xyz, 1.);
scale = vec4(tMatrix[1][3], tMatrix[2][3], tMatrix[3][3], 1.);
#endif
}
vec3 rotate_vertex_position(vec3 position, vec4 quat)
{
return position + 2.0 * cross(quat.xyz, cross(quat.xyz, position) + quat.w * position);
}
#endif
uniform vec3 billboardPos;
void main() {
#include <uv_vertex>
#include <uv2_vertex>
#include <color_vertex>
#include <morphcolor_vertex>
#if defined ( USE_ENVMAP ) || defined ( USE_SKINNING )
#include <beginnormal_vertex>
#include <morphnormal_vertex>
#include <skinbase_vertex>
#include <skinnormal_vertex>
#include <defaultnormal_vertex>
#endif
#include <begin_vertex>
#include <morphtarget_vertex>
#include <skinning_vertex>
// #include <project_vertex> COMMENTED CHUNK
#ifdef TRANSFORM_STORAGE
vec4 tQuaternion, tPivotLow, tPivotHigh, tTranslation, tScale;
objectTransform(tQuaternion, tPivotLow, tPivotHigh, tTranslation, tScale);
#endif
#ifdef USE_RTE
vec4 position_lowT = vec4(position_low, 1.);
vec4 position_highT = vec4(position, 1.);
vec4 rteLocalPosition = computeRelativePositionSeparate(position_lowT.xyz, position_highT.xyz, uViewer_low, uViewer_high);
#ifdef TRANSFORM_STORAGE
vec4 rtePivot = computeRelativePositionSeparate(tPivotLow.xyz, tPivotHigh.xyz, uViewer_low, uViewer_high);
rteLocalPosition.xyz = rotate_vertex_position((rteLocalPosition - rtePivot).xyz, tQuaternion) * tScale.xyz + rtePivot.xyz + tTranslation.xyz;
#endif
#endif
#ifdef USE_RTE
vec4 mvPosition = rteLocalPosition;
#else
vec4 mvPosition = vec4( transformed, 1.0 );
#endif
#ifdef USE_INSTANCING
mvPosition = instanceMatrix * mvPosition;
#endif
mvPosition = modelViewMatrix * mvPosition;
gl_Position = projectionMatrix * viewMatrix * modelMatrix * vec4(position, 1.);//projectionMatrix * (viewMatrix * vec4(billboardPos, 1.0) + vec4(position.x, position.y, 0., 0.0));//projectionMatrix * mvPosition;//
#include <logdepthbuf_vertex>
#include <clipping_planes_vertex>
#include <worldpos_vertex>
#include <envmap_vertex>
#include <fog_vertex>
}
`
@@ -57,6 +57,7 @@ export class SpeckleRaycaster extends Raycaster {
this.layers.enable(ObjectLayers.STREAM_CONTENT)
this.layers.enable(ObjectLayers.STREAM_CONTENT_MESH)
this.layers.enable(ObjectLayers.STREAM_CONTENT_LINE)
this.layers.enable(ObjectLayers.STREAM_CONTENT_TEXT)
// OFF by default
// this.layers.enable(ObjectLayers.STREAM_CONTENT_POINT)
}
@@ -0,0 +1,139 @@
import { Mesh } from 'three'
import { Text } from 'troika-three-text'
import { SpeckleObject } from '../tree/DataTree'
export interface SpeckleTextParams {
textValue?: string
richTextValue?: string
height?: number
}
export class SpeckleText extends Mesh {
private _text: Text = null
private _background: Mesh = null
public static SpeckleTextParamsFromMetadata(metadata: SpeckleObject) {
return {
textValue: metadata.value ? metadata.value : 'N/A',
height: metadata.height
} as SpeckleTextParams
}
public get textMesh() {
return this._text
}
public get backgroundMesh() {
return this._background
}
public constructor(uuid: string) {
super()
this._text = new Text()
this._text.uuid = uuid
this._text.depthOffset = -0.01
this.add(this._text)
}
// public async build() {
// this._text = new Text()
// this._text.text = text
// this.text.fontSize = size
// this.text.color = 0xffffff
// const material = new SpeckleBasicMaterial({ color: 0xff0000 }, ['USE_RTE'])
// // material.side = DoubleSide
// this.text.frustumCulled = false
// this.text.layers.set(ObjectLayers.PROPS)
// this.text.material = createTextDerivedMaterial(material)
// this.text.material.uniforms['billboardPos'] = material.userData.billboardPos
// this.text.material.toneMapped = false
// await this.update()
// }
public async update(params: SpeckleTextParams, updateFinished?: () => void) {
return new Promise<void>((resolve) => {
if (params.textValue) {
this._text.text = params.textValue
}
if (params.richTextValue) {
//TO DO
}
if (params.height) {
this._text.fontSize = params.height
}
this._text.sync(() => {
resolve()
if (updateFinished) updateFinished()
})
})
}
// public get vertCount() {
// return this.text.geometry.attributes.position.count
// }
// public get triCount() {
// return this.text.geometry.index.count
// }
// public async setText(text: string, size: number) {
// return new Promise<void>((resolve) => {
// this.text = new Text()
// this.text.text = text
// this.text.fontSize = size
// this.text.color = 0xffffff
// const material = new SpeckleBasicMaterial({ color: 0xff0000 }, ['USE_RTE'])
// // material.side = DoubleSide
// this.text.frustumCulled = false
// this.text.layers.set(ObjectLayers.PROPS)
// this.text.material = createTextDerivedMaterial(material)
// this.text.material.uniforms['billboardPos'] = material.userData.billboardPos
// this.text.material.toneMapped = false
// this.text.sync(() => {
// this.setBackground()
// resolve()
// })
// })
// }
// private setBackground() {
// this.text.geometry.computeBoundingBox()
// const sizeBox = this.text.geometry.boundingBox.getSize(new Vector3())
// const geometry = new PlaneGeometry(sizeBox.x, sizeBox.y)
// const material = new SpeckleBasicMaterial({ color: 0xff0000 }, ['USE_RTE'])
// material.toneMapped = false
// this.background = new Mesh(geometry, material)
// this.background.layers.set(ObjectLayers.PROPS)
// this.background.frustumCulled = false
// this.background.renderOrder = 1
// }
// public transform(matrix: Matrix4) {
// this.geometry.applyMatrix4(matrix)
// this.geometry.computeBoundingBox()
// const center = this.geometry.boundingBox.getCenter(new Vector3())
// ;(this.material as SpeckleBasicMaterial).userData.billboardPos.value = new Vector3(
// center.x,
// center.y,
// center.z
// )
// ;(this.material as SpeckleBasicMaterial).needsUpdate = true
// }
// public setPosition(pos: Vector3) {
// // this.text.position.copy(pos)
// const mat = this.text.material
// ;(mat as SpeckleBasicMaterial).userData.billboardPos.value = pos
// ;(mat as SpeckleBasicMaterial).needsUpdate = true
// const backgroundPos = new Vector3().copy(pos)
// // backgroundPos.x += sizeBox.x * 0.5
// // backgroundPos.y += sizeBox.y * 0.5
// ;(this.background.material as SpeckleBasicMaterial).userData.billboardPos.value =
// backgroundPos
// ;(this.background.material as SpeckleBasicMaterial).needsUpdate = true
// this.text.anchorX = '50%'
// this.text.anchorY = '50%'
// this.text.sync()
// }
}
@@ -260,6 +260,7 @@ export class Pipeline {
ObjectLayers.STREAM_CONTENT_MESH,
ObjectLayers.STREAM_CONTENT_LINE,
ObjectLayers.STREAM_CONTENT_POINT,
ObjectLayers.STREAM_CONTENT_TEXT,
ObjectLayers.SHADOWCATCHER
])
this.stencilMaskPass.setLayers([ObjectLayers.STREAM_CONTENT_MESH])
@@ -76,6 +76,10 @@ export class NodeRenderView {
return this._renderData.geometry && this._renderData.geometry.attributes
}
public get hasMetadata() {
return this._renderData.geometry && this._renderData.geometry.metaData
}
public get speckleType() {
return this._renderData.speckleType
}
@@ -131,6 +135,7 @@ export class NodeRenderView {
public get validGeometry() {
return (
this._renderData.geometry.attributes &&
this._renderData.geometry.attributes.POSITION &&
this._renderData.geometry.attributes.POSITION.length > 0 &&
(this._geometryType === GeometryType.MESH
@@ -180,6 +185,8 @@ export class NodeRenderView {
return GeometryType.POINT
case SpeckleType.Pointcloud:
return GeometryType.POINT_CLOUD
case SpeckleType.Text:
return GeometryType.TEXT
default:
return GeometryType.LINE
@@ -220,7 +227,8 @@ export class NodeRenderView {
const mat =
this.renderData.renderMaterial &&
(this.geometryType === GeometryType.MESH ||
this.geometryType === GeometryType.POINT)
this.geometryType === GeometryType.POINT ||
this.geometryType === GeometryType.TEXT)
? this.renderMaterialToString()
: this.renderData.displayStyle &&
this.geometryType !== GeometryType.MESH &&
@@ -231,7 +239,11 @@ export class NodeRenderView {
if (this.renderData.geometry.attributes)
geometry = this.renderData.geometry.attributes.COLOR ? 'vertexColors' : ''
const s = this.geometryType.toString() + geometry + mat
const s =
this.geometryType.toString() +
geometry +
mat +
(this.geometryType === GeometryType.TEXT ? this._renderData.id : '')
return NodeRenderView.hashCode(s)
}
}
+27 -29
View File
@@ -29,20 +29,7 @@ export class RenderTree {
this.tree.walk((node: TreeNode): boolean => {
const rendeNode = this.buildRenderNode(node)
node.model.renderView = rendeNode ? new NodeRenderView(rendeNode) : null
if (node.model.renderView && node.model.renderView.hasGeometry) {
const transform = this.computeTransform(node)
if (rendeNode.geometry.bakeTransform) {
transform.multiply(rendeNode.geometry.bakeTransform)
}
Geometry.transformGeometryData(rendeNode.geometry, transform)
node.model.renderView.computeAABB()
this._treeBounds.union(node.model.renderView.aabb)
if (!GeometryConverter.keepGeometryData) {
GeometryConverter.disposeNodeGeometryData(node.model)
}
}
this.applyTransforms(node)
return true
})
}
@@ -52,19 +39,7 @@ export class RenderTree {
(node: TreeNode): boolean => {
const rendeNode = this.buildRenderNode(node)
node.model.renderView = rendeNode ? new NodeRenderView(rendeNode) : null
if (node.model.renderView && node.model.renderView.hasGeometry) {
const transform = this.computeTransform(node)
if (rendeNode.geometry.bakeTransform) {
transform.multiply(rendeNode.geometry.bakeTransform)
}
Geometry.transformGeometryData(rendeNode.geometry, transform)
node.model.renderView.computeAABB()
this._treeBounds.union(node.model.renderView.aabb)
if (!GeometryConverter.keepGeometryData) {
GeometryConverter.disposeNodeGeometryData(node.model)
}
}
this.applyTransforms(node)
return !this.cancel
},
this.root,
@@ -73,6 +48,29 @@ export class RenderTree {
return p
}
private applyTransforms(node: TreeNode) {
if (node.model.renderView) {
const transform = this.computeTransform(node)
if (node.model.renderView.hasGeometry) {
if (node.model.renderView.renderData.geometry.bakeTransform) {
transform.multiply(node.model.renderView.renderData.geometry.bakeTransform)
}
Geometry.transformGeometryData(
node.model.renderView.renderData.geometry,
transform
)
node.model.renderView.computeAABB()
this._treeBounds.union(node.model.renderView.aabb)
if (!GeometryConverter.keepGeometryData) {
GeometryConverter.disposeNodeGeometryData(node.model)
}
} else if (node.model.renderView.hasMetadata) {
node.model.renderView.renderData.geometry.bakeTransform.premultiply(transform)
}
}
}
private buildRenderNode(node: TreeNode): NodeRenderData {
let ret: NodeRenderData = null
const geometryData = GeometryConverter.convertNodeToGeometryData(node.model)
@@ -145,7 +143,7 @@ export class RenderTree {
.all((node: TreeNode): boolean => {
return (
node.model.renderView !== null &&
node.model.renderView.hasGeometry &&
(node.model.renderView.hasGeometry || node.model.renderView.hasMetadata) &&
types.includes(node.model.renderView.renderData.speckleType)
)
})
@@ -156,7 +154,7 @@ export class RenderTree {
return this.root.all((node: TreeNode): boolean => {
return (
node.model.renderView !== null &&
node.model.renderView.hasGeometry &&
(node.model.renderView.hasGeometry || node.model.renderView.hasMetadata) &&
types.includes(node.model.renderView.renderData.speckleType)
)
})
+47
View File
@@ -11666,6 +11666,7 @@ __metadata:
three: ^0.140.0
three-mesh-bvh: 0.5.17
tree-model: 1.0.7
troika-three-text: 0.47.2
typescript: ^4.5.4
languageName: unknown
linkType: soft
@@ -19256,6 +19257,15 @@ __metadata:
languageName: node
linkType: hard
"bidi-js@npm:^1.0.2":
version: 1.0.2
resolution: "bidi-js@npm:1.0.2"
dependencies:
require-from-string: ^2.0.2
checksum: 1e33008ed4b248b0350cfed5aebbc8717489bc0d3bcee9f5f99b778d82d997df621adefe6f22fffe005dc3bd8c08445b0b17af7c5d8d1a4a25f15f7702d30e68
languageName: node
linkType: hard
"big-integer@npm:^1.6.44":
version: 1.6.51
resolution: "big-integer@npm:1.6.51"
@@ -41590,6 +41600,36 @@ __metadata:
languageName: node
linkType: hard
"troika-three-text@npm:0.47.2":
version: 0.47.2
resolution: "troika-three-text@npm:0.47.2"
dependencies:
bidi-js: ^1.0.2
troika-three-utils: ^0.47.2
troika-worker-utils: ^0.47.2
webgl-sdf-generator: 1.1.1
peerDependencies:
three: ">=0.125.0"
checksum: ca93784f214d373496f371108e3e08d9ff29e98ee6355fccc9b4d0b06f9bba8dc80155f69967e5ec6e7f60ff25f900fcfafe26a94811e0b1e430f4662550287a
languageName: node
linkType: hard
"troika-three-utils@npm:^0.47.2":
version: 0.47.2
resolution: "troika-three-utils@npm:0.47.2"
peerDependencies:
three: ">=0.125.0"
checksum: e3a5d5edb2ed0d1889cd8a1d08da3e69ca7978fab86b107863d0dd9de752756a233c48fbae27410090e95d9c1fff4cabf34441338134a554e38c90a9c056e455
languageName: node
linkType: hard
"troika-worker-utils@npm:^0.47.2":
version: 0.47.2
resolution: "troika-worker-utils@npm:0.47.2"
checksum: 67cfd8ac77bc8dd8d9543108b9cac6c36549b626e0624298c7058845eff415c9c5e4480c7e095e39a29051b59d495b10befcc38a95e5644577132a9bdad51a3a
languageName: node
linkType: hard
"ts-dedent@npm:^2.0.0, ts-dedent@npm:^2.2.0":
version: 2.2.0
resolution: "ts-dedent@npm:2.2.0"
@@ -44126,6 +44166,13 @@ __metadata:
languageName: node
linkType: hard
"webgl-sdf-generator@npm:1.1.1":
version: 1.1.1
resolution: "webgl-sdf-generator@npm:1.1.1"
checksum: babf69e99ca22e8ff387bbe50a10519969ea8030d302d5ddf509ff15355e2981edf72edfcc1b29fed78fa73a79a2458c391b1ba7c9ada63ac5be665880ec5de0
languageName: node
linkType: hard
"webidl-conversions@npm:^3.0.0":
version: 3.0.1
resolution: "webidl-conversions@npm:3.0.1"