Reputation: 1570
I am trying to load a flag (gif) texture to a sphere geometry in THREE.js, but the caveat is I am using React to do this.
const textureLoader = new THREE.TextureLoader();
const flag = getFlagForCountry(flags, x.id),
texture = textureLoader.load(require(`../assets/images/flags/${flag.name}.gif`));
const mat = new THREE.MeshLambertMaterial({
transparent: true,
opacity: .5,
map: texture
});
const sphere = new THREE.Mesh(new THREE.SphereGeometry(1, 10, 10), mat);
sphere.overdraw = true;
When I remove the map: texture
property I am able to see the sphere in the scene, but then when I add back in the texture it is simply a black screen. I know the docs for TextureLoader
say url
is a string, but I am not getting any errors and in fact I am getting warnings that make it appear like something is working. Has anyone had success loading a texture onto a sphere using require()
in React.
THREE.WebGLRenderer: image is not power of two (1181x788). Resized to 1024x512
<img crossorigin="anonymous" src="/static/media/Argentina.4c3ff3da.gif">
Upvotes: 2
Views: 3011
Reputation: 45140
import React, { Component } from "react";
import * as THREE from "three";
var earthMesh;
class ThreeScene extends Component {
componentDidMount() {
const width = this.mount.clientWidth;
const height = this.mount.clientHeight;
//ADD SCENE
this.scene = new THREE.Scene();
//ADD CAMERA
this.camera = new THREE.PerspectiveCamera(75, width / height, 0.1, 1000);
this.camera.position.z = 8;
//ADD RENDERER
this.renderer = new THREE.WebGLRenderer({ antialias: true });
this.renderer.setClearColor("#263238");
this.renderer.setSize(width, height);
this.mount.appendChild(this.renderer.domElement);
//ADD CUBE
const geometry = new THREE.BoxGeometry(5, 5, 5);
const material = new THREE.MeshBasicMaterial({
color: "#0F0",
wireframe: true
});
this.cube = new THREE.Mesh(geometry, material);
this.scene.add(this.cube);
//Add SPHERE
//LOAD TEXTURE and on completion apply it on box
var loader = new THREE.TextureLoader();
loader.load(
"data:image/png;base64,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",
this.onLoad,
this.onProgress,
this.onError
);
//LIGHTS
var lights = [];
lights[0] = new THREE.PointLight(0x304ffe, 1, 0);
lights[1] = new THREE.PointLight(0xffffff, 1, 0);
lights[2] = new THREE.PointLight(0xffffff, 1, 0);
lights[0].position.set(0, 200, 0);
lights[1].position.set(100, 200, 100);
lights[2].position.set(-100, -200, -100);
this.scene.add(lights[0]);
this.scene.add(lights[1]);
this.scene.add(lights[2]);
}
componentWillUnmount() {
this.stop();
this.mount.removeChild(this.renderer.domElement);
}
start = () => {
if (!this.frameId) {
this.frameId = requestAnimationFrame(this.animate);
}
};
stop = () => {
cancelAnimationFrame(this.frameId);
};
animate = () => {
this.earthMesh.rotation.x += 0.01;
this.cube.rotation.y += 0.01;
this.renderScene();
this.frameId = window.requestAnimationFrame(this.animate);
};
renderScene = () => {
this.renderer.render(this.scene, this.camera);
};
onLoad = texture => {
var objGeometry = new THREE.SphereBufferGeometry(3, 35, 35);
var objMaterial = new THREE.MeshPhongMaterial({
map: texture,
shading: THREE.FlatShading
});
this.earthMesh = new THREE.Mesh(objGeometry, objMaterial);
this.scene.add(this.earthMesh);
this.renderScene();
//start animation
this.start();
};
onProgress = xhr => {
console.log((xhr.loaded / xhr.total) * 100 + "% loaded");
};
// Function called when download errors
onError = error => {
console.log("An error happened" + error);
};
render() {
return (
<div
style={{ width: "400px", height: "400px" }}
ref={mount => {
this.mount = mount;
}}
/>
);
}
}
export default ThreeScene;
https://codesandbox.io/embed/kw7l49nw1r
Upvotes: 0
Reputation: 30390
I would recommend passing the image path directly to the .load()
method rather than passing it via require()
. Also, I suggest using the TextureLoader
callback, to ensure that your texture object is valid and fully loaded, before trying to make use of it.
You can make use of the callback in this way:
const textureLoader = new THREE.TextureLoader();
const flag = getFlagForCountry(flags, x.id)'
// Use the loaders callback
textureLoader.load(`../assets/images/flags/${flag.name}.gif`, function(texture) {
// The texture object has loaded and is now avalible to be used
const mat = new THREE.MeshLambertMaterial({
transparent: true,
opacity: .5,
map: texture
});
const sphere = new THREE.Mesh(new THREE.SphereGeometry(1, 10, 10), mat);
sphere.overdraw = true;
// Add sphere to your scene ... scene.add(sphere);
});
As a final note, consider adjusting your image filepath to an absolute path (by removing the ..
) if your assets
directory is located in the same directory that your webserver is running from.
Hope this helps!
Upvotes: 1