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

I'm urge to use InstancedMesh, but It's TODO at this project. What's the plan? #38

Closed
hookex opened this issue Feb 24, 2020 · 8 comments

Comments

@hookex
Copy link
Contributor

hookex commented Feb 24, 2020

        // TODO: type: 'BabylonjsCoreInstancedMesh[]' property (not coded) BabylonjsCoreMesh.instances.
        // BabylonjsCoreMesh.isUnIndexed (boolean):
        if (oldProps.isUnIndexed !== newProps.isUnIndexed) {
            updates.push({
                propertyName: 'isUnIndexed',
                value: newProps.isUnIndexed,
                type: 'boolean'
            });
        }

Can you tell me how will you code the IstancedMesh at react-Babylonjs, I want to write the code by myself by clone this project.

Thank you very much.

@brianzinn
Copy link
Owner

I can guide you through how to code that. So, you would add that comparison functionality here by generating the code:
https://github.com/brianzinn/react-babylonjs/blob/master/tools/generate-code.ts#L711

That is one part of the code that I wanted to clean up a lot - it works, but is not clean. I think there are many optimizations and further generalizations in that area.

You can run the generator with this:
yarn generate-code or npm run generate-code

If you want to debug the generator (like breakpoints in vscode) there are instructions at the top of the file generate-code.ts.

I'd really like to know more about your use-case for needing that property - if you can make a storybook story then we could maybe work through it together. Thanks for your interest in the project!

@hookex
Copy link
Contributor Author

hookex commented Feb 24, 2020

image

That's what my application looks like. It has many static or dynamic objects, and these
needs to be instanced or merged.

My application is complex, so I can't put it to storybook.

Your babylon react-reconciler layer is great.

Below is some origin code I coded. I will rewrite it by extending react-babylonjs.

    render() {
        const {data} = this.props;
        const {mesh, skeleton} = this.state;

        let instances = null;

        if (mesh) {
            instances = data.map((item, i) => {
                return <InstanceMesh
                    id={item.id} key={i}
                    mesh={mesh}
                    skeleton={skeleton}
                    index={i} data={item}/>
            })
        }

        return instances;
    }
   public createInstance(mesh: BABYLON.Mesh, data: InstanceData, name: string): BABYLON.InstancedMesh {
        const instance = mesh.createInstance(name);
        return instance;
    }
export function makeInstanceEdge(instance: BABYLON.InstancedMesh,) {
    instance.enableEdgesRendering();
    instance.edgesWidth = 10;
    instance.edgesColor = new BABYLON.Color4(0, 0, 1, 1);
}
/**
 * new api from babylon.js v4.1.0
 * 给instance上色
 * 必须先在mesh上注册,才有此api,mesh.registerInstancedBuffer("color", 4);
 * @param instance
 * @param hexColor
 */
export function makeInstanceColor(instance: BABYLON.InstancedMesh, hexColor?: string) {
    if (!instance.instancedBuffers) {
        return
    }

    let color4;

    if (hexColor) {
        color4 = BABYLON.Color4.FromHexString(hexColor);
    } else {
        color4 = new BABYLON.Color4(Math.random(), Math.random(), Math.random(), 1);
    }

    instance.instancedBuffers.color = color4;
}

@brianzinn
Copy link
Owner

I'm going to upgrade this project to 4.1 this week - I think the latest is probably the last RC version and we can incorporate your instancedBuffers.

Custom Objects that are created by something like mesh.createInstance(name) are probably better suited to a custom object (since they need an existing mesh to be created). We could have it search for the closest parent in the declared JSX (or by mesh name) using a custom LifecycleListener. I don't know how you are using skeleton (I can't see InstanceMesh). This can definitely be added and would be a really great addition!

I wanted earlier to create a hook for models, so the geometries could be used for instancing and I think this same concept can be re-used. So, a mesh hook can be used for creating instances as well. Would be interested as well as a declarative way to merge meshes after that to reduce draw calls.

@hookex
Copy link
Contributor Author

hookex commented Feb 26, 2020

Skeleton

In fact, Skeleton is not used by now. It was planned to be used for a robot arm. and use IK movement when it is linking an object.

refactor by use react-babylonjs

I am refactoring my application by using react-babylonjs, it works well, you did a great job!
Below is the refactored application(haven't use InstancedMesh)
image

transformNode bug

react-babylonjs don't support transformNode now. This is my temporary fix.

Add mesh suport

export default class MeshLifecycleListener implements LifecycleListener<Mesh> {
  onParented(parent: CreatedInstance<any>, child: CreatedInstance<any>) {
    // fix: transformNode ignored
    // todo: refactor
    if ((parent.metadata.isMesh || parent.metadata.className ==='FiberTransformNode') && child.metadata.isMesh) {
      // TODO: consider add option for setParent(), which parents and maintains mesh pos/rot in world space
      // child.hostInstance.setParent(parent.hostInstance)
      child.hostInstance.parent = parent.hostInstance
    }
  }
  onChildAdded(parent: CreatedInstance<any>, child: CreatedInstance<any>) {/* empty */}
  onMount(instance: CreatedInstance<Mesh>) {/* empty */}
  onUnmount(): void {/* empty */}
}

Add transformNodeLifecycleListener class

export default class TransformNodeLifecycleListener implements LifecycleListener<TransformNode> {
    onParented(parent: CreatedInstance<any>, child: CreatedInstance<any>) {
    }
    onChildAdded(parent: CreatedInstance<any>, child: CreatedInstance<any>) {/* empty */}
    onMount(instance: CreatedInstance<Mesh>) {/* empty */}
    onUnmount(): void {/* empty */}
}

Modify host config file.

    } else if (metadata.isMesh === true) {
      lifecycleListener = new CUSTOM_COMPONENTS.MeshLifecycleListener()
    } else if (metadata.className === 'FiberTransformNode') {
      // fix: transformNode not create
      lifecycleListener = new CUSTOM_COMPONENTS.TransformNodeLifecycleListener();
    }

Usage

        <transformNode
            name="floor-tnode"
            position={Vector3.Zero()}>

            {name && <Billboard
                name="floor-billboard"
                position={billboardPosition}
                text={name}/>}

            <plane name={id} key={id}
                   width={width} height={length}
                   position={planePosition}
                   rotation={new Vector3(Math.PI / 2, 0, 0)}
                   isPickable={true}>
                <standardMaterial
                    name={'mat' + id}
                    alpha={0.6}
                    diffuseColor={new Color3(1, 1, 1)}
                    backFaceCulling={false}/>
            </plane>
        </transformNode>

@brianzinn
Copy link
Owner

that's a good start. if you want to create a fork or I can start a branch we can get this added. I think it will be easier to add proper metadata - I have another open PR where somebody tried to parent to a camera, so having anything that inherits from TransformNode would be better than only 'isMesh'. I have time this weekend and maybe Thursday hopefully to build this out. Thanks for the ideas :)

@hookex
Copy link
Contributor Author

hookex commented Feb 26, 2020

I will create a fork and submit it in several days, maybe new features will be added when developing my application.

@hookex
Copy link
Contributor Author

hookex commented Mar 2, 2020

I wanted earlier to create a hook for models, so the geometries could be used for instancing and I think this same concept can be re-used. So, a mesh hook can be used for creating instances as well.

Do you mean by using ref and useEffect()?

@brianzinn
Copy link
Owner

Yes - just like that. I should have time this weekend. Would be like ‘useModel’. I’ve wanted to add instance code for some time :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants