You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Three.js如何根据SQL实时数据无刷新动态更新相机位置

问题根源
  • 嵌入JS的PHP代码仅在页面首次加载时由服务端执行一次,会把当时读取到的数据库坐标直接硬编码到JS脚本中,页面加载完成后前端不会自动重新执行PHP逻辑拉取最新值,你看到的页面其他位置每秒更新的坐标,和Three.js初始化时拿到的静态坐标是两套独立逻辑。
  • 现有渲染逻辑为事件触发式:render()函数仅在模型加载完成、轨道控制器交互、窗口尺寸变化三个场景执行,即便修改了相机位置参数,没有主动触发渲染的话画面不会同步更新。
  • 你使用的OrbitControls会缓存相机状态,修改相机位置后如果不调用controls.update(),控制器会在下一次交互时把相机重置回旧位置。
修复方案

第一步:新增独立数据接口

新建单独的PHP文件get_camera_pose.php,专门返回数据库中最新的相机坐标,输出JSON格式数据,不要把动态数据直接嵌在首屏JS代码里:

<?php
// 复用你现有数据库连接、查询最新x/y/z轴坐标的逻辑
// 以下数据库查询逻辑请替换成你自己的实际代码
// $conn = mysqli_connect('数据库地址','用户名','密码','库名');
// $res = mysqli_query($conn, "SELECT xaxis,yaxis,zaxis FROM 存储坐标的表 ORDER BY 主键id DESC LIMIT 1");
// $row = mysqli_fetch_assoc($res);

header('Content-Type: application/json');
echo json_encode([
    'x' => floatval($row['xaxis']),
    'y' => floatval($row['yaxis']),
    'z' => floatval($row['zaxis'])
]);
exit;
?>

第二步:修改前端Three.js代码

核心修改点:

  • 把controls变量提升到全局作用域,方便后续更新状态
  • 新增基于requestAnimationFrame的持续渲染循环,替代原有的事件触发式渲染
  • 新增定时轮询逻辑,每秒拉取一次最新坐标,更新相机位置后同步控制器状态

修改后的完整代码如下:

<script>
if ( ! Detector.webgl ) Detector.addGetWebGLMessage();

// 全局变量声明补充controls
var camera, scene, renderer, controls;

init();
// 启动渲染循环
animate();
// 启动坐标拉取轮询,间隔和你数据库更新频率一致即可
setInterval(fetchLatestCameraPos, 1000);

function init() {
    scene = new THREE.Scene();
    scene.add( new THREE.AmbientLight( 0x999999 ) );

    var pointLight = new THREE.PointLight( 0xffffff, 0.6 );
    pointLight.position.set(80, 80, 90);
    scene.add( pointLight );

    camera = new THREE.PerspectiveCamera( 35, window.innerWidth / window.innerHeight, 1, 500 );
    // Z轴朝上的配置保留
    camera.up.set( 0, 0, 1 );
    // 首屏初始坐标可以保留PHP输出,首次加载不用等接口返回
    camera.position.set( <?php echo $xaxis; ?>, <?php echo $yaxis; ?>, <?php echo $zaxis; ?> );
    scene.add( camera );

    renderer = new THREE.WebGLRenderer( { antialias: true } );
    renderer.setClearColor( 0x333333 );
    renderer.setPixelRatio( window.devicePixelRatio );
    renderer.setSize( window.innerWidth, window.innerHeight );
    document.body.appendChild( renderer.domElement );

    var loader = new THREE.ThreeMFLoader();
    loader.load( './models/3mf/cube_gears.3mf', function ( object ) {
        scene.add( object );
    } );

    // 给全局controls赋值
    controls = new THREE.OrbitControls( camera, renderer.domElement );
    controls.target.set( 80, 65, 35 );
    controls.update();

    window.addEventListener( 'resize', onWindowResize, false );
}

// 拉取最新相机坐标的方法
function fetchLatestCameraPos() {
    fetch('./get_camera_pose.php')
        .then(res => res.json())
        .then(pos => {
            // 更新相机位置
            camera.position.set(pos.x, pos.y, pos.z);
            // 必须更新控制器状态,否则会被控制器缓存的旧位置覆盖
            controls.update();
        })
        .catch(err => console.error('坐标拉取失败:', err));
}

// 持续渲染循环
function animate() {
    requestAnimationFrame(animate);
    // 如果你不需要用户手动拖拽调整视角,可以把下面这行注释掉,只在坐标更新时渲染,降低显卡占用
    controls.update();
    render();
}

function onWindowResize() {
    camera.aspect = window.innerWidth / window.innerHeight;
    camera.updateProjectionMatrix();
    renderer.setSize( window.innerWidth, window.innerHeight );
}

function render() {
    renderer.render( scene, camera );
}
</script>
优化建议
  • 如果场景不需要用户手动交互,可以去掉持续的requestAnimationFrame循环,仅在拿到新坐标、窗口尺寸变化、控制器交互三个场景调用render()即可,能大幅降低性能消耗。
  • 轮询间隔不要短于500ms,避免给服务端造成不必要的请求压力。
  • 如果后续需要毫秒级的实时更新,可以把HTTP轮询替换成WebSocket长连接主动推送,当前每秒更新的需求用轮询完全够用。

内容的提问来源于stack exchange,提问作者Chris Lane

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.27 06:18:24