I'm fairly new to threejs, wondering why I can't seem to add a simple mesh (torus with MeshBasicMaterial) to any scene.
The goal here is for me to add a sphere to the earth scene. No error is being thrown here, but the object is not appearing. Here's my code.
//// Imports ////
import './style.css'
import * as THREE from 'three'
import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls.js'
import * as dat from 'dat.gui'
//// Reference to Clouds ////
var cloudParticles = []
//// Texture Loader ////
const loader = new THREE.TextureLoader()
const star = loader.load('./star.png')
const cloud = loader.load('./smoke.png')
const earthNormalTexture = loader.load('/textures/earth_normal_map.png')
const earthTexture = loader.load('/textures/earth_texture.jpeg')
//// GUI ////
// const gui = new dat.GUI()
//// Canvas ////
const canvas = document.querySelector('canvas.webgl')
//// Scenes ////
const galaxy = new THREE.Scene()
const earth = new THREE.Scene()
const rubble_earth = new THREE.Scene()
//// Objects ////
const cloudGeometry = new THREE.PlaneGeometry(10.9, 10.5);
const particlesGeometry = new THREE.BufferGeometry;
const torusGeometry = new THREE.TorusGeometry( .7, .2, 16, 100 );
// Testing the sphere object
// const earthGeometry = new THREE.SphereGeometry(.5, 64, 64);
const cloudAmount = 100; // cloud amount
const particlesCnt = 10000; // particle amount
const posArray = new Float32Array(particlesCnt*3)
for(let i = 0; i < particlesCnt * 3; i++){
posArray[i] = 5*(Math.random() - 0.5)
}
particlesGeometry.setAttribute('position', new THREE.BufferAttribute(posArray,3));
//// Materials ////
const cloudMaterial = new THREE.MeshLambertMaterial({
map: cloud,
transparent: true
});
const particlesMaterial = new THREE.PointsMaterial({
size: 0.02,
map: star,
transparent: true,
color: 0xffd8a5
})
const earthMaterial = new THREE.MeshStandardMaterial({
metalness: 0.2,
roughness: 0.2,
normalMap: earthNormalTexture,
map: earthTexture
})
const basicMaterial = new THREE.MeshBasicMaterial()
//// Meshes ////
const particlesMesh = new THREE.Points(particlesGeometry,particlesMaterial)
const earthMesh = new THREE.Mesh(torusGeometry,basicMaterial)
galaxy.add(particlesMesh)
// Not working :(
// galaxy.add(earthMesh)
// adding cloud iteratively
for(let i = 0; i < cloudAmount; i++){
let cloudMesh = new THREE.Mesh( cloudGeometry, cloudMaterial );
cloudMesh.position.set(
Math.random()*25-3 - 7,
Math.random()*22-5 - 4,
Math.random()*5 -18.5
);
cloudMesh.rotation.z = Math.random()*2*Math.PI;
cloudMesh.material.opacity=0.15;
galaxy.add( cloudMesh );
console.log('added cloud')
cloudParticles.push(cloudMesh);
console.log(cloudParticles.length)
}
//// Lights ////
const ambient = new THREE.AmbientLight(0x555555);
const directionalLight = new THREE.DirectionalLight(0xff8c19,0.5);
const orangeLight = new THREE.PointLight(0xb76717,100,8,2);
const redLight = new THREE.PointLight(0xd8547e,100,8,1.5);
const blueLight = new THREE.PointLight(0x3677ac,100,8,3);
const pointLight = new THREE.PointLight(0xffffff, 0.1)
directionalLight.position.set(0,0,1);
orangeLight.position.set(-10,3,-14);
redLight.position.set(-5,3,-14);
blueLight.position.set(-5,3,-14);
pointLight.position.set(2,3,4);
//// Galaxy Scene ////
galaxy.add(ambient)
galaxy.add(directionalLight);
galaxy.add(orangeLight)
galaxy.add(redLight)
galaxy.add(blueLight)
galaxy.add(pointLight)
//// Earth Scene ////
const pointLightTwo = new THREE.PointLight(0xffffff, 0.1);
pointLightTwo.position.x = 2
pointLightTwo.position.y = 3
pointLightTwo.position.z = 4
earth.add(pointLightTwo)
//// Fog ////
galaxy.fog = new THREE.FogExp2(0x020008, 0.001);
/**
* Sizes
*/
const sizes = {
width: window.innerWidth,
height: window.innerHeight
}
window.addEventListener('resize', () =>
{
// Update sizes
sizes.width = window.innerWidth
sizes.height = window.innerHeight
// Update camera
camera.aspect = sizes.width / sizes.height
camera.updateProjectionMatrix()
// Update renderer
renderer.setSize(sizes.width, sizes.height)
renderer.setClearColor(galaxy.fog.color)
renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2))
})
/**
* Camera
*/
// Base camera
const camera = new THREE.PerspectiveCamera(75, sizes.width / sizes.height, 0.1, 100)
camera.position.x = 0
camera.position.y = 0
camera.position.z = 2
galaxy.add(camera)
earth.add(camera)
rubble_earth.add(camera)
// Controls
// const controls = new OrbitControls(camera, canvas)
// controls.enableDamping = true
/**
* Renderer
*/
const renderer = new THREE.WebGLRenderer({
canvas: canvas,
alpha: true
})
renderer.setSize(sizes.width, sizes.height)
renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2))
renderer.setClearColor(galaxy.fog.color)
renderer
/**
* Animate
*/
// GUI
// gui.add(earthMesh.postion,"y").min(-10).max(10).step(0.5)
// gui.add(earthMesh.postion,"x").min(-10).max(10).step(0.5)
// gui.add(earthMesh.postion,"z").min(-10).max(10).step(0.5)
// Base Scene
let scene = galaxy;
window.addEventListener("keydown", (event) => {
console.log(event.key)
switch(event.key) {
case "1":
scene = galaxy;
document.getElementById("title1").style.visibility = "visible";
break;
case "2":
scene = earth;
document.getElementById("title1").style.visibility = "hidden";
break;
case "3":
scene = rubble_earth;
document.getElementById("title1").style.visibility = "hidden";
break;
}
}, true);
const clock = new THREE.Clock()
const tick = () =>
{
const elapsedTime = clock.getElapsedTime()
// Update objects
particlesMesh.rotation.x = .01 * elapsedTime
particlesMesh.rotation.y = .05 * elapsedTime
cloudParticles.forEach(cl => {
cl.rotation.z -= 0.002;
})
// Update Orbital Controls
// controls.update()
renderer.render(scene, camera)
// Call tick again on the next frame
window.requestAnimationFrame(tick)
}
tick()
Also, eventually I want to make the sphere have this normal map and texture of the earth, is SphereGeometry the right Geometry to do this on?
I've tried messing around with the order of the objects being added to the galaxy
scene, but nothing seems to work. Please help!
Your problem stems from these lines:
galaxy.add(camera)
earth.add(camera)
rubble_earth.add(camera)
On their face, these lines would appear to make camera
a child of galaxy
, earth
, and rubble_earth
. In fact, however, the first line makes it a child of galaxy
, then the second removes it from galaxy
and makes it a child of earth
, and then the third removes it from earth
and makes it a child of rubble_earth
.
The side-effect is that the camera's world matrix is never being updated to reflect its new position, and the camera continues to render from the perspective of (0, 0, 0) (its initial position), looking down -z.
Either remove the second and third lines (in which case, galaxy
, being a Scene
, will call camera
's .updateMatrixWorld()
before rendering), or else remove all three (in which case, the renderer will call it).