Skip to content

Commit

Permalink
feat: now edit decals
Browse files Browse the repository at this point in the history
  • Loading branch information
Julien Moreau-Mathis committed Dec 18, 2024
1 parent b3fc595 commit 7567c41
Show file tree
Hide file tree
Showing 8 changed files with 160 additions and 19 deletions.
7 changes: 6 additions & 1 deletion editor/src/editor/layout/graph.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import { isSceneLinkNode } from "../../tools/guards/scene";
import { getCollisionMeshFor } from "../../tools/mesh/collision";
import { isAdvancedDynamicTexture } from "../../tools/guards/texture";
import { UniqueNumber, waitNextAnimationFrame } from "../../tools/tools";
import { isMeshMetadataNotVisibleInGraph } from "../../tools/mesh/metadata";
import { onNodeModifiedObservable, onNodesAddedObservable, onTextureModifiedObservable } from "../../tools/observables";
import { isAbstractMesh, isCamera, isCollisionInstancedMesh, isCollisionMesh, isEditorCamera, isInstancedMesh, isLight, isMesh, isNode, isTransformNode } from "../../tools/guards/nodes";

Expand Down Expand Up @@ -537,7 +538,11 @@ export class EditorGraph extends Component<IEditorGraphProps, IEditorGraphState>
}

private _parseSceneNode(node: Node): TreeNodeInfo | null {
if (isMesh(node) && node._masterMesh || isCollisionMesh(node) || isCollisionInstancedMesh(node)) {
if (
isMesh(node) && (node._masterMesh || isMeshMetadataNotVisibleInGraph(node)) ||
isCollisionMesh(node) ||
isCollisionInstancedMesh(node)
) {
return null;
}

Expand Down
36 changes: 25 additions & 11 deletions editor/src/editor/layout/inspector/decals/decals.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,9 @@ import { AbstractMesh, Mesh, Material, MeshBuilder, Vector2, Vector3, Tools } fr

import { Editor } from "../../../main";

import { registerUndoRedo } from "../../../../tools/undoredo";
import { UniqueNumber, waitNextAnimationFrame } from "../../../../tools/tools";
import { setMeshMetadataNotSerializable } from "../../../../tools/mesh/metadata";
import { setMeshMetadataNotSerializable, setMeshMetadataNotVisibleInGraph } from "../../../../tools/mesh/metadata";

import { loadImportedMaterial } from "../../preview/import/import";

Expand Down Expand Up @@ -70,10 +71,10 @@ export class EditorDecalsInspector extends Component<IEditorDecalsInspectorProps
{this._getMaterialDragAndDropComponent()}

<EditorInspectorSectionField title="Options">
<EditorInspectorNumberField object={decalsConfiguration.size} property="x" step={1} label="Width" onChange={() => this._handleUpdateCurrentDecalMesh()} />
<EditorInspectorNumberField object={decalsConfiguration.size} property="y" step={1} label="Height" onChange={() => this._handleUpdateCurrentDecalMesh()} />
<EditorInspectorNumberField object={decalsConfiguration.size} property="x" step={1} label="Width" noUndoRedo onChange={() => this._handleUpdateCurrentDecalMesh()} />
<EditorInspectorNumberField object={decalsConfiguration.size} property="y" step={1} label="Height" noUndoRedo onChange={() => this._handleUpdateCurrentDecalMesh()} />

<EditorInspectorNumberField object={decalsConfiguration} property="angle" asDegrees step={0.1} label="Angle" onChange={() => this._handleUpdateCurrentDecalMesh()} />
<EditorInspectorNumberField object={decalsConfiguration} property="angle" asDegrees step={0.1} label="Angle" noUndoRedo onChange={() => this._handleUpdateCurrentDecalMesh()} />
</EditorInspectorSectionField>
</div>
);
Expand Down Expand Up @@ -256,6 +257,7 @@ export class EditorDecalsInspector extends Component<IEditorDecalsInspectorProps
this._decalMesh.visibility = this.state.ctrlOrMetaKeyDown ? 1 : 0.35;

setMeshMetadataNotSerializable(this._decalMesh, true);
setMeshMetadataNotVisibleInGraph(this._decalMesh, true);

if (this.state.material.zOffset === 0) {
this.state.material.zOffset = -2;
Expand Down Expand Up @@ -285,21 +287,33 @@ export class EditorDecalsInspector extends Component<IEditorDecalsInspectorProps
this._handleMouseMove(event.offsetX, event.offsetY);

if (this._decalMesh) {
this._decalMesh.id = Tools.RandomId();
this._decalMesh.name = this.state.material!.name;
this._decalMesh.uniqueId = UniqueNumber.Get();
const decalMesh = this._decalMesh;
const scene = this.props.editor.layout.preview.scene;

this._decalMesh.metadata = {
decalMesh.name = this.state.material!.name;
decalMesh.id = Tools.RandomId();
decalMesh.uniqueId = UniqueNumber.Get();

decalMesh.metadata = {
decal: {
angle: decalsConfiguration.angle,
size: decalsConfiguration.size.asArray(),
meshId: EditorDecalsInspector._lastPickedMesh?.name,
sizeX: decalsConfiguration.size.x,
sizeY: decalsConfiguration.size.y,
sizeZ: decalsConfiguration.size.z,
meshId: EditorDecalsInspector._lastPickedMesh?.id,
position: EditorDecalsInspector._lastPickPosition?.asArray(),
normal: EditorDecalsInspector._lastPickedNormal?.asArray(),
},
};

setMeshMetadataNotSerializable(this._decalMesh, false);
setMeshMetadataNotSerializable(decalMesh, false);
setMeshMetadataNotVisibleInGraph(decalMesh, false);

registerUndoRedo({
executeRedo: false,
undo: () => scene.removeMesh(decalMesh),
redo: () => scene.addMesh(decalMesh),
});

this.props.editor.layout.graph.refresh();
}
Expand Down
2 changes: 1 addition & 1 deletion editor/src/editor/layout/inspector/material/pbr.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -188,7 +188,7 @@ export class EditorPBRMaterialInspector extends Component<IEditorPBRMaterialInsp
<EditorInspectorSwitchField label="Use Radiance Occlusion" object={this.props.material} property="useRadianceOcclusion" />
<EditorInspectorSwitchField label="Use Physical Light Falloff" object={this.props.material} property="usePhysicalLightFalloff" />
<EditorInspectorSwitchField label="Separate Culling Pass" object={this.props.material} property="separateCullingPass" />
<EditorInspectorNumberField label="Z Offset" object={this.props.material} property="zOffset" min={0} />
<EditorInspectorNumberField label="Z Offset" object={this.props.material} property="zOffset" />
</EditorInspectorSectionField>
</>
);
Expand Down
102 changes: 102 additions & 0 deletions editor/src/editor/layout/inspector/mesh/decal.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
import { Component, ReactNode } from "react";

import { IoIosWarning } from "react-icons/io";

import { Mesh, MeshBuilder, Vector3 } from "babylonjs";

import { EditorInspectorNumberField } from "../fields/number";
import { EditorInspectorSectionField } from "../fields/section";

export interface IMeshDecalInspectorProps {
object: Mesh;
}

export interface IMeshDecalInspectorState {
meshExists: boolean;
}

export class MeshDecalInspector extends Component<IMeshDecalInspectorProps, IMeshDecalInspectorState> {
public constructor(props: IMeshDecalInspectorProps) {
super(props);

this.state = {
meshExists: true,
};
}

public render(): ReactNode {
if (!this.props.object.metadata?.decal) {
return null;
}

const proxy = this._getProxy(() => {
this._handleUpdateCurrentDecalMesh();
});

return (
<EditorInspectorSectionField title="Decal">
<EditorInspectorNumberField object={proxy} property="sizeX" step={1} label="Width" onChange={() => this._handleUpdateCurrentDecalMesh()} />
<EditorInspectorNumberField object={proxy} property="sizeY" step={1} label="Height" onChange={() => this._handleUpdateCurrentDecalMesh()} />

<EditorInspectorNumberField object={proxy} property="angle" asDegrees step={0.1} label="Angle" onChange={() => this._handleUpdateCurrentDecalMesh()} />

{!this.state.meshExists &&
<div className="flex justify-center items-center gap-2">
<IoIosWarning size="24px" />

<div className="text-yellow-500">
Source mesh not found.
</div>
</div>
}
</EditorInspectorSectionField>
);
}

public componentDidMount(): void {
if (this.props.object.metadata?.decal) {
const scene = this.props.object.getScene();
const mesh = scene.getMeshById(this.props.object.metadata.decal.meshId);

if (!mesh) {
this.setState({ meshExists: false });
}
}
}

private _handleUpdateCurrentDecalMesh(): void {
const scene = this.props.object.getScene();
const mesh = scene.getMeshById(this.props.object.metadata.decal.meshId);
if (!mesh) {
return;
}

const configuration = this.props.object.metadata.decal;

this.props.object.geometry?.releaseForMesh(this.props.object);

const decal = MeshBuilder.CreateDecal("decal", mesh, {
localMode: true,
angle: configuration.angle,
size: new Vector3(configuration.sizeX, configuration.sizeY, configuration.sizeZ),
position: Vector3.FromArray(configuration.position),
normal: configuration.normal ? Vector3.FromArray(configuration.normal) : undefined,
});

decal.geometry?.applyToMesh(this.props.object);
decal.dispose(false, false);
}

private _getProxy<T>(onChange: () => void): T {
return new Proxy(this.props.object.metadata.decal, {
get(target, prop) {
return target[prop];
},
set(obj, prop, value) {
obj[prop] = value;
onChange();
return true;
},
});
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,11 @@ import { CreateBoxVertexData, CreateGroundVertexData, Mesh } from "babylonjs";
import { EditorInspectorNumberField } from "../fields/number";
import { EditorInspectorSectionField } from "../fields/section";

export interface IGeometryInspectorProps {
export interface IMeshGeometryInspectorProps {
object: Mesh;
}

export class GeometryInspector extends Component<IGeometryInspectorProps> {
export class MeshGeometryInspector extends Component<IMeshGeometryInspectorProps> {
public render(): ReactNode {
if (this.props.object.metadata?.type === "Box") {
return this._getBoxInspectorComponent();
Expand Down
7 changes: 4 additions & 3 deletions editor/src/editor/layout/inspector/mesh/mesh.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,6 @@ import { EditorInspectorVectorField } from "../fields/vector";
import { EditorInspectorNumberField } from "../fields/number";
import { EditorInspectorSectionField } from "../fields/section";

import { GeometryInspector } from "../geometry/geometry";

import { ScriptInspectorComponent } from "../script/script";

import { onGizmoNodeChangedObservable } from "../../preview/gizmo";
Expand All @@ -40,6 +38,8 @@ import { EditorSkyMaterialInspector } from "../material/sky";
import { EditorMultiMaterialInspector } from "../material/multi";
import { EditorStandardMaterialInspector } from "../material/standard";

import { MeshDecalInspector } from "./decal";
import { MeshGeometryInspector } from "./geometry";
import { EditorMeshCollisionInspector } from "./collision";

export class EditorMeshInspector extends Component<IEditorInspectorImplementationProps<AbstractMesh>> {
Expand Down Expand Up @@ -114,7 +114,8 @@ export class EditorMeshInspector extends Component<IEditorInspectorImplementatio

{isMesh(this.props.object) &&
<>
<GeometryInspector object={this.props.object} />
<MeshGeometryInspector object={this.props.object} />
<MeshDecalInspector object={this.props.object} />
{this._getLODsComponent()}
</>
}
Expand Down
3 changes: 2 additions & 1 deletion editor/src/project/save/scene.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import { isSceneLinkNode } from "../../tools/guards/scene";
import { isFromSceneLink } from "../../tools/scene/scene-link";
import { getBufferSceneScreenshot } from "../../tools/scene/screenshot";
import { createDirectoryIfNotExist, normalizedGlob } from "../../tools/fs";
import { isMeshMetadataNotVisibleInGraph } from "../../tools/mesh/metadata";
import { isCollisionMesh, isEditorCamera, isMesh } from "../../tools/guards/nodes";

import { serializeSSRRenderingPipeline } from "../../editor/rendering/ssr";
Expand Down Expand Up @@ -46,7 +47,7 @@ export async function saveScene(editor: Editor, projectPath: string, scenePath:
const savedFiles: string[] = [];

await Promise.all(scene.meshes.map(async (mesh) => {
if ((!isMesh(mesh) && !isCollisionMesh(mesh)) || mesh._masterMesh || isFromSceneLink(mesh)) {
if ((!isMesh(mesh) && !isCollisionMesh(mesh)) || mesh._masterMesh || isFromSceneLink(mesh) || isMeshMetadataNotVisibleInGraph(mesh)) {
return;
}

Expand Down
18 changes: 18 additions & 0 deletions editor/src/tools/mesh/metadata.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,3 +9,21 @@ export function setMeshMetadataNotSerializable(mesh: AbstractMesh, value: boolea
mesh.metadata ??= {};
mesh.metadata.doNotSerialize = value;
}

/**
* Sets the metadata of the given mesh to not be visible in graph or not.
* @param mesh defines the reference to the mesh to set the metadata to.
* @param value defines the value to set to the metadata.
*/
export function setMeshMetadataNotVisibleInGraph(mesh: AbstractMesh, value: boolean): void {
mesh.metadata ??= {};
mesh.metadata.notVisibleInGraph = value;
}

/**
* Gets wether or not the given mesh is visible in graph.
* @param mesh defines the reference to the mesh to get the metadata to.
*/
export function isMeshMetadataNotVisibleInGraph(mesh: AbstractMesh): boolean {
return mesh.metadata?.notVisibleInGraph ?? false;
}

0 comments on commit 7567c41

Please sign in to comment.