react-three-renderer
react-three-renderer copied to clipboard
Directional light too dark / not hitting object?
I've taken the three.js OBJLoader example and converted it to a React component.
As you can see in the screenshots below, something is off with the lighting. Even after increasing the intensity to 5, the directional light looks very dark, as if only the object's edges are illuminated.
Any idea what I might be doing wrong? Does your library set any defaults that I'm not taking into account? (I have no prior experience with three.js)
Original (source):
My result (source below):
import React from 'react';
import React3 from 'react-three-renderer';
import * as THREE from 'three';
import * as OBJLoader from 'three-obj-loader';
import uvGrid from '../../src/assets/images/uv-grid.jpg';
import male from '../../src/assets/objects/male.obj';
OBJLoader(THREE);
class Example extends React.Component {
constructor(props, context) {
super(props, context);
this.state = {
objectRotation: new THREE.Euler(),
};
this.lightPosition = new THREE.Vector3(0, 0, 1);
this.objectPosition = new THREE.Vector3(0, -95, 0);
this.cameraPosition = new THREE.Vector3(0, 0, 300);
this.loadObject();
}
componentWillUnmount() {
if (this.state.object) {
this.group.remove(this.state.object);
}
}
setGroup = (ref) => {
this.group = ref;
}
loadObject() {
const manager = new THREE.LoadingManager();
manager.onProgress = (item, loaded, total) => {
console.log(item, loaded, total);
};
const onProgress = (xhr) => {
if (xhr.lengthComputable) {
const percentComplete = (xhr.loaded / xhr.total) * 100;
console.log(`${Math.round(percentComplete, 2)}% downloaded`);
}
};
const texture = new THREE.Texture();
const imgLoader = new THREE.ImageLoader(manager);
imgLoader.load(uvGrid, (image) => {
texture.image = image;
texture.needsUpdate = true;
});
const objLoader = new THREE.OBJLoader(manager);
objLoader.load(male, (object) => {
object.traverse((child) => {
if (child instanceof THREE.Mesh) {
child.material.map = texture;
}
});
this.group.add(object);
this.setState({ object });
}, onProgress);
}
animate = () => {
this.setState({
objectRotation: new THREE.Euler(
0, this.state.objectRotation.y + 0.05, 0,
),
});
};
render() {
const width = 600;
const height = 600;
return (
<React3
mainCamera="camera"
width={width}
height={height}
pixelRatio={window.devicePixelRatio}
onAnimate={this.animate}
>
<scene>
<perspectiveCamera
name="camera"
fov={45}
aspect={width / height}
near={1}
far={2000}
position={this.cameraPosition}
/>
<ambientLight
color={0x101030}
/>
<directionalLight
color={0xffeedd}
position={this.lightPosition}
intensity={5}
/>
<group
ref={this.setGroup}
position={this.objectPosition}
rotation={this.state.objectRotation}
/>
</scene>
</React3>
);
}
}
export default Example;
Ah yes, this is because Three does directional light rotation in a strange way...
See https://github.com/toxicFork/react-three-renderer/issues/65#issuecomment-219002299
I think this should make it work the same as vanilla threejs:
// anywhere in the file, e.g. before the class
const origin = new THREE.Vector3(0, 0, 0);
// in the render
<directionalLight
// other props
lookAt={origin}
/>
I will need to add a note to directional light properties to explain this.
I guess it's "kind of a bug" that it behaves different than Three, but I'll still find a way to fix it without having inconsisterncies in behaviour with other components... (e.g. require one of the rotation properties?)
Nice, that fixed it. Thanks a lot!
Happy to hear :)