-
Notifications
You must be signed in to change notification settings - Fork 278
Effect editor #755
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
Draft
Soullnik
wants to merge
67
commits into
BabylonJS:master
Choose a base branch
from
Soullnik:feat/fx-editor
base: master
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Draft
Effect editor #755
Changes from all commits
Commits
Show all changes
67 commits
Select commit
Hold shift + click to select a range
f102d48
feat: implement FX Editor with toolbar, layout, and preview components
b3e0158
feat: enhance FX Editor Graph with particle management features inclu…
4d9f043
feat: enhance FX Editor with particle properties management, includin…
0b50618
feat: enhance FX Editor with new behavior properties and function edi…
327d10c
refactor: streamline FX Editor components by consolidating JSX struct…
00038a5
feat: enhance FX Editor behaviors and emission properties with improv…
20731b1
feat: implement Three.js JSON conversion for FX Editor, enabling part…
f85ea1a
feat: enhance FX Editor layout and properties management with state u…
3d22559
feat: integrate VFX system into FX Editor with enhanced particle beha…
4b8a613
Merge remote-tracking branch 'upstream/master' into feat/fx-editor
9c4b31c
refactor: remove unused loader file and streamline imports in FX Edit…
1c53452
refactor: clean up imports and formatting in FX Editor components for…
0cb7938
refactor: update Babylon.js imports across FX Editor components for c…
8ae0288
refactor: remove unused particle JSON file and enhance VFX component …
7c16a38
refactor: enhance VFXEffect structure and hierarchy management in FX …
0a337ed
refactor: streamline VFX hierarchy processing by consolidating node c…
173379a
refactor: update FX Editor properties to utilize VFXEffectNode for im…
8202dfe
refactor: update FX Editor properties to utilize VFXEffectNode for im…
97ae339
refactor: enhance VFX component structure by removing unused parsers …
e6b643b
refactor: remove VFXEmitterFactory and streamline VFX system creation…
4d56c70
refactor: enhance VFX system functionality by introducing capacity an…
f7f0f56
refactor: update VFX factories to utilize VFXData for improved resour…
5aaa41a
refactor: streamline VFX behavior implementations by removing unused …
fb2b1a2
refactor: enhance VFX parsing and system integration by implementing …
12d0b70
refactor: clean up whitespace in VFXSolidParticleSystem for improved …
64415bc
refactor: remove trailing whitespace in VFX files for improved code c…
a5e93a1
refactor: enhance ColorOverLife behavior by improving key interpolati…
33f9ab2
refactor: enhance VFX behavior and properties by implementing compreh…
23d54db
refactor: enhance VFX system by introducing a new VFXEmitterFactory f…
75496d3
feat: introduce EditorInspectorColorGradientField and GradientPicker …
fdf08ca
refactor: enhance VFX editor properties by adding emission burst mana…
305f388
feat: implement prewarm functionality in VFX systems, enhancing perfo…
85f29e8
feat: enhance FX editor functionality by implementing effect manageme…
86495cd
feat: add geometry field component to FX editor for improved mesh han…
ad69f12
refactor: rename FX editor components and interfaces for consistency,…
742ed1c
feat: implement comprehensive effect editor features including animat…
e8fa850
refactor: update FX editor components by renaming properties for cons…
4a31162
refactor: consolidate imports in geometry and renderer components, en…
cd0c0b9
refactor: update type definitions across effect components to improve…
8bf8710
refactor: standardize type definitions across effect behaviors and sy…
d95b589
refactor: update type definitions in effect behaviors and systems to …
8ca8513
refactor: update type definitions across effect components to use pre…
86799c3
refactor: transition emitter configuration to prefixed interfaces, en…
75075ed
refactor: remove deprecated particle system files to streamline the e…
7a3d382
refactor: rename particle system creation methods for consistency and…
e0d17f7
refactor: standardize property assignment syntax in effect systems fo…
a3109ff
refactor: enhance effect system configuration by standardizing proper…
80928c4
refactor: update effect editor to improve node handling and enhance e…
fc3a872
refactor: enhance effect editor and solid particle system by introduc…
3170af8
refactor: enhance data conversion and solid particle system behavior …
f4a1bc2
refactor: unify color function handling across behaviors by introduci…
d3ce226
refactor: enhance effect editor and solid particle system by implemen…
9c29ce4
refactor: enhance effect editor and particle system functionality by …
4318570
refactor: streamline effect class by consolidating system and group m…
d364ee4
Merge branch 'master' into feat/fx-editor
4a17a45
fix: imports
769920a
refactor: update effect editor to use QuarksConverter and improve dat…
e86402b
feat: enhance effect editor with Quarks file import functionality
52fcc54
refactor: update imports to use specific Babylon.js core modules
1fd2600
refactor: standardize Babylon.js imports across effect editor components
b53b8bf
feat: extend EffectSolidParticleSystem options with new properties
0b10100
feat: enhance NodeFactory with new node creation methods
4eaecdc
Merge branch 'master' into feat/fx-editor
9779440
fix: add shader imports for particle systems in effect editor preview
59d2b70
refactor: update rotation handling in converters and properties
b33dee0
refactor: clean up imports in EffectEditorObjectProperties
fefec49
refactor: enhance transform conversion in QuarksConverter and update …
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or 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 hidden or 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,230 @@ | ||
| import { DragEvent, Component, PropsWithChildren, ReactNode } from "react"; | ||
| import { extname } from "path/posix"; | ||
|
|
||
| import { toast } from "sonner"; | ||
|
|
||
| import { XMarkIcon } from "@heroicons/react/20/solid"; | ||
| import { MdOutlineQuestionMark } from "react-icons/md"; | ||
|
|
||
| import { Scene, Mesh } from "babylonjs"; | ||
|
|
||
| import { isScene } from "../../../../tools/guards/scene"; | ||
| import { registerUndoRedo } from "../../../../tools/undoredo"; | ||
|
|
||
| import { configureImportedNodeIds, loadImportedSceneFile } from "../../preview/import/import"; | ||
| import { EditorInspectorNumberField } from "./number"; | ||
|
|
||
| export interface IEditorInspectorGeometryFieldProps extends PropsWithChildren { | ||
| title: string; | ||
| property: string; | ||
| object: any; | ||
|
|
||
| noUndoRedo?: boolean; | ||
|
|
||
| scene?: Scene; | ||
| onChange?: (mesh: Mesh | null) => void; | ||
| } | ||
|
|
||
| export interface IEditorInspectorGeometryFieldState { | ||
| dragOver: boolean; | ||
| loading: boolean; | ||
| } | ||
|
|
||
| export class EditorInspectorGeometryField extends Component<IEditorInspectorGeometryFieldProps, IEditorInspectorGeometryFieldState> { | ||
| public constructor(props: IEditorInspectorGeometryFieldProps) { | ||
| super(props); | ||
|
|
||
| this.state = { | ||
| dragOver: false, | ||
| loading: false, | ||
| }; | ||
| } | ||
|
|
||
| public render(): ReactNode { | ||
| const mesh = this.props.object[this.props.property] as Mesh | null | undefined; | ||
|
|
||
| return ( | ||
| <div | ||
| onDrop={(ev) => this._handleDrop(ev)} | ||
| onDragOver={(ev) => this._handleDragOver(ev)} | ||
| onDragLeave={(ev) => this._handleDragLeave(ev)} | ||
| className={`flex flex-col w-full p-5 rounded-lg ${this.state.dragOver ? "bg-muted-foreground/75 dark:bg-muted-foreground/20" : "bg-muted-foreground/10 dark:bg-muted-foreground/5"} transition-all duration-300 ease-in-out`} | ||
| > | ||
| <div className="flex gap-4 w-full"> | ||
| {this._getPreviewComponent(mesh)} | ||
|
|
||
| <div className="flex flex-col w-full"> | ||
| <div className="flex flex-col px-2"> | ||
| <div>{this.props.title}</div> | ||
| {mesh && <div className="text-sm text-muted-foreground">{mesh.name}</div>} | ||
| </div> | ||
|
|
||
| {mesh && ( | ||
| <div className="flex flex-col gap-1 mt-1 w-full"> | ||
| <EditorInspectorNumberField noUndoRedo={this.props.noUndoRedo} label="Vertices" object={{ count: mesh.getTotalVertices() }} property="count" /> | ||
| <EditorInspectorNumberField | ||
| noUndoRedo={this.props.noUndoRedo} | ||
| label="Faces" | ||
| object={{ count: mesh.getTotalIndices() ? mesh.getTotalIndices()! / 3 : 0 }} | ||
| property="count" | ||
| /> | ||
| </div> | ||
| )} | ||
| </div> | ||
| <div | ||
| onClick={() => { | ||
| const oldMesh = this.props.object[this.props.property]; | ||
|
|
||
| this.props.object[this.props.property] = null; | ||
| this.props.onChange?.(null); | ||
|
|
||
| if (!this.props.noUndoRedo) { | ||
| registerUndoRedo({ | ||
| executeRedo: true, | ||
| undo: () => { | ||
| this.props.object[this.props.property] = oldMesh; | ||
| }, | ||
| redo: () => { | ||
| this.props.object[this.props.property] = null; | ||
| }, | ||
| }); | ||
| } | ||
|
|
||
| this.forceUpdate(); | ||
| }} | ||
| className="flex justify-center items-center w-24 h-full hover:bg-muted-foreground rounded-lg transition-all duration-300" | ||
| > | ||
| {mesh && <XMarkIcon className="w-6 h-6" />} | ||
| </div> | ||
| </div> | ||
|
|
||
| {mesh && this.props.children} | ||
| </div> | ||
| ); | ||
| } | ||
|
|
||
| private _getPreviewComponent(mesh: Mesh | null | undefined): ReactNode { | ||
| return ( | ||
| <div className={`flex justify-center items-center ${mesh ? "w-24 h-24" : "w-8 h-8"} aspect-square`}> | ||
| {mesh ? ( | ||
| <div className="w-24 h-24 flex items-center justify-center bg-background rounded-lg"> | ||
| <div className="text-xs text-center text-muted-foreground">{mesh.name}</div> | ||
| </div> | ||
| ) : ( | ||
| <MdOutlineQuestionMark className="w-8 h-8" /> | ||
| )} | ||
| </div> | ||
| ); | ||
| } | ||
|
|
||
| private _handleDragOver(ev: DragEvent<HTMLDivElement>): void { | ||
| ev.preventDefault(); | ||
| this.setState({ dragOver: true }); | ||
| } | ||
|
|
||
| private _handleDragLeave(ev: DragEvent<HTMLDivElement>): void { | ||
| ev.preventDefault(); | ||
| this.setState({ dragOver: false }); | ||
| } | ||
|
|
||
| private async _handleDrop(ev: DragEvent<HTMLDivElement>): Promise<void> { | ||
| ev.preventDefault(); | ||
| this.setState({ dragOver: false, loading: true }); | ||
|
|
||
| try { | ||
| const absolutePath = JSON.parse(ev.dataTransfer.getData("assets"))[0]; | ||
| const extension = extname(absolutePath).toLowerCase(); | ||
|
|
||
| const supportedExtensions = [".x", ".b3d", ".dae", ".glb", ".gltf", ".fbx", ".stl", ".lwo", ".dxf", ".obj", ".3ds", ".ms3d", ".blend", ".babylon"]; | ||
|
|
||
| if (!supportedExtensions.includes(extension)) { | ||
| toast.error(`Unsupported geometry format: ${extension}`); | ||
| this.setState({ loading: false }); | ||
| return; | ||
| } | ||
|
|
||
| const scene = this.props.scene ?? (isScene(this.props.object) ? this.props.object : this.props.object.getScene?.()); | ||
|
|
||
| if (!scene) { | ||
| toast.error("Scene is not available"); | ||
| this.setState({ loading: false }); | ||
| return; | ||
| } | ||
|
|
||
| const result = await loadImportedSceneFile(scene, absolutePath); | ||
|
|
||
| if (!result || !result.meshes || result.meshes.length === 0) { | ||
| toast.error("Failed to load geometry file"); | ||
| this.setState({ loading: false }); | ||
| return; | ||
| } | ||
|
|
||
| // Use the first mesh or find a mesh without parent | ||
| let importedMesh: Mesh | null = null; | ||
| for (const m of result.meshes) { | ||
| if (m instanceof Mesh && !m.parent) { | ||
| importedMesh = m; | ||
| break; | ||
| } | ||
| } | ||
|
|
||
| if (!importedMesh && result.meshes.length > 0 && result.meshes[0] instanceof Mesh) { | ||
| importedMesh = result.meshes[0]; | ||
| } | ||
|
|
||
| if (!importedMesh) { | ||
| toast.error("No valid mesh found in geometry file"); | ||
| this.setState({ loading: false }); | ||
| return; | ||
| } | ||
|
|
||
| // Configure imported mesh | ||
| configureImportedNodeIds(importedMesh); | ||
| importedMesh.setEnabled(false); // Hide the source mesh | ||
|
|
||
| const oldMesh = this.props.object[this.props.property]; | ||
|
|
||
| this.props.object[this.props.property] = importedMesh; | ||
| this.props.onChange?.(importedMesh); | ||
|
|
||
| if (!this.props.noUndoRedo) { | ||
| registerUndoRedo({ | ||
| executeRedo: true, | ||
| undo: () => { | ||
| this.props.object[this.props.property] = oldMesh; | ||
| if (importedMesh && importedMesh !== oldMesh) { | ||
| importedMesh.dispose(); | ||
| } | ||
| }, | ||
| redo: () => { | ||
| this.props.object[this.props.property] = importedMesh; | ||
| }, | ||
| onLost: () => { | ||
| if (importedMesh && importedMesh !== oldMesh) { | ||
| importedMesh.dispose(); | ||
| } | ||
| }, | ||
| }); | ||
| } | ||
|
|
||
| // Dispose other meshes from the imported file | ||
| for (const m of result.meshes) { | ||
| if (m !== importedMesh) { | ||
| m.dispose(); | ||
| } | ||
| } | ||
|
|
||
| // Dispose transform nodes | ||
| for (const tn of result.transformNodes) { | ||
| tn.dispose(); | ||
| } | ||
|
|
||
| this.forceUpdate(); | ||
| } catch (error) { | ||
| console.error("Failed to load geometry:", error); | ||
| toast.error(`Failed to load geometry: ${error instanceof Error ? error.message : String(error)}`); | ||
| } finally { | ||
| this.setState({ loading: false }); | ||
| } | ||
| } | ||
| } | ||
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should be drawn as a simple react element like here for example: https://github.com/BabylonJS/Editor/blob/master/editor/src/editor/layout/inspector/mesh/mesh.tsx#L105
This example draws the type of the mesh which is not editable but here just for information