Related
I was able to use the OBB.js in three.js examples to obtain center, halfSize, and rotation values. How do we calculate 8 corners of bounding box and draw the box around the object if we know the center, halfSize, and rotation matrix as follows:
{
center: Vector3
x: 4.453294992446899
y: 7.885950803756714
z: 0.4816467687487602
halfSize: Vector3
x: 0.19511961936950684
y: 0.2595798969268799
z: 0.34599775820970535
rotation: Matrix3
elements: Array(9)
0: 1
1: 0
2: 0
3: 0
4: 1
5: 0
6: 0
7: 0
8: 1
}
Something like this:
body{
overflow: hidden;
margin: 0;
}
<script type="module">
import * as THREE from "https://cdn.jsdelivr.net/npm/three#0.126.0/build/three.module.js";
import {OrbitControls} from "https://cdn.jsdelivr.net/npm/three#0.126.0/examples/jsm/controls/OrbitControls.js";
let scene = new THREE.Scene();
let camera = new THREE.PerspectiveCamera(60, innerWidth / innerHeight, 1, 1000);
camera.position.set(0, 5, 20);
let renderer = new THREE.WebGLRenderer();
renderer.setSize(innerWidth, innerHeight);
document.body.appendChild(renderer.domElement);
let controls = new OrbitControls(camera, renderer.domElement);
scene.add(new THREE.GridHelper());
let halfSize = new THREE.Vector3( 0.19511961936950684, 0.2595798969268799, 0.34599775820970535);
let rotMat = new THREE.Matrix3().identity();
let rot = new THREE.Matrix4().identity().setFromMatrix3(rotMat);
let g = new THREE.SphereGeometry(1, 36, 18);
g.scale(halfSize.x, halfSize.y, halfSize.z);
let obj = new THREE.Mesh(g, new THREE.MeshNormalMaterial());
obj.position.set( 4.453294992446899, 7.885950803756714, 0.4816467687487602);
obj.rotation.setFromRotationMatrix(rot);
obj.updateMatrixWorld();
scene.add(obj);
let gH = new THREE.BufferGeometry().setFromPoints([
new THREE.Vector3(1, 1, 1),
new THREE.Vector3(1, 1, -1),
new THREE.Vector3(1, -1, -1),
new THREE.Vector3(1, -1, 1),
new THREE.Vector3(-1, 1, 1),
new THREE.Vector3(-1, 1, -1),
new THREE.Vector3(-1, -1, -1),
new THREE.Vector3(-1, -1, 1)
]);
gH.setIndex([
0, 1, 1, 2, 2, 3, 3, 0,
4, 5, 5, 6, 6, 7, 7, 4,
0, 4, 1, 5, 2, 6, 3, 7
])
let mH = new THREE.LineBasicMaterial({color: "yellow"});
let oH = new THREE.LineSegments(gH, mH);
oH.scale.copy(halfSize);
oH.position.copy(obj.position);
oH.rotation.setFromRotationMatrix(rot);
scene.add(oH);
renderer.setAnimationLoop( _ => {
renderer.render(scene, camera);
});
</script>
I am trying to font images from a sprite sheet to a canvas from a for loop. i have made a simple class called Font to load a font spritesheet. within the class i have a function called drawChar(posX, posY) after declaring a new font object inside my loop i call font.drawChar(posX, posY); only the last image seems to appear but it is in the correct location. here is my code
index.html
var screenbuffer = [
[0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1],
[0, 0, 1, 0, 0, 1, 1, 1, 0, 1, 1, 1],
[0, 0, 1, 0, 0, 1, 1, 1, 0, 1, 1, 1],
[0, 0, 1, 0, 0, 1, 1, 1, 0, 1, 1, 1],
[0, 0, 1, 0, 0, 1, 1, 1, 0, 1, 1, 1],
[0, 0, 1, 0, 0, 1, 1, 1, 0, 1, 1, 1],
[0, 0, 1, 0, 0, 1, 1, 1, 0, 1, 1, 1],
[0, 0, 1, 0, 0, 1, 1, 1, 0, 1, 1, 1],
];
const ctx = setupCanvas(document.getElementById("canvas"));
const font = new Font('img/IBM8x16_NoPadding_extended.png')
window.onload = () => {
loadScreen(32, 64, screenbuffer);
//ctx.drawImage(font.fontImage, 10, 10);
}
//const canvas = document.getElementById("canvas");
function setupCanvas(canvas) {
// Get the device pixel ratio, falling back to 1.
var dpr = window.devicePixelRatio || 1;
// Get the size of the canvas in CSS pixels.
var rect = canvas.getBoundingClientRect();
// Give the canvas pixel dimensions of their CSS
// size * the device pixel ratio.
canvas.width = rect.width * dpr;
canvas.height = rect.height * dpr;
var ctx = canvas.getContext('2d');
// Scale all drawing operations by the dpr, so you
// don't have to worry about the difference.
ctx.scale(dpr, dpr);
return ctx;
}
function loadScreen(resX, resY, screen){
var drawPosX = 0;
var drawPosY = 0;
var tilesizeX = 32;
var tilesizeY = 64;
for(var i = 0; i < screen.length; i++) {
var screenLine = screen[i];
for(var j = 0; j < screenLine.length; j++) {
drawPosX = j;
drawPosY = i;
font.drawChar(drawPosX * tilesizeX, drawPosY * tilesizeY)
}
}
}
font.js
class Font{
constructor(src, tilesizeX, tilesizeY){
this.fontImage = new Image();
this.fontImage.src = src;
//this.fontImage.onload = this.drawChar();
}
drawChar(posX, posY){
console.log(posX, posY)
// draw color
ctx.fillStyle = "#00F";
ctx.fillRect(posX, posY, 32, 64);
// set composite mode
ctx.globalCompositeOperation = "destination-in";
// draw image
ctx.drawImage(this.fontImage, 8, 0, 8 , 16 , posX, posY, 32, 64);
ctx.globalCompositeOperation = "source-over";
}
}
what could I be doing wrong? the only thing I can think of is maybe it has something to do with ctx.globalCompositeOperation but I am still uncertain.
I use Aframe library, when creating a plane, I have used these points
point_1 = [0, 0, 0];
point_2 = [1, 0, 0];
point_3 = [1, 1, 0];
point_4 = [0, 1, 0];
to make a plane in XY plane, It works, code: https://jsfiddle.net/qtv10291/yp4mx6re/8/
But when I change point to:
point_1 = [0, 0, 0];
point_2 = [1, 0, 0];
point_3 = [1, 0, 1];
point_4 = [0, 0, 1];
to create a plane in XZ plane, It doesn't work and error THREE.DirectGeometry: Faceless geometries are not supported., code: https://jsfiddle.net/qtv10291/49gvwL8a/
Shape is only 2D and only accept (x, y) points, The third axis of the points you passed in are ignored.
If you want to create an XZ plane, either rotate the XY plane 90 degrees:
const geometry = new THREE.ShapeGeometry( polygon );
geometry.rotateX(-Math.PI * 0.5);
Or create it via vertices and faces:
const geometry = new THREE.Geometry();
geometry.vertices = points;
geometry.faces.push( new THREE.Face3( 2, 1, 0 ), new THREE.Face3( 2, 0, 3 ) );
I'm trying to animate a three.js block in such a way that it returns to its original position when the animation ends, using tween.js.
Is there a way to achieve this with tween.js only using one tween?
I have got this working as shown below:
var position = {x: -200, y: 150, width: 1, height: 1, depth: 1, rotx: -0.5, roty: 0.7, rotz: 0.9};
var target = {x: 200, y: -100, width: 0.4, height: 3, depth: 8, rotx: 0.3, roty: -0.4, rotz: -0.6};
var position2 = {x: -200, y: 150, width: 1, height: 1, depth: 1, rotx: -0.5, roty: 0.7, rotz: 0.9};
var mesh = new THREE.Mesh(
new THREE.CubeGeometry(190, 45, 30),
new THREE.MeshBasicMaterial({color: 0x444444}),
0
);
mesh.position.set(position.x, position.y, 0);
mesh.rotation.set(position.rotx, position.roty, position.rotz);
scene.add(mesh);
var t1 = new TWEEN.Tween(position).to(target, 2000);
t1.onUpdate(function() {
mesh.position.set(position.x, position.y, 0);
mesh.scale.set(position.width, position.height, position.depth);
mesh.rotation.set(position.rotx, position.roty, position.rotz);
});
t1.easing(TWEEN.Easing.Quadratic.Out);
t1.onComplete(function() {t2.start();});
var t2 = new TWEEN.Tween(target).to(position2, 2000);
t2.onUpdate(function() {
mesh.position.set(target.x, target.y, 0);
mesh.scale.set(target.width, target.height, target.depth);
mesh.rotation.set(target.rotx, target.roty, target.rotz);
});
t2.easing(TWEEN.Easing.Quadratic.In);
t1.start();
And I have the tweens updating in my animation function:
function animate() {
requestAnimationFrame(animate);
renderer.render(scene, camera);
mesh.__dirtyPosition = true;
mesh.__dirtyRotation = true;
TWEEN.update();
}
animate();
This is working as I expect it to, but it is clearly very inefficient, and difficult to work around.
Any and all help will be appreciated.
You're overcomplicating things a bit by re-naming the x, y, z properties to width, height, depth or rotx, roty, rotz. This only means you have to manually translate these properties onUpdate when you do scale.x = position.width and rotation.x = position.rotx. I recommend you keep x, y, z, to avoid these repetitive assignments.
// We set our start and target pos using the THREE.js "x, y, z" nomenclature
var startPos = {x: -200, y: 150, z: 0};
var targetPos = {x: 200, y: -100, z: 0};
// Scale also is defined in "x, y, z"
var startScale = {x: 1, y: 1, z: 1};
var targetScale = {x: 0.4, y: 3, z: 8};
// Rotation also has "x, y, z" degrees in Euler angles
var startRot = {x: -0.5, y: 0.7, z: 0.9};
var targetRot = {x: 0.3, y: -0.4, z: -0.6};
// Standard mesh setup
var mesh = new THREE.Mesh(
new THREE.CubeGeometry(190, 45, 30),
new THREE.MeshBasicMaterial({color: 0x444444})
);
mesh.position.copy(startPos);
mesh.rotation.copy(startRot);
scene.add(mesh);
// Create shortcuts for shorter easing names
var QuadOut = TWEEN.Easing.Quadratic.Out;
var QuadIn = TWEEN.Easing.Quadratic.In;
// Create one tween for position
// Notice that you can chain the animation
// back to startPos by doing double ".to().to()""
var t1 = new TWEEN.Tween(mesh.position)
.to(targetPos, 2000, QuadOut)
.to(startPos, 2000, QuadIn);
// Second, we tween the mesh's rotation
var t2 = new TWEEN.Tween(mesh.rotation)
.to(targetRot, 2000, QuadOut)
.to(startRot, 2000, QuadIn);
// Third, we tween the mesh's scale
var t3 = new TWEEN.Tween(mesh.scale)
.to(targetScale, 2000, QuadOut)
.to(startScale, 2000, QuadIn);
t1.start();
t2.start();
t3.start();
And finally, during animate(), you no longer have to change __dirtyPosition or anything, because the tween is updating the mesh's properties directly.
function animate() {
requestAnimationFrame(animate);
TWEEN.update();
renderer.render(scene, camera);
}
animate();
This should be really, really simple - but it's wrecking my head by not working.
console.log(this.cameraTarget.position); // THREE.Vector3 {x: 374, y: 0, z: -186, constructor: function, set: function…}
var targetSphere = new THREE.Mesh(new THREE.SphereGeometry(10, 100, 100), new THREE.MeshNormalMaterial());
targetSphere.position = this.cameraTarget.position;
console.log(targetSphere.position); // THREE.Vector3 {x: 0, y: 0, z: 0, constructor: function, set: function…}
So this.cameraTarget is an object (not an Object3D) that has a position property which is a Vector3. When I assign that to the position property of a Mesh, it gets ignored. Totally. Any ideas?