Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improved Story viewport brackets and helpers #313

Open
wants to merge 5 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion libs/ff-scene/source/components/CDirectionalLight.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,10 @@ export default class CDirectionalLight extends CLight
protected static readonly dirLightIns = {
position: types.Vector3("Light.Position"),
target: types.Vector3("Light.Target", [ 0, -1, 0 ]),
shadowSize: types.Number("Shadow.Size", 100),
shadowSize: types.Number("Shadow.Size", {
preset: 100,
min: 0,
}),
};

ins = this.addInputs<CLight, typeof CDirectionalLight["dirLightIns"]>(CDirectionalLight.dirLightIns);
Expand Down
5 changes: 4 additions & 1 deletion libs/ff-scene/source/components/CHemisphereLight.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,10 @@ import CLight from "./CLight";

////////////////////////////////////////////////////////////////////////////////


/**
* Implementeation of [HemisphereLight](https://threejs.org/docs/?q=HemisphereLight#api/en/lights/HemisphereLight) from three.js
* It does NOT work on Standard materials that have a metallic value of 1
*/
export default class CHemisphereLight extends CLight
{
static readonly typeName: string = "CHemisphereLight";
Expand Down
5 changes: 4 additions & 1 deletion libs/ff-scene/source/components/CLight.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,10 @@ export default class CLight extends CObject3D

protected static readonly lightIns = {
color: types.ColorRGB("Light.Color"),
intensity: types.Number("Light.Intensity", 1),
intensity: types.Number("Light.Intensity", {
preset:1,
min: 0,
}),
shadowEnabled: types.Boolean("Shadow.Enabled"),
shadowResolution: types.Enum("Shadow.Resolution", EShadowMapResolution, EShadowMapResolution.Medium),
shadowBlur: types.Number("Shadow.Blur", 1),
Expand Down
155 changes: 91 additions & 64 deletions libs/ff-scene/source/components/CPickSelection.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,78 +5,109 @@
* License: MIT
*/

import Component, { types } from "@ff/graph/Component";
import Component, { IUpdateContext, types } from "@ff/graph/Component";
import ComponentTracker from "@ff/graph/ComponentTracker";
import Node from "@ff/graph/Node";
import CSelection from "@ff/graph/components/CSelection";

import Bracket from "@ff/three/Bracket";
import Axes from "@ff/three/Axes";

import { IPointerEvent } from "../RenderView";

import SpotLightHelper from "@ff/three/lights/SpotLightHelper";
import DirectionalLightHelper from "@ff/three/lights/DirectionalLightHelper";
import PointLightHelper from "@ff/three/lights/PointLightHelper";
import AmbientLightHelper from "@ff/three/lights/AmbientLightHelper";
import RectLightHelper from "@ff/three/lights/RectLightHelper";

import CObject3D from "./CObject3D";
import CTransform from "./CTransform";
import CScene, { ISceneAfterRenderEvent } from "./CScene";
import { DirectionalLight, DirectionalLightHelper, HemisphereLight, HemisphereLightHelper, Object3D, PointLight, PointLightHelper, RectAreaLight, SpotLight, SpotLightHelper } from "three";

import { Box3, Color, Object3D } from "three";
////////////////////////////////////////////////////////////////////////////////

const helpers = [
[DirectionalLightHelper, DirectionalLight],
[PointLightHelper, PointLight],
[SpotLightHelper, SpotLight],
[HemisphereLightHelper, HemisphereLight],
[PointLightHelper, RectAreaLight],
[DirectionalLightHelper, "DirectionalLight"],
[PointLightHelper, "PointLight"],
[SpotLightHelper, "SpotLight"],
[AmbientLightHelper, "HemisphereLight"],
[AmbientLightHelper, "AmbientLight"],
[RectLightHelper, "RectAreaLight"],
] as const;

const _inputs = {
viewportPicking: types.Boolean("Viewport.Picking", true),
viewportBrackets: types.Boolean("Viewport.Brackets", true),
viewportAxes: types.Boolean("Viewport.Axes", false),
};

type HelperClass = Object3D & {dispose: ()=>void, update: ()=>void};
export default class CPickSelection extends CSelection
{
static readonly typeName: string = "CPickSelection";

ins = this.addInputs<CSelection, typeof _inputs>(_inputs);

private _brackets = new Map<Component, any>();
private _sceneTracker: ComponentTracker<CScene> = null;
private _brackets = new Map<Component, HelperClass>();
private _axes :HelperClass;


create()
{
super.create();

this.system.on<IPointerEvent>("pointer-up", this.onPointerUp, this);

this._sceneTracker = new ComponentTracker(this.system.components, CScene, component => {
component.on<ISceneAfterRenderEvent>("after-render", this.onSceneAfterRender, this);
}, component => {
component.off<ISceneAfterRenderEvent>("after-render", this.onSceneAfterRender, this);
});
}

dispose()
{
this._sceneTracker.dispose();

this.system.off<IPointerEvent>("pointer-up", this.onPointerUp, this);
this._sceneTracker.dispose();

super.dispose();
}

update()
{
if(this.ins.viewportBrackets.changed){
for(let bracket of this._brackets.values()){
bracket.visible = this.ins.viewportBrackets.value;
}
}
if(this.ins.viewportAxes.changed){
//FIXME : add axes helper to scene
if(this._axes){
console.debug("Remove scene axes");
this._axes.removeFromParent();
this._axes.dispose();
}
if(this.ins.viewportAxes.value){
console.debug("Create scene axes : ", this.ins.viewportAxes.value);
//Length should be half CVGrid's size.
const scene = this.system.getMainComponent(CScene);
let bbox = new Box3();
bbox.expandByObject(scene.scene);
let length = Math.max(bbox.max.x, bbox.max.y, bbox.max.z);
let f = 1;

while (length / f > 5) {
f = f * 10;
}

length = Math.ceil(length / f) * f/2;
this._axes = new Axes(scene.scene, {length: length, width: 3, colors: [new Color(0x9a3c4a), new Color(0x628928), new Color(0x3d5e8b)], depthTest: true});
scene.scene.add(this._axes);
}
}
return true;
}

protected onSelectNode(node: Node, selected: boolean)
{
super.onSelectNode(node, selected);

const transform = node.getComponent(CTransform, true);
const transform = node.getComponent(CObject3D, true);
if (transform) {
this.updateBracket(transform, selected);
}
Expand All @@ -87,25 +118,10 @@ export default class CPickSelection extends CSelection
super.onSelectComponent(component, selected);

if (component instanceof CObject3D || component instanceof CTransform) {
this.updateBracket(component, selected);
this.updateBracket(component, selected);
}
}

// protected onActiveGraph(graph: Graph)
// {
// if (this._sceneTracker) {
// this._sceneTracker.dispose();
// }
//
// if (graph) {
// this._sceneTracker = new ComponentTracker(graph.components, CScene, component => {
// component.on<ISceneAfterRenderEvent>("after-render", this.onSceneAfterRender, this);
// }, component => {
// component.off<ISceneAfterRenderEvent>("after-render", this.onSceneAfterRender, this);
// });
// }
// }

protected onPointerUp(event: IPointerEvent)
{
if (!this.ins.viewportPicking.value || !event.isPrimary || event.isDragging) {
Expand All @@ -119,55 +135,66 @@ export default class CPickSelection extends CSelection
this.clearSelection();
}
}

protected onSceneAfterRender(event: ISceneAfterRenderEvent)
{
if (!this.ins.viewportBrackets.value) {
return;
}

const renderer = event.context.renderer;
const camera = event.context.camera;

for (let bracket of this._brackets.values()) {
if(helpers.some(([HelperCl])=> bracket instanceof HelperCl)){
bracket.update();
/** @bug PointLightHelper doesn't call it internally in its update() method. */
bracket.updateWorldMatrix( true, false );
}
renderer.render(bracket as any, camera);
tick(ctx:IUpdateContext) :boolean{
for(let b of this._brackets.values()){
b.update();
}
return false;
}

protected updateBracket(component: CTransform | CObject3D, selected: boolean)
{
if (!component) {
return;
}

if(!this.ins.viewportBrackets.value) return; //Don't create brackets to be hidden
const object3D = component.object3D;
const transform = component.transform;
if (selected) {
const object3D = component.object3D;
if (object3D) {
let bracket;
for(let [HelperCl, Cl] of helpers){
if(object3D.children[0] instanceof Cl){
bracket = new HelperCl(object3D.children[0] as any, 1.0);
let bracket :HelperClass;
if((object3D as any).isLight){

let HelperCl = helpers.find(([h,type])=>type === object3D.type)?.[0];
if(HelperCl){
object3D.updateMatrix();
bracket = new HelperCl(object3D as any);
/** @bug PointLightHelper doesn't call it internally in its update() method. */
bracket.updateWorldMatrix( true, false );
}
}
if(!bracket){
bracket = new Bracket(component.object3D);

if(!bracket){
bracket = new Bracket(object3D);
}
object3D.add(bracket);
this._brackets.set(component, bracket);
}

if(transform){
let o = new Axes(transform.object3D);
this._brackets.set(transform, o);
transform.object3D.add(o);
}else{
console.warn("Component has no transform");
}
}
else {
const bracket = this._brackets.get(component);
if (bracket) {
this._brackets.delete(component);
bracket.dispose();
if(object3D){
const bracket = this._brackets.get(component);
if (bracket) {
this._brackets.delete(component);
bracket.removeFromParent();
bracket.dispose();
}
}
if(transform){
const bracket = this._brackets.get(transform);
if (bracket) {
this._brackets.delete(transform);
bracket.removeFromParent();
bracket.dispose();
}
}
}

Expand Down
19 changes: 15 additions & 4 deletions libs/ff-scene/source/components/CRectLight.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,8 @@ export default class CRectLight extends CLight
static readonly typeName: string = "CRectLight";

protected static readonly rectLightIns = {
position: types.Vector3("Light.Position", [ 0, 1, 0 ]),
target: types.Vector3("Light.Target", [ 0, 0, 0 ]),
position: types.Vector3("Light.Position", [ 0, 0, 0 ]),
target: types.Vector3("Light.Target", [ 0, -1, 0 ]),
size: types.Vector2("Light.Size", [10, 10]),
};

Expand All @@ -24,7 +24,10 @@ export default class CRectLight extends CLight
super(node, id);

this.object3D = new RectAreaLight();

this.light.width = 1;
this.light.height = 1;
this.object3D.matrixAutoUpdate = false;
this.transform.ins.scale.addEventListener("value",this.update, this);
}

get light(): RectAreaLight {
Expand All @@ -40,10 +43,18 @@ export default class CRectLight extends CLight

if (ins.position.changed || ins.target.changed) {
light.position.fromArray(ins.position.value);
light.lookAt(new Vector3().fromArray(ins.target.value));
light.updateMatrix();
}

//RectAreaLight's size ignores scaling
this.light.width = this.transform.ins.scale.value[0]*10;
this.light.height = this.transform.ins.scale.value[2]*10;

return true;
}

dispose(){
super.dispose();
this.transform.ins.scale.removeEventListener("value",this.update);
}
}
11 changes: 9 additions & 2 deletions libs/ff-scene/source/components/CSpotLight.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,16 @@ export default class CSpotLight extends CLight
protected static readonly spotLightIns = {
position: types.Vector3("Light.Position"),
target: types.Vector3("Light.Target", [ 0, -1, 0 ]),
distance: types.Number("Light.Distance"),
distance: types.Number("Light.Distance", {
preset: 0,
min: 0
}),
decay: types.Number("Light.Decay", 1),
angle: types.Number("Light.Angle", 45),
angle: types.Number("Light.Angle", {
preset:45,
min: 0,
max: 89
}),
penumbra: types.Percent("Light.Penumbra", 0.5),
};

Expand Down
Loading