three.js Not working orbit around Parent Node - javascript

import * as THREE from "three";
// // Canvas
const canvas = document.querySelector("canvas.webgl");
// // Scene
const scene = new THREE.Scene();
// Renderer
const renderer = new THREE.WebGLRenderer({
canvas: canvas,
});
renderer.setSize(1200, 800);
const objects = [];
const radius = 1;
const widthSegments = 6;
const heightSegments = 6;
const sphereGeometry = new THREE.SphereGeometry(
radius,
widthSegments,
heightSegments
);
const solarSystem = new THREE.Object3D();
scene.add(solarSystem);
objects.push(solarSystem);
const sunMaterial = new THREE.MeshPhongMaterial({ emissive: "red" });
const sunMesh = new THREE.Mesh(sphereGeometry, sunMaterial);
sunMesh.scale.set(5, 5, 5);
solarSystem.add(sunMesh);
objects.push(sunMesh);
const EarthSystem = new THREE.Object3D();
solarSystem.add(EarthSystem);
objects.push(EarthSystem);
const earthMaterial = new THREE.MeshPhongMaterial({ emissive: "blue" });
const earthMesh = new THREE.Mesh(sphereGeometry, earthMaterial);
earthMesh.position.x = 20;
earthMesh.scale.set(2, 2, 2);
EarthSystem.add(earthMesh);
objects.push(earthMesh);
const MoonMaterial = new THREE.MeshPhongMaterial({ emissive: "gray" });
const moonMesh = new THREE.Mesh(sphereGeometry, MoonMaterial);
EarthSystem.add(moonMesh);
moonMesh.position.x = 25;
objects.push(moonMesh);
/**
* Sizes
*/
const sizes = {
width: 1200,
height: 800,
};
/**
* Camera
*/
const camera = new THREE.PerspectiveCamera(
60,
sizes.width / sizes.height,
0.1,
500
);
camera.position.set(0, 50, 0);
camera.up.set(0, 0, 1);
camera.lookAt(0, 0, 0);
scene.add(camera);
// /**
// * Renderer
// */
function animate() {
requestAnimationFrame(animate);
objects.forEach((obj) => {
obj.rotation.y += 0.007;
});
renderer.render(scene, camera);
}
animate();
I am making solar system. In center I make Sun add in SolarSystem first. And then I make EarthSystem and add in SolarSystem. Earth in EarthSystem and normally orbit around Sun. But I have problem in Moon. I make Moon and add in EarthSystem but not orbit around earth only around Sun with earth. How can I solve this problem?

Related

ThreeJS is not casting shadows

I am building a basic Three JS application. Basically, I am learning Three JS and so that I am experimenting with it. Now, I am building a scene where there is a floor, an object and a light. I want to see the shadow of the object on the floor due to light. This is my code.
import * as THREE from 'three';
const scene = new THREE.Scene();
const aspect_ratio = window.innerWidth / window.innerHeight;
const camera = new THREE.PerspectiveCamera(75, aspect_ratio, 1, 10000);
camera.position.z = 500;
scene.add(camera);
const renderer = new THREE.WebGLRenderer();
renderer.shadowMapEnabled = true;
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.append(renderer.domElement);
var shape = new THREE.TorusGeometry(100, 50, 8, 20);
var cover = new THREE.MeshPhongMaterial();
cover.emissive.setRGB(0.8, 0.1, 0.1);
cover.specular.setRGB(0.9, 0.9, 0.9);
var donut = new THREE.Mesh(shape, cover); scene.add(donut);
donut.castShadow = true;
var sunlight = new THREE.DirectionalLight();
sunlight.intensity = 0.5;
sunlight.position.set(100, 100, 100);
scene.add(sunlight);
sunlight.castShadow = true;
var shape = new THREE.PlaneGeometry(1500, 1500);
var cover = new THREE.MeshBasicMaterial();
var ground = new THREE.Mesh(shape, cover);
scene.add(ground);
ground.position.set(0, -180, 0);
ground.rotation.set(-Math.PI/2, 0, 0);
ground.receiveShadow = true;
function animate() {
requestAnimationFrame(animate);
renderer.render(scene, camera);
}
animate();
I am supposed to see the shadow of the donut on the floor. But this is what I see instead without shadow.
What is wrong with my code and how can I fix it?
You have to make the ground to receive shadow
to do this:
ground.receiveShadow = true;
There are multiple issues in your code. The most important problem is that you do not configure your shadow frustum correctly. Besides, MeshBasicMaterial is not affected by light and thus can't receive shadows. Try it like so:
const scene = new THREE.Scene();
const aspect_ratio = window.innerWidth / window.innerHeight;
const camera = new THREE.PerspectiveCamera(75, aspect_ratio, 1, 10000);
camera.position.z = 500;
scene.add(camera);
const renderer = new THREE.WebGLRenderer();
renderer.shadowMap.enabled = true;
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.append(renderer.domElement);
const donutGeometry = new THREE.TorusGeometry(100, 50, 8, 20);
const donutMaterial = new THREE.MeshPhongMaterial();
donutMaterial.emissive.setRGB(0.8, 0.1, 0.1);
donutMaterial.specular.setRGB(0.9, 0.9, 0.9);
const donut = new THREE.Mesh(donutGeometry, donutMaterial);
scene.add(donut);
donut.castShadow = true;
var sunlight = new THREE.DirectionalLight();
sunlight.intensity = 0.5;
sunlight.position.set(100, 100, 100);
scene.add(sunlight);
sunlight.castShadow = true;
sunlight.shadow.camera.top = 200;
sunlight.shadow.camera.bottom = - 200;
sunlight.shadow.camera.left = - 200;
sunlight.shadow.camera.right = 200;
sunlight.shadow.camera.near = 1;
sunlight.shadow.camera.far = 1000;
//scene.add( new THREE.CameraHelper( sunlight.shadow.camera ) );
const groundGeometry = new THREE.PlaneGeometry(1500, 1500);
const groundMaterial = new THREE.MeshPhongMaterial();
const ground = new THREE.Mesh(groundGeometry, groundMaterial);
scene.add(ground);
ground.position.set(0, -180, 0);
ground.rotation.set(-Math.PI/2, 0, 0);
ground.receiveShadow = true;
function animate() {
requestAnimationFrame(animate);
renderer.render(scene, camera);
}
animate();
body {
margin: 0;
}
<script src="https://cdn.jsdelivr.net/npm/three#0.144/build/three.min.js"></script>

Adding Cannon.js Body to Three.js Mesh causing Vec3 error with groups and multiple shapes

Basically I've created a group of 2 meshes in Three.js and a Body containing 2 Shapes in Cannon.
Separately they appear fine but when I copy the Body position to the meshes to add physics the code breaks, nothing appears on screen and when logging the positions, for the Body everythings ok but the mesh its showing as undefined.
(The end goal is to replace the mesh with the model)
Any help would be great, heres the code in question:
import './style.css'
import * as THREE from 'three'
import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls.js'
import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader.js'
import { DRACOLoader } from 'three/examples/jsm/loaders/DRACOLoader.js'
import * as dat from 'lil-gui'
import * as CANNON from 'cannon-es'
/**
* Base
*/
// Debug
const gui = new dat.GUI()
// Canvas
const canvas = document.querySelector('canvas.webgl')
// Scene
const scene = new THREE.Scene()
/**
* Models
*/
const dracoLoader = new DRACOLoader()
dracoLoader.setDecoderPath('/draco/')
const gltfLoader = new GLTFLoader()
gltfLoader.setDRACOLoader(dracoLoader)
let mixer = null
let gunModel = null
gltfLoader.load(
'/models/hamburger.glb',
(gltf) =>
{
gltf.scene.position.set(0, 4, 0)
gunModel = gltf.scene
scene.add(gunModel)
console.log(gunModel.position)
}
)
/**
* test wireframe cubes
*/
const YGeo = new THREE.BoxBufferGeometry(2, 6, 2);
const YMat = new THREE.MeshBasicMaterial({
color: 'green',
wireframe: true
})
const gun = new THREE.Group();
const blockY = new THREE.Mesh(YGeo, YMat);
blockY.position.x = 4;
const XGeo = new THREE.BoxBufferGeometry(6,2,2);
const XMat = new THREE.MeshBasicMaterial({
color: 'green',
wireframe: true
})
const blockX = new THREE.Mesh(XGeo, XMat);
blockX.position.y = 2
gun.add(blockY)
gun.add(blockX)
gui.add(gun.position, 'y', 0, 5, 0.01);
gui.add(gun.position, 'x', -3, 4, 0.01)
gui.add(gun.position, 'z', -3, 3, 0.01)
scene.add(gun)
/**
* Floor
*/
const floor = new THREE.Mesh(
new THREE.PlaneGeometry(50, 50),
new THREE.MeshStandardMaterial({
color: '#444444',
metalness: 0,
roughness: 0.5
})
)
floor.receiveShadow = true
floor.rotation.x = - Math.PI * 0.5
scene.add(floor)
/**
* Lights
*/
const ambientLight = new THREE.AmbientLight(0xffffff, 0.8)
scene.add(ambientLight)
const directionalLight = new THREE.DirectionalLight(0xffffff, 0.6)
directionalLight.castShadow = true
directionalLight.shadow.mapSize.set(1024, 1024)
directionalLight.shadow.camera.far = 15
directionalLight.shadow.camera.left = - 7
directionalLight.shadow.camera.top = 7
directionalLight.shadow.camera.right = 7
directionalLight.shadow.camera.bottom = - 7
directionalLight.position.set(5, 5, 5)
scene.add(directionalLight)
/**
* 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.setPixelRatio(Math.min(window.devicePixelRatio, 2))
})
/**
* Camera
*/
// Base camera
const camera = new THREE.PerspectiveCamera(75, sizes.width / sizes.height, 0.1, 100)
camera.position.set(- 8, 4, 8)
scene.add(camera)
// Controls
const controls = new OrbitControls(camera, canvas)
controls.target.set(0, 1, 0)
controls.enableDamping = true
/**
* Renderer
*/
const renderer = new THREE.WebGLRenderer({
canvas: canvas
})
renderer.shadowMap.enabled = true
renderer.shadowMap.type = THREE.PCFSoftShadowMap
renderer.setSize(sizes.width, sizes.height)
renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2))
/**
* Physics
*/
const world = new CANNON.World({
gravity: new CANNON.Vec3(0, -9.81, 0)
});
const floorBody = new CANNON.Body({
shape: new CANNON.Plane(),
mass: 0
})
world.addBody(floorBody)
const shapeY = new CANNON.Box(new CANNON.Vec3(1,3,1))
const shapeX = new CANNON.Box(new CANNON.Vec3(3,1,1))
const boxBody = new CANNON.Body({
mass: 1
})
boxBody.addShape(shapeY, new CANNON.Vec3(3, 0, 0), new CANNON.Quaternion())
boxBody.addShape(shapeX, new CANNON.Vec3(0,2,0), new CANNON.Quaternion())
world.addBody(boxBody)
boxBody.position.set(-0.56, 4.13, -0.02)
console.log(boxBody.position)
gui.add(boxBody.position, 'y', 0, 10, 0.01);
/**
* Animate
*/
const clock = new THREE.Clock()
let previousTime = 0
const tick = () =>
{
const elapsedTime = clock.getElapsedTime()
const deltaTime = elapsedTime - previousTime
previousTime = elapsedTime
world.step(1/60, deltaTime, 3)
floor.position.copy(floorBody.position);
floorBody.quaternion.copy(floor.quaternion);
// if(gunModel) {
// gunModel.position.copy(boxBody);
// gunModel.quaternion.copy(boxBody)
// console.log(gunModel.position)
// }
gun.position.copy(boxBody);
gun.quaternion.copy(boxBody)
console.log(gun.position.x)
if(mixer)
{
mixer.update(deltaTime)
}
// Update controls
controls.update()
// Render
renderer.render(scene, camera)
// Call tick again on the next frame
window.requestAnimationFrame(tick)
}
tick()
// access boxBody attributes?
gun.position.copy(boxBody.position);
gun.quaternion.copy(boxBody.quaternion);
console.log(gun.position.x)

Three.js – Create half a ring and animate it

I've created a Ring and would like to have only half of it. And after that animate it, that it builds itself up from 0 to half.
var geometry = new THREE.RingGeometry(10, 9, 32);
var material = new THREE.MeshBasicMaterial({
color: 0xffff00,
side: THREE.DoubleSide,
});
var mesh = new THREE.Mesh(geometry, material);
scene.add(mesh);
How can I archive it? I'm new to three.js.
Use thetaStart and thetaLength to animate the half-ring.
body{
overflow: hidden;
margin: 0;
}
<script type="module">
import * as THREE from "https://cdn.jsdelivr.net/npm/three#0.118.3/build/three.module.js";
var scene = new THREE.Scene();
var camera = new THREE.PerspectiveCamera(60, innerWidth / innerHeight, 1, 100);
camera.position.set(0, 0, 10);
var renderer = new THREE.WebGLRenderer({antialias: true});
renderer.setSize(innerWidth, innerHeight);
document.body.appendChild(renderer.domElement);
var grid = new THREE.GridHelper(10, 10);
grid.rotation.x = Math.PI * 0.5;
scene.add(grid);
var innerRadius = 1;
var outerRadius = 2;
// re-building geometry
var usualRingGeom = new THREE.RingBufferGeometry(innerRadius, outerRadius, 32, 1, 0, 1);
var usualRingMat = new THREE.MeshBasicMaterial({color: 0xffff00});
var usualRing = new THREE.Mesh(usualRingGeom, usualRingMat);
scene.add(usualRing);
var clock = new THREE.Clock();
renderer.setAnimationLoop(()=>{
let t = clock.getElapsedTime();
// re-building geometry
usualRingGeom = new THREE.RingBufferGeometry(innerRadius, outerRadius, 32, 1, 0, (Math.sin(t) * 0.5 + 0.5) * Math.PI);
usualRing.geometry.dispose();
usualRing.geometry = usualRingGeom;
renderer.render(scene, camera);
});
</script>
PS You also can achieve the same result without re-building a geometry. For that, you can bend a plane in js (changing vertices) or in shaders :)

Not being able to cast shadow

I've made this table mesh which i would like to cast shadows on the pane(floor) mesh. I've been trying playing around with the ShadowMap for quite some while now but i cant seem to get it to work.
This is the current look:
camera & scene
const scene = new THREE.Scene();
const camera = new THREE.PerspectiveCamera(35, (window.innerWidth / window.innerHeight), 0.1, 1000);
camera.position.z = 8;
camera.position.y = 2;
camera.lookAt( scene.position );
The table mesh
const boxWidth = 1; const boxHeight = 0.1; const boxDepth = 1;
const tableBoardGeometry = new THREE.BoxGeometry(boxWidth, boxHeight, boxDepth);
const textureLoader = new THREE.TextureLoader();
const customPicture = textureLoader.load('https://threejsfundamentals.org/threejs/lessons/resources/images/compressed-but-large-wood-texture.jpg')
const tableBoardMaterial = new THREE.MeshLambertMaterial({map: customPicture, wireframe: false})
const tableBoard = new THREE.Mesh(tableBoardGeometry, tableBoardMaterial)
tableBoard.position.set(0, 0, 0)
tableBoard.castShadow = true;
The lightning & shadow
const lightAndShadow = () => {
const ambientLight = new THREE.AmbientLight(0xffffff, 0.75);
const lightIntensity = 1.3; const lightDistance = 18;
const light = new THREE.PointLight(0xffffff, lightIntensity, lightDistance);
light.position.set(1, 1, 1)
light.castShadow = true
light.target = tableBoard;
renderer.shadowMap.enabled = true;
renderer.shadowMap.type = THREE.PCFShadowMap;
light.shadow = new THREE.LightShadow(new THREE.PerspectiveCamera(100, 1, 500, 1000))
light.shadow.bias = 0.0001
light.shadow.mapSize.width = 2048*2
light.shadow.mapSize.height = 2048*2
scene.add(light, ambientLight);
}
The floor mesh
const floorWidh = 20; const floorHeight = 20; const floorWidthSegments = 50; const floorHeightSegments = 50;
const floorGeometry = new THREE.PlaneGeometry( floorWidh, floorHeight, floorWidthSegments, floorHeightSegments );
floorGeometry.rotateX( - Math.PI / 2 );
const floorTexture = new THREE.TextureLoader().load('https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcQOOcWSD0K2mPwokAFfZIhq5Xl49bh8B17RlU6NqCGa4UOKydgX');
floorTexture.wrapS = floorTexture.wrapT = THREE.RepeatWrapping;
floorTexture.repeat.set(20, 20);
const floorMaterial = new THREE.MeshBasicMaterial({color: 0xFFFFFF, wireframe: false}),
floor = new THREE.Mesh( floorGeometry, floorMaterial );
floor.position.set(0, -tableLegHeightPosition, 0)
floor.receiveShadow = true;
Any suggestions on how i can get the shadows to work would be much appreciated.
light.shadow = new THREE.LightShadow(new THREE.PerspectiveCamera(100, 1, 500, 1000))
You are overriding the default camera parameters of LightShadow and defining the Near Clipping plane to 500 which is making the tableBoard shadows to disappear.
You can reduce this number to the default of 0.5 or something near to it. Having the near clipping plane as 500 is a very big number for your case.
From the Docs:
.shadow : LightShadow
A LightShadow used to calculate shadows for this light.
The lightShadow's camera is set to a PerspectiveCamera with fov of 90, aspect of 1, near clipping plane at 0.5 and far clipping plane at 500.
Refer Three.js complete doc for Point light shadows here

How to create an infinite floor (skyline) in Three.js?

QUESTION:
So I came across this:
https://skin-tracker.com/pubg/outfit?no=000000000000000000000000000&set=1&char=1
I have the central ground area which is textured already in my code. But I have no idea how to make it extend up to the horizon like seen in the link.
It seems the person who coded what you see in the link hit some kind of limitation and had to use a single color for what extends beyond the central floor area.
How can I make my floor extend to the horizon/ create a skyline ?
CODE:
var floorTexture = new THREE.ImageUtils.loadTexture( '../../public/assets/grassTile.jpg' );
floorTexture.wrapS = floorTexture.wrapT = THREE.RepeatWrapping;
floorTexture.repeat.set( 10, 10 );
var floorMaterial = new THREE.MeshBasicMaterial({ map: floorTexture, side: THREE.DoubleSide });
var floorGeometry = new THREE.PlaneGeometry(1000, 1000, 10, 10);
var mesh = new THREE.Mesh(floorGeometry, floorMaterial);
mesh.rotation.x = - Math.PI / 2;
mesh.receiveShadow = true;
scene.add( mesh );
You can simply create an enormous textured plane. I found no limitations with the example below. If you implement something like this and encounter errors/problems, update your question with the errors you're seeing.
// prepare the renderer
let WIDTH
let HEIGHT
let aspectRatio = function() {
return WIDTH / HEIGHT
}
const renderer = new THREE.WebGLRenderer({
antialias: true,
alpha: true
})
document.body.appendChild(renderer.domElement)
const camera = new THREE.PerspectiveCamera(32, aspectRatio(), 1, 1000)
camera.position.set(0, 10, 50)
function resize() {
WIDTH = window.innerWidth
HEIGHT = window.innerHeight
renderer.setSize(WIDTH, HEIGHT)
camera.aspect = aspectRatio()
camera.updateProjectionMatrix()
}
resize()
window.addEventListener("resize", resize)
const scene = new THREE.Scene()
const light = new THREE.DirectionalLight(0xffffff, 1, Infinity)
light.position.set(0, 0, 1)
camera.add(light)
scene.add(camera)
const sun = new THREE.DirectionalLight(0xffffcc)
sun.position.set(0, 1, 0)
scene.add(sun)
// populate the scene
let geo = new THREE.BoxBufferGeometry(10, 10, 10)
let mat = new THREE.MeshLambertMaterial({
color: "red"
})
let mesh = new THREE.Mesh(geo, mat)
scene.add(mesh)
let tex = new THREE.TextureLoader().load("https://upload.wikimedia.org/wikipedia/commons/4/4c/Grass_Texture.png")
tex.anisotropy = 32
tex.repeat.set(100, 100)
tex.wrapT = THREE.RepeatWrapping
tex.wrapS = THREE.RepeatWrapping
geo = new THREE.PlaneBufferGeometry(10000, 10000)
mat = new THREE.MeshLambertMaterial({
map: tex
})
mesh = new THREE.Mesh(geo, mat)
mesh.position.set(0, -5, 0)
mesh.rotation.set(Math.PI / -2, 0, 0)
scene.add(mesh)
let axis = new THREE.Vector3(0, 1, 0)
function updateCamera() {
camera.position.applyAxisAngle(axis, 0.01)
}
// rendering functions
function render() {
renderer.render(scene, camera)
camera.lookAt(scene.position)
}
let animationLoopId = null
function animationLoop() {
animationLoopId = requestAnimationFrame(animationLoop)
updateCamera()
render()
}
animationLoop()
html,
body {
padding: 0;
margin: 0;
overflow: hidden;
background: skyBLue;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/97/three.js"></script>

Categories