I want to render a 3D gltf model using react-babylonjs. On a button click event, I want to change the model’s texture.
I have tried the code below, but new texture is not geting applied to the model:
<Model
rotation={modelRotation} position={modelPosition}
rootUrl={${baseUrl}car/
} sceneFilename=“lowpolyCar.gltf” }
scaling={modelScaling}>
<standardMaterial
albedoTexture={${baseUrl}car/textures/carTex1.png
}
/>
I want to specifically update index 1 of the loaded meshes in the scene array.
Same model, and texture application works in babylonjs like this:
myMesh.loadedMeshes[1].albedoTexture = new BABYLON.Texture(“textureURL”, scene, true, false);
Pinging @brianzinn who owns that space
Firstly, the texture I haven’t tried assigning directly - definitely it won’t work to assign a URL.
You can you try this:
<standardMaterial>
<texture assignTo="albedoTexture" url={'${baseUrl}car/textures/carTex1.png'} />
</standardMaterial>
What you will find though is that it will assign it to the root mesh, which is a mesh that is not part of your original model and the texture assignment will not be visible. The root mesh is added by the <Model />
and allows you to scale and position the model as you have done (even though a model can have multiple meshes). The onModelLoaded
is the handler you would need to assign the textures imperatively as you have done. I have been working on a new declarative way that looks like this:
import { useLoader } from 'react-babylonjs';
// this hook doesn't exist right now!
const [model] = useLoader(rootUrl, sceneFilename);
<mesh assignFrom={model.meshes[0]}>
<standardMaterial>
<texture assignTo="albedoTexture" url={'${baseUrl}car/textures/carTex1.png'} />
</standardMaterial>
</mesh>
You may be able to do it right now though using assignTo
- I can probably do that easily by adding the loaded model somewhere if not available. The assign to will walk the object heirarchy and assign dynamically. For example:
<texture assignTo="meshes[0].albedoTexture" ... />
I think there are going to be a lot of edge cases and issues with a declarative design - as here for example, it would remove the existing materials and textures.
I should be able to get the last example working for you by adding a property. I have a releases going out soon that fixes a bunch of github issues and can get that out quickly. Are you able to share a repo?
Shared the repo on personal message.
1 Like
You will need to wait for next NPM - this works and clicking your colour buttons changes the albedoTexture on your car I was missing a couple of changes:
- Texture to be able to assign to model (was only able to assign directly to materials before)
- Update ‘assignTo’ to work with arrays, so we can do
meshes[0].material.albedoTexture
.
import React, { useState } from 'react';
import { Engine, Scene } from 'react-babylonjs'
import { Vector3 } from '@babylonjs/core';
// DefaultPlayground from your repo - changed it around a bit
export default (props) => {
const [modelState, setModelState] = useState(null);
return (<div style={{ height: '100%', width: '100%' }}>
<Engine antialias adaptToDeviceRatio canvasId='babylonJS' style={{ height: '100%', width: '100%' }} >
<Scene canvasId="scene_1" style={{ height: '100%', width: '100%' }} >
<arcRotateCamera name="arc" target={new Vector3(0, 1, 0)} minZ={1} alpha={(-Math.PI / 2) + 0.5 } beta={(0.5+ (Math.PI / 4))} radius={10} lowerBetaLimit={(Math.PI / 2) - 1.5} upperBetaLimit={4}
lowerRadiusLimit={1.84} />
<hemisphericLight name="light1" intensity={0.7} direction={Vector3.Up()} />
<model
rotation={props.modelRotation} position={props.modelPosition}
rootUrl={`assets/car/`} sceneFilename={props.modelUrl}
onModelLoaded={model => setModelState(model)}
scaling={props.modelScaling}>
{modelState &&
<texture key={props.textureUrl} name={props.textureUrl} assignTo={'meshes[1].material.albedoTexture'} url={`assets/${props.textureUrl}`} />
}
</model>
</Scene>
</Engine>
</div>)
};
Your main app looks then like this:
<div className="App">
<div style={{ height: '75%', width: '50%', padding: '5px' }}>
<DefaultPlayground
modelUrl='lowpolyCar.gltf'
modelRotation={modelRotation}
modelScaling={modelScaling}
modelPosition={modelPosition}
textureUrl={this.state.texturePath}
/>
</div>
<ColorPanel1 changeColor={this.changeColor} />
</div>
Cool idea what you are building! Cheers.
I published a beta NPM yesterday, if you want to try it out.
Hi @brianzinn,
I have tried the npm package version: 2.2.1-beta.2
It’s giving me an error:
./node_modules/react-babylonjs/dist/react-babylonjs.js
Module not found: Can’t resolve ‘@babylonjs/core/Materials/Node/nodeMaterial’ in node_modules\react-babylonjs\dist’
So, is the error related to the npm package or something else?
I hope not. I did change “type”:“module” in package.json, but I also tested it out on another CRA project. Is your repository up to date with a repro? I can check that if so. Otherwise also there is a 2.2.1 out that hopefully has no issues