Skip to content

Commit

Permalink
feat(GUI): New feature of scissor the GUI content. (#219)
Browse files Browse the repository at this point in the history
You can set the button transition mode to color mode.
You can scissor the GUI content by the UIPanel.
merge GUIMesh to UIPanel
  • Loading branch information
hellmor committed Jun 21, 2023
1 parent fab97a5 commit 722abe1
Show file tree
Hide file tree
Showing 19 changed files with 439 additions and 251 deletions.
97 changes: 97 additions & 0 deletions samples/gui/Sample_UIPanelScissor.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
import { GUIHelp } from "@orillusion/debug/GUIHelp";
import { createExampleScene, createSceneParam } from "@samples/utils/ExampleScene";
import { Engine3D, Object3DUtil, Object3D, Color, WorldPanel, GUICanvas, UIImage, makeAloneSprite, BitmapTexture2D, UITextField, UIShadow, Time, ImageType } from "@orillusion/core";
import { GUIUtil } from "@samples/utils/GUIUtil";
import { VideoTexture } from "@orillusion/media-extention";

class Sample_UIPanelScissor {

async run() {
Engine3D.setting.shadow.autoUpdate = true;
Engine3D.setting.shadow.shadowBias = 0.002;

GUIHelp.init();

await Engine3D.init({ renderLoop: () => { this.loop(); } });

let param = createSceneParam();
param.camera.distance = 50;
let exampleScene = createExampleScene(param);
Engine3D.startRenderView(exampleScene.view);

// create floor
let floor = Object3DUtil.GetSingleCube(100, 2, 50, 0.5, 0.5, 0.5);
exampleScene.scene.addChild(floor);
floor.y = -20;

// enable ui canvas at index 0
let canvas = exampleScene.view.enableUICanvas();
//create UI root
let panelRoot: Object3D = new Object3D();
panelRoot.scaleX = panelRoot.scaleY = panelRoot.scaleZ = 0.1;
await Engine3D.res.loadFont('fnt/0.fnt');

this.createPanel(panelRoot, canvas, new Color(1, 1, 1, 1));
}

private async createPanel(panelRoot: Object3D, canvas: GUICanvas, color: Color) {
let panel = panelRoot.addComponent(WorldPanel);
panel.cullMode = "none";
canvas.addChild(panel.object3D);
panel.scissorEnable = true;
panel.scissorCornerRadius = 40;
panel.scissorFadeOutSize = 10;
panel.uiTransform.resize(400, 300);
panel.visible = true;
panel.color = color;

let obj = new Object3D();
panelRoot.addChild(obj);

//image
let image = obj.addComponent(UIImage);
image.uiTransform.resize(300, 200);

{
//make sprite
// let texture = new BitmapTexture2D();
// texture.flipY = true;
// await texture.load('textures/KB3D_NTT_Ads_basecolor.png');
// image.sprite = makeAloneSprite('sprite', texture);
}

{
// make video
let videoTexture = new VideoTexture();
await videoTexture.load('/video/dt.mp4');
image.sprite = makeAloneSprite('dt.mp4', videoTexture);
image.uiTransform.resize(350, 250);
}

{
//textfield
let child = new Object3D();
obj.addChild(child);
let textfield = this.textField = child.addComponent(UITextField);
textfield.uiTransform.resize(200, 100);
textfield.fontSize = 32;
textfield.color = new Color(0, 0.5, 1, 1.0);
textfield.text = 'Scissor Panel';
//shadow
child.addComponent(UIShadow);
}

GUIUtil.renderUIPanel(panel, true);
}

private textField: UITextField;
private loop(): void {
if (this.textField) {
let angle = Time.time * 0.001;
this.textField.uiTransform.setXY(Math.sin(angle) * 100, Math.cos(angle) * 20);
}
}
}


new Sample_UIPanelScissor().run();
42 changes: 42 additions & 0 deletions samples/utils/GUIUtil.ts
Original file line number Diff line number Diff line change
Expand Up @@ -276,6 +276,48 @@ export class GUIUtil {
panel.billboard = v;
});

let scissorData = {
scissorCornerRadius: panel.scissorCornerRadius,
scissorFadeOutSize: panel.scissorFadeOutSize,
panelWidth: 400,
panelHeight: 300,
backGroundVisible: panel.visible,
backGroundColor: panel.color,
scissorEnable: panel.scissorEnable

};
let changeSissor = () => {
panel.scissorCornerRadius = scissorData.scissorCornerRadius;
panel.scissorEnable = scissorData.scissorEnable;
panel.scissorFadeOutSize = scissorData.scissorFadeOutSize;
panel.color = scissorData.backGroundColor;
panel.visible = scissorData.backGroundVisible;
panel.uiTransform.resize(scissorData.panelWidth, scissorData.panelHeight);
}
GUIHelp.add(scissorData, 'scissorCornerRadius', 0, 100, 0.1).onChange(() => {
changeSissor();
});
GUIHelp.add(scissorData, 'scissorFadeOutSize', 0, 100, 0.1).onChange(() => {
changeSissor();
});
GUIHelp.add(scissorData, 'panelWidth', 1, 400, 1).onChange(() => {
changeSissor();
});
GUIHelp.add(scissorData, 'panelHeight', 1, 300, 1).onChange(() => {
changeSissor();
});
GUIHelp.add(scissorData, 'backGroundVisible').onChange(() => {
changeSissor();
});

GUIHelp.addColor(scissorData, 'backGroundColor').onChange(() => {
changeSissor();
});

GUIHelp.add(scissorData, 'scissorEnable').onChange(() => {
changeSissor();
});

//depth test
if (panel['isWorldPanel']) {
GUIHelp.add(panel, 'depthTest');
Expand Down
13 changes: 7 additions & 6 deletions src/components/BillboardComponent.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,11 @@ import { BillboardType } from './gui/GUIConfig';
export class BillboardComponent extends ComponentBase {
public type: BillboardType;
public camera: Camera3D;
private _cameraDirection: Vector3;
private _cameraPosition: Vector3;

constructor() {
super();
this._cameraDirection = new Vector3();
this._cameraPosition = new Vector3();
}

public onUpdate() {
Expand All @@ -22,13 +22,14 @@ export class BillboardComponent extends ComponentBase {

private updateBillboardMatrix(): void {
let camera = this.transform.view3D.camera;
this._cameraDirection.copyFrom(camera.transform.back);
this._cameraPosition.copyFrom(camera.transform.back);
if (this.type == BillboardType.BillboardXYZ) {
} else if (this.type == BillboardType.BillboardY) {
this._cameraDirection.y = 0;
this._cameraPosition.y = 0;
}
this._cameraDirection.normalize();
this.transform.lookAt(Vector3.ZERO, this._cameraDirection, camera.transform.up);
this._cameraPosition.normalize();
this._cameraPosition.add(this.object3D.localPosition, this._cameraPosition);
this.transform.lookAt(this.object3D.localPosition, this._cameraPosition, camera.transform.up);
}

public cloneTo(obj: Object3D) {
Expand Down
53 changes: 27 additions & 26 deletions src/components/gui/GUIPick.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,8 @@ import { Vector3 } from '../../math/Vector3';
import { Time } from '../../util/Time';
import { IUIInteractive, UIInteractiveStyle } from './uiComponents/IUIInteractive';
import { UITransform } from './uiComponents/UITransform';
import { ViewPanel } from './uiComponents/ViewPanel';
import { WorldPanel } from './uiComponents/WorldPanel';
import { Object3D } from '../../core/entities/Object3D';
import { View3D } from '../../core/View3D';
import { zSorterUtil } from '../../util/ZSorterUtil';
import { UIPanel } from './uiComponents/UIPanel';

/**
* Pickup logic for GUI interactive components
Expand Down Expand Up @@ -121,43 +118,46 @@ export class GUIPick {
}

private _colliderOut: IUIInteractive[] = [];
private _uiList: UITransform[] = [];
private _transformList: UITransform[] = [];
private _sortWorldPanelList = [];
private _iteractive2PanelDict: Map<IUIInteractive, UIPanel> = new Map<IUIInteractive, UIPanel>();

private collectEntities(): IUIInteractive[] {
this._colliderOut.length = 0;
this._uiList.length = 0;
this._sortWorldPanelList.length = 0;
this._iteractive2PanelDict.clear();

this._view.canvasList.forEach(canvas => {
if (canvas && canvas.transform && canvas.transform.parent) {
let viewPanels = canvas.object3D.getComponents(ViewPanel);
let worldPanels = canvas.object3D.getComponents(WorldPanel);
worldPanels = zSorterUtil.sort(this._view.camera, worldPanels, this.getObject3D, this._sortWorldPanelList) as any;

for (let panel of worldPanels) {
panel.object3D.getComponents(UITransform, this._uiList);
let panels = canvas.object3D.getComponentsByProperty('isUIPanel', true, true) as UIPanel[];

panels.sort((a, b) => {
let aOrder = a['_uiRenderer']['__renderOrder'];
let bOrder = b['_uiRenderer']['__renderOrder'];
return aOrder > bOrder ? -1 : 1;
})

for (let panel of panels) {
this._transformList.length = 0;
panel.object3D.getComponents(UITransform, this._transformList);
for (const uiTransform of this._transformList) {
let interactiveList = uiTransform.uiInteractiveList;
if (interactiveList && interactiveList.length > 0) {
for (let item of interactiveList) {
this._colliderOut.push(item);
this._iteractive2PanelDict.set(item, panel);
}
}
}
}

for (let panel of viewPanels) {
panel.object3D.getComponents(UITransform, this._uiList);
}

for (const uiTransform of this._uiList) {
let interactiveList = uiTransform.uiInteractiveList;
if (interactiveList && interactiveList.length > 0) {
this._colliderOut.push(...interactiveList);
}
}
}
});

return this._colliderOut;
}

private getObject3D(userData: WorldPanel): Object3D {
return userData.object3D;
}

private pick(colliders: IUIInteractive[], camera: Camera3D) {
this._ray = this._view.camera.screenPointToRay(Engine3D.inputSystem.mouseX, Engine3D.inputSystem.mouseY);
let screenPos = new Vector2(Engine3D.inputSystem.mouseX, Engine3D.inputSystem.mouseY);
Expand All @@ -166,7 +166,8 @@ export class GUIPick {
let intersect: { intersect: boolean; intersectPoint?: Vector3; distance: number; interactive?: IUIInteractive };
for (const iterator of colliders) {
if (iterator.interactive && iterator.enable && iterator.interactiveVisible) {
intersect = iterator.rayPick(this._ray, screenPos, screenSize);
let panel = this._iteractive2PanelDict.get(iterator);
intersect = iterator.rayPick(this._ray, panel, screenPos, screenSize);
if (intersect) {
intersect.interactive = iterator;
return intersect;
Expand Down
47 changes: 0 additions & 47 deletions src/components/gui/core/GUICanvas.ts
Original file line number Diff line number Diff line change
@@ -1,25 +1,13 @@
import { Object3D } from "../../../core/entities/Object3D";
import { webGPUContext } from "../../../gfx/graphics/webGpu/Context3D";
import { ComponentBase } from "../../ComponentBase";
import { GUIConfig } from "../GUIConfig";
import { UIPanel } from "../uiComponents/UIPanel";
import { UITransform } from "../uiComponents/UITransform";
import { GUIGeometryRebuild } from "./GUIGeometryRebuild";
import { GUIMaterial } from "./GUIMaterial";
import { GUIMesh } from "./GUIMesh";

/**
* GUI Root Container
* @group GPU GUI
*/
export class GUICanvas extends ComponentBase {
private _rebuild: GUIGeometryRebuild;

public index: number = 0;
init() {
super.init();
this._rebuild = new GUIGeometryRebuild();
}

/**
*
Expand All @@ -42,41 +30,6 @@ export class GUICanvas extends ComponentBase {
return this;
}

onUpdate() {
this.rebuildGUIMesh();
}

private rebuildGUIMesh() {
let panelList: UIPanel[] = this.object3D.getComponentsByProperty('isUIPanel', true, true);

let camera = this.object3D?.transform?.view3D?.camera;
let screenWidth = webGPUContext.canvas.clientWidth;
let screenHeight = webGPUContext.canvas.clientHeight;
let transforms: UITransform[] = [];
for (let panel of panelList) {
transforms.length = 0;
let guiMesh: GUIMesh = panel.guiMesh;
panel.object3D.getComponents(UITransform, transforms);
if (transforms.length > 0) {
this._rebuild.build(transforms, guiMesh, panel.needUpdateGeometry);
guiMesh.updateGUIData(screenWidth, screenHeight, camera);
for (const t of transforms) {
t.needUpdateQuads = false;
}
}

//calc render order
let canvas = panel.object3D.getComponentFromParent(GUICanvas);
let canvasIndex = canvas ? canvas.index : 0;
guiMesh.uiRenderer.enable = transforms.length > 0;
let renderStart = panel['isViewPanel'] ? GUIConfig.SortOrderStartView : GUIConfig.SortOrderStartWorld;
guiMesh.uiRenderer.renderOrder = canvasIndex * GUIConfig.SortOrderCanvasSpan + renderStart + panel.panelOrder;
//
guiMesh.uiRenderer.needSortOnCameraZ = panel.needSortOnCameraZ;
(guiMesh.uiRenderer.material as GUIMaterial).setLimitVertex(guiMesh.limitVertexCount);
panel.needUpdateGeometry = false;
}
}

public cloneTo(obj: Object3D) {
console.error('UICanvas Can not be Clone!');
Expand Down

0 comments on commit 722abe1

Please sign in to comment.