-
Notifications
You must be signed in to change notification settings - Fork 622
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(octree): Use octree to Filter the scene tree (#275)
Use octree to Filter the scene tree sort transparent nodes. Merge transparent tree and opaque to one tree.
- Loading branch information
Showing
20 changed files
with
948 additions
and
103 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,115 @@ | ||
import { GUIHelp } from '@orillusion/debug/GUIHelp'; | ||
import { BoundingBox, BoxGeometry, Color, Engine3D, LitMaterial, MeshRenderer, Object3D, Object3DUtil, PointerEvent3D, Time, Vector3, View3D, } from '@orillusion/core'; | ||
import { createExampleScene, createSceneParam } from '@samples/utils/ExampleScene'; | ||
import { OctreeEntity } from '../../src/core/tree/octree/OctreeEntity'; | ||
import { Octree } from '../../src/core/tree/octree/Octree'; | ||
|
||
// A sample to use octTree | ||
export class Sample_OctTreeBox { | ||
view: View3D; | ||
entities: OctreeEntity[] = []; | ||
tree: Octree; | ||
red = new Color(1, 0, 0, 1); | ||
gree = new Color(0, 1, 0, 1); | ||
yellow = new Color(1, 1, 0, 1) | ||
blue = new Color(0, 0, 1, 1) | ||
white = new Color(1, 1, 1, 1) | ||
|
||
movingBox: BoundingBox; | ||
|
||
async run() { | ||
// init engine | ||
await Engine3D.init({ renderLoop: () => { this.loop() } }); | ||
GUIHelp.init(); | ||
let param = createSceneParam(); | ||
param.camera.distance = 400; | ||
param.camera.near = 0.1; | ||
param.camera.far = 10000; | ||
let exampleScene = createExampleScene(param); | ||
Engine3D.startRenderViews([exampleScene.view]); | ||
Engine3D.getRenderJob(exampleScene.view); | ||
|
||
this.view = exampleScene.view; | ||
|
||
let box: BoundingBox = new BoundingBox(); | ||
box.setFromMinMax(new Vector3(-100, -100, -100), new Vector3(100, 100, 100)); | ||
this.tree = new Octree(box); | ||
|
||
this.entities = this.initBoxList(); | ||
let center = new Vector3(3, -3, -100); | ||
let size = new Vector3(200, 137, 134); | ||
this.movingBox = new BoundingBox().setFromCenterAndSize(center, size); | ||
|
||
let updateBox = () => { | ||
this.movingBox.setFromCenterAndSize(this.movingBox.center, this.movingBox.size); | ||
} | ||
|
||
GUIHelp.addFolder('Center'); | ||
GUIHelp.add(this.movingBox.center, 'x', -100, 100, 1).onChange(() => { updateBox(); }); | ||
GUIHelp.add(this.movingBox.center, 'y', -100, 100, 1).onChange(() => { updateBox(); }); | ||
GUIHelp.add(this.movingBox.center, 'z', -100, 100, 1).onChange(() => { updateBox(); }); | ||
GUIHelp.open(); | ||
GUIHelp.endFolder(); | ||
GUIHelp.addFolder('Size'); | ||
GUIHelp.add(this.movingBox.size, 'x', 1, 200, 1).onChange(() => { updateBox(); }); | ||
GUIHelp.add(this.movingBox.size, 'y', 1, 200, 1).onChange(() => { updateBox(); }); | ||
GUIHelp.add(this.movingBox.size, 'z', 1, 200, 1).onChange(() => { updateBox(); }); | ||
GUIHelp.open(); | ||
GUIHelp.endFolder(); | ||
} | ||
|
||
_material: LitMaterial; | ||
|
||
private initBoxList(): OctreeEntity[] { | ||
this._material = new LitMaterial(); | ||
|
||
let object3D: Object3D; | ||
let entities: OctreeEntity[] = []; | ||
let geometry = new BoxGeometry(); | ||
for (let i = 0; i < 100; i++) { | ||
for (let j = 0; j < 100; j++) { | ||
for (let k = 0; k < 4; k++) { | ||
object3D = new Object3D(); | ||
let renderer = object3D.addComponent(MeshRenderer); | ||
renderer.geometry = geometry; | ||
renderer.material = this._material; | ||
object3D.localPosition.set(Math.random() - 0.5, Math.random() - 0.5, Math.random() - 0.5); | ||
object3D.localPosition.multiplyScalar(190); | ||
object3D.localPosition = object3D.localPosition; | ||
object3D.localScale = new Vector3(1 + Math.random(), 1 + Math.random(), 1 + Math.random()); | ||
object3D.name = 'name' + i; | ||
|
||
let entity: OctreeEntity = new OctreeEntity(renderer); | ||
entities.push(entity); | ||
this.tree.tryInsertEntity(entity); | ||
this.view.scene.addChild(object3D); | ||
} | ||
} | ||
} | ||
return entities; | ||
} | ||
|
||
private queryResult: OctreeEntity[] = []; | ||
private octreeTest() { | ||
this.queryResult.length = 0; | ||
|
||
let now: number = Date.now(); | ||
this.tree.boxCasts(this.movingBox, this.queryResult); | ||
let time: number = Date.now() - now; | ||
console.log('time: ' + time + ' count: ' + this.queryResult.length); | ||
|
||
let retBoolean = {}; | ||
for (let item of this.queryResult) { | ||
retBoolean[item.uuid] = true; | ||
} | ||
for (let item of this.entities) { | ||
item.renderer.enable = retBoolean[item.uuid]; | ||
} | ||
this.view.graphic3D.drawBoundingBox('pick', this.movingBox, this.gree); | ||
} | ||
|
||
loop() { | ||
this.entities && this.octreeTest(); | ||
} | ||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,117 @@ | ||
import { GUIHelp } from '@orillusion/debug/GUIHelp'; | ||
import { BoundingBox, BoxGeometry, Camera3D, Color, Engine3D, Frustum, LitMaterial, MeshRenderer, Object3D, Object3DUtil, PointerEvent3D, Time, Vector3, View3D, } from '@orillusion/core'; | ||
import { createExampleScene, createSceneParam } from '@samples/utils/ExampleScene'; | ||
import { OctreeEntity } from '../../src/core/tree/octree/OctreeEntity'; | ||
import { Octree } from '../../src/core/tree/octree/Octree'; | ||
import { GUIUtil } from '@samples/utils/GUIUtil'; | ||
import { Stats } from '@orillusion/stats'; | ||
|
||
// A sample to use octTree | ||
export class Sample_OctTreeFrustum { | ||
view: View3D; | ||
entities: OctreeEntity[] = []; | ||
tree: Octree; | ||
red = new Color(1, 0, 0, 1); | ||
gree = new Color(0, 1, 0, 1); | ||
yellow = new Color(1, 1, 0, 1) | ||
blue = new Color(0, 0, 1, 1) | ||
white = new Color(1, 1, 1, 1) | ||
|
||
camera: Camera3D; | ||
frustumBound: BoundingBox; | ||
async run() { | ||
|
||
Engine3D.setting.occlusionQuery.octree = { width: 1000, height: 1000, depth: 1000, x: 0, y: 0, z: 0 } | ||
|
||
// init engine | ||
await Engine3D.init({ renderLoop: () => { this.loop() } }); | ||
GUIHelp.init(); | ||
let param = createSceneParam(); | ||
param.camera.distance = 400; | ||
param.camera.near = 0.1; | ||
param.camera.far = 10000; | ||
let exampleScene = createExampleScene(param); | ||
Engine3D.startRenderViews([exampleScene.view]); | ||
Engine3D.getRenderJob(exampleScene.view); | ||
|
||
this.view = exampleScene.view; | ||
this.view.scene.addComponent(Stats); | ||
|
||
let box: BoundingBox = new BoundingBox(); | ||
box.setFromCenterAndSize(new Vector3(), new Vector3(1000, 1000, 1000)); | ||
this.tree = new Octree(box); | ||
|
||
this.entities = this.initBoxList(); | ||
this.camera = new Object3D().addComponent(Camera3D); | ||
this.camera.perspective(60, Engine3D.aspect, 1, 1000); | ||
this.view.scene.addChild(this.camera.object3D); | ||
|
||
this.frustumBound = new BoundingBox(); | ||
|
||
GUIUtil.renderTransform(this.camera.transform); | ||
} | ||
|
||
_material: LitMaterial; | ||
|
||
private initBoxList(): OctreeEntity[] { | ||
this._material = new LitMaterial(); | ||
|
||
let object3D: Object3D; | ||
let entities: OctreeEntity[] = []; | ||
let geometry = new BoxGeometry(); | ||
for (let i = 0; i < 100; i++) { | ||
for (let j = 0; j < 100; j++) { | ||
for (let k = 0; k < 5; k++) { | ||
object3D = new Object3D(); | ||
let renderer = object3D.addComponent(MeshRenderer); | ||
renderer.geometry = geometry; | ||
renderer.material = this._material; | ||
object3D.localPosition.set(Math.random() - 0.5, Math.random() - 0.5, Math.random() - 0.5); | ||
object3D.localPosition.multiplyScalar(480); | ||
object3D.localPosition = object3D.localPosition; | ||
object3D.localScale = new Vector3(1 + Math.random(), 1 + Math.random(), 1 + Math.random()); | ||
object3D.name = 'name' + i; | ||
|
||
let entity: OctreeEntity = new OctreeEntity(renderer); | ||
entities.push(entity); | ||
this.tree.tryInsertEntity(entity); | ||
this.view.scene.addChild(object3D); | ||
} | ||
} | ||
} | ||
return entities; | ||
} | ||
|
||
|
||
private queryResult: OctreeEntity[] = []; | ||
private octreeTest() { | ||
let range = this.camera.frustum.genBox(this.camera.pvMatrixInv); | ||
this.frustumBound.setFromMinMax(new Vector3(range.minX, range.minY, range.minZ), new Vector3(range.maxX, range.maxY, range.maxZ)); | ||
this.view.graphic3D.drawCameraFrustum(this.camera, this.gree); | ||
this.view.graphic3D.drawBoundingBox('box', this.frustumBound, this.red); | ||
|
||
let frustum = this.camera.frustum; | ||
|
||
//__________exec octree query | ||
let now = performance.now(); | ||
this.queryResult.length = 0; | ||
// this.tree.boxCasts(this.frustumBound, this.queryResult); | ||
this.tree.frustumCasts(frustum, this.queryResult); | ||
|
||
console.log('exec octree: ', performance.now() - now, 'count', this.queryResult.length); | ||
//end—————————————— | ||
|
||
let retBoolean = {}; | ||
for (let item of this.queryResult) { | ||
retBoolean[item.uuid] = true; | ||
} | ||
for (let item of this.entities) { | ||
item.renderer.enable = retBoolean[item.uuid]; | ||
} | ||
} | ||
|
||
loop() { | ||
this.entities && this.octreeTest(); | ||
} | ||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,123 @@ | ||
import { GUIHelp } from '@orillusion/debug/GUIHelp'; | ||
import { BoundingBox, BoxGeometry, Color, Engine3D, LitMaterial, MeshRenderer, Object3D, Object3DUtil, PointerEvent3D, Time, Vector3, View3D, } from '@orillusion/core'; | ||
import { createExampleScene, createSceneParam } from '@samples/utils/ExampleScene'; | ||
import { OctreeEntity } from '../../src/core/tree/octree/OctreeEntity'; | ||
import { Octree } from '../../src/core/tree/octree/Octree'; | ||
|
||
// A sample to use octTree | ||
export class Sample_OctTreeRay { | ||
view: View3D; | ||
entities: OctreeEntity[] = []; | ||
tree: Octree; | ||
red = new Color(1, 0, 0, 1); | ||
gree = new Color(0, 1, 0, 1); | ||
yellow = new Color(1, 1, 0, 1) | ||
blue = new Color(0, 0, 1, 1) | ||
white = new Color(1, 1, 1, 1) | ||
|
||
async run() { | ||
Engine3D.setting.occlusionQuery.octree = { width: 400, height: 400, depth: 400, x: 0, y: 0, z: 0 } | ||
// init engine | ||
await Engine3D.init({ renderLoop: () => { this.loop() } }); | ||
GUIHelp.init(); | ||
let param = createSceneParam(); | ||
param.camera.distance = 400; | ||
param.camera.near = 0.1; | ||
param.camera.far = 10000; | ||
let exampleScene = createExampleScene(param); | ||
Engine3D.startRenderViews([exampleScene.view]); | ||
Engine3D.getRenderJob(exampleScene.view); | ||
|
||
this.view = exampleScene.view; | ||
|
||
let box: BoundingBox = new BoundingBox(); | ||
box.setFromCenterAndSize(new Vector3(), new Vector3(400, 400, 400)); | ||
this.tree = new Octree(box); | ||
|
||
this.entities = this.initBoxList(); | ||
} | ||
|
||
_material: LitMaterial; | ||
|
||
private initBoxList(): OctreeEntity[] { | ||
this._material = new LitMaterial(); | ||
|
||
let object3D: Object3D; | ||
let entities: OctreeEntity[] = []; | ||
let geometry = new BoxGeometry(); | ||
for (let i = 0; i < 100; i++) { | ||
for (let j = 0; j < 100; j++) { | ||
for (let k = 0; k < 2; k++) { | ||
object3D = new Object3D(); | ||
let renderer = object3D.addComponent(MeshRenderer); | ||
renderer.geometry = geometry; | ||
renderer.material = this._material; | ||
object3D.localPosition.set(Math.random() - 0.5, Math.random() - 0.5, Math.random() - 0.5); | ||
object3D.localPosition.multiplyScalar(190); | ||
object3D.localPosition = object3D.localPosition; | ||
object3D.localScale = new Vector3(1 + Math.random(), 1 + Math.random(), 1 + Math.random()); | ||
object3D.name = 'name' + i; | ||
|
||
let entity: OctreeEntity = new OctreeEntity(renderer); | ||
entities.push(entity); | ||
this.tree.tryInsertEntity(entity); | ||
this.view.scene.addChild(object3D); | ||
} | ||
} | ||
} | ||
return entities; | ||
} | ||
|
||
|
||
private queryResult: OctreeEntity[] = []; | ||
private octreeTest() { | ||
let ray = this.view.camera.screenPointToRay(Engine3D.inputSystem.mouseX, Engine3D.inputSystem.mouseY); | ||
this.queryResult.length = 0; | ||
let now: number = Date.now(); | ||
this.tree.rayCasts(ray, this.queryResult); | ||
let time: number = Date.now() - now; | ||
console.log('time: ' + time + ' count: ', this.queryResult.length); | ||
this.view.graphic3D.ClearAll(); | ||
|
||
let retBoolean = {}; | ||
let boundList = {}; | ||
for (let item of this.queryResult) { | ||
if (ray.intersectBox(item.renderer.object3D.bound)) { | ||
retBoolean[item.uuid] = true; | ||
boundList[item.owner.uuid] = item.owner; | ||
} | ||
} | ||
for (let item of this.entities) { | ||
item.renderer.enable = !retBoolean[item.uuid]; | ||
} | ||
|
||
//show box | ||
for (let key in boundList) { | ||
let tree = boundList[key]; | ||
this.view.graphic3D.drawBoundingBox(key, tree.box, this.gree); | ||
} | ||
} | ||
|
||
loop() { | ||
this.entities && this.updateBoxTransform(); | ||
} | ||
|
||
private counter: number = 0; | ||
private updateBoxTransform() { | ||
this.octreeTest(); | ||
this.counter += Time.delta; | ||
if (this.counter > 4000) { | ||
this.counter = 0; | ||
let obj: Object3D; | ||
for (const entity of this.entities) { | ||
obj = entity.renderer.object3D; | ||
if (Math.random() < 0.1) { | ||
obj.localPosition.set(Math.random() - 0.5, Math.random() - 0.5, Math.random() - 0.5); | ||
obj.localPosition.multiplyScalar(190); | ||
obj.localPosition = obj.localPosition; | ||
entity.update(this.tree); | ||
} | ||
} | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.