Developing 3D Grain Silos and Warehouse Monitoring Systems with Three.js

Feature Overview

  • Render a 3D layout of grain storage facilities.
  • Switch between first-person and third-person camera perspectives.
  • Simulate barn door opening and closing animations.
  • Animate grain transport vehicles entering and leaving the site.
  • Support VR-style viewing modes.

Implementation Details

Displaying Storage Information

Show storage details such as identifier, capacity, and stock date when an object is selected.

StorageController.prototype.displayInfoPanel = function (target, worldPos, onClose) {
    const screenPos = Engine3D.convertToScreen(worldPos);
    $('#InfoTooltip').remove();
    $('body').append(`<div id='InfoTooltip' style='position:absolute;left:${screenPos.x - 30}px;top:${screenPos.y}px;width:2px;height:2px;z-index:1000;'></div>`);

    layer.closeAll();
    let content = '<div></div>';
    let dims = ['150px', '100px'];

    if (UIHelper) {
        const result = UIHelper.renderStorageCard(1);
        if (result) {
            content = result.markup;
            dims = result.size;
        }
    }

    layer.tips(content, '#InfoTooltip', {
        closeBtn: 1,
        shade: false,
        shadeClose: true,
        area: dims,
        time: 0,
        cancel: function (idx, layero) {
            layer.close(idx);
            if (onClose) onClose();
        },
        tips: [2, 'rgba(0,0,0,0.1)']
    });
}

Customize the UI content for the storage card:

UIHelper.prototype.renderStorageCard = function (level) {
    const randomId = Math.floor(Math.random() * 90);
    const randomTons = Math.floor(Math.random() * 10000);
    const markup = `
        <div style='font-size:32px;color:white;text-align:center;line-height:90px;'>
            <small style='font-size:26px'>Silo: 0${randomId}</small><br/>
            <small style='font-size:26px'>Capacity: ${randomTons} tons</small><br/>
            <small style='font-size:26px'>Date: 2020-05-20</small>
        </div>`;
    return {
        markup: markup,
        size: ['auto', '100px']
    };
}

Defining a Silo Model

The following JSON defines a silo usinng extruded geometry with specific materials and transformations.

{
    "visible": true,
    "name": "grainSilo",
    "type": "ExtrudeGeometry",
    "position": { "x": -7027.718, "y": -2429.816, "z": -2366.768 },
    "material": {
        "color": 16711680,
        "faces": {
            "top": { "color": 16777215, "side": 1, "opacity": 1, "texture": "../img/3dImg/dg.jpg", "repeatX": true, "tileX": 0.01, "repeatY": true, "tileY": 0.01 },
            "bottom": { "color": 16777215, "side": 1, "opacity": 1, "texture": "../img/3dImg/dg.jpg" },
            "side": { "color": 16777215, "opacity": 1, "texture": "../img/3dImg/dg.jpg", "repeatX": true, "tileX": 0.1, "repeatY": true, "tileY": 0.005 }
        }
    },
    "scale": { "x": 1, "y": 1, "z": 1 },
    "shape": {
        "points": [
            { "x": 0, "y": 0 },
            { "x": 2930, "y": 0 },
            { "x": 2930, "y": 420 },
            { "x": 1530, "y": 550 },
            { "x": 0, "y": 420 }
        ],
        "holes": []
    },
    "extrude": { "depth": 5900, "segments": 2, "steps": 2, "bevel": false },
    "rotation": [
        { "axis": "x", "angle": 0 },
        { "axis": "y", "angle": 1.5707963267948966 },
        { "axis": "z", "angle": 0 }
    ]
}

Camera Perspectives

Switch to a third-person view:

StorageController.prototype.activateThirdPerson = function () {
    Engine3D.moveCamera(
        { x: -13164.34, y: 7433.84, z: -26817.98 },
        { x: 500.68, y: -2274.56, z: -9758.79 },
        1000,
        () => {
            Scene3D.firstPersonMode = false;
            Scene3D.mobileView = false;
            Scene3D.customControls = false;
        }
    );
}

Switch to a first-person view with WASD controls:

StorageController.prototype.activateFirstPerson = function () {
    layer.msg('Controls: W-S-A-D for movement');
    Engine3D.moveCamera(
        { x: 5693.55, y: -2278.79, z: -8633.34 },
        { x: -525.77, y: -1986.19, z: -7655.68 },
        1000,
        () => {
            Scene3D.firstPersonMode = true;
            Scene3D.viewHeight = -2000;
            Scene3D.mobileView = true;
            Scene3D.customControls = true;
        }
    );
}

Door Animation

Toggle the barn doors open or closed:

StorageController.prototype.toggleDoors = function () {
    $('#toggleBtn').hide();
    Engine3D.moveCamera(
        { x: -4532.01, y: -2148.20, z: -6284.60 },
        { x: -4012.91, y: -2341.79, z: -5196.68 },
        1000,
        () => {
            const barn = Engine3D.findMesh('mainBarn');
            const leftDoor = Engine3D.findMesh('leftDoor');
            const rightDoor = Engine3D.findMesh('rightDoor');

            const isClosed = $('#toggleBtn').data('status') === 'closed';

            if (isClosed) {
                new TWEEN.Tween(leftDoor.rotation)
                    .to({ y: -Math.PI / 1.5 }, 2000).start();
                new TWEEN.Tween(rightDoor.rotation)
                    .to({ y: Math.PI / 1.5 }, 2000)
                    .onComplete(() => {
                        $('#toggleBtn').text('Close Doors').show().data('status', 'open');
                    }).start();
            } else {
                new TWEEN.Tween(leftDoor.rotation)
                    .to({ y: 0 }, 2000).start();
                new TWEEN.Tween(rightDoor.rotation)
                    .to({ y: 0 }, 2000)
                    .onComplete(() => {
                        $('#toggleBtn').text('Open Doors').show().data('status', 'closed');
                    }).start();
            }
        }
    );
}

Vehicle Animation

Simulate a truck arriving to load grain:

function animateTruckArrival() {
    Engine3D.moveCamera(
        { x: 801.50, y: 958.56, z: -12201.04 },
        { x: -3801.09, y: -2092.37, z: -5062.51 },
        1000,
        startTruckSequence
    );
}

function startTruckSequence() {
    const truckBody = Engine3D.findMesh('truckBody');
    const trailer = Engine3D.findMesh('trailer');
    const grainLoad = Engine3D.findMesh('grainLoad');

    grainLoad.position.set(-4189.89, 0, -5816.50);
    grainLoad.scale.y = 0.1;
    grainLoad.rotation.y = Math.PI / 2;
    truckBody.rotation.y = Math.PI / 2;
    trailer.rotation.y = Math.PI / 2;

    truckBody.visible = true;
    trailer.visible = true;

    truckBody.position.set(-22422.47, 0, -6239.19);
    trailer.position.set(-22620.57, 0, -5932.50);

    new TWEEN.Tween(trailer.position)
        .to({ x: -3726.21 }, 6000).start();
    new TWEEN.Tween(truckBody.position)
        .to({ x: -3528.85 }, 6000)
        .onComplete(adjustPosition).start();
}

function adjustPosition() {
    const truckBody = Engine3D.findMesh('truckBody');
    const trailer = Engine3D.findMesh('trailer');

    new TWEEN.Tween(truckBody.position).to({ x: -3532.54 }, 2000).start();
    new TWEEN.Tween(trailer.position).to({ x: -3729.16 }, 2000)
        .onComplete(finalizeLoad).start();
}

Temperature and Humidity Monitoring

Visualize sensor data inside the silo:

StorageController.prototype.showClimateData = function (siloId) {
    const sensors = Engine3D.findMeshesByPattern(`sensor_${siloId}_`);
    DataService.fetchClimate(siloId, (readings) => {
        const labels = Engine3D.createLabels(sensors, readings);
        Engine3D.renderLabels(labels);
    });
}

Tags: Three.js WebGL 3D Visualization IoT Monitoring Warehouse Management

Posted on Thu, 21 May 2026 21:56:38 +0000 by sureshmaharana