Implementing Industrial Digital Twins with Three.js: Interactive 3D Visualization and Real-time Data Integration

Digital twin implementations for industrial environments consist of three primary technical layers: data acquisition via sensors, network transmission and storage, and visual presentation. This discussion focuses on the presentation layer using WebGL (Three.js) for browser-based 3D visualization.

Industrial Park Overview and Model Rendering

Creating the base 3D environment involves loading architectural models with appropriate rendering settings.

const sceneConfiguration = {
    renderDistance: 100000000,
    enableAntialiasing: true,
    asyncLoading: false,
    showGridHelper: false,
    backgroundColor: 0x4068b0,
    backgroundOpacity: 0,
};

const industrialModels = [];

// Load industrial park model data
fetchModelData('./models/industrial_park.json', function(modelData) {
    industrialModels = modelData;
});

initializeThreeJSRenderer('viewer-container', sceneConfiguration, industrialModels);

Interactive Navigation and Scene Management

Implementing scene transitions through model interaction provides intuitive navigation between different facility levels.

function handleModelSelection(modelObject, faceIndex) {
    if (modelObject.name.includes('building_unit_112')) {
        // Camera transition before scene change
        manipulateCamera.viewFocus(modelObject, faceIndex);
        
        setTimeout(() => {
            window.location.href = 'production_floor.html';
        }, 2000);
    }
}

Detail View with Contextual Emphasis

Isolating specific equipment while maintaining spatial context can be achieved through selective rendering and opacity transitions.

function displayFurnaceDetails(selectedObject) {
    const furnaceStates = { CURRENT_STATE: 10 };
    clearAllInterfaceMessages();
    
    hideAllModels(() => {
        let targetObject = selectedObject;
        if (targetObject.name.includes('FURNACE')) {
            targetObject = findSceneObject(targetObject.name.split('FURNACE')[0]);
        }
        
        if (targetObject.originalYPosition) {
            targetObject.position.y = targetObject.originalYPosition;
        }
        targetObject.visible = true;
        
        const workpieceName = determineWorkpieceId(targetObject.name);
        const workpiece = findSceneObject(workpieceName);
        workpiece.visible = true;
        
        if (workpiece.originalYPosition) {
            workpiece.position.y = workpiece.originalYPosition;
        }
        
        // Transition effects
        fadeObjectOpacity([workpiece], 0, 1, 100, () => {});
        fadeObjectOpacity([targetObject], 0, 0.2, 1000, () => {
            displayNetworkData(findSceneObject(furnaceMappings[targetObject.name + '_workpiece']));
        });
    });
}

Sensor Visualization and Data Overlay

Real-time sensor data integration requires dynamic positioning of informational overlays within the 3D space.

function displaySensorInformation(sensorObject) {
    hideDetailPanels();
    
    const screenCoordinates = convertToScreenSpace(sensorObject.position);
    const markerDivId = 'SensorMarkerHelper';
    
    removeExistingMarker(markerDivId);
    document.body.insertAdjacentHTML('beforeend',
        `<div id="${markerDivId}" style="position:absolute;left:${screenCoordinates.x}px;top:${screenCoordinates.y}px;height:2px;width:2px;z-index:1000;"></div>`
    );
    
    const sensorType = identifySensorType(sensorObject.name);
    const detailPanelId = getDetailPanelId(sensorType);
    
    document.getElementById(detailPanelId).style.display = 'block';
    document.getElementById(detailPanelId).style.left = `${screenCoordinates.x}px`;
    document.getElementById(detailPanelId).style.top = `${screenCoordinates.y - 170}px`;
}

Real-time Animation System for Production Processes

Animating industrial equipment requires coordintaed camera movements and object transformations to simulate production workflows.

Robotic Arm Material Handling

function executeMaterialRetrieval(furnaceId) {
    const operationInProgress = true;
    const roboticArm = findSceneObject('robotic_arm_369');
    const armAttachment = findSceneObject('arm_attachment_373');
    
    if (furnaceId === 'furnace_1135') {
        new TWEEN.Tween(roboticArm.position).to({ x: 7054.110 }, 1000).start();
        new TWEEN.Tween(armAttachment.position).to({ x: 7054.110 }, 1000).onComplete(() => {
            moveCameraToPosition(
                {x: 11987.945, y: 5821.875, z: 639.598},
                {x: 5418.917, y: -132.795, z: 2029.241},
                500,
                () => {
                    executeFurnaceDoorAnimation(700, furnaceId);
                    scheduleRoboticOperations();
                }
            );
        }).start();
    }
}

function scheduleRoboticOperations() {
    setTimeout(() => {
        executeArmExtension(500);
        setTimeout(() => {
            displayWorkpiece();
            setTimeout(() => {
                executeArmRetraction();
                setTimeout(() => {
                    moveCameraToPosition(
                        { x: 10739.533, y: 4071.901, z: 4924.279 },
                        { x: 6579.256, y: 55.126, z: 1749.544 },
                        500,
                        () => {
                            executeWorkpieceLift();
                            setTimeout(() => {
                                executeMaterialCollection();
                                setTimeout(() => {
                                    hideWorkpiece();
                                    findSceneObject('workpiece_0').visible = true;
                                    setTimeout(() => {
                                        operationInProgress = false;
                                        executeArmRetraction();
                                        resetArmPosition();
                                    }, 200);
                                }, 600);
                            }, 600);
                        }
                    );
                }, 600);
            }, 300);
        }, 800);
    }, 1000);
}

Industrial Furnace Animation Control

function animateFurnaceOperation(movementDistance, furnaceName) {
    const furnaceComponents = [];
    const targetFurnace = furnaceName || 'furnace_1135';
    
    furnaceComponents.push(findSceneObject(targetFurnace).children[19]); // Component 1
    furnaceComponents.push(findSceneObject(targetFurnace).children[11]); // Component 2
    furnaceComponents.push(findSceneObject(targetFurnace).children[12]); // Component 3
    
    furnaceComponents.forEach(component => {
        if (!component.initialY) {
            component.initialY = component.position.y;
        }
        component.currentY = component.position.y;
    });
    
    const movement = { y: 0 };
    
    new TWEEN.Tween(movement).to({ y: movementDistance }, 500)
        .onUpdate(function() {
            furnaceComponents.forEach((component, index) => {
                component.position.y = component.currentY + this.y;
                const minPosition = component.initialY - movementDistance;
                if (component.position.y < minPosition) {
                    component.position.y = minPosition;
                }
                component.matrixAutoUpdate = true;
            });
        })
        .start();
}

Workpiece Processing Sequence

function processWorkpieceAtPress() {
    const operationActive = true;
    
    updateCameraView(
        { x: 7193.942, y: 1335.120, z: 1186.335 },
        { x: 6790.381, y: 763.191, z: -44.540 },
        500,
        () => {
            executePressOperation(() => {
                operationActive = false;
            }, 0);
        }
    );
}

function executeCoolingSpray() {
    const operationActive = true;
    updateCameraView(
        { x: 6992.126, y: 548.546, z: 1331.912 },
        { x: 6795.575, y: 631.176, z: -557.178 },
        500,
        () => {
            activateSprayArm(() => {
                findSceneObject('spray_nozzle_1368').visible = true;
                
                setTimeout(() => {
                    findSceneObject('spray_nozzle_1368').visible = false;
                    deactivateSprayArm(() => {
                        operationActive = false;
                    });
                }, 3000);
            });
        }
    );
}

Conveyor System and Trimming Operations

function transferToTrimmingStation() {
    const operationActive = true;
    
    findSceneObject('forged_part_3').visible = true;
    updateCameraView(
        { x: 3088.224, y: 2460.282, z: 3740.127 },
        { x: 4081.729, y: 203.355, z: 654.513 },
        500,
        () => {
            executeConveyorMovement(() => {
                operationActive = false;
            });
        }
    );
}

function executeTrimmingOperation() {
    const operationActive = true;
    updateCameraView(
        { x: 1268.735, y: 1568.104, z: -2963.545 },
        { x: 1348.071, y: 377.406, z: 594.059 },
        500,
        () => {
            activateTrimmingMachine(() => {
                operationActive = false;
            });
        }
    );
}

Tags: threejs digital-twin WebGL industrial-visualization 3d-animation

Posted on Wed, 03 Jun 2026 16:21:03 +0000 by RonHam