多面板示例
下面这个例子,使用两个 WorldPanel
演示在实际3D场景中两种经典的面板使用场景:
- 其中一个面板,固定在3D场景中,面板内置有一个文本组件,文本信息可以动态实时更新内容
- 另一个面板,它被绑定在另一个3D节点上,可以随着父节点实时更新位置;且可以通过设置
billboard
类型来锁定其旋转角度,让面板始终朝向相机视角;配合depthTest
可以实现不会被遮挡的标注效果
ts
import {
Scene3D,
PropertyAnimation,
Engine3D,
Object3D,
Object3DUtil,
PropertyAnimClip,
WrapMode,
WorldPanel,
BillboardType,
TextAnchor,
UIImage,
UIShadow,
UITextField,
Vector3,
Color,
Time,
AtmosphericComponent,
Camera3D,
GPUCullMode,
HoverCameraController,
UIPanel,
View3D,
DirectLight
} from '@orillusion/core'
import * as dat from 'dat.gui'
class Sample_POI {
scene: Scene3D
panel: WorldPanel
position: Vector3
gui: dat.GUI
async run() {
Engine3D.setting.shadow.autoUpdate = true
Engine3D.setting.shadow.updateFrameRate = 1
Engine3D.setting.shadow.shadowBound = 20
Engine3D.setting.shadow.shadowBias = 0.0001
// initializa engine
await Engine3D.init({ renderLoop: () => this.loop() })
// create new scene as root node
let scene3D: Scene3D = new Scene3D()
scene3D.addComponent(AtmosphericComponent)
// create camera
let cameraObj: Object3D = new Object3D()
let camera = cameraObj.addComponent(Camera3D)
// adjust camera view
camera.perspective(60, Engine3D.aspect, 1, 5000.0)
// set camera controller
let controller = cameraObj.addComponent(HoverCameraController)
controller.setCamera(0, -20, 15)
// add camera node
scene3D.addChild(cameraObj)
let lightObj = new Object3D()
lightObj.rotationX = 45
let dl = lightObj.addComponent(DirectLight)
dl.intensity = 10
dl.castShadow = true
scene3D.addChild(lightObj)
let view = new View3D()
view.scene = scene3D
view.camera = camera
Engine3D.startRenderView(view)
this.scene = scene3D
await this.initScene()
this.gui = new dat.GUI()
this.initDuckPOI()
this.initScenePOI()
}
private modelContainer: Object3D
async initScene() {
// floor
let floor: Object3D = Object3DUtil.GetSingleCube(16, 0.1, 16, 1, 1, 1)
this.scene.addChild(floor)
await Engine3D.res.loadFont('https://cdn.orillusion.com/fnt/0.fnt')
// load external model
let model = (await Engine3D.res.loadGltf('https://cdn.orillusion.com/PBR/Duck/Duck.gltf')) as Object3D
model.rotationY = 180
this.modelContainer = new Object3D()
this.modelContainer.addChild(model)
this.scene.addChild(this.modelContainer)
model.scaleX = model.scaleY = model.scaleZ = 0.01
await this.initPropertyAnim(this.modelContainer)
let chair = (await Engine3D.res.loadGltf('https://cdn.orillusion.com/PBR/SheenChair/SheenChair.gltf')) as Object3D
chair.scaleX = chair.scaleY = chair.scaleZ = 8
this.scene.addChild(chair)
}
private async initPropertyAnim(owner: Object3D) {
// add PropertyAnimation
let animation = owner.addComponent(PropertyAnimation)
//load a animation clip
let json: any = await Engine3D.res.loadJSON('https://cdn.orillusion.com/json/anim_0.json')
let animClip = new PropertyAnimClip()
animClip.parse(json)
animClip.wrapMode = WrapMode.Loop
animation.defaultClip = animClip.name
animation.autoPlay = true
// register clip to animation
animation.appendClip(animClip)
animation.play(animation.defaultClip)
return animation
}
private initDuckPOI() {
let canvas = this.scene.view.enableUICanvas()
//panel
this.panel = new Object3D().addComponent(WorldPanel)
this.panel.billboard = BillboardType.BillboardXYZ
//add to canvas
canvas.addChild(this.panel.object3D)
this.panel.object3D.localScale = new Vector3(0.1, 0.1, 0.1)
//poi
let panelRoot = new Object3D()
this.panel.object3D.addChild(panelRoot)
let image = panelRoot.addComponent(UIImage)
image.uiTransform.resize(32, 6)
image.uiTransform.setXY(20, 20)
image.color = new Color(1, 1, 1, 0.5)
image.isShadowless = true
let text = panelRoot.addComponent(UITextField)
text.text = 'Happy Duck'
text.fontSize = 4
text.color = new Color(0, 0, 0, 1)
text.alignment = TextAnchor.MiddleCenter
this.renderUIPanel(this.panel, 'Duck Panel')
}
private sceneText: UITextField
private initScenePOI() {
let canvas = this.scene.view.enableUICanvas()
//panel
let panel = new Object3D().addComponent(WorldPanel)
panel.cullMode = 'none'
//add to canvas
canvas.addChild(panel.object3D)
panel.object3D.localScale = new Vector3(0.1, 0.1, 0.1)
//poi
let panelRoot = new Object3D()
panel.transform.rotationX = -30
panel.transform.y = 3.1
panel.transform.x = 1
panel.object3D.addChild(panelRoot)
let text = panelRoot.addComponent(UITextField)
text.uiTransform.resize(80, 16)
text.text = this.title
text.fontSize = 10
text.color = new Color(0.5, 1.0, 0.5, 1.0)
text.alignment = TextAnchor.MiddleLeft
panelRoot.addComponent(UIShadow).shadowOffset.multiplyScaler(0.2)
this.sceneText = text
this.renderUIPanel(panel, 'Chair Panel')
}
private charCount = 0
private title: string = 'Hello, Orillusion'
private lastTitle = this.title
private loop(): void {
if (this.panel) {
this.position ||= new Vector3()
this.position.copyFrom(this.modelContainer.transform.worldPosition)
this.panel.object3D.localPosition = this.position
}
if (this.sceneText) {
let count = 1 + (Math.floor(Time.frame * 0.1) % 30)
if (this.charCount != count) {
this.charCount = count
let newTitle = this.title.slice(0, this.charCount)
if (newTitle != this.lastTitle) {
this.sceneText.text = newTitle
this.lastTitle = newTitle
}
}
}
}
renderUIPanel(panel: WorldPanel, name: string = 'GUI Panel') {
let f = this.gui.addFolder(name)
//cull mode
let cullMode = {}
cullMode[GPUCullMode.none] = GPUCullMode.none
cullMode[GPUCullMode.front] = GPUCullMode.front
cullMode[GPUCullMode.back] = GPUCullMode.back
// change cull mode by click dropdown box
f.add({ cullMode: GPUCullMode.none }, 'cullMode', cullMode).onChange((v) => {
panel.cullMode = v
})
//billboard
let billboard = {}
billboard['None'] = BillboardType.None
billboard['Y'] = BillboardType.BillboardY
billboard['XYZ'] = BillboardType.BillboardXYZ
// change billboard by click dropdown box
f.add({ billboard: panel.billboard }, 'billboard', billboard).onChange((v) => {
panel.billboard = v
})
//depth test
f.add(panel, 'depthTest')
f.open()
}
}
new Sample_POI().run()
import {
Scene3D,
PropertyAnimation,
Engine3D,
Object3D,
Object3DUtil,
PropertyAnimClip,
WrapMode,
WorldPanel,
BillboardType,
TextAnchor,
UIImage,
UIShadow,
UITextField,
Vector3,
Color,
Time,
AtmosphericComponent,
Camera3D,
GPUCullMode,
HoverCameraController,
UIPanel,
View3D,
DirectLight
} from '@orillusion/core'
import * as dat from 'dat.gui'
class Sample_POI {
scene: Scene3D
panel: WorldPanel
position: Vector3
gui: dat.GUI
async run() {
Engine3D.setting.shadow.autoUpdate = true
Engine3D.setting.shadow.updateFrameRate = 1
Engine3D.setting.shadow.shadowBound = 20
Engine3D.setting.shadow.shadowBias = 0.0001
// initializa engine
await Engine3D.init({ renderLoop: () => this.loop() })
// create new scene as root node
let scene3D: Scene3D = new Scene3D()
scene3D.addComponent(AtmosphericComponent)
// create camera
let cameraObj: Object3D = new Object3D()
let camera = cameraObj.addComponent(Camera3D)
// adjust camera view
camera.perspective(60, Engine3D.aspect, 1, 5000.0)
// set camera controller
let controller = cameraObj.addComponent(HoverCameraController)
controller.setCamera(0, -20, 15)
// add camera node
scene3D.addChild(cameraObj)
let lightObj = new Object3D()
lightObj.rotationX = 45
let dl = lightObj.addComponent(DirectLight)
dl.intensity = 10
dl.castShadow = true
scene3D.addChild(lightObj)
let view = new View3D()
view.scene = scene3D
view.camera = camera
Engine3D.startRenderView(view)
this.scene = scene3D
await this.initScene()
this.gui = new dat.GUI()
this.initDuckPOI()
this.initScenePOI()
}
private modelContainer: Object3D
async initScene() {
// floor
let floor: Object3D = Object3DUtil.GetSingleCube(16, 0.1, 16, 1, 1, 1)
this.scene.addChild(floor)
await Engine3D.res.loadFont('https://cdn.orillusion.com/fnt/0.fnt')
// load external model
let model = (await Engine3D.res.loadGltf('https://cdn.orillusion.com/PBR/Duck/Duck.gltf')) as Object3D
model.rotationY = 180
this.modelContainer = new Object3D()
this.modelContainer.addChild(model)
this.scene.addChild(this.modelContainer)
model.scaleX = model.scaleY = model.scaleZ = 0.01
await this.initPropertyAnim(this.modelContainer)
let chair = (await Engine3D.res.loadGltf('https://cdn.orillusion.com/PBR/SheenChair/SheenChair.gltf')) as Object3D
chair.scaleX = chair.scaleY = chair.scaleZ = 8
this.scene.addChild(chair)
}
private async initPropertyAnim(owner: Object3D) {
// add PropertyAnimation
let animation = owner.addComponent(PropertyAnimation)
//load a animation clip
let json: any = await Engine3D.res.loadJSON('https://cdn.orillusion.com/json/anim_0.json')
let animClip = new PropertyAnimClip()
animClip.parse(json)
animClip.wrapMode = WrapMode.Loop
animation.defaultClip = animClip.name
animation.autoPlay = true
// register clip to animation
animation.appendClip(animClip)
animation.play(animation.defaultClip)
return animation
}
private initDuckPOI() {
let canvas = this.scene.view.enableUICanvas()
//panel
this.panel = new Object3D().addComponent(WorldPanel)
this.panel.billboard = BillboardType.BillboardXYZ
//add to canvas
canvas.addChild(this.panel.object3D)
this.panel.object3D.localScale = new Vector3(0.1, 0.1, 0.1)
//poi
let panelRoot = new Object3D()
this.panel.object3D.addChild(panelRoot)
let image = panelRoot.addComponent(UIImage)
image.uiTransform.resize(32, 6)
image.uiTransform.setXY(20, 20)
image.color = new Color(1, 1, 1, 0.5)
image.isShadowless = true
let text = panelRoot.addComponent(UITextField)
text.text = 'Happy Duck'
text.fontSize = 4
text.color = new Color(0, 0, 0, 1)
text.alignment = TextAnchor.MiddleCenter
this.renderUIPanel(this.panel, 'Duck Panel')
}
private sceneText: UITextField
private initScenePOI() {
let canvas = this.scene.view.enableUICanvas()
//panel
let panel = new Object3D().addComponent(WorldPanel)
panel.cullMode = 'none'
//add to canvas
canvas.addChild(panel.object3D)
panel.object3D.localScale = new Vector3(0.1, 0.1, 0.1)
//poi
let panelRoot = new Object3D()
panel.transform.rotationX = -30
panel.transform.y = 3.1
panel.transform.x = 1
panel.object3D.addChild(panelRoot)
let text = panelRoot.addComponent(UITextField)
text.uiTransform.resize(80, 16)
text.text = this.title
text.fontSize = 10
text.color = new Color(0.5, 1.0, 0.5, 1.0)
text.alignment = TextAnchor.MiddleLeft
panelRoot.addComponent(UIShadow).shadowOffset.multiplyScaler(0.2)
this.sceneText = text
this.renderUIPanel(panel, 'Chair Panel')
}
private charCount = 0
private title: string = 'Hello, Orillusion'
private lastTitle = this.title
private loop(): void {
if (this.panel) {
this.position ||= new Vector3()
this.position.copyFrom(this.modelContainer.transform.worldPosition)
this.panel.object3D.localPosition = this.position
}
if (this.sceneText) {
let count = 1 + (Math.floor(Time.frame * 0.1) % 30)
if (this.charCount != count) {
this.charCount = count
let newTitle = this.title.slice(0, this.charCount)
if (newTitle != this.lastTitle) {
this.sceneText.text = newTitle
this.lastTitle = newTitle
}
}
}
}
renderUIPanel(panel: WorldPanel, name: string = 'GUI Panel') {
let f = this.gui.addFolder(name)
//cull mode
let cullMode = {}
cullMode[GPUCullMode.none] = GPUCullMode.none
cullMode[GPUCullMode.front] = GPUCullMode.front
cullMode[GPUCullMode.back] = GPUCullMode.back
// change cull mode by click dropdown box
f.add({ cullMode: GPUCullMode.none }, 'cullMode', cullMode).onChange((v) => {
panel.cullMode = v
})
//billboard
let billboard = {}
billboard['None'] = BillboardType.None
billboard['Y'] = BillboardType.BillboardY
billboard['XYZ'] = BillboardType.BillboardXYZ
// change billboard by click dropdown box
f.add({ billboard: panel.billboard }, 'billboard', billboard).onChange((v) => {
panel.billboard = v
})
//depth test
f.add(panel, 'depthTest')
f.open()
}
}
new Sample_POI().run()
下面这个例子,集中展示了多种 GUI
组件组合以及多 UIPanel
混合渲染:
ts
import {
AtmosphericComponent,
BillboardType,
CEvent,
CEventDispatcher,
Camera3D,
Color,
DirectLight,
Engine3D,
HoverCameraController,
ImageType,
Object3D,
Object3DUtil,
PointerEvent3D,
Scene3D,
TextAnchor,
Time,
UIImage,
UIInteractive,
UITextField,
Vector3,
View3D,
WorldPanel,
clamp
} from '@orillusion/core'
class GUIPanelPOI {
private readonly alpha = 0.8
private objUI: Object3D
private index: number
private _originColor: Color = new Color()
private _remainTime: number = -1
private _backImage: UIImage
private _outColor = new Color(0, 0.5, 0.75, this.alpha)
constructor(obj, index: number) {
this.objUI = obj
this.index = index
this.displayUIDetail()
}
update(delta: number): void {
if (this._remainTime > 0) {
this._remainTime -= delta
let progress = clamp(this._remainTime, 0, 500)
progress = 1 - progress / 500
let color = this._backImage.color
color.r = this._originColor.r * progress + (1.0 - progress) * 0.2
color.g = this._originColor.g * progress + (1.0 - progress) * 0.2
color.b = this._originColor.b * progress + (1.0 - progress) * 0.2
this._backImage.color = color
}
this.updateFrame()
}
private lastIndex: number = -1
private frame: number = Math.floor(Math.random() * 10000)
private frameStart = 65 //65~77
private frameCount = 13
private _icon: UIImage
private _frameSpeed = 0.05 + 0.1 * Math.random()
updateFrame() {
this.frame++
let newIndex = Math.floor(this.frame * this._frameSpeed) % this.frameCount
if (newIndex != this.lastIndex) {
this.lastIndex = newIndex
let frameKey = (this.lastIndex + this.frameStart).toString().padStart(5, '0')
this._icon.sprite = Engine3D.res.getGUISprite(frameKey)
}
}
private displayUIDetail(): void {
let uiChild = this.objUI.addChild(new Object3D()) as Object3D
let r = Math.random() * 0.25 + 0.2
let b = Math.random() * 0.25 + 0.2
let g = Math.random() * 0.25 + 0.2
this._originColor.setTo(r, g, b, this.alpha)
//back
this._backImage = this.addImage(uiChild, ' ', 200, 120, r, g, b, this.alpha)
this._backImage.uiTransform.x = 100
this._backImage.uiTransform.y = -60
uiChild.addEventListener(
PointerEvent3D.PICK_CLICK_GUI,
() => {
this._remainTime = 500
sampleUIPanelClick.data = this.objUI
sampleUIPanelDispatcher.dispatchEvent(sampleUIPanelClick)
},
this
)
uiChild.addEventListener(
PointerEvent3D.PICK_OVER_GUI,
() => {
this._backImage.color = this._outColor
},
this
)
uiChild.addEventListener(
PointerEvent3D.PICK_OUT_GUI,
() => {
this._backImage.color = this._originColor
},
this
)
let button = uiChild.addComponent(UIInteractive)
button.interactive = true
//icon
{
let iconNode = uiChild.addChild(new Object3D()) as Object3D
let icon = this.addImage(iconNode, '', 100, 100, 1, 1, 1)
icon.uiTransform.x = -75
icon.uiTransform.y = 25
this._icon = icon
this.updateFrame()
}
//text
{
let textChild = this.objUI.addChild(new Object3D()) as Object3D
let text = textChild.addComponent(UITextField)
text.uiTransform.resize(120, 60)
text.uiTransform.x = 110
text.uiTransform.y = -48
text.alignment = TextAnchor.UpperLeft
text.text = 'Orilussion'
text.fontSize = 22
text.color = new Color(0.9, 0.9, 0.9, 1.0)
}
//text
{
let textChild = this.objUI.addChild(new Object3D()) as Object3D
let text = textChild.addComponent(UITextField)
text.uiTransform.resize(140, 60)
text.uiTransform.x = 110
text.uiTransform.y = -100
text.alignment = TextAnchor.UpperLeft
text.text = '次时代WebGPU 3D Engine'
text.fontSize = 18
text.color = new Color(0.8, 0.8, 0.8, 1.0)
}
}
private addImage(obj: Object3D, texture: string, w: number, h: number, r: number, g: number, b: number, a: number = 1): UIImage {
let image = obj.addComponent(UIImage)
image.sprite = Engine3D.res.getGUISprite(texture)
image.uiTransform.resize(w, h)
image.imageType = ImageType.Sliced
image.color.setTo(r, g, b, a)
return image
}
}
class GUIPanelBinder {
objUI: Object3D
panel: GUIPanelPOI
ball: Object3D
constructor(ball: Object3D, ui: Object3D, index: number) {
this.ball = ball
this.objUI = ui
this.objUI.name = 'panel ' + index
this.objUI.scaleX = this.objUI.scaleY = this.objUI.scaleZ = 0.1
this.panel = new GUIPanelPOI(this.objUI, index)
}
update(delta: number) {
this.objUI.localPosition = this.ball.transform.worldPosition
this.panel.update(delta)
}
}
let sampleUIPanelClick: CEvent = new CEvent('ClickUIPanel')
let sampleUIPanelDispatcher: CEventDispatcher = new CEventDispatcher()
class Sample_UIMultiPanel {
camera: Camera3D
scene: Scene3D
view: View3D
async run() {
Engine3D.setting.shadow.autoUpdate = true
Engine3D.setting.shadow.shadowBias = 0.0001
Engine3D.setting.shadow.shadowBound = 200
await Engine3D.init({
renderLoop: () => {
this.renderUpdate()
}
})
// create new scene as root node
let scene3D: Scene3D = new Scene3D()
scene3D.addComponent(AtmosphericComponent)
// create camera
let cameraObj: Object3D = new Object3D()
let camera = cameraObj.addComponent(Camera3D)
// adjust camera view
camera.perspective(60, Engine3D.aspect, 1, 5000.0)
// set camera controller
let controller = cameraObj.addComponent(HoverCameraController)
controller.setCamera(0, -10, 150, new Vector3(0, 15, 0))
// add camera node
scene3D.addChild(cameraObj)
// create light
let light: Object3D = new Object3D()
// add direct light component
let component: DirectLight = light.addComponent(DirectLight)
// adjust lighting
light.rotationX = 21
light.rotationY = 120
component.lightColor = new Color(1.0, 1.0, 1.0, 1.0)
component.intensity = 30
component.castShadow = true
// add light object
scene3D.addChild(light)
let view = new View3D()
view.scene = scene3D
view.camera = camera
Engine3D.startRenderView(view)
this.scene = scene3D
this.camera = view.camera
this.view = view
let model = await Engine3D.res.loadGltf('https://cdn.orillusion.com/gltfs/wukong/wukong.gltf')
model.localScale = new Vector3(1, 1, 1).multiplyScalar(50)
this.scene.addChild(model)
this.scene.addChild(Object3DUtil.GetSingleCube(400, 1, 400, 0.2, 0.2, 0.2))
await Engine3D.res.loadFont('https://cdn.orillusion.com/fnt/0.fnt')
await Engine3D.res.loadAtlas('https://cdn.orillusion.com/atlas/Sheet_atlas.json')
this.makeUIPanelList()
}
private nodeList: GUIPanelBinder[] = []
private bindTarget3DRoot: Object3D
private makeUIPanelList(): void {
this.bindTarget3DRoot = new Object3D()
this.bindTarget3DRoot.y = 50
this.scene.addChild(this.bindTarget3DRoot)
let canvas = this.view.enableUICanvas()
for (let i = 0; i < 50; i++) {
//panel
let panelRoot: Object3D = new Object3D()
let panel = panelRoot.addComponent(WorldPanel)
panel.billboard = BillboardType.BillboardXYZ
panel.needSortOnCameraZ = true
canvas.addChild(panel.object3D)
//random position
let angle = Math.PI * 2 * Math.random()
let pos = new Vector3()
pos.set(Math.sin(angle), Math.cos(angle), (Math.random() - 0.5) * 2)
pos.multiplyScalar(50 * Math.sqrt(Math.random() + 0.25))
let ball = this.bindTarget3DRoot.addChild(new Object3D()) as Object3D
ball.localPosition = pos
//binder
let node = new GUIPanelBinder(ball, panelRoot, i)
this.nodeList.push(node)
}
sampleUIPanelDispatcher.addEventListener(
sampleUIPanelClick.type,
(e) => {
let target = e.data as Object3D
let targetPos = this.view.camera.worldToScreenPoint(target.transform.worldPosition)
let orginPos = this.view.camera.worldToScreenPoint(new Vector3())
this.isSpeedAdd = targetPos.x > orginPos.x ? 1 : -1
this.speedAngle += 50
console.log(this.isSpeedAdd)
},
this
)
}
private speedAngle: number = 1
private isSpeedAdd: number = 1
renderUpdate() {
if (this.bindTarget3DRoot) {
this.speedAngle -= 0.2
this.speedAngle = Math.max(this.speedAngle, 1)
this.bindTarget3DRoot.rotationY += 0.01 * this.speedAngle * this.isSpeedAdd
for (let binder of this.nodeList) {
binder.update(Time.delta)
}
}
}
}
new Sample_UIMultiPanel().run()
import {
AtmosphericComponent,
BillboardType,
CEvent,
CEventDispatcher,
Camera3D,
Color,
DirectLight,
Engine3D,
HoverCameraController,
ImageType,
Object3D,
Object3DUtil,
PointerEvent3D,
Scene3D,
TextAnchor,
Time,
UIImage,
UIInteractive,
UITextField,
Vector3,
View3D,
WorldPanel,
clamp
} from '@orillusion/core'
class GUIPanelPOI {
private readonly alpha = 0.8
private objUI: Object3D
private index: number
private _originColor: Color = new Color()
private _remainTime: number = -1
private _backImage: UIImage
private _outColor = new Color(0, 0.5, 0.75, this.alpha)
constructor(obj, index: number) {
this.objUI = obj
this.index = index
this.displayUIDetail()
}
update(delta: number): void {
if (this._remainTime > 0) {
this._remainTime -= delta
let progress = clamp(this._remainTime, 0, 500)
progress = 1 - progress / 500
let color = this._backImage.color
color.r = this._originColor.r * progress + (1.0 - progress) * 0.2
color.g = this._originColor.g * progress + (1.0 - progress) * 0.2
color.b = this._originColor.b * progress + (1.0 - progress) * 0.2
this._backImage.color = color
}
this.updateFrame()
}
private lastIndex: number = -1
private frame: number = Math.floor(Math.random() * 10000)
private frameStart = 65 //65~77
private frameCount = 13
private _icon: UIImage
private _frameSpeed = 0.05 + 0.1 * Math.random()
updateFrame() {
this.frame++
let newIndex = Math.floor(this.frame * this._frameSpeed) % this.frameCount
if (newIndex != this.lastIndex) {
this.lastIndex = newIndex
let frameKey = (this.lastIndex + this.frameStart).toString().padStart(5, '0')
this._icon.sprite = Engine3D.res.getGUISprite(frameKey)
}
}
private displayUIDetail(): void {
let uiChild = this.objUI.addChild(new Object3D()) as Object3D
let r = Math.random() * 0.25 + 0.2
let b = Math.random() * 0.25 + 0.2
let g = Math.random() * 0.25 + 0.2
this._originColor.setTo(r, g, b, this.alpha)
//back
this._backImage = this.addImage(uiChild, ' ', 200, 120, r, g, b, this.alpha)
this._backImage.uiTransform.x = 100
this._backImage.uiTransform.y = -60
uiChild.addEventListener(
PointerEvent3D.PICK_CLICK_GUI,
() => {
this._remainTime = 500
sampleUIPanelClick.data = this.objUI
sampleUIPanelDispatcher.dispatchEvent(sampleUIPanelClick)
},
this
)
uiChild.addEventListener(
PointerEvent3D.PICK_OVER_GUI,
() => {
this._backImage.color = this._outColor
},
this
)
uiChild.addEventListener(
PointerEvent3D.PICK_OUT_GUI,
() => {
this._backImage.color = this._originColor
},
this
)
let button = uiChild.addComponent(UIInteractive)
button.interactive = true
//icon
{
let iconNode = uiChild.addChild(new Object3D()) as Object3D
let icon = this.addImage(iconNode, '', 100, 100, 1, 1, 1)
icon.uiTransform.x = -75
icon.uiTransform.y = 25
this._icon = icon
this.updateFrame()
}
//text
{
let textChild = this.objUI.addChild(new Object3D()) as Object3D
let text = textChild.addComponent(UITextField)
text.uiTransform.resize(120, 60)
text.uiTransform.x = 110
text.uiTransform.y = -48
text.alignment = TextAnchor.UpperLeft
text.text = 'Orilussion'
text.fontSize = 22
text.color = new Color(0.9, 0.9, 0.9, 1.0)
}
//text
{
let textChild = this.objUI.addChild(new Object3D()) as Object3D
let text = textChild.addComponent(UITextField)
text.uiTransform.resize(140, 60)
text.uiTransform.x = 110
text.uiTransform.y = -100
text.alignment = TextAnchor.UpperLeft
text.text = '次时代WebGPU 3D Engine'
text.fontSize = 18
text.color = new Color(0.8, 0.8, 0.8, 1.0)
}
}
private addImage(obj: Object3D, texture: string, w: number, h: number, r: number, g: number, b: number, a: number = 1): UIImage {
let image = obj.addComponent(UIImage)
image.sprite = Engine3D.res.getGUISprite(texture)
image.uiTransform.resize(w, h)
image.imageType = ImageType.Sliced
image.color.setTo(r, g, b, a)
return image
}
}
class GUIPanelBinder {
objUI: Object3D
panel: GUIPanelPOI
ball: Object3D
constructor(ball: Object3D, ui: Object3D, index: number) {
this.ball = ball
this.objUI = ui
this.objUI.name = 'panel ' + index
this.objUI.scaleX = this.objUI.scaleY = this.objUI.scaleZ = 0.1
this.panel = new GUIPanelPOI(this.objUI, index)
}
update(delta: number) {
this.objUI.localPosition = this.ball.transform.worldPosition
this.panel.update(delta)
}
}
let sampleUIPanelClick: CEvent = new CEvent('ClickUIPanel')
let sampleUIPanelDispatcher: CEventDispatcher = new CEventDispatcher()
class Sample_UIMultiPanel {
camera: Camera3D
scene: Scene3D
view: View3D
async run() {
Engine3D.setting.shadow.autoUpdate = true
Engine3D.setting.shadow.shadowBias = 0.0001
Engine3D.setting.shadow.shadowBound = 200
await Engine3D.init({
renderLoop: () => {
this.renderUpdate()
}
})
// create new scene as root node
let scene3D: Scene3D = new Scene3D()
scene3D.addComponent(AtmosphericComponent)
// create camera
let cameraObj: Object3D = new Object3D()
let camera = cameraObj.addComponent(Camera3D)
// adjust camera view
camera.perspective(60, Engine3D.aspect, 1, 5000.0)
// set camera controller
let controller = cameraObj.addComponent(HoverCameraController)
controller.setCamera(0, -10, 150, new Vector3(0, 15, 0))
// add camera node
scene3D.addChild(cameraObj)
// create light
let light: Object3D = new Object3D()
// add direct light component
let component: DirectLight = light.addComponent(DirectLight)
// adjust lighting
light.rotationX = 21
light.rotationY = 120
component.lightColor = new Color(1.0, 1.0, 1.0, 1.0)
component.intensity = 30
component.castShadow = true
// add light object
scene3D.addChild(light)
let view = new View3D()
view.scene = scene3D
view.camera = camera
Engine3D.startRenderView(view)
this.scene = scene3D
this.camera = view.camera
this.view = view
let model = await Engine3D.res.loadGltf('https://cdn.orillusion.com/gltfs/wukong/wukong.gltf')
model.localScale = new Vector3(1, 1, 1).multiplyScalar(50)
this.scene.addChild(model)
this.scene.addChild(Object3DUtil.GetSingleCube(400, 1, 400, 0.2, 0.2, 0.2))
await Engine3D.res.loadFont('https://cdn.orillusion.com/fnt/0.fnt')
await Engine3D.res.loadAtlas('https://cdn.orillusion.com/atlas/Sheet_atlas.json')
this.makeUIPanelList()
}
private nodeList: GUIPanelBinder[] = []
private bindTarget3DRoot: Object3D
private makeUIPanelList(): void {
this.bindTarget3DRoot = new Object3D()
this.bindTarget3DRoot.y = 50
this.scene.addChild(this.bindTarget3DRoot)
let canvas = this.view.enableUICanvas()
for (let i = 0; i < 50; i++) {
//panel
let panelRoot: Object3D = new Object3D()
let panel = panelRoot.addComponent(WorldPanel)
panel.billboard = BillboardType.BillboardXYZ
panel.needSortOnCameraZ = true
canvas.addChild(panel.object3D)
//random position
let angle = Math.PI * 2 * Math.random()
let pos = new Vector3()
pos.set(Math.sin(angle), Math.cos(angle), (Math.random() - 0.5) * 2)
pos.multiplyScalar(50 * Math.sqrt(Math.random() + 0.25))
let ball = this.bindTarget3DRoot.addChild(new Object3D()) as Object3D
ball.localPosition = pos
//binder
let node = new GUIPanelBinder(ball, panelRoot, i)
this.nodeList.push(node)
}
sampleUIPanelDispatcher.addEventListener(
sampleUIPanelClick.type,
(e) => {
let target = e.data as Object3D
let targetPos = this.view.camera.worldToScreenPoint(target.transform.worldPosition)
let orginPos = this.view.camera.worldToScreenPoint(new Vector3())
this.isSpeedAdd = targetPos.x > orginPos.x ? 1 : -1
this.speedAngle += 50
console.log(this.isSpeedAdd)
},
this
)
}
private speedAngle: number = 1
private isSpeedAdd: number = 1
renderUpdate() {
if (this.bindTarget3DRoot) {
this.speedAngle -= 0.2
this.speedAngle = Math.max(this.speedAngle, 1)
this.bindTarget3DRoot.rotationY += 0.01 * this.speedAngle * this.isSpeedAdd
for (let binder of this.nodeList) {
binder.update(Time.delta)
}
}
}
}
new Sample_UIMultiPanel().run()