I am making the solar system simulation which simply contains the sun(point light source), the earth and the moon, I can see succesfully these stars on the screen, when I only apply translations to them
Here is the example screen
but as soon as I added the orbit transformaion to the earth, I got this weird result...
It seems that the earth sunddenly stuck in the sun but, at least I can see that somehow the moon is revolving the earth
When I applyed the orbit transformation to the moon also, I got this result..
As you can see that both the earth and the moon stuck in the sun...
Here is the code and the tree how I want their hierarchical transformation to be organized..
function RenderPerSec(gl, sun, SunModelMatrix, SunNormalMat,
earth, EarthModelMatrix, EarthNormalMat,
moon, MoonModelMatrix, MoonNormalMat,
MvpMatrix, loc_uModelMatrix, loc_uNormalMatrix, loc_uMvpMatrix,
loc_uSunTrigger, loc_uEarthTrigger, loc_uMoonTrigger,
w, h)
{
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
///Hierarchical Transformation///
/*
P
|
V
|
SUN(Fixed)
|
EARTH
Translation from the sun
Rotation around the sun
/ | \
tilted 23.5 degree MOON Rotation itself
Along the X-axis |
Translation from the earth
Rotation around the earth
Rotation itself..
*/
let MVPStack = [];
MvpMatrix.setIdentity();
//Projection
MvpMatrix.setPerspective(60, w/h, 1, 1000);
//View
MvpMatrix.lookAt(0, 15, 10, 0, 0, 0, 0, 1, 0);
//Model Transforms...
//Sun
SunModelMatrix.setTranslate(0, 0, 0);
MvpMatrix.multiply(SunModelMatrix);
MVPStack.push(new Matrix4(MvpMatrix));
gl.uniform1i(loc_uSunTrigger, 1);
gl.uniform1i(loc_uEarthTrigger, 0);
gl.uniform1i(loc_uMoonTrigger, 0);
RenderSun(gl, sun, SunModelMatrix, SunNormalMat, MvpMatrix, loc_uModelMatrix, loc_uNormalMatrix, loc_uMvpMatrix);
//Earth, translation and rotation 23.5 along the X-axis, rotation itself
EarthModelMatrix.setTranslate(5, 0, 0); //Translation from the sun
EarthModelMatrix.setRotate(CURRENT_EATHR_REVOLVING_ANGLE, 0, 1, 0); //Revolving around the sun
MvpMatrix = MVPStack.pop();
MvpMatrix.multiply(EarthModelMatrix);
MVPStack.push(new Matrix4(MvpMatrix));
gl.uniform1i(loc_uSunTrigger, 0);
gl.uniform1i(loc_uEarthTrigger, 1);
gl.uniform1i(loc_uMoonTrigger, 0);
RenderEarth(gl, earth, EarthModelMatrix, EarthNormalMat, MvpMatrix, loc_uModelMatrix, loc_uNormalMatrix, loc_uMvpMatrix);
//Moon, translation and rotation itself
MoonModelMatrix.setTranslate(2.5, 0, 0);
MoonModelMatrix.setRotate(CURRENT_MOON_REVOLVING_ANGLE, 0, 1, 0);
MvpMatrix = MVPStack.pop();
MvpMatrix.multiply(MoonModelMatrix, EarthModelMatrix);
gl.uniform1i(loc_uSunTrigger, 0);
gl.uniform1i(loc_uEarthTrigger, 0);
gl.uniform1i(loc_uMoonTrigger, 1);
RenderMoon(gl, moon, MoonModelMatrix, MoonNormalMat, MvpMatrix, loc_uModelMatrix, loc_uNormalMatrix, loc_uMvpMatrix);
}
if I remove setRotate functions in this code I can get the first result..
and here is the render function
function RenderSun(gl, sun, SunModelMatrix, SunNormalMat, MvpMatrix, loc_uModelMatrix, loc_uNormalMatrix, loc_uMvpMatrix)
{
gl.bindVertexArray(sun.vao);
SunNormalMat.setInverseOf(SunModelMatrix);
SunNormalMat.transpose();
// Pass the model matrix to uModelMatrix
gl.uniformMatrix4fv(loc_uModelMatrix, false, SunModelMatrix.elements);
// Pass the model view projection matrix to umvpMatrix
gl.uniformMatrix4fv(loc_uMvpMatrix, false, MvpMatrix.elements);
// Pass the transformation matrix for normals to uNormalMatrix
gl.uniformMatrix4fv(loc_uNormalMatrix, false, SunNormalMat.elements);
gl.drawElements(gl.TRIANGLES, sun.n, sun.type, 0);
}
function RenderEarth(gl, earth, EarthModelMatrix, EarthNormalMat, MvpMatrix, loc_uModelMatrix, loc_uNormalMatrix, loc_uMvpMatrix)
{
gl.bindVertexArray(earth.vao);
EarthNormalMat.setInverseOf(EarthModelMatrix);
EarthNormalMat.transpose();
gl.uniformMatrix4fv(loc_uModelMatrix, false, EarthModelMatrix.elements);
gl.uniformMatrix4fv(loc_uMvpMatrix, false, MvpMatrix.elements);
gl.uniformMatrix4fv(loc_uNormalMatrix, false, EarthNormalMat.elements);
gl.drawElements(gl.TRIANGLES, earth.n, earth.type, 0);
}
function RenderMoon(gl, moon, MoonModelMatrix, MoonNormalMat, MvpMatrix, loc_uModelMatrix, loc_uNormalMatrix, loc_uMvpMatrix)
{
gl.bindVertexArray(moon.vao);
MoonNormalMat.setInverseOf(MoonModelMatrix);
MoonNormalMat.transpose();
gl.uniformMatrix4fv(loc_uModelMatrix, false, MoonModelMatrix.elements);
gl.uniformMatrix4fv(loc_uMvpMatrix, false, MvpMatrix.elements);
gl.uniformMatrix4fv(loc_uNormalMatrix, false, MoonNormalMat.elements);
gl.drawElements(gl.TRIANGLES, moon.n, moon.type, 0);
}
I am using a stack to implement the hierarchical transformations... could somebody help me?
There's an article on this here and stack based one here
In general you would need to do something like
push(0,0,0)
push(sun rotation)
draw sun
pop() // sun rotation
push(earth orbit rotation)
push(earth translation)
push(earth rotation)
draw earth
pop() // earth rotation
push(moon orbit rotation)
push(moon translation)
push(moon rotation)
draw moon
pop() // moon rotation
pop() // moon translation
pop() // moon orbit rotation
pop() // earth translation
pop() // earth orbit rotation
pop() // center of solar system
Your matrix math library is not familar to me but functions named setTranslate
and setRotate
do not sound like the appropriate functions. They sound like they set translation or set the rotation rather than multiply an existing matrix by a translation matrix or a rotation matrix.
In most 3D math libraries to make a sphere appear at some distance from the center of rotation it would be something like
mathlib.translate(centerOfRotation) // move 0,0,0 to center of rotation
mathlib.rotate(orbitRotation) // rotate space
mathlib.translate(orbitRadius) // move some distance from center in rotated space
Or a longer form
mat = identity();
mat = mathlib.multiply(mat, mathlib.translation(centerOfRotation))
mat = mathlib.multiply(mat, mathlib.rotatation(orbitRotation))
mat = mathlib.multiply(mat, mathlib.translation(orbitRadius))
If it's a auto stacking library then the shorter form would have already stacked 3 matrices.
Note since the only part you seem to be having issues with is the matrix stack part here's some code using a matrix stack to compute the 3 matrices (sun, earth, moon) and then it uses those matrices with 2D canvas (which you can ignore)
'use strict';
const ctx = document.querySelector('canvas').getContext('2d');
const m4 = twgl.m4;
const stack = [];
const current = () => stack[stack.length - 1];
const pop = () => stack.pop();
const identity = () => stack.push(m4.identity());
const translate = (t) => stack.push(m4.translate(current(), t));
const rotate = (axis, r) => stack.push(m4.axisRotate(current(), axis, r));
const zAxis = [0, 0, 1];
function render(time) {
time *= 0.001; // convert to seconds
twgl.resizeCanvasToDisplaySize(ctx.canvas);
const {width, height} = ctx.canvas;
ctx.setTransform(1, 0, 0, 1, 0, 0);
ctx.clearRect(0, 0, width, height);
let sunMat;
let earthMat;
let moonMat;
identity();
// translate to center of solar system
translate([width / 2, height / 2, 0]);
rotate(zAxis, time * 4); // sun rotation
sunMat = current();
pop(); // sun rotation
rotate(zAxis, time / 2) // push(earth orbit rotation)
translate([height / 4, 0, 0]); //push(earth translation)
rotate(zAxis, time * 8); // push(earth rotation)
earthMat = current(); //
pop(); // earth rotation
rotate(zAxis, time * 2); //push(moon orbit rotation)
translate([height / 8, 0, 0]); // push(moon translation)
rotate(zAxis, time * 16); //push(moon rotation)
moonMat = current();
pop(); // moon rotation
pop(); // moon translation
pop(); // moon orbit rotation
pop(); // earth translation
pop(); // earth orbit rotation
pop(); // center of solar system
pop(); // identity
drawSquare(sunMat, 40, 'orange');
drawSquare(earthMat, 20, 'blue');
drawSquare(moonMat, 10, 'gray');
requestAnimationFrame(render);
}
requestAnimationFrame(render);
function drawSquare(mat, size, color) {
ctx.setTransform(mat[0], mat[1], mat[4], mat[5], mat[12], mat[13]);
ctx.strokeStyle = color;
ctx.strokeRect(-size / 2, -size / 2, size, size);
}
body { margin: 0; }
canvas { width: 100vw; height: 100vh; display: block; }
<script src="https://twgljs.org/dist/4.x/twgl-full.js"></script>
<canvas></canvas>
here's one with explicit push
'use strict';
const ctx = document.querySelector('canvas').getContext('2d');
const m4 = twgl.m4;
const stack = [m4.identity()];
const current = () => stack[stack.length - 1];
const currentCopy = () => stack[stack.length - 1].slice();
const push = () => stack.push(currentCopy());
const pop = () => stack.pop();
const identity = () => m4.identity(current());
const translate = (t) => m4.translate(current(), t, current());
const rotate = (axis, r) => m4.axisRotate(current(), axis, r, current());
const zAxis = [0, 0, 1];
function render(time) {
time *= 0.001; // convert to seconds
twgl.resizeCanvasToDisplaySize(ctx.canvas);
const {width, height} = ctx.canvas;
ctx.setTransform(1, 0, 0, 1, 0, 0);
ctx.clearRect(0, 0, width, height);
let sunMat;
let earthMat;
let moonMat;
push();
// translate to center of solar system
translate([width / 2, height / 2, 0]);
push();
rotate(zAxis, time * 4); // sun rotation
sunMat = currentCopy();
pop(); // sun rotation
rotate(zAxis, time / 2) // earth orbit rotation
translate([height / 4, 0, 0]); // earth translation
push();
rotate(zAxis, time * 8); // earth rotation
earthMat = currentCopy(); //
pop(); // earth rotation
push();
rotate(zAxis, time * 2); // moon orbit rotation
translate([height / 8, 0, 0]); // moon translation
rotate(zAxis, time * 16); // moon rotation
moonMat = currentCopy();
pop();
pop();
drawSquare(sunMat, 40, 'orange');
drawSquare(earthMat, 20, 'blue');
drawSquare(moonMat, 10, 'gray');
requestAnimationFrame(render);
}
requestAnimationFrame(render);
function drawSquare(mat, size, color) {
ctx.setTransform(mat[0], mat[1], mat[4], mat[5], mat[12], mat[13]);
ctx.strokeStyle = color;
ctx.strokeRect(-size / 2, -size / 2, size, size);
}
body { margin: 0; }
canvas { width: 100vw; height: 100vh; display: block; }
<script src="https://twgljs.org/dist/4.x/twgl-full.js"></script>
<canvas></canvas>