Skip to content
Advertisement

Three.JS: Move 3D cube with accelerometer data over x an y-axis

Following my previous post

I am developing a 3D model that moves based on input from accelerometer and gyroscope sensors. The 3D model is written with three.js, and the input data for rotation and translation are in JSON format. Currently the 3D cube moves in 3D space but I have two main problems:

  1. The 3D cube move off boundary when the accelerometer value is too high.
  2. It seems that the 3D cube only move in one axis, for example, even though there is X, Y and Z value, the object only translate in the Y axis, but not UP/DOWN.

I basically want the 3D cube to move only UP/DOWN using the X-axis data. Below is my code:

index.html

import * as THREE from "three";
import data from "../data/data.json"
import "./style.css"

const canvas = document.querySelector('#canvas');
const accelPanel = document.querySelector('#accelPanel');
const renderer = new THREE.WebGLRenderer({ canvas });

const fov = 70;
const aspect = 2;  // the canvas default
const near = 20;
const far = 500;
const camera = new THREE.PerspectiveCamera(fov, aspect, near, far);
camera.position.set(0, 50, 1.5);
camera.up.set(0, 0, 1);
camera.lookAt(0, 0, 0);

const scene = new THREE.Scene();
{
    const color = 0x00afaf;
    const intensity = 10;
    const light = new THREE.PointLight(color, intensity);
    scene.add(light);
}
const boxGeometry = new THREE.BoxGeometry();
const boxMaterial = new THREE.MeshBasicMaterial({ color: "green", wireframe: false });
const object = new THREE.Mesh(boxGeometry, boxMaterial);

var cubeAxis = new THREE.AxesHelper(3);
object.add(cubeAxis);

object.scale.set(5, 5, 5)
scene.add(object);
scene.background = new THREE.Color(0.22, 0.23, 0.22);

let currentIndex = 0
let time = data[currentIndex].time
let velocity = new THREE.Vector3()
requestAnimationFrame(render);

function render(dt) {
    dt *= 0.0001 // in seconds
    time += dt
    document.querySelector("#time").textContent = time.toFixed(2)

    // Find datapoint matching current time
    while (data[currentIndex].time < time) {
        currentIndex++
        if (currentIndex >= data.length) return
    }
    const { rotX, rotY, rotZ, accX, accY, accZ } = data[currentIndex]

    const acceleration = new THREE.Vector3( accX, accY, accZ)
    object.rotation.set(rotX, rotY, rotZ)
    object.position.add(velocity.clone().multiplyScalar(dt)).add(acceleration.clone().multiplyScalar(50 * dt ** 2))
    velocity.add(acceleration.clone().multiplyScalar(dt))

    resizeToClient();
    renderer.render(scene, camera);
    requestAnimationFrame(render);
}

function resizeToClient() {
    const needResize = resizeRendererToDisplaySize()
    if (needResize) {
        const canvas = renderer.domElement;
        camera.aspect = canvas.clientWidth / canvas.clientHeight;
        camera.updateProjectionMatrix();
    }
}

function resizeRendererToDisplaySize() {
    const canvas = renderer.domElement;
    const width = canvas.clientWidth;
    const height = canvas.clientHeight;
    const needResize = canvas.width !== width || canvas.height !== height;
    if (needResize) {
        renderer.setSize(width, height, false);
    }
    return needResize;
}

index.html

<!DOCTYPE html>
<html>

<head>
    <meta charset="UTF-8">
</head>

<body>
    <canvas id="canvas" width="1500" height="800" style="border:1px solid #000000;"></canvas>
    <div id="accelPanel"></div>
    <div id="info">
        <div>t = <span id="time">0</span> s</div>
    </div>
</body>
</html>

I tried to modify these lines which are responsible of rotation and positioning:

object.rotation.set(rotX, rotY, rotZ)
object.position.add(velocity.clone().multiplyScalar(dt)).add(acceleration.clone().multiplyScalar(50 * dt ** 2))

But it doesn’t seem that the problem is from coming from them.

this is an example of the input data:

[
    {
        "time": 8029,
        "rotX": 0.836885376331281,
        "rotY": -0.05305800926062761,
        "rotZ": 0.03822271061867582,
        "accX": -0.0265087890625,
        "accY": -0.046376953125,
        "accZ": 0.0312451171875
    },
    {
        "time": 8030.000000000001,
        "rotX": 0.836885376331281,
        "rotY": -0.05305800926062761,
        "rotZ": 0.03822271061867582,
        "accX": -0.0265087890625,
        "accY": -0.046376953125,
        "accZ": 0.0312451171875
    },
    {
        "time": 8031,
        "rotX": 0.836885376331281,
        "rotY": -0.05305800926062761,
        "rotZ": 0.03822271061867582,
        "accX": -0.0265087890625,
        "accY": -0.046376953125,
        "accZ": 0.0312451171875
    }
]

and this is how accelerometerX data looks like (Click here to download the data):

enter image description here

These are the movements UP and DOWN but somehow this is not showing in the animation.

Is there is a way to make the 3D cube moves similarly to the image below (only UP and DOWN and the car is just for illustration):

enter image description here

to have a look a live preview of the 3D cube, click here (it is from the previous post I made).

Advertisement

Answer

Looks like you’re doing all kinds of multiplication to the position, velocity, and acceleration vectors, and it’s hard to gauge what magnitude the final position ends up having.

Why don’t you start with something simple, like object.position.y = accY * 30; So the data that’s barely noticeable in the [-0.1, 0.1] range gets turned to [-15, 15] range, and then you can fine-tune it.

Another issue I’m noticing is that your camera position is (0, 50, 1.5), which is very high looking from the top-down, and therefore it’s not letting you see any y-axis movement. If you want your camera to capture up/down movement, don’t place it up so high: camera.position.set(0, 0, 15) should suffice.

User contributions licensed under: CC BY-SA
3 People found this is helpful
Advertisement