Здравствуйте, уважаемые эксперты.
Возникла необходимость сделать небольшую анимацию с падающими кубами. Цель в том, чтобы некоторое множество кубиков начали падать с высоты, отображаясь изначально стороной А к камере, а затем после падения перевернулись вверх стороной Х.
Я нашел реализацию, близкую к тому, что мне нужно. Для реализации полета кубов был использован Away3D + Jiglib. Немного разобравшись с кодом, я смог добиться некоторых успехов. Но возникает два вопроса, которые я не могу решить, т.к. не соображаю в трехмерной графике и тем более, движках.
1. Почему некоторые кубы падают сквозь плоскость? Как этого избежать? Рисовать несколько плоскостей друг под другом, "затормаживая" движение (обход бага)? При чем чем быстрее скорость и больше количество кубов, тем больше они проваливаются.
2. Как заставить кубики упасть нужной стороной вверх? Для этого я определил углы поворота для каждой из сторон (использую их при отправной точке полета). Думая над этой проблемой, я вижу два решения:
I) Заставить кубики катиться, прорисовывая анимацию. Абсолютно не представляю, как это сделать. Мне даже не удалось просто насильно передвинуть кубик по какой-нибудь траектории.

II) "Прикрепить" к нужной грани каждого куба (внутри него) "утяжелитель" - некий объект, масса которого создаст эффект неваляшки. Объект должен быть достаточно тяжелым и находиться с некоторым смещением от центра нужной грани, например так:
ооооооо
оооо
хоо
ооооооо
ооооооо
То есть, у куба будет смещенный центр тяжести, который заставит его перевернуться в нужную сторону. При этом он, конечно, может "хромать" при анимации, но это не критично.
Но опять же, я не представляю, как присоединить к существующему объекту ещё объект, чтобы они двигались неотрывно друг от друга. Я так понимаю, это нужно создавать другую модель, не куб.
Вот код, на который я опираюсь (используется слегка устаревший away3d для совместимости с jiglib):

Код AS3:
import away3d.cameras.*;
import away3d.containers.*;
import away3d.materials.*;
import away3d.primitives.*
import away3d.lights.DirectionalLight3D
import jiglib.physics.RigidBody;
import jiglib.plugin.away3d.Away3DPhysics;
import jiglib.plugin.away3d.Away3dMesh;
import jiglib.math.JNumber3D
import flash.utils.*; // Временно
var scene:Scene3D;
var camera:HoverCamera3D;
var view:View3D;
var light:DirectionalLight3D;
var physics:Away3DPhysics;
var speed:Number = 8; // Скорость физического движка
var boxWidth:Number = 400; // Ширина коробочки по X
var boxHeight:Number = 65; // Глубина коробочки по Z
var boxDepth:Number = 400; // Длина коробочки по Y
var boxThickness:Number = 0.5; // Ширина границ
var cubeTextures:Array = [ new WireColorMaterial(0xFF4444), //Куб
new WireColorMaterial(0x44FF44),
new WireColorMaterial(0x4444FF),
new WireColorMaterial(0xFFFF44),
new WireColorMaterial(0x44FFFF),
new WireColorMaterial(0xFF44FF) ]
var wallTexture:WireColorMaterial = new WireColorMaterial(0xFFFFFF); // Текстура стенок
var groundTexture:WireColorMaterial = new WireColorMaterial(0xFFFFFF); // Фон доски
var backgroundTexture:WireColorMaterial = new WireColorMaterial(0x000000); // Задний план
var cubeScale:Number = 15; // Размер кубиков
var cubes:Array = new Array()
var cubeMaxLinVel = 30; // Максимальная скорость линейного движения (не уверен)
var cubeMaxRotVel = 20; // Максимальная скорость вращения объекта (не уверен)
var flyHeight:Number = cubeScale*5+200; // Регулятор высоты полета
var cubeMass:Number = 10; // Масса кубика, влияет на скорость полета
// Стороны
var cubeNumbersRotation:Array = new Array();
cubeNumbersRotation[1] = new Array(0, 0, 90); //сторона 1
cubeNumbersRotation[2] = new Array(90, 90, 0); //сторона 2
cubeNumbersRotation[3] = new Array(270, 0, 270); //сторона 3
cubeNumbersRotation[4] = new Array(90, 0, 0);//сторона 4
cubeNumbersRotation[5] = new Array(0, 0, 0); //сторона 5
cubeNumbersRotation[6] = new Array(0, 0, 180); //сторона 6 (180, 0, 0)
var startSide = 1; // Какой стороной вверх начинать полет
var stopSide = 5; // Какой стороной вверх приземлиться (<<<<<<<<<<<<<<<<< как?)
function initAway3D():void {
scene = new Scene3D();
camera = new HoverCamera3D();
camera.distance = 400; // Дистанция к объекту внимания
camera.moveCamera(); // Надо подвинуть камеру после установки дистанции
// Освещение
light = new DirectionalLight3D({color:0xAAFFAA, ambient:0.25, diffuse:0.75, specular:0.9})
scene.addChild(light)
view=new View3D({scene:scene,camera:camera});
view.x=stage.stageWidth/2; // Координаты расположения картинки
view.y=stage.stageHeight/2; // Координаты расположения картинки
addChild(view);
physics = new Away3DPhysics(view,speed); // Старт физического движка
}
function createWalls():void { // Ограничиваем пространства для падения кубов, чтобы не выпадали
//стенка
var left:RigidBody = physics.createCube({width:boxThickness, height:boxHeight, depth:boxDepth+0.5});
left.movable = false;
left.x = -(boxWidth+boxThickness)/2
Away3dMesh(left.skin).mesh.material = wallTexture
//стенка
var right:RigidBody = physics.createCube({width:boxThickness, height:boxHeight, depth:boxDepth+0.5});
right.movable = false;
right.x = (boxWidth+boxThickness)/2
Away3dMesh(right.skin).mesh.material = wallTexture
//стенка
var front:RigidBody = physics.createCube({width:boxWidth, height:boxHeight, depth:boxThickness});
front.movable = false;
front.z = (boxDepth+boxThickness)/2
Away3dMesh(front.skin).mesh.material = wallTexture
//стенка
var back:RigidBody = physics.createCube({width:boxWidth, height:boxHeight, depth:boxThickness});
back.movable = false;
back.z = -(boxDepth+boxThickness)/2
Away3dMesh(back.skin).mesh.material = wallTexture
//пол
var ground:RigidBody = physics.createCube({width:boxWidth, height:boxThickness, depth:boxDepth, segmentsW:2, segmentsH:2});
ground.movable = false;
ground.y = -(boxHeight+boxThickness)/2
Away3dMesh(ground.skin).mesh.material = groundTexture
Away3dMesh(ground.skin).mesh.pushback = true
}
function createBackground():void {
var ground:RigidBody = physics.createCube({width:960, height:1, depth:960, segmentsW:2, segmentsH:2});
ground.movable = false;
ground.y = -(boxHeight+boxThickness)/2 - 10; // На 1 меньше, чем пол у пространства
Away3dMesh(ground.skin).mesh.material = backgroundTexture;
Away3dMesh(ground.skin).mesh.pushback = true; // отталкивать кубики
}
function createCube():void {
var cube:RigidBody = physics.createCube({width:cubeScale, height:cubeScale, depth:cubeScale});
cube.y=500;
cube.movable=false;
cube.mass = cubeMass;
cube.maxRotVelocities = cubeMaxRotVel;
cube.maxLinVelocities = cubeMaxLinVel;
Cube(Away3dMesh(cube.skin).mesh).cubeMaterials.left = cubeTextures[0]
Cube(Away3dMesh(cube.skin).mesh).cubeMaterials.right = cubeTextures[1]
Cube(Away3dMesh(cube.skin).mesh).cubeMaterials.front = cubeTextures[2]
Cube(Away3dMesh(cube.skin).mesh).cubeMaterials.back = cubeTextures[3]
Cube(Away3dMesh(cube.skin).mesh).cubeMaterials.top = cubeTextures[4]
Cube(Away3dMesh(cube.skin).mesh).cubeMaterials.bottom = cubeTextures[5]
cubes.push(cube);
}
function resetAllCubesE(e:Event):void
{
resetAllCubes();
}
function resetAllCubes():void {
for(var i:int = 0; i<cubes.length; i++) {
cubes[i].movable=true; // Разрешаем движение
cubes[i].moveTo( new JNumber3D( i*(Math.random()*15)*(Math.random()*-1), flyHeight + i*(cubeScale*3) , i*(Math.random()*15)*(Math.random()*-1) ) ) // перемещаем по X, Z (высота полета) и Y
cubes[i].rotationX = cubeNumbersRotation[startSide][0];
cubes[i].rotationY = cubeNumbersRotation[startSide][1];
cubes[i].rotationZ = cubeNumbersRotation[startSide][2];
}
}
function initListeners():void {
stage.addEventListener(Event.ENTER_FRAME, render);
stage.addEventListener(MouseEvent.MOUSE_DOWN,resetAllCubesE)
}
function render( e:Event ):void {
view.render();
camera.targetpanangle = stage.mouseX/stage.stageWidth*360
camera.targettiltangle = stage.mouseY/stage.stageHeight*30
//camera.hover(); // Активация движения камеры мышью
camera.x = 200;
camera.z = 300;
camera.y = 360
physics.step();
light.x = camera.x
light.y = camera.y
light.z = camera.z
}
initAway3D();
createBackground();
createWalls();
createCube();
createCube();
createCube();
createCube();
createCube();
createCube();
createCube();
initListeners();
Во вложении - fla-файл.
Заранее благодарю откликнувшихся за помощь.