three.jsmeshscene

Why can't I add more meshes to my threejs scene?


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!


Solution

  • 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).