Здравствуйте, Zubkin, Вы писали:
Z>Здравствуйте, Eugene Kilachkoff, Вы писали:
Z>>>вопрос:
Z>>>как "должна" выглядеть архитектура такого приложения?
EK>>Ну, обычно в 3D выделяют несколько общеупотребительных примитивов:
Z>благодарю за ответ.
Z>если я правильно понял,
Z>я должен создать классы для этих общеупотребительных примитивов,
Ну примерно. Типа далее псевдокод.
class Vector { float x,y,z; }
class Face { int idx1,idx2,idx3; }
class Mesh { Vector[] vertices; Face[] faces; }
// ну и так далее
Z>каждый описывает своё состояние (вращение, scale и т.д.),
Немного не так.
class Matrix
{
float[4][4] data;
static Matrix buildI()
{
return ( [ 1 0 0 0 ],
[ 0 1 0 0 ],
[ 0 0 1 0 ],
[ 0 0 0 1 ] );
}
static Matrix buildT(Vector v)
{
return ( [ 0 0 0 v.x ],
[ 0 0 0 v.y ],
[ 0 0 0 v.z ],
[ 0 0 0 1 ] );
}
// далее как в учебнике
static Matrix buildRotX(float angle) ...
static Matrix buildRotY(float angle) ...
static Matrix buildRotZ(float angle) ...
}
class TransformationStack
{
Matrix[] transformations;
void push(Matrix m) { transformations.append(m); }
Matrix collapse()
{
Matrix r = Matrix.buildI();
foreach(m in transformations) r = m * r;
// вообще, справа или слева умножать зависит от того, в каком порядке хранятся матрицы в стеке
// и от представления векторов.
// обычно предполагается что используются вектор-столбцы и они умножаются на матрицу справа
// соответственно, для набора преобразований "R: поворот на 30", затем "T: перенос в (1,0,0)"
// результирующий вектор должен получаться как Vr = T * R * v
return r;
}
}
class Object3D
{
Mesh[] meshes;
TransformationStack tstack;
String name;
}
Можно еще использовать представление вращения в виде кватернионов (google for quaternion rotation).
Z>все объекты храняться в одной структуре,
Z>потом есть Scenegraph который регуларно проходит по структуре
Scenegraph -- это и есть структура.
class SceneGraph
{
class Group { WeakReference<Object3D>[] members; }
class TreeNode { WeakRefernce<Object3D> object; TreeNode parent; TreeNode[] child; }
Object3D[] objectPool; // хранилище всех объектов, чтобы не бегать долго по деревьям
Group[] groupList; // логическая группировка (ex: голова -- это глаза, плюс уши, плюс зубы и так далее)
TreeNode[] kinematicTreeRoots; // лес деревьев подчинения объектов для прямой (forward) кинематики
// (если потянуть за туловище, голова, руки и ноги потянутся за ним.
// НО, если потянуть за ногу, все остальное останется на месте, для этого нужна уже inverse kinematics
void drawAll()
{
foreach(node in kinematicTreeRoots) drawRecursive(node,Matrix.buildI());
// те, которые сами по себе. Хотя для них лучше ввести отдельный root.
foreach(obj in objectPool)
if wasNotDrawnInPreviousStep(obj) drawObject(obj);
}
void drawRecursive(TreeNode node,Matrix parentTransform)
{
foreach(n in node.child) drawRecursive(n,n.object.tstack.collapse());
Matrix myTransform = node.object.tstack.collapse() * parentTransform; // watch the order !
Mesh m = transformMesh(node.object.mesh, myTransform);
drawMesh(m);
}
}