我正在使用三个.js和所有示例(mrdoob,stemkoski)编写和动画循环,我看到在线在脚本开头使用未受保护的全局变量。我试图将它们包含在 init() 函数中,然后通过动画循环将它们作为参数传递。但是,渲染器未定义。
我不确定我在下面错过了什么。我的主要问题是如何理解设置具有良好闭包的动画循环的最佳实践(保护本来是全局的变量)。谢谢!
// THE MAIN ANIMATION LOOP:
// UPDATE the scene
function update(keyboard, controls, stats, clock) {
// delta = change in time since last call (in seconds)
var delta = clock.getDelta();
// functionality provided by THREEx.KeyboardState.js
if ( keyboard.pressed("z") )
{
// do something
}
controls.update();
stats.update();
};
// RENDER the scene
function render(renderer, scene, camera) {
renderer.render(scene, camera);
};
// ANIMATE the scene
function animate(scene, camera, renderer, controls, stats, keyboard, clock) {
requestAnimationFrame(animate);
render(renderer, scene, camera);
update(keyboard, controls, stats, clock);
};
// *********************
// INITIALIZES THE SCENE
function init(images) { // `images` is passed by a callback from loadImages
// standard global variables, held privately
var container, scene, camera, renderer, controls, stats;
var keyboard = new THREEx.KeyboardState();
var clock = new THREE.Clock();
///////////
// SCENE //
///////////
scene = new THREE.Scene();
////////////
// CAMERA //
////////////
// set the view size in pixels (custom or according to window size)
var SCREEN_WIDTH = 1920, SCREEN_HEIGHT = 1080;
// var SCREEN_WIDTH = window.innerWidth, SCREEN_HEIGHT = window.innerHeight;
// camera attributes
var VIEW_ANGLE = 20, ASPECT = SCREEN_WIDTH / SCREEN_HEIGHT, NEAR = 0.1, FAR = 20000;
// set up camera
camera = new THREE.PerspectiveCamera(VIEW_ANGLE, ASPECT, NEAR, FAR);
// add the camera to the scene
scene.add(camera);
// the camera defaults to position (0,0,0)
// so pull it back (z = 400) and up (y = 100) and set the angle towards the scene origin
// (x,y,z)
camera.position.set(0,150,1000);
camera.lookAt(scene.position);
//////////////
// RENDERER //
//////////////
// create and start the renderer; choose antialias setting.
if (Detector.webgl)
renderer = new THREE.WebGLRenderer( {antialias:true} );
else
renderer = new THREE.CanvasRenderer();
renderer.setSize(SCREEN_WIDTH, SCREEN_HEIGHT);
// attach div element to variable to contain the renderer
container = document.getElementById( 'ThreeJS' );
// attach renderer to the container div
container.appendChild( renderer.domElement );
///////////
// STATS //
///////////
// displays current and past frames per second attained by scene
stats = new Stats();
stats.domElement.style.position = 'absolute';
stats.domElement.style.bottom = '0px';
stats.domElement.style.zIndex = 100;
container.appendChild( stats.domElement );
///////////
// LIGHT //
///////////
// create a light
var light = new THREE.PointLight(0xffffff);
light.position.set(100,250,0);
scene.add(light);
////////////
// IMAGES //
////////////
var element1 = THREE.ImageUtils.loadTexture(images.dresser10);
var element2 = THREE.ImageUtils.loadTexture(images.dresser14);
var element1Material = new THREE.SpriteMaterial( { map: element1, useScreenCoordinates: true, alignment: THREE.SpriteAlignment.topLeft } );
var sprite = new THREE.Sprite(element1Material);
sprite.position.set( 50, 50, 0 );
sprite.scale.set( 64, 64, 1.0 ); // imageWidth, imageHeight
scene.add(sprite);
animate(container, scene, camera, renderer, controls, stats, keyboard, clock);
};
// ********************************************************
// CHECKS TO SEE IF THE WINDOW HAS LOADED BEFORE PROCEEDING
// Once the window is loaded, calls the init function
window.addEventListener ("load", eventWindowLoaded, false);
function eventWindowLoaded() {
loadImages(init); // calls to initialize the scene once the images are loaded
}
我按照上面的@Bergi的建议,在Crockford风格的模块中重写了动画循环,该模块返回了一个充满特权方法的对象,可以访问现在受保护的变量。这里适用于任何寻找类似模式的人:
// ************************
// THE MAIN ANIMATION LOOP:
var animLoop = (function () {
// standard global variables, held privately in this module
var container, scene, camera, renderer, controls, stats;
var keyboard = new THREEx.KeyboardState();
var clock = new THREE.Clock();
// SCENE
scene = new THREE.Scene();
// CAMERA
var SCREEN_WIDTH = window.innerWidth, SCREEN_HEIGHT = window.innerHeight;
var VIEW_ANGLE = 20, ASPECT = SCREEN_WIDTH / SCREEN_HEIGHT, NEAR = 0.1, FAR = 20000;
camera = new THREE.PerspectiveCamera(VIEW_ANGLE, ASPECT, NEAR, FAR);
scene.add(camera);
camera.position.set(0,150,1000);
camera.lookAt(scene.position);
// RENDERER
if (Detector.webgl) {
renderer = new THREE.WebGLRenderer( {antialias:true} );
} else {
renderer = new THREE.CanvasRenderer();
}
renderer.setSize(SCREEN_WIDTH, SCREEN_HEIGHT);
container = document.getElementById( 'ThreeJS' );
container.appendChild( renderer.domElement );
// LIGHT
var light = new THREE.PointLight(0xffffff);
light.position.set(100,250,0);
scene.add(light);
// IMAGES
var images;
var element1, element2, element1Material, sprite;
// RETURN:
// *** returns an object full of functions with priviledged access to the private variables listed above ***
return {
setImages: function (images_) { // sets the value of the images (array) above
images = images_;
},
createSprites: function () {
var element1 = THREE.ImageUtils.loadTexture(images.dresser10.src);
var element1Material = new THREE.SpriteMaterial( { map: element1, useScreenCoordinates: true, alignment: THREE.SpriteAlignment.topLeft } );
var sprite = new THREE.Sprite(element1Material);
sprite.position.set( 50, 50, 0 );
sprite.scale.set( 64, 64, 1.0 );
scene.add(sprite);
},
update: function () {
var delta = clock.getDelta();
// functionality provided by THREEx.KeyboardState.js
if ( keyboard.pressed("z") )
{
// do something
}
},
render: function () {
renderer.render(scene, camera);
}
};
}());
// ANIMATE the scene
function animate() {
requestAnimationFrame( animate );
animLoop.render();
animLoop.update();
};
// INITIALIZES THE SCENE
function init(images) { // `images` is passed by a callback not included here
animLoop.setImages(images); // places the initial array of images as a private variable in the animLoop object
animLoop.createSprites();
animate();
};
window.addEventListener ("load", eventWindowLoaded, false);
function eventWindowLoaded() {
loadImages(init); // calls to initialize the scene once the images are loaded
};