playcanvas / editor

Issue tracker for the PlayCanvas Editor
https://playcanvas.com/
154 stars 28 forks source link

Add support to create/edit/inspect custom assets #888

Open heretique opened 1 year ago

heretique commented 1 year ago

Hey PlayCanvas team,

the PC editor features an amazing set of features, probably the best of any web-based 3D engine today but since we started using the engine, we felt limited by the fact that it offers so little customization of the game data.

At the moment the only customization of the sort I'm writing about that the editor allows is through use of scripts and their attributes. These can be inspected and edited, assigned references to them etc.

We have tons of custom data types within our game, custom material definitions, prop definitions (templates with additional metadata), terrain blocks, accessories definitions, etc. Handling all of these assets is painful, especially since most of them reference PC supported assets (render, model, anim, material, etc) and feels like something that doesn't really fit well with the rest. The engine supports implementing and registering our own resource loaders and hence our own custom assets but because the editor doesn't know about these, we have to keep switching between editing some of the assets in PC editor and some outside in text editors or with custom tools. Now imagine doing this for hundreds or thousands of assets while trying to reconcile changes in both pools of assets.

It would be great if the editor API would provide some sort of hooks for handling these custom assets:

I'm really curious if we're an outlier and these needs of ours are particular but based on my past experience a multipurpose game engine and it's tooling should be really flexible with its data model and provide a lot of extensibility.

I know this is a big ask but I'm hopeful 🙏 .

yaustar commented 1 year ago

@ellthompson was looking at extending the API and allowing for extensions in the editor for some of these hooks that you mention.

The custom resource loader, do you mean in the engine or just being able to upload a JSON file as a material for example?

We are also thinking about how we go about GLB importing and haven't quite got to the point where we have a clear path.

heretique commented 1 year ago

In the engine, I can register new resource loaders, hence load new types of assets. For example, I implemented a new type of asset called custom-material, this one holds the "material specification" for a new class of materials I implemented that extends pc.Material.

Now if I'm using the engine by itself I can do something like this:

  1. Register new resource loaders

    init(options: any) {
    // add resource handlers to options before calling super.init
    options.resourceHandlers.push(CustomMaterialHandler);
    options.resourceHandlers.push(PropHandler);
    super.init(options);
    
    // register custom materials
    MaterialRegistry.registerCustomMaterials(this.graphicsDevice, [TestMaterial, AnotherTestMaterial]);
    }
  2. Add custom assets to the pc.AssetRegistry
    
    const noise = new pc.Asset("noise", "texture", {
      url: "/assets/textures/T_Noise_06.png",
    });

const customMaterial = new pc.Asset("custom-material-test", "custom-material", null, { type: "TestMaterial", params: { color: { type: "color", value: [1, 1, 1, 1] }, diffuse: { type: "asset", value: noise.id, }, }, options: {}, });

3. And use them
  // Create box entity
  const cube = new pc.Entity();
  cube.addComponent("model", {
    type: "box",
    materialAsset: customMaterial.id,
  });

![image](https://user-images.githubusercontent.com/139596/191816949-fc403cce-c8b5-4a5e-9090-81b618152705.png)

Imagine how useful would be to be able to edit the custom material asset, which is basically a JSON file with some `params` record of `name:value` pairs inside the editor and assign textures to it or assign this asset to a render asset just as I would do with a normal material. It will allow us to build the full asset dependency graphs inside PC and never leave the editor.
leonidaspir commented 1 year ago

@heretique I very much see a lot of potential on what you are describing. From my experience there has been demand to extend parts of the editor like that, for example being able to make your custom components in the editor.

Regarding the asset context menu you can add your own entries like this (note this is unofficial editor API, you can find out how to do this by studing the editor.js file):

        // prepare some menu items
        var menuItems = new Array(5);
        for (let k = 1; k <= 3; k++) {

            var menuItem = new pcui.MenuItem({
                text: "Item " + k,
                icon: null,
                dividor: 2 ** k,
                onSelect: (item, currentAsset) => {
                  // do something with the selected item
                }
            });
            menuItems.push(menuItem);
        }

        var menuData = {
            text: 'My Menu',
            icon: 'E288',
            items: menuItems,
            onIsVisible: (item, currentAsset) => {

                // show this submenu only when one or more material assets are selected
                var selectedAssets = assetPanel._selectedAssets;
                var numAssets = selectedAssets.length;
                var bVisible = selectedAssets.length >= 1;
                for (let i = 0; i < numAssets; i++) {
                    if (selectedAssets[i]._data.type !== "material") {
                        bVisible = false;
                        break
                    }
                }
                return bVisible;
            }
        };

        editor.call('assets:contextmenu:add', menuData);