I am trying to create in three.js a ball which moves forward and back constantly but no success. It just does not work. Only moves in one direction.
My code:
var scene = new THREE.Scene();
var camera = new THREE.PerspectiveCamera( 75, window.innerWidth/window.innerHeight, 0.1, 1000 );
var renderer = new THREE.WebGLRenderer();
renderer.setSize( window.innerWidth, window.innerHeight );
document.body.appendChild( renderer.domElement );
var faceradius = 0.2;
var bodyradius = 0.2;
var geometry = new THREE.SphereGeometry( faceradius, 32, 32 );//sphere size
var material = new THREE.MeshBasicMaterial( { color: 0x24D69D } ); //red color
var face = new THREE.Mesh( geometry, material );
scene.add( face );
var group = new THREE.Group();
group.add(face);
scene.add(group);
var counter = 0;
camera.position.z = 5;
var render = function () {
requestAnimationFrame( render );
if (counter < 100){
group.position.x += 0.01;
counter++;
}
renderer.render(scene, camera);
if (counter > 100){
group.position.x -= 0.01;
counter++;
}
if (counter > 200){
counter = 0;
}
renderer.render(scene, camera);
};
render();
Try this:
var render = function () {
requestAnimationFrame( render );
if (counter <=100){ //Note the <=
group.position.x += 0.01;
counter++;
}
if (counter > 100){
group.position.x -= 0.01;
counter++;
}
if (counter > 200){
counter = 0;
}
renderer.render(scene, camera);
};
From what I can tell, animation is a recursive function so a counter is not going to go up - each time you call it the counter will go back to its original value.
What you need to do is create a ball object using sphere as a base, then add a direction property.
Related
I am trying to simulate a rubik's cube with three.js and now my goal is to rotate the faces using keyboard keys. The first rotation is doing fine but the second rotation snaps right in and also it is rotating in the direction of the first one (if I start with up clockwise the bottom will rotate against clockwise and vice versa).
this is my code:
import * as THREE from 'three'
import { TrackballControls } from 'three/examples/jsm/controls/TrackballControls';
const scene = new THREE.Scene();
const camera = new THREE.PerspectiveCamera( 75, window.innerWidth / window.innerHeight, 0.1, 1000 );
const renderer = new THREE.WebGLRenderer({canvas: document.querySelector("canvas.webgl")});
renderer.setSize( window.innerWidth, window.innerHeight );
document.body.appendChild( renderer.domElement );
const geometry = new THREE.BoxGeometry(1, 1, 1);
const materials = [
new THREE.MeshBasicMaterial({color: 'white'}),
new THREE.MeshBasicMaterial({color: 'yellow'}),
new THREE.MeshBasicMaterial({color: 'red'}),
new THREE.MeshBasicMaterial({color: 'darkorange'}),
new THREE.MeshBasicMaterial({color: 'blue'}),
new THREE.MeshBasicMaterial({color: 'green'}),
];
for(let i = 0; i < geometry.groups.length; i++)
geometry.groups[i].materialIndex = i;
const cube = [];
for(let y = -1; y <= 1; y++){
for(let x = -1; x <= 1; x++){
for(let z = -1; z <= 1; z++){
const mesh = new THREE.Mesh(geometry, materials);
mesh.position.x = x;
mesh.position.y = y;
mesh.position.z = z;
cube.push(mesh);
scene.add(mesh);
}
}
}
const controls = new TrackballControls( camera, renderer.domElement );
controls.noPan = true;
controls.noZoom = true;
controls.rotateSpeed = 3;
camera.position.z = 7.5;
controls.update();
const turnSpeed = 2;
const face = new THREE.Group();
l
et indexes = [];
scene.add(face);
function resetFace(){
let tempQuaternion = new THREE.Quaternion();
for(let i = 0; i < indexes.length; i++){
cube[i].getWorldQuaternion(tempQuaternion);
scene.add(cube[i]);
cube[i].quaternion.copy(tempQuaternion);
}
indexes = [];
}
function getU(){
resetFace();
for(let i = 18; i < 27; i++){
face.add(cube[i]);
indexes.push(i);
}
}
function getB(){
resetFace();
for(let i = 0; i < 9; i++){
face.add(cube[i]);
indexes.push(i);
}
}
function B() {
requestAnimationFrame( B );
controls.update();
// rotate
if(face.rotation.y < THREE.MathUtils.degToRad(90))
face.rotation.y += THREE.MathUtils.degToRad(turnSpeed);
renderer.render( scene, camera );
}
function U() {
requestAnimationFrame( U );
controls.update();
// rotate
if(face.rotation.y > THREE.MathUtils.degToRad(-90))
face.rotation.y -= THREE.MathUtils.degToRad(turnSpeed);
renderer.render( scene, camera );
}
document.addEventListener("keydown", (event) => {
console.log("animation start");
if(event.code == "KeyA"){
getU();
U();
}
else if(event.code == "KeyB"){
getB();
B();
}
})
function animate(){
requestAnimationFrame( animate );
controls.update();
renderer.render( scene, camera );
}
animate();
And the result is this:
I've tried to change the camera view (say: Front View, Left View, Right View, Back View, Bottom View and Top View ) in button click. I have achieved by changing the camera position for each view where I have a concern that what if camera position or the mesh position get changes. I have given the mesh position to the camera position in the initial View and the mesh disappeared from the scene.
So is there any alternate to achieve this without hard coding the camera position.
Kindly, help me out with the issue.
Here's the fiddle https://jsfiddle.net/8L10qkzt/1/ and my piece of code
var camera, scene, renderer;
var views;
init();
animate();
function init() {
camera = new THREE.PerspectiveCamera(70, window.innerWidth / window.innerHeight, 0.01, 10);
camera.position.z = 1;
scene = new THREE.Scene();
var geometry = new THREE.BoxGeometry(0.2, 0.2, 0.2);
var material = new THREE.MeshNormalMaterial();
var mesh = new THREE.Mesh(geometry, material);
scene.add(mesh);
renderer = new THREE.WebGLRenderer({ antialias: true });
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);
const controls = new THREE.OrbitControls(camera, renderer.domElement);
controls.enableDamping = true;
setTimeout(() => {
controls.enableDamping = false;
controls.reset();
}, 5000);
document.querySelector('#frontView').addEventListener('click', () => {
console.log("frontview");
camera.position.x = 0;
camera.position.y = 0;
camera.position.z = 1;
scene.add(mesh);
controls.update();
render();
});
document.querySelector('#sideView').addEventListener('click', () => {
console.log("Side View");
camera.position.x = 1;
camera.position.y = 1;
camera.position.z = 1;
scene.add(mesh);
controls.update();
render();
});
document.querySelector('#backView').addEventListener('click', () => {
console.log("Back View");
});
}
function render() {
for (var ii = 0; ii < views; ++ii) {
var view = views[ii];
var camera = view.camera;
view.updateCamera(camera, scene, mouseX, mouseY);
var left = Math.floor(windowWidth * view.left);
var top = Math.floor(windowHeight * view.top);
var width = Math.floor(windowWidth * view.width);
var height = Math.floor(windowHeight * view.height);
renderer.setViewport(left, top, width, height);
renderer.setScissor(left, top, width, height);
renderer.setScissorTest(true);
renderer.setClearColor(view.background);
camera.aspect = width / height;
camera.updateProjectionMatrix();
renderer.render(scene, camera);
}
}
function animate() {
render();
requestAnimationFrame(animate);
renderer.render(scene, camera);
}
I'm trying to change multiple views (say : Front View, Side View and Back View) in button click by changing the camera position. I have tried that way but can't able to achieve the back view of the object.Kindly help me out with the issue. I have mentioned the fiddle link https://jsfiddle.net/8L10qkzt/1/
var camera, scene, renderer;
var views;
init();
animate();
function init() {
camera = new THREE.PerspectiveCamera(70, window.innerWidth / window.innerHeight, 0.01, 10);
camera.position.z = 1;
scene = new THREE.Scene();
var geometry = new THREE.BoxGeometry(0.2, 0.2, 0.2);
var material = new THREE.MeshNormalMaterial();
var mesh = new THREE.Mesh(geometry, material);
scene.add(mesh);
renderer = new THREE.WebGLRenderer({ antialias: true });
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);
const controls = new THREE.OrbitControls(camera, renderer.domElement);
controls.enableDamping = true;
setTimeout(() => {
controls.enableDamping = false;
controls.reset();
}, 5000);
document.querySelector('#frontView').addEventListener('click', () => {
console.log("frontview");
camera.position.x = 0;
camera.position.y = 0;
camera.position.z = 1;
scene.add(mesh);
controls.update();
render();
});
document.querySelector('#sideView').addEventListener('click', () => {
console.log("Side View");
camera.position.x = 1;
camera.position.y = 1;
camera.position.z = 1;
scene.add(mesh);
controls.update();
render();
});
document.querySelector('#backView').addEventListener('click', () => {
console.log("Back View");
});
}
function render() {
for (var ii = 0; ii < views; ++ii) {
var view = views[ii];
var camera = view.camera;
view.updateCamera(camera, scene, mouseX, mouseY);
var left = Math.floor(windowWidth * view.left);
var top = Math.floor(windowHeight * view.top);
var width = Math.floor(windowWidth * view.width);
var height = Math.floor(windowHeight * view.height);
renderer.setViewport(left, top, width, height);
renderer.setScissor(left, top, width, height);
renderer.setScissorTest(true);
renderer.setClearColor(view.background);
camera.aspect = width / height;
camera.updateProjectionMatrix();
renderer.render(scene, camera);
}
}
function animate() {
render();
requestAnimationFrame(animate);
renderer.render(scene, camera);
}
I've updated your code with some changes. First, it's good for debugging to add the following helper in order to easily verify the position of the camera.
scene.add( new THREE.AxesHelper() );
Next, the event handler for the "back view" button looks like so:
console.log("Back View");
camera.position.x = 0;
camera.position.y = 0;
camera.position.z = - 1;
controls.update();
As you can see, it's not necessary to call render() again since you already have an ongoing animation loop.
Hint: By applying an array of materials to your box mesh, it's easier to distinct the different sides of your cube.
https://jsfiddle.net/zejLa143/1/
three.js R108
I have a simple Three.js scene in which i have generated some meshes.
Some of these have name property = 'quadrant'.
I just want get all the meshes named 'quadrant' in any way.
i used scene.getObjectByName("quadrant"); and it works but return me only the first element named 'quadrant' finded. how can i do?
i did some digging to clarify this for myself too. So, long story short, you wont be able to access all meshes using getObjectByName method. It doesn't work like class selector in css.
Three.JS documentation points out:
.getObjectByName ( name : String ) --
Searches through the object's children and returns the first with a matching name.
So, you have 2 options:
Give each mesh unique name
traverse through scene's objects
I made code snippet with animation and material modification, because it wasn't clear what you want to achieve.
Example contains:
How tu use getObjectByName method for one object to modify it's material
How to traverse through scene's children and check if they have "quadrant" name
So, in short:
scene.traverse(function(child) {
if (child.name === "quadrant") {
child.material = ClassMaterial; //apply same material to all meshes
}
});
Hope solution is clear, good luck.
More detailed example:
var scene = new THREE.Scene();
var camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 0.1, 1000);
camera.position.z = 50;
var renderer = new THREE.WebGLRenderer();
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);
var geometry = new THREE.BoxGeometry(1, 1, 1);
var material = new THREE.MeshBasicMaterial({
color: 0x00ff00
});
var UniceMaterial = new THREE.MeshBasicMaterial({
color: 0xffff00
});
var ClassMaterial = new THREE.MeshBasicMaterial({
color: 0x00ffff
});
for (j = 0; j < 10; j++) {
var cube = new THREE.Mesh(geometry, material);
cube.name = "demo";
cube.myid = j;
cube.position.x = j * -2;
cube.position.y = j - 2;
cube.position.z = j / 100;
scene.add(cube);
}
for (i = 0; i < 10; i++) {
var cube = new THREE.Mesh(geometry, material);
cube.name = "quadrant";
cube.myid = i;
cube.position.x = i * 2;
cube.position.y = i + 2;
cube.position.z = i / 100;
scene.add(cube);
}
for (i = 0; i < 4; i++) {
var cube = new THREE.Mesh(geometry, material);
cube.name = "quadrant" + 1;
cube.myid = i;
cube.position.x = 0;
cube.position.y = i * -4;
cube.position.z = i / 100;
scene.add(cube);
}
scene.traverse(function(child) {
//if (child instanceof THREE.Mesh) {
if (child.name === "quadrant") {
child.material = ClassMaterial;
//console.log (child);
}
//child.material = ClassMaterial;
//}
});
ObjectWithGetMethod = scene.getObjectByName("quadrant1");
ObjectWithGetMethod.material = UniceMaterial;
var animate = function() {
requestAnimationFrame(animate);
scene.traverse(function(cube) {
if (cube.name === "demo") {
cube.rotation.x += 0.01;
cube.rotation.y += 0.01;
}
});
//despite you try to select "quadrant" it animates last added cube:
if (cube.name = "quadrant") {
cube.rotation.x += 0.01;
cube.rotation.y += 0.01;
}
renderer.render(scene, camera);
};
animate();
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/90/three.min.js"></script>
<html>
<head>
<title>My first three.js app</title>
<style>
body {
margin: 0;
}
canvas {
width: 100%;
height: 100%
}
</style>
</head>
<body>
</body>
</html>
When I start the script, camera has starting values. When I will move it and click button to set up startign values it is never same. What values I missed?
The best way, I suppose, it is to look at the example.
I used console.log for debbuging camera values.
HTML:
<button id="buttonTest">
TEST
</button>
Please, move cube before click!
<div id="wrapper">
</div>
JS:
var camera, scene, renderer, geometry, material, mesh;
init();
animate();
function init() {
window.wrapper = document.getElementById('wrapper');
var buttonTest = document.getElementById('buttonTest');
buttonTest.addEventListener('click', function() {
test();
});
scene = new THREE.Scene();
camera = new THREE.PerspectiveCamera(50, window.innerWidth / window.innerHeight, 1, 10000);
camera.position.z = 500;
scene.add(camera);
geometry = new THREE.CubeGeometry(200, 200, 200);
material = new THREE.MeshNormalMaterial();
mesh = new THREE.Mesh(geometry, material);
scene.add(mesh);
renderer = new THREE.WebGLRenderer({
preserveDrawingBuffer: true
});
renderer.setPixelRatio(window.devicePixelRatio);
renderer.setSize(window.innerWidth, window.innerHeight);
renderer.setClearColor(new THREE.Color("hsl(193, 50%, 57%)"));
wrapper.appendChild(renderer.domElement);
controls = new THREE.TrackballControls(camera, renderer.domElement);
controls.rotateSpeed = 4.0;
controls.zoomSpeed = 1.2;
controls.panSpeed = 0.1;
controls.noZoom = false;
controls.noPan = false;
controls.staticMoving = true;
controls.dynamicDampingFactor = 0.3;
controls.keys = [ 65, 83, 68 ];
controls.addEventListener( 'change', render );
console.log('camera_default: '+camera.position.x+', '+camera.position.y+', '+camera.position.z);
console.log('quaternion_default: '+camera.quaternion.x+', '+
camera.quaternion.y+', '+camera.quaternion.z+', '+camera.quaternion.w);
}
function animate() {
requestAnimationFrame(animate);
controls.update();
render();
}
function render() {
camera.lookAt(scene.position);
renderer.render(scene, camera);
}
function test() {
// lines below shows actual settings
console.log('camera_now: '+camera.position.x+', '+camera.position.y+', '+camera.position.z);
console.log('quaternion_now: '+camera.quaternion.x+', '+
camera.quaternion.y+', '+camera.quaternion.z+', '+camera.quaternion.w);
window.setTimeout(function() {
// this is recovering camera values like
// it was on the sart of script
// it is not enought, what I missed?
camera.position.x = 0;
camera.position.y = 0;
camera.position.z = 500;
camera.quaternion.x = 0.0;
camera.quaternion.y = 0.0;
camera.quaternion.z = 0.0;
camera.quaternion.w = 1.0;
console.log('camera_recover_default: '+camera.position.x+', '+camera.position.y+', '+camera.position.z);
console.log('quaternion_recover_default: '+camera.quaternion.x+', '+
camera.quaternion.y+', '+camera.quaternion.z+', '+camera.quaternion.w);
},1500);
}
I suggest simply doing controls.reset(), it should fix your problems.
replace
camera.position.x = 0;
camera.position.y = 0;
camera.position.z = 500;
camera.quaternion.x = 0.0;
camera.quaternion.y = 0.0;
camera.quaternion.z = 0.0;
camera.quaternion.w = 1.0;
with
controls.reset();
Be sure to reset your camera's up vector. When you call camera.lookAt, it uses the up vector to calculate the new rotation matrix, which is then applied as a quaternion.
camera.up.set(0, 1, 0);
Add that after resetting your position/quaterion, and the camera should appear at its starting point.