Правильный порядок преобразования для графа сцены
Я работаю над быстрым движком WebGL с графом сцен, чтобы быстро создать прототип моей игровой идеи на Reddit ( https://www.reddit.com/r/gameideas/comments/3dsy8m/revolt/). Теперь, после того, как я выполнил некоторые базовые операции рендеринга, я не могу определить правильный порядок, хорошо тот, который выглядит правильным для большинства людей, который я должен использовать для преобразования узлов в графе сцены.
Трудно объяснить, что происходит, но я надеюсь, что вы понимаете, что это не так, как большинство ожидает от этого в любом другом движке.
Вот упрощенная версия того, что я сейчас делаю.
- Mat4 = glMatrix 0.9.5
- Utils = Пользовательские утилиты
Узел (Рендер):
@param {parentMatrix}
// Create Local Matrix
self.lMatrix = mat4.create();
mat4.identity(self.lMatrix);
mat4.translate(self.lMatrix, self.position);
mat4.rotate(self.lMatrix, self.rotation[0], [1, 0, 0]);
mat4.rotate(self.lMatrix, self.rotation[1], [0, 1, 0]);
mat4.rotate(self.lMatrix, self.rotation[2], [0, 0, 1]);
var wMatrix = mat4.create();
mat4.identity(wMatrix);
if(parentMatrix){
mat4.multiply(self.lMatrix, parentMatrix, wMatrix);
}
else{
mat4.set(self.lMatrix, wMatrix);
}
// Render
var children = this.children,
numChildren = children.length,
child;
for(var i = 0; i < numChildren; i++){
child = children[i];
child.render(wMatrix);
}
Entity (Рендер):
@param {parentMatrix}
// Set Transformation matrix
var tMatrix = mat4.create();
mat4.identity(tMatrix);
mat4.translate(tMatrix, self.position);
mat4.rotate(tMatrix, self.rotation[0], [1, 0, 0]);
mat4.rotate(tMatrix, self.rotation[1], [0, 1, 0]);
mat4.rotate(tMatrix, self.rotation[2], [0, 0, 1]);
mat4.scale(tMatrix, self.scale || [1, 1, 1]);
var wMatrix = mat4.create();
mat4.identity(wMatrix);
mat4.multiply(tMatrix, parentMatrix, wMatrix);
Utils.loadTMatrix(wMatrix);
this.texture.bind();
this.mesh.render();
2 ответа
Я не нашел оригинального способа, на который надеялся, потому что раньше я кешировал матрицы и надеялся продолжать делать это, но теперь я нашел гораздо более простой способ после воссоздания моего старого движка с нуля.
Engine.prototype.NODE.prototype.render = function(parentMatrix){
var children = this.children,
numChildren = children.length,
child, pos, rot, scale;
// If has set matrix to a copy of it
if(parentMatrix){
this.matrix = mat4.clone(parentMatrix);
}
else{
// Else set it to a identity matrix
mat4.identity(this.matrix);
}
// If matrix needs updating reconstruct it
pos = [this.position.x,
this.position.y,
this.position.z];
rot = [this.rotation.x,
this.rotation.y,
this.rotation.z];
scale = [this.scale.x,
this.scale.y,
this.scale.z];
// Recreate Transformation matrix
mat4.translate(this.matrix, this.matrix, pos);
mat4.rotate(this.matrix, this.matrix, rot[0], [1, 0, 0]);
mat4.rotate(this.matrix, this.matrix, rot[1], [0, 1, 0]);
mat4.rotate(this.matrix, this.matrix, rot[2], [0, 0, 1]);
mat4.scale(this.matrix, this.matrix, scale);
// Render Children with this matrix
for(var i = 0; i < numChildren; i++){
child = children[i];
child.render(this.matrix);
}
}
Что я в основном делаю, так это то, что если матрица имеет родителя (это не корневой узел), то я начинаю матрицу как клон ее родителя, иначе я устанавливаю матрицу в ее единичную матрицу. Затем применяя к нему регулярные преобразования. Если я найду способ продолжить кеширование матриц, я выложу его как можно скорее.
Обычный порядок - SRT, или масштаб, вращение, затем перевод.
Также я не уверен, что вы можете просто сделать
mat4.rotate(tMatrix, self.rotation[0], [1, 0, 0]);
mat4.rotate(tMatrix, self.rotation[1], [0, 1, 0]);
mat4.rotate(tMatrix, self.rotation[2], [0, 0, 1]);
с углами Эйлера и получить правильную ориентацию результата. Я не использую углы Эйлера, поэтому я не совсем понимаю детали. Кто-нибудь, пожалуйста, поправьте меня, если я ошибаюсь. Смотрите эту страницу для преобразования между углом Эйлера и матрицей вращения: http://www.euclideanspace.com/maths/geometry/rotations/conversions/eulerToMatrix/.