Transformation matrix not working with Three.js - three.js

I'm starting to learn Three.js now, and trying to do some really basic things at first, like creating a box and then applying a transformation matrix on it, rotating 15deg on Z axis:
<html>
<head>
<title>My first Three.js app</title>
<style>
body {
margin: 0;
}
canvas {
width: 100%;
height: 100%;
}
</style>
</head>
<body>
<script src="scripts/three.js"></script>
<script>
var scene = new THREE.Scene();
var camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 100000);
var renderer = new THREE.WebGLRenderer();
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);
var geometry = new THREE.BoxGeometry(1, 0.5, 0.1);
var material = new THREE.MeshBasicMaterial({ color: 0x00ff00 });
material.wireframe = true;
var cube = new THREE.Mesh(geometry, material);
cube.matrixAutoUpdate = false;
var matrix = new THREE.Matrix4(0.9659, 0.2588, 0.000, 0,
-0.2588, 0.9659, 0.000, 0,
0.0000, 0.0000, 1.000, 0,
0.0000, 0.0000, 0.000, 1);
cube.applyMatrix(matrix);
scene.add(cube);
camera.position.z = 5;
//camera.position.x = 5;
//camera.position.y = 5;
var n1 = cube.matrix.elements;
camera.lookAt(new THREE.Vector3(0, 0, 0));
var render = function () {
requestAnimationFrame(render);
//cube.rotation.x += 0.01;
//cube.rotation.y += 0.01;
renderer.render(scene, camera);
};
render();
</script>
</body>
</html>
The problem is that the box is not changing at all, it remains on the same position/orientation.
If I inspect the applied_matrix variable, it returns an identity matrix, like if I never applied my matrix.
What am I missing?

You got a warning in the console said: THREE.Matrix4: the constructor no longer reads arguments. use .set() instead.
So please instead of:
var matrix = new THREE.Matrix4(0.9659, 0.2588, 0.000, 0,
-0.2588, 0.9659, 0.000, 0,
0.0000, 0.0000, 1.000, 0,
0.0000, 0.0000, 0.000, 1);
Try
var matrix = new THREE.Matrix4().set((0.9659, 0.2588, 0.000, 0,
-0.2588, 0.9659, 0.000, 0,
0.0000, 0.0000, 1.000, 0,
0.0000, 0.0000, 0.000, 1);

Related

Three JS rotation on specific axis

How can I have an ThreeJS object rotate on an axis that is at angle.
Like from this codepen I made, the left square rotates on its center and moved up when you click on the "rotate up" button.
I want the left cure rotate along the red axis in the image attached and move along on that axis when click on the "Rotate 45 degree" button. I can make up move along the axis, but the rotation is wrong. How can I make the cute rotate along the red axis?
****EDIT:
PS: Sorry I cannot get the snippet working here. Please use the codepen link for the demo.
https://codepen.io/eforblue/pen/MWpYggY
var upTl = gsap.timeline();
var degreeTl = gsap.timeline();
var width = window.innerWidth;
var height = window.innerHeight;
var renderer = new THREE.WebGLRenderer({ antialias: true });
renderer.setSize(width, height);
document.body.appendChild(renderer.domElement);
var scene = new THREE.Scene();
var cubeGeometry = new THREE.CubeGeometry(100, 100, 100);
var cubeMaterial = new THREE.MeshLambertMaterial({ color: 0xffffff });
var cube = new THREE.Mesh(cubeGeometry, cubeMaterial);
scene.add(cube);
var cube2 = new THREE.Mesh(cubeGeometry, cubeMaterial);
cube2.position.set(200, 200, 0);
cube2.rotation.z = 45;
scene.add(cube2);
var camera = new THREE.PerspectiveCamera(45, width / height, 0.1, 10000);
camera.position.set(0, 500, 3000);
camera.lookAt(cube.position);
scene.add(camera);
var skyboxGeometry = new THREE.CubeGeometry(100, 100, 100);
var skyboxMaterial = new THREE.MeshBasicMaterial({ color: 0x000000, side: THREE.BackSide });
var skybox = new THREE.Mesh(skyboxGeometry, skyboxMaterial);
var pointLight = new THREE.PointLight(0xffffff);
pointLight.position.set(0, 300, 200);
scene.add(pointLight);
var clock = new THREE.Clock();
function render() {
requestAnimationFrame(render);
// cube.rotation.y -= clock.getDelta();
renderer.render(scene, camera);
}
render();
$('.up').on('click', () => {
console.log('click')
upTl.to( cube.rotation, 1, { y: Math.PI * 3 }, 0 )
.to( cube.position, 1, { y: cube.position.y + 400 }, 0 )
})
$('.degree').on('click', () => {
degreeTl.to( cube2.rotation, 1, { y: Math.PI * 3 }, 0 )
.to( cube2.position, 1, { x: cube2.position.x + 300, y:cube2.position.y + 300 }, 0 )
});
canvas {
position: fixed;
top: 0;
left: 0;
}
button {
position:relative;
z-index: 99;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/3.6.1/gsap.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/r128/three.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="./main.js"></script>
<button class="up">rotate up</button>
<button class="degree">rotate 45deg</button>
In your case it's easier to use quaternions to rotate around your red axis, you can use the following function and define your rotation axis in the "axis" parameter.
static rotateAroundWorldAxis(mesh, point, axis, angle) {
const q = new Quaternion();
q.setFromAxisAngle(axis, angle);
mesh.applyQuaternion(q);
mesh.position.sub(point);
mesh.position.applyQuaternion(q);
mesh.position.add(point);
return mesh;
}

Create object with different colors on faces

Drawing a Tetrahedron, I would like to set one color per face, for example, red, green, blue and orange.
Here is the code :
const divid = document.getElementById("myid");
let scene = new THREE.Scene();
let camera = new THREE.PerspectiveCamera(
70,
window.innerWidth / window.innerHeight,
1,
1000
);
let renderer = new THREE.WebGLRenderer({ alpha: true });
divid.appendChild(renderer.domElement);
camera.position.z = 3;
let triangle = new THREE.Mesh(
new THREE.TetrahedronBufferGeometry(),
new THREE.MeshBasicMaterial({ color: 0xff0000 })
);
scene.add(triangle);
let animate = function() {
requestAnimationFrame(animate);
triangle.rotation.x += 0.005;
triangle.rotation.y += 0.01;
renderer.render(scene, camera);
};
animate();
Can't we pass an array of 4 colors to set on each face ?
Code available here too : https://codepen.io/jeffprod/pen/JjdLdjO
Use .vertexColors: true with the material and add color attribute to the geometry, setting the same colour to each vertex of a face:
let scene = new THREE.Scene();
let camera = new THREE.PerspectiveCamera(
70,
innerWidth / innerHeight,
1,
1000
);
let renderer = new THREE.WebGLRenderer({
alpha: true
});
renderer.setSize(innerWidth, innerHeight);
document.body.appendChild(renderer.domElement);
camera.position.z = 3;
let geom = new THREE.TetrahedronBufferGeometry();
geom.setAttribute("color", new THREE.Float32BufferAttribute([
1, 0, 0, //red
1, 0, 0,
1, 0, 0,
0, 1, 0, //green
0, 1, 0,
0, 1, 0,
0, 0, 1, //blue
0, 0, 1,
0, 0, 1,
1, 0.75, 0.25, //orange (sort of)
1, 0.75, 0.25,
1, 0.75, 0.25
], 3));
let triangle = new THREE.Mesh(
geom,
new THREE.MeshBasicMaterial({
vertexColors: true
})
);
scene.add(triangle);
let animate = function() {
requestAnimationFrame(animate);
triangle.rotation.x += 0.005;
triangle.rotation.y += 0.01;
renderer.render(scene, camera);
};
animate();
body {
overflow: hidden;
margin: 0;
}
<script src="https://threejs.org/build/three.min.js"></script>

Threejs How to Add in and Out curves in a custom shape?

I have a simple shape made in 3js with 8 points. The shape is without curves. I am not very good in absarc or curves in Threejs. I have tried to search online but I didn't get exact example.
My shape output:
While I need output like this:
Just an option, using .absarc():
var scene = new THREE.Scene();
var camera = new THREE.PerspectiveCamera(60, innerWidth / innerHeight, 1, 100);
camera.position.set(0, 0, 6);
var renderer = new THREE.WebGLRenderer({
antialias: true
});
renderer.setSize(innerWidth, innerHeight);
document.body.appendChild(renderer.domElement);
var controls = new THREE.OrbitControls(camera, renderer.domElement);
var grid = new THREE.GridHelper(10, 10);
grid.rotation.x = -Math.PI * 0.5;
grid.position.set(0, 0, -0.01);
scene.add(grid);
var s = new THREE.Shape();
s.absarc(0, 0, 0.5, Math.PI * 0.5, -Math.PI * 0.5, true);
s.lineTo(0, -2);
s.absarc(-1, 0, Math.sqrt(2) * 2, -Math.PI * 0.25, Math.PI * 0.25, false);
s.lineTo(0, 2);
var sGeom = new THREE.ShapeBufferGeometry(s);
var sMat = new THREE.MeshBasicMaterial({
color: "teal"
});
var shape = new THREE.Mesh(sGeom, sMat);
scene.add(shape);
var lineGeom = new THREE.BufferGeometry().setFromPoints(s.getPoints());
var lineMat = new THREE.LineBasicMaterial({
color: "orange"
});
var outline = new THREE.LineLoop(lineGeom, lineMat);
scene.add(outline);
renderer.setAnimationLoop(() => {
renderer.render(scene, camera);
});
body {
overflow: hidden;
margin: 0;
}
<script src="https://threejs.org/build/three.min.js"></script>
<script src="https://threejs.org/examples/js/controls/OrbitControls.js"></script>

How to create simple vertical bounce animation to a sphere

I'd like for a spinning sphere I created to also bounce vertically an infinite amount of times that looks realistic to the way a ball would bounce in real life strictly on the y axis.
The webgl examples I've found seem be a bit overloaded (multiple balls bouncing on multiple planes) and I haven't been able to deduce the core setup to achieve what I need.
var scene = new THREE.Scene();
var camera = new THREE.PerspectiveCamera(50, 300 / 200, 1, 1000);
var renderer = new THREE.WebGLRenderer();
renderer.setSize(300, 200);
document.body.appendChild(renderer.domElement);
var geometry = new THREE.SphereGeometry(3, 50, 50, 0, Math.PI * 2, 0, Math.PI * 2);
var material = new THREE.MeshNormalMaterial();
var cube = new THREE.Mesh(geometry);
scene.add(cube);
camera.position.z = 10;
var render = function () {
requestAnimationFrame(render);
cube.rotation.x -= 0.10;
cube.rotation.y += 0.00;
renderer.render(scene, camera);
};
render();
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/94/three.min.js"></script>
So, just an option with Math.sin():
var scene = new THREE.Scene();
var camera = new THREE.PerspectiveCamera(60, window.innerWidth / window.innerHeight, 1, 1000);
camera.position.set(2, 3, 5);
camera.lookAt(scene.position);
var renderer = new THREE.WebGLRenderer();
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);
var plane = new THREE.Mesh(new THREE.PlaneGeometry(5, 10, 5, 10), new THREE.MeshBasicMaterial({
color: 0x00ffff,
wireframe: true
}));
plane.rotation.x = -Math.PI * 0.5;
scene.add(plane);
var ball = new THREE.Mesh(new THREE.SphereGeometry(0.5, 16, 8), new THREE.MeshBasicMaterial({
color: 0xff00ff,
wireframe: true
}));
scene.add(ball);
var clock = new THREE.Clock();
var time = 0;
var delta = 0;
render();
function render() {
requestAnimationFrame(render);
delta = clock.getDelta();
time += delta;
ball.rotation.x = time * 4;
ball.position.y = 0.5 + Math.abs(Math.sin(time * 3)) * 2;
ball.position.z = Math.cos(time) * 4;
renderer.render(scene, camera);
}
body {
overflow: hidden;
margin: 0;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/94/three.min.js"></script>

How to add shading to object model in threeJS?

I have a custom-made object, an obelisk, next to a cube. The obelisk is made with THREE.Geometry (each vertex and face added manually), while the cube is made with THREE.BoxGeometry. They both use THREE.MeshNormalMaterial.
So why does the cube get colors that change with rotation, while the obelisk is just gray? I've managed to get other meshes to add color to the obelisk, but can't figure out how to get the sides to change colors during rotation.
<!DOCTYPE html>
<html>
<head>
<title>Washington Monument</title>
<style>
html, body {
margin: 0; padding:0;
overflow: hidden;
}
canvas {
width: 100%; height: 100%;
}
</style>
</head>
<body>
<script src="../../lib/three.min.js"></script>
<script>
var scene = new THREE.Scene();
var fieldOfView = 45;
var aspect = window.innerWidth/window.innerHeight;
var nearClippingPlane = 0.01;
var farClippingPlane = 1000;
var camera = new THREE.PerspectiveCamera(fieldOfView, aspect, nearClippingPlane, farClippingPlane);
var renderer = new THREE.WebGLRenderer({antialias: true});
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);
var obeliskMaterial = new THREE.MeshNormalMaterial();
var obeliskGeometry = new THREE.Geometry();
obeliskGeometry.vertices.push(new THREE.Vector3( 8.40, -80, 8.40));
obeliskGeometry.vertices.push(new THREE.Vector3( 8.40, -80, -8.40));
obeliskGeometry.vertices.push(new THREE.Vector3(-8.40, -80, -8.40));
obeliskGeometry.vertices.push(new THREE.Vector3(-8.40, -80, 8.40));
obeliskGeometry.vertices.push(new THREE.Vector3( 5.25, 72.36, 5.25));
obeliskGeometry.vertices.push(new THREE.Vector3( 5.25, 72.36, -5.25));
obeliskGeometry.vertices.push(new THREE.Vector3(-5.25, 72.36, -5.25));
obeliskGeometry.vertices.push(new THREE.Vector3(-5.25, 72.36, 5.25));
obeliskGeometry.vertices.push(new THREE.Vector3( 0, 89.29, 0));
obeliskGeometry.faces.push(new THREE.Face3(0, 1, 5), new THREE.Face3(0, 5, 4));
obeliskGeometry.faces.push(new THREE.Face3(1, 2, 6), new THREE.Face3(1, 6, 5));
obeliskGeometry.faces.push(new THREE.Face3(2, 3, 7), new THREE.Face3(2, 7, 6));
obeliskGeometry.faces.push(new THREE.Face3(3, 0, 4), new THREE.Face3(3, 4, 7));
obeliskGeometry.faces.push(new THREE.Face3(4, 5, 8));
obeliskGeometry.faces.push(new THREE.Face3(5, 6, 8));
obeliskGeometry.faces.push(new THREE.Face3(6, 7, 8));
obeliskGeometry.faces.push(new THREE.Face3(7, 4, 8));
var obeliskMesh = new THREE.Mesh(obeliskGeometry, obeliskMaterial);
scene.add(obeliskMesh);
var material = new THREE.MeshNormalMaterial();
var geom = new THREE.BoxGeometry(16, 16, 8);
var cube = new THREE.Mesh(geom, material);
cube.position.x = 40;
scene.add(cube);
camera.position.z = 320;
var render = function () {
requestAnimationFrame(render);
obeliskMesh.rotation.y += 0.01;
cube.rotation.y += 0.01;
renderer.render(scene, camera);
};
render();
</script>
</body>
</html>
If you want to use MeshNormalMaterial in a custom geometry, you have to compute the normals of the geometry before creating the mesh:
obeliskGeometry.computeFaceNormals();
In your example:
[...]
obeliskGeometry.faces.push(new THREE.Face3(7, 4, 8));
obeliskGeometry.computeFaceNormals();
var obeliskMesh = new THREE.Mesh(obeliskGeometry, obeliskMaterial);
[...]

Resources