I'm trying to create a scene from a set of triangles using Threejs. To get the shape of all the triangles i used a BufferGeometry
which seems to create the shape correctly. However, it does not respond to lighting. I have tried with several different materials including standard, phong and lambert. With on luck. I understood that one might need to compute normals to the mesh, so i tried adding computeVertexNormals
to the code as well but no luck. Ive also tried using flatshading, but that did not seem to have any effect either.
I then figured it might be the geometry and not the material that was throwing me of, so I tried adding a spinning torus to my scence using phong material, but it does not get iluminated either.
The code I have so far is this:
import * as THREE from 'three';
import {OrbitControls} from 'three/addons/controls/OrbitControls.js';
const canvas = document.querySelector('#c')
const scene = new THREE.Scene();
const camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000000);
const renderer = new THREE.WebGLRenderer({antialias: true,castShadow:true, canvas});
const controls = new OrbitControls(camera, canvas)
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement)
const topoGeometry = new THREE.BufferGeometry();
// Fetching triangles from static file
await fetch('http://{localserver}/topography.json')
.then((response) => response.json())
.then((json) => {
const vertices = new Float32Array(json.geometry.vertices.map((coord) => {
return [coord[0], coord[1], coord[2]]
}).flat())
const indices = json.geometry.triangles.flat()
topoGeometry.setIndex( indices )
topoGeometry.setAttribute('position', new THREE.BufferAttribute(vertices, 3))
topoGeometry.computeVertexNormals()
});
const topoMaterial = new THREE.MeshStandardMaterial({
wireframe: false,
color: 0x00ff00,
});
const topo = new THREE.Mesh( topoGeometry, topoMaterial )
scene.add(topo)
camera.position.z = 2000;
camera.position.x = 0;
camera.position.y = 0;
const torusGeometry = new THREE.TorusGeometry(50,50)
const torusMaterial = new THREE.MeshPhongMaterial()
const torus = new THREE.Mesh(boxGeometry, boxMaterial)
torus.position.setZ(400)
scene.add(torus)
//Adding pointlight to scene
const light = new THREE.PointLight( 0xffffff, 1, 1000 );
light.position.set( 0, 0, 600 );
light.castShadow = true;
scene.add( light );
const lighthelper = new THREE.PointLightHelper(light,30, 0xffffff)
const gridHelper = new THREE.GridHelper(3000,50)
gridHelper.rotateX(Math.PI / 2)
scene.add(lighthelper, gridHelper)
function animate(){
requestAnimationFrame(animate)
camera.updateProjectionMatrix()
controls.update(0.01)
box.rotateX(0.01)
box.rotateY(0.01)
renderer.render(scene, camera)
}
animate()
Point lights use a physically correct unit (candela) with latest three.js
releases so an intensity value of 1
is way too low for your scene. Since it has a large scale, try it with a value around 100000
or even higher.
Depending on what geometry you are showing, consider to scale down the scene to a physically correct scale. 1 world unit should correspond to 1 meter. If your geometry represents a terrain, consider to use a directional light since it better represents the sun/daylight.