Is it possible to not render shadows or move the light while I rotate the object?
ambev7labs opened this issue · 3 comments
ambev7labs commented
My rendered object has a lot of details and the shadows are hiding them
ACERY1 commented
same problem
JoueBien commented
Been looking to solve this myself. Here is an excerpt with the lighting issue fixed and a number of the modern react issues solved. Still looking to port the entire thing over to FC but haven't gotten that far yet.
import React, {Component} from 'react';
import PropTypes from 'prop-types'
import ReactDOM from 'react-dom';
import * as THREE from 'three';
import STLLoaderModule from 'three-stl-loader'
import OrbitControlsModule from 'three-orbit-controls'
import {ScaleLoader} from 'react-spinners';
const STLLoader = STLLoaderModule(THREE);
const OrbitControls = OrbitControlsModule(THREE);
function lightOnScene (scene, x, y, z, brightness) {
const directionalLight = new THREE.DirectionalLight(0xffffff, brightness);
directionalLight.position.x = x;
directionalLight.position.y = y;
directionalLight.position.z = z;
directionalLight.position.normalize();
scene.add(directionalLight);
return directionalLight
}
function ambientLightOnScene(scene, brightness) {
const ambientLight = new THREE.AmbientLight(0x404040, brightness); // soft white light
scene.add(ambientLight);
}
class STLViewer extends Component {
static propTypes = {
className: PropTypes.string,
url: PropTypes.string,
file: PropTypes.object,
width: PropTypes.number,
height: PropTypes.number,
backgroundColor: PropTypes.string,
modelColor: PropTypes.string,
sceneClassName: PropTypes.string,
onSceneRendered: PropTypes.func,
lightIntensity: PropTypes.number,
};
static defaultProps = {
backgroundColor: '#EAEAEA',
modelColor: '#B92C2C',
lineColor: '#000000',
height: 400,
width: 400,
rotate: true,
orbitControls: true,
sceneClassName: '',
lightIntensity: 0.4,
};
componentDidMount() {
this.renderModel(this.props);
}
renderModel(props) {
let camera, scene, renderer, mesh, distance, controls;
const {url, file, width, height, modelColor, backgroundColor, orbitControls, sceneClassName, onSceneRendered, lineColor, lightIntensity} = props;
let xDims, yDims, zDims;
scene = new THREE.Scene();
distance = 10000;
// Light all sides
// lightOnScene(scene, 0, 1, 0, lightIntensity)
// lightOnScene(scene, 0, -1, 0, lightIntensity)
// lightOnScene(scene, 1, 0, 0, lightIntensity)
// lightOnScene(scene, -1, 0, 0, lightIntensity)
// lightOnScene(scene, 0, 0, 1, lightIntensity)
// lightOnScene(scene, 0, 0, -1, lightIntensity)
// BG Lighting
ambientLightOnScene(scene, lightIntensity)
// When We load show model
const onLoad = geometry => {
// geometry.computeFaceNormals();
geometry.computeVertexNormals();
geometry.center();
// Edge Lines
const edges = new THREE.EdgesGeometry( geometry );
const line = new THREE.LineSegments( edges, new THREE.LineBasicMaterial( {
color: lineColor,
linewidth: 3,
} ) );
// Mesh
mesh = new THREE.Mesh(
geometry,
new THREE.MeshLambertMaterial({
// overdraw: true,
color: modelColor,
}
));
// Some extra stuff
geometry.computeBoundingBox();
xDims = geometry.boundingBox.max.x - geometry.boundingBox.min.x;
yDims = geometry.boundingBox.max.y - geometry.boundingBox.min.y;
zDims = geometry.boundingBox.max.z - geometry.boundingBox.min.z;
// Add items to Scene
scene.add(mesh);
scene.add(line);
// Set the Camera
camera = new THREE.PerspectiveCamera(30, width / height, 1, distance);
camera.position.set(0, 0, Math.max(xDims * 3, yDims * 3, zDims * 3));
scene.add(camera);
// Set Render
renderer = new THREE.WebGLRenderer({
preserveDrawingBuffer: true,
antialias: true
});
renderer.setSize(width, height);
renderer.setClearColor(backgroundColor, 1);
renderer.domElement.className = sceneClassName;
// Set controlls
if (orbitControls) {
controls = new OrbitControls(camera, this.container.current);
controls.enableKeys = false;
controls.addEventListener('change', orbitRender);
}
// hack instead of state managment becase reasons?
this.container.current.replaceChild(renderer.domElement, this.firstChild.current)
// Call render
render();
// Run call back on render changed
if (typeof onSceneRendered === "function") {
onSceneRendered(this.container.current)
}
};
const onProgress = (xhr) => {
if (xhr.lengthComputable) {
let percentComplete = xhr.loaded / xhr.total * 100;
}
};
// Load model in and then show it
const loader = new STLLoader();
if (file) {
loader.loadFile(file, onLoad, onProgress);
} else {
loader.load(url, onLoad, onProgress);
}
const render = () => {
renderer.render(scene, camera);
};
const orbitRender = () => {
render();
};
}
shouldComponentUpdate(nextProps, nextState) {
if (JSON.stringify(nextProps) === JSON.stringify(this.props)) {
return false
}
return true
}
componentDidUpdate(nextProps, nextState) {
this.renderModel(nextProps);
}
componentDidCatch(error, info) {
console.log(error, info)
}
constructor (props) {
super(props);
// Refs
this.container = React.createRef();
this.firstChild = React.createRef();
}
render() {
return (
<div
ref={this.container}
className={this.props.className}
style={{
width: this.props.width,
height: this.props.height,
overflow: 'hidden',
}}
>
<div
ref={this.firstChild}
style={{
height: '100%',
display: 'flex',
justifyContent: 'center',
alignItems: 'center',
}}>
<ScaleLoader
color={'#123abc'}
loading={true}
/>
</div>
</div>
);
};
};
export {
// OBJViewer,
STLViewer
}
<STLViewer
url={`${window.location.origin}/${publicPath}`}
modelColor="#ffa500"
className='wrapper'
sceneClassName='canvas'
height={800}
width={800}
lightIntensity={4}
/>
JoueBien commented
Basically the same thing but in an FC and without having to replace the dom.
import React, {Suspense, useRef, useState} from 'react';
import * as THREE from 'three';
import {
Canvas, ambientLight,
lineSegments, edgesGeometry, lineBasicMaterial,
pointLight, meshStandardMaterial, color
} from '@react-three/fiber'
import { OrbitControls } from "@react-three/drei"
import {STLLoader} from 'three/examples/jsm/loaders/STLLoader'
import { useLoader } from '@react-three/fiber'
function StlGeometry(props) {
// Props
const {
url, file, width, height,
modelColor, backgroundColor, className, orbitControls,
onSceneRendered, lineColor, linewidth, brightness,
onGeometryLoaded
} = props
// State
const bufferedGeometry = useLoader(STLLoader, url)
// Computed
if (bufferedGeometry) {
bufferedGeometry.computeVertexNormals()
bufferedGeometry.center()
bufferedGeometry.computeBoundingBox()
onGeometryLoaded(bufferedGeometry)
}
// ..
return <>
{/* The 3D object */}
<mesh
castShadow
receiveShadow
position={[0, 0, 0]}
geometry={bufferedGeometry}
>
<meshStandardMaterial color={modelColor} />
</mesh>
{/* The edge lines in a color */}
<lineSegments>
<edgesGeometry
attach="geometry"
args={[bufferedGeometry]}
/>
<lineBasicMaterial
color={lineColor || 'black'}
attach="material"
linewidth={linewidth || 1}
/>
</lineSegments>
</>
}
export const STLViewerFC = (props) => {
// Props
const {
url, file, width, height,
modelColor, backgroundColor, className, orbitControls,
onSceneRendered, lineColor, linewidth, brightness,
} = props
// Ref
const container = useRef()
// State
const distance = 10000;
const [camera, setCamera] = useState(
new THREE.PerspectiveCamera(30, width / height, 1, distance)
)
// When the obj loads move the camera to a good position
const onGeometryLoaded = (geometry) => {
const xDims = geometry.boundingBox.max.x - geometry.boundingBox.min.x;
const yDims = geometry.boundingBox.max.y - geometry.boundingBox.min.y;
const zDims = geometry.boundingBox.max.z - geometry.boundingBox.min.z;
camera.position.set(0, 0, Math.max(xDims * 3, yDims * 3, zDims * 3));
setCamera(camera)
}
// On update pass up ref
if (typeof onSceneRendered === "function") {
onSceneRendered(container)
}
// ..
return <>
{/* Make sure we wait for the 3D obj to load */}
<Suspense fallback={null}>
<Canvas
ref={container}
className={className}
style={{
width: width || '400px',
height: height || '400px',
overflow: 'hidden',
}}
camera={camera}
backgroundColor={backgroundColor || '#EAEAEA'}
>
{/* Light up the entire scene */}
<ambientLight
brightness={brightness || 5}
/>
{/* The 3D object */}
<StlGeometry {...props} onGeometryLoaded={onGeometryLoaded} />
{/* Background */}
<color attach="background" args={[backgroundColor || "#EAEAEA"]} />
{/* Enable Orbit Controls */}
{orbitControls === true && <>
<OrbitControls />
</>}
</Canvas>
</Suspense>
</>
}
export {
// OBJViewer,
// STLViewer,
// STLViewerFC
}