在Animate中更新ThreeJS模型的位置(如何在回调之外访问模型的位置)

时间:2018-03-28 04:29:06

标签: javascript callback three.js global-variables

我正试图创建一个围绕地球运行的国际空间站模型。我正在使用threeJS来实现这一目标。到目前为止,除了更新导入的ISS模型的位置之外,我还能完美地完成所有工作。我有一个球体围绕地球运行,每隔5秒从一次AJAX调用获得它的位置,然后转换为地球球体模型上的坐标。我本质上想用ISS的模型替换轨道上的球体(代码中的posSphere)。因模型异步加载而出现问题。我目前尝试的是在模型的animate函数中包含参数,并在回调时将其发送到animate函数,但这会导致整个场景冻结。

<!DOCTYPE html>
<html lang="en">
    <head>
        <title>three.js webgl - OBJLoader + MTLLoader</title>
        <meta charset="utf-8">
        <meta name="viewport" content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0">
        <style>
            body {
                font-family: Monospace;
                background-color: #000;
                color: #fff;
                margin: 0px;
                overflow: hidden;
            }
        </style>
    </head>

    <body>

        <script src="Resources/three.js"></script>
        <script src="Resources/TDSLoader.js"></script>
        <script src="Resources/FBXLoader.js"></script>
        <script src="Resources/GLTFLoader.js"></script>
        <script src="Resources/inflate.min.js"></script>
        <script src="Resources/TrackballControls.js"></script>
<script>
var lat, long, issPosition;
//*********************PRELIM FUNCTIONS BEGIN**********************************
//AJAX request for current position of the ISS
function GetValue() {
var xhr = new XMLHttpRequest();
xhr.onreadystatechange = function() {
if (this.readyState == 4 && this.status == 200) {
    var requestResponse = xhr.responseText;
    var issInfo = JSON.parse(requestResponse);
    var Lat = issInfo.iss_position.latitude;
    var Long = issInfo.iss_position.longitude;
    callback(Lat, Long); //callback function with lat and long info
                }
            };
            xhr.open("GET", "http://api.open-notify.org/iss-now.json", true);
            xhr.send();
        }

    function callback(Lat, Long) {
        lat = Lat; //set global variables equal to lat and long so animate function has access
        long = Long;
    }

    GetValue(); //function call to get iss location
    setInterval(GetValue, 5000); //interval for iss location, updates every 5 seconds

//convert long & lat to 3D coordinate
function latLongToVector3(lat, lon, radius, heigth) {
    var phi = (lat)*Math.PI/180;
    var theta = (lon-180)*Math.PI/180;

    var x = -(radius+heigth) * Math.cos(phi) * Math.cos(theta);
    var y = (radius+heigth) * Math.sin(phi);
    var z = (radius+heigth) * Math.cos(phi) * Math.sin(theta);

        return new THREE.Vector3(x,y,z);
    }     
//******************PRELIM FUNCTIONS END********************************************

//******************THREE JS ENVIRONMENT BEGIN**************************************   
var width = window.innerWidth;
var height = window.innerHeight;

var scene = new THREE.Scene();

var camera = new THREE.PerspectiveCamera(75, width/height, 0.01, 1000);
camera.position.z = 400;

var controls = new THREE.TrackballControls( camera );

                controls.rotateSpeed = 1.0;
                controls.zoomSpeed = 1.2;
                controls.panSpeed = 0.8;

                controls.noZoom = false;
                controls.noPan = false;

                controls.staticMoving = true;
                controls.dynamicDampingFactor = 0.3;

                controls.keys = [ 65, 83, 68 ];

var renderer = new THREE.WebGLRenderer();
renderer.shadowMap.enabled = true;
renderer.shadowMap.type = THREE.PCFSoftShadowMap;
renderer.setSize(width, height);
document.body.appendChild(renderer.domElement);

var direcLight = new THREE.DirectionalLight(0xffffff, 0.3);
direcLight.position.set(-3,3,1.5);
direcLight.castShadow = true;
scene.add(direcLight);

var ambientLight = new THREE.AmbientLight(0xc9c9c9, 1.5);
scene.add(ambientLight);

var geometry1 = new THREE.SphereGeometry(200,32,32);
var geometry2 = new THREE.SphereGeometry(202.5,32,32);
var geometry3 = new THREE.SphereGeometry(3, 32, 32);
var material1 = new THREE.MeshBasicMaterial ({
    color: 0xff0000
});
var material2 = new THREE.MeshPhongMaterial({
    map: new THREE.TextureLoader().load('Resources/Earth3/earthmapoftwo.jpg'),
    bumpMap: new THREE.TextureLoader().load('Resources/Earth3/Bump2.jpg'),
    bumpScale: 1,
    specularMap: new THREE.TextureLoader().load('Resources/Earth3/oceanmaskbytwo.png'),
    specular: new THREE.Color('grey'),
    shininess: 40
});
var material3 = new THREE.MeshPhongMaterial({
    alphaMap: new THREE.TextureLoader().load('Resources/Earth3/Clouds.png'),
    transparent: true,
});

var issModel;
var loaderGLTF = new THREE.GLTFLoader();  
loaderGLTF.load(
    "Resources/Earth3/iss.gltf",
    function(gltf) { //I want to be able to access this gltf outside of this callback function 
        gltf.scene.scale.x = 0.1;
        gltf.scene.scale.y = 0.1;
        gltf.scene.scale.z = 0.1;
        console.log(gltf.scene.position);
        scene.add(gltf.scene);
        animate(gltf); //send gltf to animate function, this does not work
    }
)

var sphere = new THREE.Mesh(geometry1, material2); 
var clouds = new THREE.Mesh(geometry2, material3);
var posSphere = new THREE.Mesh(geometry3, material1);

sphere.receiveShadow = true;
clouds.receiveShadow = true;
posSphere.receiveShadow = true;
scene.add(sphere);
scene.add(clouds);
scene.add(posSphere);

function animate(gltf) {
    clouds.rotation.x += 0.0001;
    clouds.rotation.y += 0.0001;
    clouds.rotation.z += 0.0001; 

    issPosition = latLongToVector3(lat, long, 200, 10);
    posSphere.position.x = issPosition.x; //sphere's location is updated with the issPosition & works 
    posSphere.position.y = issPosition.y;
    posSphere.position.z = issPosition.z;

    gltf.scene.position.x = issPosition.x; //Part I am struggling with here, how to access the gltf's position from within this function. Essentially I want to replace the sphere with the gltf
    gltf.scene.position.y = issPosition.y;
    gltf.scene.position.z = issPosition.z;

    controls.update();
    requestAnimationFrame(animate);
    renderer.render(scene, camera);
            }          
animate();
//**************************THREE JS ENVIRONMENT END*************************************  
</script>

</body>
</html>

1 个答案:

答案 0 :(得分:0)

您正在为animate函数定义一个参数,然后立即调用它而不使用参数..(在代码的最后一行向下)。这就是为什么你的应用程序是&#34;冻结&#34;。 (它没有冻结..它可能会抛出异常..您可以在调试器控制台中看到.. Ctrl + Shift + J < / kbd>在chrome或更多工具中 - >来自右上方菜单的开发人员工具。例外情况应该在底部显示为红色。)

取出你所做的代码行&#39; animate(gltf)&#39;而是做&#34; issModel = gltf.scene;&#34;

然后在你的动画函数中而不是做&#34; gltf.scene.position.x =&#34;等

执行&#34; issModel.position.copy(issPosition);&#34;

如果你仍然陷入困境,请尝试在某个地方在线托管,我们可以深入了解。