Просмотр исходного кода

Add basic support for LineSegments2/fat lines, support for importing fat lines in gltf, add track param for material clone, small Box3B fix for lines, add examples for lines.

master
Palash Bansal 1 год назад
Родитель
Сommit
f5a0f0b295
Аккаунт пользователя с таким Email не найден
35 измененных файлов: 664 добавлений и 60 удалений
  1. 36
    0
      examples/fat-lines/index.html
  2. 55
    0
      examples/fat-lines/script.ts
  3. 36
    0
      examples/gltf-mesh-lines/index.html
  4. 84
    0
      examples/gltf-mesh-lines/script.ts
  5. 2
    0
      examples/index.html
  6. 4
    4
      package-lock.json
  7. 3
    3
      package.json
  8. 7
    0
      src/assetmanager/IAssetImporter.ts
  9. 87
    7
      src/assetmanager/import/GLTFLoader2.ts
  10. 11
    0
      src/core/IMaterial.ts
  11. 1
    0
      src/core/geometry/BufferGeometry2.ts
  12. 20
    0
      src/core/geometry/LineGeometry2.ts
  13. 19
    0
      src/core/geometry/LineSegmentsGeometry2.ts
  14. 23
    0
      src/core/geometry/WireframeGeometry3.ts
  15. 5
    0
      src/core/index.ts
  16. 1
    1
      src/core/material/LegacyPhongMaterial.ts
  17. 45
    5
      src/core/material/LineMaterial2.ts
  18. 2
    2
      src/core/material/ObjectShaderMaterial.ts
  19. 1
    1
      src/core/material/PhysicalMaterial.ts
  20. 1
    1
      src/core/material/ShaderMaterial2.ts
  21. 1
    1
      src/core/material/UnlitLineMaterial.ts
  22. 1
    1
      src/core/material/UnlitMaterial.ts
  23. 15
    10
      src/core/material/iMaterialCommons.ts
  24. 48
    8
      src/core/object/IObjectUi.ts
  25. 1
    0
      src/core/object/Mesh2.ts
  26. 55
    0
      src/core/object/MeshLine.ts
  27. 55
    0
      src/core/object/MeshLineSegments.ts
  28. 8
    2
      src/three/Threejs.ts
  29. 0
    1
      src/three/controls/OrbitControls3.ts
  30. 24
    7
      src/three/math/Box3B.ts
  31. 4
    1
      src/three/widgets/BoxSelectionWidget.ts
  32. 2
    0
      src/three/widgets/CameraHelper2.ts
  33. 2
    0
      src/three/widgets/DirectionalLightHelper2.ts
  34. 2
    0
      src/three/widgets/PointLightHelper2.ts
  35. 3
    5
      src/three/widgets/SpotLightHelper2.ts

+ 36
- 0
examples/fat-lines/index.html Просмотреть файл

@@ -0,0 +1,36 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Fat Lines/Mesh Lines</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<!-- Import maps polyfill -->
<!-- Remove this when import maps will be widely supported -->
<script async src="https://unpkg.com/es-module-shims@1.6.3/dist/es-module-shims.js"></script>

<script type="importmap">
{
"imports": {
"threepipe": "./../../dist/index.mjs",
"@threepipe/plugin-tweakpane": "./../../plugins/tweakpane/dist/index.mjs"
}
}

</script>
<style id="example-style">
html, body, #canvas-container, #mcanvas {
width: 100%;
height: 100%;
margin: 0;
overflow: hidden;
}
</style>
<script type="module" src="../examples-utils/simple-code-preview.mjs"></script>
<script id="example-script" type="module" src="./script.js" data-scripts="./script.ts;./script.js"></script>
</head>
<body>
<div id="canvas-container">
<canvas id="mcanvas"></canvas>
</div>

</body>

+ 55
- 0
examples/fat-lines/script.ts Просмотреть файл

@@ -0,0 +1,55 @@
import {
_testFinish,
Color,
GLTFLoader2,
IObject3D,
LineMaterial2,
LoadingScreenPlugin,
PickingPlugin, PopmotionPlugin,
ThreeViewer,
} from 'threepipe'
import {TweakpaneUiPlugin} from '@threepipe/plugin-tweakpane'

async function init() {

const viewer = new ThreeViewer({
canvas: document.getElementById('mcanvas') as HTMLCanvasElement,
msaa: true,
plugins: [LoadingScreenPlugin, PickingPlugin],
dropzone: true,
})

viewer.scene.autoNearFarEnabled = false

GLTFLoader2.UseMeshLines = true

viewer.scene.backgroundColor = new Color(0x333333)

await viewer.load<IObject3D>('https://asset-samples.threepipe.org/demos/temple-lines.glb.zip', {
autoScale: true,
autoCenter: true,
})

const popmotion = viewer.addPluginSync(PopmotionPlugin)

const material = viewer.materialManager.findMaterialsByName('Stone')[0] as LineMaterial2

popmotion.animate({
from: 0,
to: 1,
duration: 1000,
repeat: Infinity,
repeatType: 'mirror',
onUpdate: (v) => {
material.linewidth = Math.sin(v * Math.PI) * 3.5 + 1
material.color.setHSL(v, 0.5, 0.7)
material.setDirty()
},
})

const ui = viewer.addPluginSync(new TweakpaneUiPlugin(true))
ui.setupPluginUi(PickingPlugin)

}

init().finally(_testFinish)

+ 36
- 0
examples/gltf-mesh-lines/index.html Просмотреть файл

@@ -0,0 +1,36 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>glTF Mesh(Fat) Lines Import</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<!-- Import maps polyfill -->
<!-- Remove this when import maps will be widely supported -->
<script async src="https://unpkg.com/es-module-shims@1.6.3/dist/es-module-shims.js"></script>

<script type="importmap">
{
"imports": {
"threepipe": "./../../dist/index.mjs",
"@threepipe/plugin-tweakpane": "./../../plugins/tweakpane/dist/index.mjs"
}
}

</script>
<style id="example-style">
html, body, #canvas-container, #mcanvas {
width: 100%;
height: 100%;
margin: 0;
overflow: hidden;
}
</style>
<script type="module" src="../examples-utils/simple-code-preview.mjs"></script>
<script id="example-script" type="module" src="./script.js" data-scripts="./script.ts;./script.js"></script>
</head>
<body>
<div id="canvas-container">
<canvas id="mcanvas"></canvas>
</div>

</body>

+ 84
- 0
examples/gltf-mesh-lines/script.ts Просмотреть файл

@@ -0,0 +1,84 @@
import {
_testFinish,
BufferGeometry,
BufferGeometry2,
Color,
GLTFLoader2,
IMaterial,
IObject3D,
LineSegmentsGeometry,
LineSegmentsGeometry2,
LoadingScreenPlugin,
Object3D,
ThreeViewer,
} from 'threepipe'
import {TweakpaneUiPlugin} from '@threepipe/plugin-tweakpane'

async function init() {

const viewer = new ThreeViewer({
canvas: document.getElementById('mcanvas') as HTMLCanvasElement,
msaa: true,
plugins: [LoadingScreenPlugin],
dropzone: true,
})

viewer.scene.autoNearFarEnabled = false

GLTFLoader2.UseMeshLines = true

viewer.scene.backgroundColor = new Color(0x333333)

// await viewer.setEnvironmentMap('https://threejs.org/examples/textures/equirectangular/venice_sunset_1k.hdr')
const obj1 = await viewer.load<IObject3D>('https://raw.githubusercontent.com/KhronosGroup/glTF-Sample-Assets/refs/heads/main/Models/MeshPrimitiveModes/glTF/MeshPrimitiveModes.gltf', {
autoScale: true,
autoCenter: true,
useMeshLines: true,
})

const obj2 = await viewer.load<IObject3D>('https://raw.githubusercontent.com/KhronosGroup/glTF-Sample-Assets/refs/heads/main/Models/MeshPrimitiveModes/glTF/MeshPrimitiveModes.gltf', {
autoScale: true,
autoCenter: true,
useMeshLines: false,
})

const ui = viewer.addPluginSync(new TweakpaneUiPlugin(true))

const mats: IMaterial[] = []
const o1: IObject3D[] = []
const o2: IObject3D[] = []
const p1 = viewer.scene.addObject(new Object3D()).translateY(0.75)
const p2 = viewer.scene.addObject(new Object3D()).translateY(-0.75)
p1.scale.setScalar(0.6)
p2.scale.setScalar(0.6)
obj1?.traverse(o=>{
if (o.materials?.[0].isLineMaterial) {
mats.push(o.materials[0])
o1.push(o)
}
})
obj2?.traverse(o=>{
if (o.materials?.[0].isUnlitLineMaterial) {
mats.push(o.materials[0])
o2.push(o)
}
})
o1.forEach(o=>p1.add(o))
o2.forEach(o=>p2.add(o))
obj1?.dispose(true)
obj2?.dispose(true)

mats.map(m=>{
if (!m.appliedMeshes.size) return
m.linewidth = 10
ui.appendChild(m.uiConfig)
})

console.log(LineSegmentsGeometry)
console.log(LineSegmentsGeometry2)
console.log(BufferGeometry)
console.log(BufferGeometry2)

}

init().finally(_testFinish)

+ 2
- 0
examples/index.html Просмотреть файл

@@ -440,6 +440,7 @@
<li><a href="./splat-load/">SPLAT Load<br/>(Gaussian Splatting) </a></li>
<li><a href="./extra-importer-plugins/">Extra (3ds, 3mf, collada, amf, bvh, vox, gcode, mdd, pcd, tilt, wrl, ldraw, vtk, xyz) Load </a></li>
<li><a href="./gltf-meshopt-compression/">glTF MeshOpt Decode (Compression Extension) </a></li>
<li><a href="./gltf-mesh-lines/">glTF Mesh Lines <br/>(Fat Lines) </a></li>
<li><a href="./b3dm-load/">B3DM Load (3D Tile) </a></li>
<li><a href="./i3dm-load/">I3DM Load (3D Tile) </a></li>
<li><a href="./pnts-load/">PNTS Load (3D Points) </a></li>
@@ -504,6 +505,7 @@
<li><a href="./obj-to-glb/">Convert OBJ to GLB </a></li>
<li><a href="./3dm-to-glb/">Convert 3DM to GLB </a></li>
<li><a href="./hdr-to-exr/">Convert HDR to EXR </a></li>
<li><a href="./fat-lines/">Fat Lines <br/>(Mesh Lines) </a></li>
</ul>
<h2 class="category">Experiments</h2>
<ul>

+ 4
- 4
package-lock.json Просмотреть файл

@@ -9,7 +9,7 @@
"version": "0.0.41",
"license": "Apache-2.0",
"dependencies": {
"@types/three": "https://github.com/repalash/three-ts-types/releases/download/v0.157.1005/package.tgz",
"@types/three": "https://github.com/repalash/three-ts-types/releases/download/v0.157.1006/package.tgz",
"@types/webxr": "^0.5.1",
"@types/wicg-file-system-access": "^2020.9.5",
"popmotion": "^11.0.5",
@@ -2402,9 +2402,9 @@
"license": "MIT"
},
"node_modules/@types/three": {
"version": "0.157.1005",
"resolved": "https://github.com/repalash/three-ts-types/releases/download/v0.157.1005/package.tgz",
"integrity": "sha512-Qb6XlwUyDAoNUi9IxS5lYmkShRsVFCAsG4KAXTPlmi6G2V/GIzmvXZ5Ut2SV1L+7nCEFwtvENkzP3/MVQ9cWUQ==",
"version": "0.157.1006",
"resolved": "https://github.com/repalash/three-ts-types/releases/download/v0.157.1006/package.tgz",
"integrity": "sha512-WiV0kRvPyPK3KEOGshnPDbgJzfa/YozkFSSfVu32WgFYp9hiSSVQK8wROq5We/DTWs8BmnyWuh7lzbz/4DC3jQ==",
"dependencies": {
"fflate": "~0.6.10",
"meshoptimizer": "~0.18.1"

+ 3
- 3
package.json Просмотреть файл

@@ -121,7 +121,7 @@
"vitepress-plugin-nprogress": "^0.0.4"
},
"dependencies": {
"@types/three": "https://github.com/repalash/three-ts-types/releases/download/v0.157.1005/package.tgz",
"@types/three": "https://github.com/repalash/three-ts-types/releases/download/v0.157.1006/package.tgz",
"@types/webxr": "^0.5.1",
"@types/wicg-file-system-access": "^2020.9.5",
"popmotion": "^11.0.5",
@@ -143,8 +143,8 @@
"ts-browser-helpers": "^0.16.2",
"three": "https://github.com/repalash/three.js-modded/releases/download/v0.157.1007/package.tgz",
"three-f": "https://github.com/repalash/three.js-modded/archive/refs/tags/v0.157.1007.tar.gz",
"@types/three": "https://github.com/repalash/three-ts-types/releases/download/v0.157.1005/package.tgz",
"@types/three-f": "https://github.com/repalash/three-ts-types/archive/refs/tags/v0.157.1005.tar.gz",
"@types/three": "https://github.com/repalash/three-ts-types/releases/download/v0.157.1006/package.tgz",
"@types/three-f": "https://github.com/repalash/three-ts-types/archive/refs/tags/v0.157.1006.tar.gz",
"@types/three-pkg": "https://gitpkg.now.sh/repalash/three-ts-types/types/three?modded_three"
},
"local_dependencies": {

+ 7
- 0
src/assetmanager/IAssetImporter.ts Просмотреть файл

@@ -163,6 +163,13 @@ export interface ImportAssetOptions extends ProcessRawOptions, LoadFileOptions {
* Pass a custom file to use for the import. This will be used in the importer, and nothing will be fetched from the path
*/
importedFile?: IFile,

/**
* Use {@link MeshLine}(an extension of three.js `Line2`) instead of default `Line` for lines. This allows changing line width(fat lines) and other properties.
*
* Note - Only for gltf, glb files or files loaded with {@link GLTFLoader2}. If this flag is not passed, the default value is the value of the static property `GLTFLoader2.UseMeshLines`.
*/
useMeshLines?: boolean,
}

// export type IAssetImporterEventTypes = 'onLoad' | 'onProgress' | 'onStop' | 'onError' | 'onStart' | 'loaderCreate' | 'importFile' | 'importFiles' | 'processRaw' | 'processRawStart'

+ 87
- 7
src/assetmanager/import/GLTFLoader2.ts Просмотреть файл

@@ -1,6 +1,6 @@
import type {GLTF, GLTFLoaderPlugin, GLTFParser} from 'three/examples/jsm/loaders/GLTFLoader.js'
import {GLTFLoader} from 'three/examples/jsm/loaders/GLTFLoader.js'
import {LoadingManager, Object3D, OrthographicCamera, Texture} from 'three'
import {Line, LineLoop, LineSegments, LoadingManager, Object3D, OrthographicCamera, Texture} from 'three'
import {AnyOptions, safeSetProperty} from 'ts-browser-helpers'
import {ThreeViewer} from '../../viewer'
import {generateUUID} from '../../three'
@@ -20,6 +20,11 @@ import {ILoader} from '../IImporter'
import {ThreeSerialization} from '../../utils'
import {
DirectionalLight2,
LineGeometry2,
LineMaterial2,
LineSegmentsGeometry2,
MeshLine,
MeshLineSegments,
PerspectiveCamera0,
PhysicalMaterial,
PointLight2,
@@ -28,12 +33,15 @@ import {
UnlitMaterial,
} from '../../core'
import {AssetImporter} from '../AssetImporter'
import {ImportAddOptions} from '../AssetManager'

// todo move somewhere
const supportedEmbeddedFiles = ['hdr', 'exr', 'webp', 'avif', 'ktx', 'hdrpng', 'svg', 'cube'] // ktx2, drc handled separately
const supportedEmbeddedFiles = ['hdr', 'exr', 'webp', 'avif', 'ktx', 'hdrpng', 'svg', 'cube', 'ico', 'bmp', 'gif', 'tiff'] // ktx2, drc handled separately

export class GLTFLoader2 extends GLTFLoader implements ILoader<GLTF, Object3D|undefined> {
isGLTFLoader2 = true
importOptions?: ImportAddOptions

constructor(manager: LoadingManager) {
super(manager)
this.preparsers.push(glbEncryptionPreparser)
@@ -59,6 +67,15 @@ export class GLTFLoader2 extends GLTFLoader implements ILoader<GLTF, Object3D|un
GLTFMaterialsAlphaMapExtension.Import,
]

/**
* Use {@link MeshLine}(an extension of three.js `Line2`) instead of default `Line` for lines. This allows changing line width and other properties.
*
* This is the default value for the flag, it can also be controlled by using the `useMeshLines` in the import options.
*
* Note - Lines may not export correctly when loaded with this.
*/
static UseMeshLines = false

/**
* Preparsers are run on the arraybuffer/string before parsing to read the glb/gltf data
*/
@@ -80,8 +97,12 @@ export class GLTFLoader2 extends GLTFLoader implements ILoader<GLTF, Object3D|un
// todo save the path of invalid textures, check if they can be found in the loaded libs, and ask the user in UI to remap it to something else manually
if (!Texture.DEFAULT_IMAGE) Texture.DEFAULT_IMAGE = AssetImporter.WHITE_IMAGE_DATA

const useMeshLines = this.importOptions?.useMeshLines ?? GLTFLoader2.UseMeshLines
GLTFLoader.ObjectConstructors.LineBasicMaterial = useMeshLines ? LineMaterial2 as any : UnlitLineMaterial as any

return res ? super.parse(res, path, (ret)=>{
Texture.DEFAULT_IMAGE = val
GLTFLoader.ObjectConstructors.LineBasicMaterial = useMeshLines ? LineMaterial2 as any : UnlitLineMaterial as any
onLoad && onLoad(ret)
}, onError) : onError && onError(new ErrorEvent('no data'))
})
@@ -101,12 +122,25 @@ export class GLTFLoader2 extends GLTFLoader implements ILoader<GLTF, Object3D|un
const scene: RootSceneImportResult|undefined = res ? res.scene || !!res.scenes && res.scenes.length > 0 && res.scenes[0] : undefined as any
if (!scene) return undefined
if (res.animations.length > 0) scene.animations = res.animations
scene.traverse((node: Object3D) => {
if (node.userData.gltfUUID) { // saved in GLTFExporter2
safeSetProperty(node, 'uuid', node.userData.gltfUUID, true, true)
delete node.userData.gltfUUID // have issue with cloning if we don't dispose.

const useMeshLines = this.importOptions?.useMeshLines ?? GLTFLoader2.UseMeshLines
// todo: move out and put the chosen setting in userData.
if (useMeshLines) {
const lines: Line[] = []
scene.traverse((node: Object3D) => {
if (node.userData.gltfUUID) { // saved in GLTFExporter2
safeSetProperty(node, 'uuid', node.userData.gltfUUID, true, true)
delete node.userData.gltfUUID // have issue with cloning if we don't dispose.
}
if ((node as Line).isLine) lines.push(node as Line)
})

// convert lines to mesh/fat lines
for (const line of lines) {
convertToFatLine(line)
}
})
}

// todo: replacing lights and camera, todo: remove and change constructors in GLTFLoader.js
if (!scene.userData) scene.userData = {}
if (res.userData) scene.userData.gltfExtras = res.userData // todo: put back in gltf in GLTFExporter2
@@ -192,3 +226,49 @@ export interface GLTFPreparser{
process(data: string | ArrayBuffer, path: string): Promise<string | ArrayBuffer>
[key: string]: any
}

// sample test model - https://raw.githubusercontent.com/KhronosGroup/glTF-Sample-Assets/refs/heads/main/Models/MeshPrimitiveModes/glTF/MeshPrimitiveModes.gltf
// todo maybe do the same as others inside GLTFLoader.js
function convertToFatLine(line: Line) {
const parent = line.parent
if (!parent) {
console.warn('GLTFLoader2: Line has no parent', line)
return
}
if (line.geometry.index) line.geometry = line.geometry.toNonIndexed() // Line2 requires non indexed
const line2 =
(line as LineSegments).isLineSegments ?
new MeshLineSegments(new LineSegmentsGeometry2(), line.material as LineMaterial2) :
new MeshLine(new LineGeometry2(), line.material as LineMaterial2)
let positions = line.geometry.attributes.position.array as Float32Array
if ((line as LineLoop).isLineLoop) {
// add first pos as last.
const pos = new Float32Array(positions.length + 3)
pos.set(positions)
pos.set(positions.subarray(0, 3), positions.length)
positions = pos
}
line2.geometry.setPositions(positions)
line2.computeLineDistances()
const index = parent.children.indexOf(line)
parent.add(line2)
const {geometry, material} = line2
const ud = line.userData
line.userData = {}
line2.copy(line as any, false)
line2.geometry = geometry
line2.material = material
;[...line.children].map(c => {
line2.add(c)
})
line2.userData = {...line2.userData, ...ud}
material.userData.renderToGBuffer = false // this is set in LineMaterial2
material.userData.renderToDepth = false
line.removeFromParent()
// put at the same index
const index2 = parent.children.indexOf(line2)
if (index2 >= 0 && index2 !== index) {
parent.children.splice(index2, 1)
parent.children.splice(index, 0, line2)
}
}

+ 11
- 0
src/core/IMaterial.ts Просмотреть файл

@@ -249,6 +249,14 @@ export interface IMaterial<TE extends IMaterialEventMap = IMaterialEventMap> ext
*/
dispose(force?: boolean): void

/**
* Clones the Material.
* This is a shallow clone, so the properties are copied by reference.
*
* @param track - if true, the clone id and count will be tracked in the userData and a suffix will be appended to the name. default - false
*/
clone(track?: boolean): this;

// optional from subclasses, added here for autocomplete
flatShading?: boolean
map?: ITexture | null
@@ -276,8 +284,11 @@ export interface IMaterial<TE extends IMaterialEventMap = IMaterialEventMap> ext

isRawShaderMaterial?: boolean
isPhysicalMaterial?: boolean
isLineMaterial?: boolean
isUnlitMaterial?: boolean
isGBufferMaterial?: boolean
isLineMaterial2?: boolean
isUnlitLineMaterial?: boolean

// [key: string]: any
}

+ 1
- 0
src/core/geometry/BufferGeometry2.ts Просмотреть файл

@@ -17,3 +17,4 @@ export class BufferGeometry2<Attributes extends NormalOrGLBufferAttributes = Nor
}

}


+ 20
- 0
src/core/geometry/LineGeometry2.ts Просмотреть файл

@@ -0,0 +1,20 @@
import {NormalBufferAttributes, NormalOrGLBufferAttributes} from 'three'
import type {IGeometry, IGeometryEventMap, IGeometryUserData} from '../IGeometry'
import {LineGeometry} from 'three/examples/jsm/lines/LineGeometry'
import {iGeometryCommons} from './iGeometryCommons'
import type {IObject3D} from '../IObject'

export class LineGeometry2<Attributes extends NormalOrGLBufferAttributes = NormalBufferAttributes, TE extends IGeometryEventMap = IGeometryEventMap> extends LineGeometry<Attributes, TE> implements IGeometry<Attributes, TE> {
assetType: 'geometry' // dont set the value here since its checked in upgradeGeometry
center2 = iGeometryCommons.center2
setDirty = iGeometryCommons.setDirty
refreshUi = iGeometryCommons.refreshUi
appliedMeshes = new Set<IObject3D>()
declare userData: IGeometryUserData

constructor() {
super()
iGeometryCommons.upgradeGeometry.call(this)
}

}

+ 19
- 0
src/core/geometry/LineSegmentsGeometry2.ts Просмотреть файл

@@ -0,0 +1,19 @@
import {NormalBufferAttributes, NormalOrGLBufferAttributes} from 'three'
import type {IGeometry, IGeometryEventMap, IGeometryUserData} from '../IGeometry'
import {LineSegmentsGeometry} from 'three/examples/jsm/lines/LineSegmentsGeometry'
import {iGeometryCommons} from './iGeometryCommons'
import type {IObject3D} from '../IObject'

export class LineSegmentsGeometry2<Attributes extends NormalOrGLBufferAttributes = NormalBufferAttributes, TE extends IGeometryEventMap = IGeometryEventMap> extends LineSegmentsGeometry<Attributes, TE> implements IGeometry<Attributes, TE> {
assetType: 'geometry' // dont set the value here since its checked in upgradeGeometry
center2 = iGeometryCommons.center2
setDirty = iGeometryCommons.setDirty
refreshUi = iGeometryCommons.refreshUi
appliedMeshes = new Set<IObject3D>()
declare userData: IGeometryUserData

constructor() {
super()
iGeometryCommons.upgradeGeometry.call(this)
}
}

+ 23
- 0
src/core/geometry/WireframeGeometry3.ts Просмотреть файл

@@ -0,0 +1,23 @@
import {
BufferGeometry,
NormalBufferAttributes,
NormalOrGLBufferAttributes,
} from 'three'
import type {IGeometry, IGeometryEventMap, IGeometryUserData} from '../IGeometry'
import {WireframeGeometry2} from 'three/examples/jsm/lines/WireframeGeometry2'
import {iGeometryCommons} from './iGeometryCommons'
import type {IObject3D} from '../IObject'

export class WireframeGeometry3<Attributes extends NormalOrGLBufferAttributes = NormalBufferAttributes, TE extends IGeometryEventMap = IGeometryEventMap> extends WireframeGeometry2<Attributes, TE> implements IGeometry<Attributes, TE> {
assetType: 'geometry' // dont set the value here since its checked in upgradeGeometry
center2 = iGeometryCommons.center2
setDirty = iGeometryCommons.setDirty
refreshUi = iGeometryCommons.refreshUi
appliedMeshes = new Set<IObject3D>()
declare userData: IGeometryUserData

constructor(geometry: BufferGeometry) {
super(geometry)
iGeometryCommons.upgradeGeometry.call(this)
}
}

+ 5
- 0
src/core/index.ts Просмотреть файл

@@ -10,7 +10,12 @@ export {UnlitLineMaterial, LineBasicMaterial2} from './material/UnlitLineMateria
export {LineMaterial2} from './material/LineMaterial2'
export {LegacyPhongMaterial} from './material/LegacyPhongMaterial'
export {Mesh2} from './object/Mesh2'
export {MeshLine} from './object/MeshLine'
export {MeshLineSegments} from './object/MeshLineSegments'
export {BufferGeometry2} from './geometry/BufferGeometry2'
export {LineGeometry2} from './geometry/LineGeometry2'
export {LineSegmentsGeometry2} from './geometry/LineSegmentsGeometry2'
export {WireframeGeometry3} from './geometry/WireframeGeometry3'
export {AmbientLight2} from './light/AmbientLight2'
export {DirectionalLight2} from './light/DirectionalLight2'
export {HemisphereLight2} from './light/HemisphereLight2'

+ 1
- 1
src/core/material/LegacyPhongMaterial.ts Просмотреть файл

@@ -41,7 +41,7 @@ export class LegacyPhongMaterial<TE extends IMaterialEventMap = IMaterialEventMa
readonly appliedMeshes: Set<IObject3D> = new Set()
readonly setDirty = iMaterialCommons.setDirty
dispose(): this {return iMaterialCommons.dispose(super.dispose).call(this)}
clone(): this {return iMaterialCommons.clone(super.clone).call(this)}
clone(track = false): this {return iMaterialCommons.clone(super.clone).call(this, track)}
dispatchEvent<T extends Extract<keyof (TE&IMaterialEventMap), string>>(event: BaseEvent<T> & (TE&IMaterialEventMap)[T]): void {iMaterialCommons.dispatchEvent(super.dispatchEvent).call(this, event)}
generator?: IMaterialGenerator


+ 45
- 5
src/core/material/LineMaterial2.ts Просмотреть файл

@@ -1,7 +1,26 @@
import {generateUiConfig, uiColor, uiInput, uiNumber, UiObjectConfig, uiToggle, uiVector} from 'uiconfig.js'
import {BaseEvent, Color, IUniform, Material, Shader, Vector2, WebGLRenderer} from 'three'
import {
BaseEvent,
BufferGeometry,
Camera,
Color,
IUniform,
Material,
Object3D,
Scene,
Shader,
Vector2,
WebGLRenderer,
} from 'three'
import {SerializationMetaType, shaderReplaceString, ThreeSerialization} from '../../utils'
import {IMaterial, IMaterialEventMap, IMaterialGenerator, IMaterialParameters, IMaterialTemplate} from '../IMaterial'
import {
IMaterial,
IMaterialEventMap,
IMaterialGenerator,
IMaterialParameters,
IMaterialTemplate,
IMaterialUserData,
} from '../IMaterial'
import {MaterialExtension} from '../../materials'
import {iMaterialCommons, threeMaterialPropList} from './iMaterialCommons'
import {IObject3D} from '../IObject'
@@ -19,12 +38,14 @@ export class LineMaterial2<TE extends IMaterialEventMap = IMaterialEventMap> ext
public static readonly TYPE = 'LineMaterial2' // not using .type because it is used by three.js
assetType = 'material' as const

declare userData: IMaterialUserData

public readonly isLineMaterial2 = true

readonly appliedMeshes: Set<IObject3D> = new Set()
readonly setDirty = iMaterialCommons.setDirty
dispose(): this {return iMaterialCommons.dispose(super.dispose).call(this)}
clone(): this {return iMaterialCommons.clone(super.clone).call(this)}
clone(track = false): this {return iMaterialCommons.clone(super.clone).call(this, track)}
dispatchEvent<T extends Extract<keyof (TE&IMaterialEventMap), string>>(event: BaseEvent<T> & (TE&IMaterialEventMap)[T]): void {iMaterialCommons.dispatchEvent(super.dispatchEvent).call(this, event)}

generator?: IMaterialGenerator
@@ -36,6 +57,8 @@ export class LineMaterial2<TE extends IMaterialEventMap = IMaterialEventMap> ext
if (customMaterialExtensions) this.registerMaterialExtensions(customMaterialExtensions)
iMaterialCommons.upgradeMaterial.call(this)
this.setValues(parameters)
// this.userData.renderToGBuffer = false
// this.userData.renderToDepth = false
}

// region Material Extension
@@ -65,7 +88,18 @@ export class LineMaterial2<TE extends IMaterialEventMap = IMaterialEventMap> ext
super.onBeforeCompile(shader, renderer)
}

onAfterRender = iMaterialCommons.onAfterRenderOverride(super.onAfterRender)
autoUpdateResolution = true

onBeforeRender(renderer: WebGLRenderer, scene: Scene, camera: Camera, geometry: BufferGeometry, object: Object3D): void {
if (this.autoUpdateResolution) renderer.getSize(this.resolution)
super.onBeforeRender(renderer, scene, camera, geometry, object)
iMaterialCommons.onBeforeRender.call(this, renderer, scene, camera, geometry, object)
}

onAfterRender(renderer: WebGLRenderer, scene: Scene, camera: Camera, geometry: BufferGeometry, object: Object3D): void {
super.onAfterRender(renderer, scene, camera, geometry, object)
iMaterialCommons.onAfterRender.call(this, renderer, scene, camera, geometry, object)
}

// endregion

@@ -94,6 +128,12 @@ export class LineMaterial2<TE extends IMaterialEventMap = IMaterialEventMap> ext
expanded: true,
onChange: (ev)=>{
if (!ev.config || ev.config.onChange) return
// this.uniformsNeedUpdate = true
// this.appliedMeshes.forEach(m=>{
// if ((m.isLineSegments2 || m.isLineSegments) && m.computeLineDistances) {
// m.computeLineDistances()
// }
// })
// todo set needsUpdate true only for properties that require it like maps.
this.setDirty({uiChangeEvent: ev, needsUpdate: !!ev.last, refreshUi: !!ev.last})
},
@@ -119,7 +159,7 @@ export class LineMaterial2<TE extends IMaterialEventMap = IMaterialEventMap> ext
*/
setValues(parameters: Material|(LineMaterialParameters&{type?:string}), allowInvalidType = true, clearCurrentUserData: boolean|undefined = undefined): this {
if (!parameters) return this
if (parameters.type && !allowInvalidType && !['LineMaterial', this.constructor.TYPE].includes(parameters.type)) {
if (parameters.type && !allowInvalidType && !['LineMaterial', this.constructor.TYPE].includes(parameters.type) && !(parameters as LineMaterial2).isLineMaterial && !(parameters as LineMaterial2).isLineMaterial2) {
console.error('Material type is not supported:', parameters.type)
return this
}

+ 2
- 2
src/core/material/ObjectShaderMaterial.ts Просмотреть файл

@@ -33,7 +33,7 @@ export class ObjectShaderMaterial<TE extends IMaterialEventMap = IMaterialEventM
readonly appliedMeshes: Set<IObject3D> = new Set()
readonly setDirty = iMaterialCommons.setDirty
dispose(): this {return iMaterialCommons.dispose(super.dispose).call(this)}
clone(): this {return iMaterialCommons.clone(super.clone).call(this)}
clone(track = false): this {return iMaterialCommons.clone(super.clone).call(this, track)}
dispatchEvent<T extends Extract<keyof (TE&IMaterialEventMap), string>>(event: BaseEvent<T> & (TE&IMaterialEventMap)[T]): void {iMaterialCommons.dispatchEvent(super.dispatchEvent).call(this, event)}

generator?: IMaterialGenerator
@@ -233,4 +233,4 @@ export class ObjectShaderMaterial<TE extends IMaterialEventMap = IMaterialEventM
}
}

// todo gltf material extension
// todo gltf material extension

+ 1
- 1
src/core/material/PhysicalMaterial.ts Просмотреть файл

@@ -48,7 +48,7 @@ export class PhysicalMaterial<TE extends IMaterialEventMap = IMaterialEventMap>
readonly appliedMeshes: Set<IObject3D> = new Set()
readonly setDirty = iMaterialCommons.setDirty
dispose(): this {return iMaterialCommons.dispose(super.dispose).call(this)}
clone(): this {return iMaterialCommons.clone(super.clone).call(this)}
clone(track = false): this {return iMaterialCommons.clone(super.clone).call(this, track)}
dispatchEvent<T extends Extract<keyof (TE&IMaterialEventMap), string>>(event: BaseEvent<T> & (TE&IMaterialEventMap)[T]): void {iMaterialCommons.dispatchEvent(super.dispatchEvent).call(this, event)}

generator?: IMaterialGenerator

+ 1
- 1
src/core/material/ShaderMaterial2.ts Просмотреть файл

@@ -47,7 +47,7 @@ export class ShaderMaterial2<TE extends IMaterialEventMap = IMaterialEventMap> e
readonly appliedMeshes: Set<any> = new Set()
readonly setDirty = iMaterialCommons.setDirty
dispose(): this {return iMaterialCommons.dispose(super.dispose).call(this)}
clone(): this {return iMaterialCommons.clone(super.clone).call(this)}
clone(track = false): this {return iMaterialCommons.clone(super.clone).call(this, track)}
dispatchEvent<T extends Extract<keyof (TE&IMaterialEventMap), string>>(event: BaseEvent<T> & (TE&IMaterialEventMap)[T]): void {iMaterialCommons.dispatchEvent(super.dispatchEvent).call(this, event)}

readonly isRawShaderMaterial: boolean

+ 1
- 1
src/core/material/UnlitLineMaterial.ts Просмотреть файл

@@ -43,7 +43,7 @@ export class UnlitLineMaterial<TE extends IMaterialEventMap = IMaterialEventMap>
readonly appliedMeshes: Set<IObject3D> = new Set()
readonly setDirty = iMaterialCommons.setDirty
dispose(): this {return iMaterialCommons.dispose(super.dispose).call(this)}
clone(): this {return iMaterialCommons.clone(super.clone).call(this)}
clone(track = false): this {return iMaterialCommons.clone(super.clone).call(this, track)}
dispatchEvent<T extends Extract<keyof (TE&IMaterialEventMap), string>>(event: BaseEvent<T> & (TE&IMaterialEventMap)[T]): void {iMaterialCommons.dispatchEvent(super.dispatchEvent).call(this, event)}

generator?: IMaterialGenerator

+ 1
- 1
src/core/material/UnlitMaterial.ts Просмотреть файл

@@ -44,7 +44,7 @@ export class UnlitMaterial<TE extends IMaterialEventMap = IMaterialEventMap> ext
readonly appliedMeshes: Set<IObject3D> = new Set()
readonly setDirty = iMaterialCommons.setDirty
dispose(): this {return iMaterialCommons.dispose(super.dispose).call(this)}
clone(): this {return iMaterialCommons.clone(super.clone).call(this)}
clone(track = false): this {return iMaterialCommons.clone(super.clone).call(this, track)}
dispatchEvent<T extends Extract<keyof (TE&IMaterialEventMap), string>>(event: BaseEvent<T> & (TE&IMaterialEventMap)[T]): void {iMaterialCommons.dispatchEvent(super.dispatchEvent).call(this, event)}

generator?: IMaterialGenerator

+ 15
- 10
src/core/material/iMaterialCommons.ts Просмотреть файл

@@ -113,20 +113,25 @@ export const iMaterialCommons = {
superDispose.call(this)
},
clone: (superClone: Material['clone']): IMaterial['clone'] =>
function(this: IMaterial): IMaterial {
if (!this.userData.cloneId) {
this.userData.cloneId = '0'
}
if (!this.userData.cloneCount) {
this.userData.cloneCount = 0
function(this: IMaterial, track = false): IMaterial {
if (track) {
if (!this.userData.cloneId) {
this.userData.cloneId = '0'
}
if (!this.userData.cloneCount) {
this.userData.cloneCount = 0
}
this.userData.cloneCount += 1
}
this.userData.cloneCount += 1

const material: IMaterial = this.generator?.({})?.setValues(this, false) ?? superClone.call(this)

material.userData.cloneId = material.userData.cloneId + '_' + this.userData.cloneCount
material.userData.cloneCount = 0
material.name = material.name + '_' + material.userData.cloneId
if (track) {

material.userData.cloneId = material.userData.cloneId + '_' + this.userData.cloneCount
material.userData.cloneCount = 0
material.name = (material.name || 'mat') + '_' + material.userData.cloneId
}

return material
},

+ 48
- 8
src/core/object/IObjectUi.ts Просмотреть файл

@@ -5,11 +5,20 @@ import {Vector3} from 'three'
import {ThreeViewer} from '../../viewer'
import {UnlitMaterial} from '../material/UnlitMaterial'
import {PhysicalMaterial} from '../material/PhysicalMaterial'
import {LineMaterial2} from '../material/LineMaterial2'
import {UnlitLineMaterial} from '../material/UnlitLineMaterial'
import {IMaterial} from '../IMaterial'

// todo move somewhere?
const defaultMaterial = new UnlitMaterial()
defaultMaterial.name = 'Default Unlit Material'
defaultMaterial.uiConfig = undefined as any
const defaultUnlitLineMaterial = new UnlitLineMaterial()
defaultUnlitLineMaterial.name = 'Default Unlit Line Material'
defaultUnlitLineMaterial.uiConfig = undefined as any
const defaultLineMaterial = new LineMaterial2()
defaultLineMaterial.name = 'Default Line Material'
defaultLineMaterial.uiConfig = undefined as any

export function makeICameraCommonUiConfig(this: ICamera, config: UiObjectConfig): UiObjectConfig[] {
return [
@@ -67,6 +76,9 @@ export function makeIObject3DUiConfig(this: IObject3D, isMesh?:boolean): UiObjec
type: 'checkbox',
label: 'Visible',
property: [this, 'visible'],
onChange: (e)=>{
this.setDirty?.({uiChangeEvent: e, refreshScene: true, refreshUi: true, change: 'visible'})
},
},
{
type: 'button',
@@ -90,21 +102,27 @@ export function makeIObject3DUiConfig(this: IObject3D, isMesh?:boolean): UiObjec
type: 'input',
label: 'Name',
property: [this, 'name'],
onChange: (e: any)=>{
if (e.last) this.setDirty?.({refreshScene: true, frameFade: false, refreshUi: true})
onChange: (e)=>{
if (e.last) this.setDirty?.({uiChangeEvent: e, refreshScene: true, frameFade: false, refreshUi: true})
},
},
{
type: 'checkbox',
label: 'Casts Shadow',
hidden: () => !(this as any).isMesh,
hidden: () => !this.isMesh,
property: [this, 'castShadow'],
onChange: (e)=>{
this.setDirty?.({uiChangeEvent: e, refreshScene: true, refreshUi: true, change: 'castShadow'})
},
},
{
type: 'checkbox',
label: 'Receive Shadow',
hidden: () => !(this as any).isMesh,
hidden: () => !this.isMesh,
property: [this, 'receiveShadow'],
onChange: (e)=>{
this.setDirty?.({uiChangeEvent: e, refreshScene: true, refreshUi: true, change: 'receiveShadow'})
},
},
{
type: 'checkbox',
@@ -235,17 +253,39 @@ export function makeIObject3DUiConfig(this: IObject3D, isMesh?:boolean): UiObjec
{
label: 'Remove Material(s)',
type: 'button',
hidden: ()=>!this.materials?.length || this.materials.length === 1 && this.materials[0] === defaultMaterial,
hidden: ()=>!this.materials?.length || this.materials.length === 1 && (<IMaterial[]>[defaultMaterial, defaultLineMaterial, defaultUnlitLineMaterial]).includes(this.materials[0]),
value: ()=>{
const mat = this.materials
this.material = this.isLineSegments2 ?
[defaultLineMaterial] : this.isLineSegments ?
[defaultUnlitLineMaterial] : [defaultMaterial]
return ()=> this.material = mat
},
},
{
label: 'New Line Material',
type: 'button',
hidden: ()=>!this.isLineSegments2 || !(!this.materials?.length || this.materials.length === 1 && this.materials[0] === defaultLineMaterial),
value: ()=>{
const mat = this.materials
this.material = [new LineMaterial2()]
return ()=> this.material = mat
},
},
{
label: 'New Unlit Line Material',
type: 'button',
hidden: ()=>!this.isLineSegments || !(!this.materials?.length || this.materials.length === 1 && this.materials[0] === defaultUnlitLineMaterial),
value: ()=>{
const mat = this.materials
this.material = [defaultMaterial]
this.material = [new UnlitLineMaterial()]
return ()=> this.material = mat
},
},
{
label: 'New Physical Material',
type: 'button',
hidden: ()=>!(!this.materials?.length || this.materials.length === 1 && this.materials[0] === defaultMaterial),
hidden: ()=>!(!this.materials?.length || this.materials.length === 1 && this.materials[0] === defaultMaterial) || !!this.isLineSegments2 || !!this.isLineSegments,
value: ()=>{
const mat = this.materials
this.material = [new PhysicalMaterial()]
@@ -255,7 +295,7 @@ export function makeIObject3DUiConfig(this: IObject3D, isMesh?:boolean): UiObjec
{
label: 'New Unlit Material',
type: 'button',
hidden: ()=>!(!this.materials?.length || this.materials.length === 1 && this.materials[0] === defaultMaterial),
hidden: ()=>!(!this.materials?.length || this.materials.length === 1 && this.materials[0] === defaultMaterial) || !!this.isLineSegments2 || !!this.isLineSegments,
value: ()=>{
const mat = this.materials
this.material = [new UnlitMaterial()]

+ 1
- 0
src/core/object/Mesh2.ts Просмотреть файл

@@ -50,3 +50,4 @@ export class Mesh2<
// endregion

}


+ 55
- 0
src/core/object/MeshLine.ts Просмотреть файл

@@ -0,0 +1,55 @@
import {LineGeometry2} from '../geometry/LineGeometry2'
import {LineMaterial2} from '../material/LineMaterial2'
import {IObject3D, IObject3DEventMap, IObject3DUserData} from '../IObject'
import {Line2} from 'three/examples/jsm/lines/Line2'
import {iObjectCommons} from './iObjectCommons'
import {IMaterial} from '../IMaterial'

export class MeshLine<
TGeometry extends LineGeometry2 = LineGeometry2,
TMaterial extends LineMaterial2 = LineMaterial2,
TE extends IObject3DEventMap = IObject3DEventMap
> extends Line2<TGeometry, TMaterial, TE> implements IObject3D<TE> {
assetType = 'model' as const
setDirty = iObjectCommons.setDirty
refreshUi = iObjectCommons.refreshUi
public readonly isMeshLine = true

declare material: TMaterial
declare readonly materials: IMaterial[]
declare geometry: TGeometry

/**
* @deprecated use `this` instead
*/
get modelObject(): this {
return this
}

constructor(geometry?: TGeometry, material?: TMaterial) {
super(geometry, material)
iObjectCommons.upgradeObject3D.call(this)
}

declare userData: IObject3DUserData

// region inherited type fixes
// re-declaring from IObject3D because: https://github.com/microsoft/TypeScript/issues/16936

traverse: (callback: (object: IObject3D) => void) => void
traverseVisible: (callback: (object: IObject3D) => void) => void
traverseAncestors: (callback: (object: IObject3D) => void) => void
getObjectById: <T extends IObject3D = IObject3D>(id: number) => T | undefined
getObjectByName: <T extends IObject3D = IObject3D>(name: string) => T | undefined
getObjectByProperty: <T extends IObject3D = IObject3D>(name: string, value: string) => T | undefined
copy: (source: MeshLine | IObject3D, recursive?: boolean, ...args: any[]) => this
clone: (recursive?: boolean) => this
remove: (...object: IObject3D[]) => this
declare parent: IObject3D | null
declare children: IObject3D[]
dispose: (removeFromParent?: boolean) => void

// endregion

}


+ 55
- 0
src/core/object/MeshLineSegments.ts Просмотреть файл

@@ -0,0 +1,55 @@
import {LineSegmentsGeometry2} from '../geometry/LineSegmentsGeometry2'
import {LineMaterial2} from '../material/LineMaterial2'
import {IObject3D, IObject3DEventMap, IObject3DUserData} from '../IObject'
import {LineSegments2} from 'three/examples/jsm/lines/LineSegments2'
import {iObjectCommons} from './iObjectCommons'
import {IMaterial} from '../IMaterial'
import {MeshLine} from './MeshLine'

export class MeshLineSegments<
TGeometry extends LineSegmentsGeometry2 = LineSegmentsGeometry2,
TMaterial extends LineMaterial2= LineMaterial2,
TE extends IObject3DEventMap = IObject3DEventMap
> extends LineSegments2<TGeometry, TMaterial, TE> implements IObject3D<TE> {
assetType = 'model' as const
setDirty = iObjectCommons.setDirty
refreshUi = iObjectCommons.refreshUi
public readonly isMeshLineSegments = true

declare material: TMaterial
declare readonly materials: IMaterial[]
declare geometry: TGeometry

/**
* @deprecated use `this` instead
*/
get modelObject(): this {
return this
}

constructor(geometry?: TGeometry, material?: TMaterial) {
super(geometry, material)
iObjectCommons.upgradeObject3D.call(this)
}

declare userData: IObject3DUserData

// region inherited type fixes
// re-declaring from IObject3D because: https://github.com/microsoft/TypeScript/issues/16936

traverse: (callback: (object: IObject3D) => void) => void
traverseVisible: (callback: (object: IObject3D) => void) => void
traverseAncestors: (callback: (object: IObject3D) => void) => void
getObjectById: <T extends IObject3D = IObject3D>(id: number) => T | undefined
getObjectByName: <T extends IObject3D = IObject3D>(name: string) => T | undefined
getObjectByProperty: <T extends IObject3D = IObject3D>(name: string, value: string) => T | undefined
copy: (source: MeshLine | IObject3D, recursive?: boolean, ...args: any[]) => this
clone: (recursive?: boolean) => this
remove: (...object: IObject3D[]) => this
declare parent: IObject3D | null
declare children: IObject3D[]
dispose: (removeFromParent?: boolean) => void

// endregion

}

+ 8
- 2
src/three/Threejs.ts Просмотреть файл

@@ -232,8 +232,14 @@ export {EffectComposer} from 'three/examples/jsm/postprocessing/EffectComposer.j
export type {GLTFLoaderPlugin, GLTF, GLTFReference, GLTFReferenceType} from 'three/examples/jsm/loaders/GLTFLoader'
export {GLTFParser, GLTFBinaryExtension, GLTFLoader} from 'three/examples/jsm/loaders/GLTFLoader'
export {GLTFExporter} from 'three/examples/jsm/exporters/GLTFExporter'

export {LineSegments2} from 'three/examples/jsm/lines/LineSegments2.js'
export {Line2} from 'three/examples/jsm/lines/Line2.js'
export {LineSegmentsGeometry} from 'three/examples/jsm/lines/LineSegmentsGeometry.js'
export {LineGeometry} from 'three/examples/jsm/lines/LineGeometry.js'
export {LineMaterial} from 'three/examples/jsm/lines/LineMaterial.js'
export {Wireframe} from 'three/examples/jsm/lines/Wireframe.js'
export {WireframeGeometry2} from 'three/examples/jsm/lines/WireframeGeometry2.js'
export {OrbitControls} from 'three/examples/jsm/controls/OrbitControls.js'
export * from 'three/examples/jsm/utils/BufferGeometryUtils.js'
export type {Event, EventListener, EventListener2} from 'three'
export type {Event, EventListener, EventListener2, Event2} from 'three'
export type {MeshPhysicalMaterialParameters, MeshBasicMaterialParameters, MaterialParameters} from 'three'

+ 0
- 1
src/three/controls/OrbitControls3.ts Просмотреть файл

@@ -55,6 +55,5 @@ export class OrbitControls3 extends OrbitControls implements IUiConfigContainer,

throttleUpdate = 60 // throttle to 60 updates per second (implemented in OrbitControls.js.update() method)

// todo add to three-ts-types
stopDamping!: () => void
}

+ 24
- 7
src/three/math/Box3B.ts Просмотреть файл

@@ -1,4 +1,14 @@
import {Box2, Box3, BufferAttribute, Camera, InterleavedBufferAttribute, Mesh, Object3D, Vector3} from 'three'
import {
Box2,
Box3,
BufferAttribute,
BufferGeometry,
Camera,
InterleavedBufferAttribute,
Mesh,
Object3D,
Vector3,
} from 'three'
import type {IObject3D} from '../../core'

export class Box3B extends Box3 {
@@ -10,7 +20,7 @@ export class Box3B extends Box3 {
if (!object.visible && ignoreInvisible) return this
if (ignoreObject && ignoreObject(object)) return this

// copied the whole function from three.js to pass in ignoreInvisible
// copied the whole function from three.js to pass in ignoreInvisible, support precise

// Computes the world-axis-aligned bounding box of an object (including its children),
// accounting for both the object's, and children's, world transforms
@@ -20,7 +30,7 @@ export class Box3B extends Box3 {
// InstancedMesh has boundingBox = null, so it can be computed
if ((object as IObject3D).boundingBox !== undefined) {

if ((object as IObject3D).boundingBox === null && typeof (object as IObject3D).computeBoundingBox === 'function') {
if (/* (object as IObject3D).boundingBox === null && */typeof (object as IObject3D).computeBoundingBox === 'function') {

(object as IObject3D).computeBoundingBox!()

@@ -42,7 +52,10 @@ export class Box3B extends Box3 {
const geometry = (object as Mesh).geometry

if (geometry !== undefined) {
if (precise && geometry.attributes != undefined && geometry.attributes.position !== undefined) {
// checking for computeBoundingBox to support when overridden in subclass.
if (precise && geometry.attributes != undefined && geometry.attributes.position !== undefined && Object.getPrototypeOf(geometry).computeBoundingBox === BufferGeometry.prototype.computeBoundingBox) {
// in case of precise, apply the matrix to positions before expanding the box
// todo add precise option to computeBoundingBox
const position = geometry.attributes.position as any as BufferAttribute | InterleavedBufferAttribute
for (let i = 0, l = position.count; i < l; i++) {
this._vector.fromBufferAttribute(position, i).applyMatrix4(object.matrixWorld)
@@ -51,10 +64,14 @@ export class Box3B extends Box3 {
} else {
if (geometry.boundingBox === null)
geometry.computeBoundingBox()
Box3B._box.copy(geometry.boundingBox!)
Box3B._box.applyMatrix4(object.matrixWorld)
if (geometry.boundingBox) {
Box3B._box.copy(geometry.boundingBox)
Box3B._box.applyMatrix4(object.matrixWorld)

this.union(Box3B._box)
this.union(Box3B._box)
} else {
console.warn('Box3B - Unable to compute bounds for', object, geometry)
}

}
}

+ 4
- 1
src/three/widgets/BoxSelectionWidget.ts Просмотреть файл

@@ -12,9 +12,12 @@ export class BoxSelectionWidget extends SelectionWidget {
color: '#ff2222' as any, transparent: true, opacity: 0.9,
linewidth: 5, // in pixels
resolution: new Vector2(1024, 1024), // to be set by renderer, eventually
worldUnits: false,
dashed: false,
toneMapped: false,
})
matLine.userData.renderToGBuffer = false
matLine.userData.renderToDepth = false
this.lineMaterial = matLine

const ls = new LineSegmentsGeometry()
@@ -33,7 +36,7 @@ export class BoxSelectionWidget extends SelectionWidget {
if (selected) {
const bbox = new Box3B().expandByObject(selected, false)
// const scale = bbox.getBoundingSphere(new Sphere()).radius
bbox.getSize(this.scale).multiplyScalar(this.boundingScaleMultiplier).clampScalar(0.1, 100)
bbox.getSize(this.scale).multiplyScalar(this.boundingScaleMultiplier).clampScalar(0.1, 1e8)
this.setVisible(true)
}
}

+ 2
- 0
src/three/widgets/CameraHelper2.ts Просмотреть файл

@@ -43,6 +43,8 @@ export class CameraHelper2 extends ACameraHelperWidget {
depthTest: false,
depthWrite: false,
})
material.userData.renderToGBuffer = false
material.userData.renderToDepth = false

const {vertices, colors, pointMap} = generateVertices()


+ 2
- 0
src/three/widgets/DirectionalLightHelper2.ts Просмотреть файл

@@ -43,6 +43,8 @@ export class DirectionalLightHelper2 extends ALightHelperWidget {
depthTest: false,
depthWrite: false,
})
this.material.userData.renderToGBuffer = false
this.material.userData.renderToDepth = false

this.lightPlane = new Line2(geometry, this.material)
this.add(this.lightPlane)

+ 2
- 0
src/three/widgets/PointLightHelper2.ts Просмотреть файл

@@ -41,6 +41,8 @@ export class PointLightHelper2 extends ALightHelperWidget {
depthTest: false,
depthWrite: false,
})
this.material.userData.renderToGBuffer = false
this.material.userData.renderToDepth = false

this.lightSphere = new Wireframe(geometry, this.material)
this.lightSphere.computeLineDistances()

+ 3
- 5
src/three/widgets/SpotLightHelper2.ts Просмотреть файл

@@ -1,5 +1,4 @@
import {ColorRepresentation, Object3D, SpotLight, Vector3} from 'three'
import {LineGeometry} from 'three/examples/jsm/lines/LineGeometry.js'
import {LineSegments2} from 'three/examples/jsm/lines/LineSegments2.js'
import {LineSegmentsGeometry} from 'three/examples/jsm/lines/LineSegmentsGeometry.js'
import {onChange} from 'ts-browser-helpers'
@@ -24,7 +23,7 @@ export class SpotLightHelper2 extends ALightHelperWidget {

if (size === undefined) size = 0.5

let geometry = new LineSegmentsGeometry()
const geometry = new LineSegmentsGeometry()
const positions = [
0, 0, 0, 0, 0, 1,
0, 0, 0, 1, 0, 1,
@@ -59,13 +58,12 @@ export class SpotLightHelper2 extends ALightHelperWidget {
depthTest: false,
depthWrite: false,
})
this.material.userData.renderToGBuffer = false
this.material.userData.renderToDepth = false

this.cone = new LineSegments2(geometry, this.material)
this.add(this.cone)

geometry = new LineGeometry()
geometry.setPositions([0, 0, 0, 0, 0, 1])

this.update()

this.traverse(o => {

Загрузка…
Отмена
Сохранить