[Solved] Loaded texture not applied to object in React.js app

Im just start learning three.js and try combine it with react.

Problem is:
texture has loaded (on debug I can check it on const texture = this.state.texture string), but my rendered on canvas object is still black.

source code:

        import './game.scss';
        import MainBar from '../MainBar/MainBar.jsx';
        import Slide from '@material-ui/core/Slide';
        import AsideLinks from '../AsideLinks/AsideLinks.jsx';
        import Footer from '../Footer/Footer.jsx';
        import { withStyles } from '@material-ui/core/styles';
        import * as THREE from 'three';

    const onWindowResize = () => {
        camera.aspect = container.clientWidth / container.clientHeight;
        camera.updateProjectionMatrix();
        renderer.setSize( container.clientWidth, container.clientHeight );
    }

    const styles = theme => ({
        page: theme.aside.page,
        aside: theme.aside.aside,
        body: {
            ...theme.aside.body,
            minHeight: 'initial',
            height: 'calc(100% - 81px)',
        },
        canvas: {
            height: '100%',
            width: '100%',
        }
    });

    window.addEventListener( 'resize', onWindowResize );

    let container, scene, camera, mesh, renderer;

    const update = () => {
        mesh.rotation.z += 0.01;
        mesh.rotation.x += 0.01;
        mesh.rotation.y += 0.01;
    }

    const render3 = () => {
        renderer.render( scene, camera );
    }

    class Game extends React.Component {
        constructor(props) {
            super(props);
            this.state = {
                isAsideOpen: false,
                mesh: mesh,
                texture: null,
            }

        this.toggleAside = this.toggleAside.bind(this);
    }

    componentDidMount = () => {
        this.setState({mesh: mesh});
        this.getTexture().then(
            t => this.setState({texture: t})
        );
    }
    
    componentDidUpdate = () => {
        if (this.state.texture !== null) {
            this.init();
        }
    }

    getTexture = () => {
        return new Promise(async (s, r) => {
            const textureLoader = new THREE.TextureLoader();
            let t = await textureLoader.load( 'textures/uv_test_bw.png' );
            s(t)
        })
    }

    toggleAside = () => {
        this.setState({isAsideOpen: !this.state.isAsideOpen});
    }

    init = () => {
        container = document.querySelector( '#scene-container' );
        scene = new THREE.Scene();
        scene.background = new THREE.Color(0x333333);
    
        const fov = 35;
        const aspect = container.clientWidth / container.clientHeight;
        const near = 0.1;
        const far = 100;
    
        camera = new THREE.PerspectiveCamera( fov, aspect, near, far );
        camera.position.set( 4, 2, 20 );
        camera.lookAt(new THREE.Vector3(0,0,0));
    
        const geometry = new THREE.BoxBufferGeometry( 2, 2, 2 );
        
        const texture = this.state.texture;
        texture.encoding = THREE.sRGBEncoding;
        texture.anisotropy = 16;
        const material = new THREE.MeshStandardMaterial( {
            map: texture,
          } );
        mesh = new THREE.Mesh( geometry, material );
        
    
        const light = new THREE.DirectionalLight( 0xffffff, 5.0 );
        light.position.set( 10, 10, 10 );
        scene.add( light );
    
        scene.add( mesh );
    
        renderer = new THREE.WebGLRenderer({antialias: true});
        renderer.setSize( container.clientWidth, container.clientHeight );
        renderer.setPixelRatio( window.devicePixelRatio );
        container.appendChild( renderer.domElement );
    
        renderer.setAnimationLoop( ()=>{
            update();
            render3();
        })
    }

    render = () => {

    const {classes} = this.props;
    return  <div className={classes.page}>
            <MainBar toggleAside={this.toggleAside}></MainBar>
            <Slide className={classes.aside} direction="right" in={this.state.isAsideOpen} mountOnEnter unmountOnExit>
                <AsideLinks/>
            </Slide>
            <div id="scene-container" className={classes.body}>
            </div>
            <Footer/>
        </div>;
    }    
}

export default withStyles(styles)(Game);

Do you see the mesh when applying a simple color to the material?

const material = new THREE.MeshStandardMaterial( { color: 0xff0000  } );

Fixed.

I just forgot include file-loader to webpack.config and there was wrong path regarding this image import.

Hello, @Mugen87.
I have a problem with applying materials to the loaded model. And in my case I don’t see the material when trying apply a simple color like in your example (MeshStandardMaterial).
What may cause this?

Try to add some lights to your scene and see if it solves your problem. Something like:

var ambientLight = new THREE.AmbientLight( 0xcccccc, 0.4 );
scene.add( ambientLight );

var pointLight = new THREE.PointLight( 0xffffff, 0.8 );
camera.add( pointLight );
scene.add( camera );

This is done, but doesn’t solve the problem. I’ll better create a new topic because I’m struggling with this for 3 days in a row. And tried everything.

Hey, just for future users. import the image at the top of the file as a variable like you would with a regular react file and then use that variable WITHOUT the curly braces in the load() function.

eg.
import imageVarName from “./imagepath”
const loader = new THREE.TextureLoader();
const material = new THREE.PointsMaterial({
map: loader.load(imageVarName),
});

Yep - by using loader.load({ imageVarName }) someone would be basically trying to load a stringified object, ie. "[object Object]" (ES6 prop-shorthand.)

Keep in mind this is heavily dependent on your setup and bundler. :slight_smile: