Comments (17)
Sorry I never responded to this.
I don't know what the "right" way is. Basically I just swap left and right sides to whatever library's multiply function is until things work.
In this case since the matrix is often called worldViewProjection I wanted my example to do (world * view * projection) = worldViewProjeciton
so it matched the name. So for example
m4.multiply(view, projection, viewProjection);
which is (view * projection) = (viewProjection)
. That seems more clear than (projection * view) = viewProjection
.
If I understand matrix math correctly (and it's sad that my math sucks so bad) if I understand correctly you can just swap the multiple in the shader from
gl_Position = matrix * position
to
gl_Position = position * matrix;
To get column vs row style results. Then just swap the first and second arguments to all matrix multiply functions. It's not quite that simple because functions like translate, rotate, that multiply in place won't do the right thing.
For those functions they were designed to mimic OpenGL's translate, rotate, scale functions so they can be used in the same order as old OpenGL examples
from twgl.js.
I have the same confusion as @mseefelder when I read the m4.multiply(). First of all, using column-major order is good, since that's the OpenGL convention. And if users call m4.multiply(a, b, result), I think what they expect is "result = a * b" which is matrix multiplication in math, but the implementation is like "result = b * a". A good reference of GL math is glm project.
from twgl.js.
Yea, I agree multiply
is backward. I guess I'm a little afraid of switching it since it break anyone using it 😢
I could add mult
and switch all the examples?
I could add mult
and deprecate multiply
with a single message if it's used as in
"multiply" is deprecated. use "mult" instead
I could just break everyone?
I could set the version to 2.0 and hope everyone realizes 2.0 = breaking API changes
I could rename it twgl2?
I could just remove it from twgl and make a new library for math which you include separetely?
Other ideas?
from twgl.js.
To be clear I just wrote this test
var m4 = twgl.m4;
var m1 = m4.identity();
m1 = m4.translate(m1, [1, 2, 3]);
m1 = m4.rotateZ(m1, 1.2);
m1 = m4.scale(m1, [2, 3, 4]);
var m2 = m4.identity();
m2 = m4.multiply(m2, m4.translation([1, 2, 3]));
m2 = m4.multiply(m2, m4.rotationZ(1.2));
m2 = m4.multiply(m2, m4.scaling([2, 3, 4]));
var m3 = m4.identity();
m3 = m4.multiply(m4.translation([1, 2, 3]), m3);
m3 = m4.multiply(m4.rotationZ(1.2), m3);
m3 = m4.multiply(m4.scaling([2, 3, 4]), m3);
console.log(m1);
console.log(m2);
console.log(m3);
I think m1
and m2
should be equal but m1
and m3
are equal. That's arguably wrong
from twgl.js.
I think I'm leaning toward just adding mult
, changing all the samples to use it and just documenting that multiply
is the opposite of mult
.
that way nothing old breaks but most people won't see multiply
, specially of the docs warn in red that you probably want to use mult
thoughts?
from twgl.js.
Hmmm, I did a quick search and replace of m4.multiply(a, b...)
with m4.mult(b, a...
but now I have the issue that it reads poorly as pointed out above
In other words where is it used to look like this
viewProjection = m4.multiply(view, projection);
now it looks like this
viewProjection = m4.mult(projection, view);
which is completely unintuitive. Yea I get that the top is backward from some other math libs and it's backwards from the translate/rotate/scale functions. Still I'm not sure which is better.
I suppose I could refactor the second version to this
projectionView = m4.mult(projection, view);
But I've never heard of a projectionView
matrix. It's always a viewProjection
matrix. I guess whoever picked that naming convention kind of screwed up ? 😕
from twgl.js.
glm
and twgl
are not the same
twgl:
<script src="twgl-full.min.js"></script>
<script>
var m4 = twgl.m4;
var m1 = m4.identity();
m1 = m4.translate(m1, [1, 2, 3]);
m1 = m4.axisRotate(m1, [2, 3, 4], 1.2);
m1 = m4.scale(m1, [4, 5, 6]);
var m2 = m4.identity();
m2 = m4.multiply(m2, m4.translation([1, 2, 3]));
m2 = m4.multiply(m2, m4.axisRotation([2, 3, 4], 1.2));
m2 = m4.multiply(m2, m4.scaling([4, 6, 7]));
var m3 = m4.identity();
m3 = m4.multiply(m4.translation([1, 2, 3]), m3);
m3 = m4.multiply(m4.axisRotation([2, 3, 4], 1.2), m3);
m3 = m4.multiply(m4.scaling([4, 5, 6]), m3);
console.log("m1:", m1);
console.log("m2:", m2);
console.log("m3:", m3);
</script>
glm:
#include <glm/gtx/matrix_operation.hpp>
#include <glm/vec3.hpp> // glm::vec3
#include <glm/vec4.hpp> // glm::vec4
#include <glm/mat4x4.hpp> // glm::mat4
#include <glm/gtc/matrix_transform.hpp> // glm::translate, glm::rotate, glm::scale, glm::perspective
#include <stdio.h>
void pm(const char* name, const glm::mat4& m1)
{
printf("%s\n%f %f %f %f\n%f %f %f %f\n%f %f %f %f\n%f %f %f %f\n\n",
name,
m1[0][0], m1[0][1], m1[0][2], m1[0][3],
m1[1][0], m1[1][1], m1[1][2], m1[1][3],
m1[2][0], m1[2][1], m1[2][2], m1[2][3],
m1[3][0], m1[3][1], m1[3][2], m1[3][3]);
}
int main()
{
int Error(0);
glm::mat4 m1 = glm::mat4();
m1 = glm::translate(m1, glm::vec3(1, 2, 3));
m1 = glm::rotate(m1, 1.2f, glm::vec3(2, 3, 4));
m1 = glm::scale(m1, glm::vec3(4, 5, 6));
glm::mat4 m2 = glm::mat4();
m2 = m2 * glm::translate(glm::mat4(), glm::vec3(1, 2, 3));
m2 = m2 * glm::rotate(glm::mat4(), 1.2f, glm::vec3(2, 3, 4));
m2 = m2 * glm::scale(glm::mat4(), glm::vec3(4, 5, 6));
glm::mat4 m3 = glm::mat4();
m3 = glm::translate(glm::mat4(), glm::vec3(1, 2, 3)) * m3;
m3 = glm::rotate(glm::mat4(), 1.2f, glm::vec3(2, 3, 4)) * m3;
m3 = glm::scale(glm::mat4(), glm::vec3(4, 5, 6)) * m3;
pm("m1:", m1);
pm("m2:", m2);
pm("m3:", m3);
return Error;
}
twgl results:
m1:
1.8012336492538452 3.2969088554382324 -1.3732985258102417 0
-2.8018763065338135 2.8012335300445557 3.0500128269195557 0
4.1707634925842285 -0.49379199743270874 4.284962177276611 0
1 2 3 1
foo.html:4 m2:
1.8012336492538452 4.9453630447387695 -2.4032723903656006 0
-2.2415010929107666 3.361480236053467 4.270018100738525 0
2.7805089950561523 -0.49379199743270874 4.999122619628906 0
5.659758567810059 10.1869478225708 21.134132385253906 1
foo.html:4 m3:
1.8012336492538452 3.2969088554382324 -1.3732985258102417 0
-2.8018763065338135 2.8012335300445557 3.0500128269195557 0
4.1707634925842285 -0.49379199743270874 4.284962177276611 0
1 2 3 1
glm results:
m1:
1.801233 3.296909 -1.373298 0.000000
-2.801876 2.801233 3.050013 0.000000
4.170763 -0.493792 4.284962 0.000000
1.000000 2.000000 3.000000 1.000000
m2:
1.801233 3.296909 -1.373298 0.000000
-2.801876 2.801233 3.050013 0.000000
4.170763 -0.493792 4.284962 0.000000
1.000000 2.000000 3.000000 1.000000
m3:
1.801233 4.121136 -2.059947 0.000000
-2.241501 2.801233 3.660015 0.000000
2.780509 -0.411493 4.284962 0.000000
5.659758 8.489123 18.114967 1.000000
In twgl m1 and m3 match. In glm m1 and m2 match
from twgl.js.
Yes, you're right, and in my experience GLM is the right multiplication order. In OpenGL the MVP matrix actually equals "projectMatrix * viewMatrix * modelMatrix", and in a shader we usually write "gl_Position = mvp * a_position". However if we use "twgl.multiply(projectMatrix, twgl.multiply(viewMatrix, modelMatrix))" we will get the wrong MVP matrix.
from twgl.js.
from twgl.js.
In my opinion, I think the current implementation is buggy because people treat it as "a * b" as documented while it's actually "b * a", so I think it's better to fix the "bug" rather than make a new right implementation named "mult", and maybe this fix can be emphasized in the document or the change list.
BTW, I remember that there is a project called gl-matrix or glMatrix, I never used it before but I looked into some of the code and it seems it has some optimization in matrix calculation. Maybe you can integrate it into twgl to replace m4 and everything related to math, and focus on enhancing very useful and core functionality and "adding new features".
Anyway, it's just something flash in my mind, everything is up to you. It's a very useful project, please keep up the good work!
from twgl.js.
FYI: glMatrix is not as fast as twgl
http://greggman.github.io/webgl-matrix-benchmarks/matrix_benchmark.html
I'm also not a fan of glMatrix's API that requires a destination in all functions so I'm not personally going to switch to it. On the other hand you're free to use twgl with any math library you want. The base twgl doesn't include or even use a math library.
from twgl.js.
So I finally swapped multiply and pushed version 2.0. See changelist
Thanks for pointing out my mistake/misunderstanding. I ended up refactoring all the examples on webglfundamentals.org as well because of this.
from twgl.js.
It seems that multiply has been swapped, but the same change was not made to the prebaked transformation functions (axisRotate, translate, scale, ....). It appears these functions now perform pre-transformations (applied before the contents of the passed matrix, equivalent to a multiplication on the right), rather than post-transformations (applied after the contents of the passed matrix, equivalent to a multiplication on the left). Is this the intention? To me post-transformations would be far more intuitive.
Note, on my system twgl is only in fifth place on the matrix benchmark. glMatrix is in third. TDLMath is in first.
from twgl.js.
The m4 currently functions match OpenGL
glMatrixMode(gl.MODELVIEW)
glRotate(angle, axisX, axisY, axisZ)
glTranslate(tx, ty, tz)
glScale(sx, sy, sz)
would be this in m4
var modelView = m4.identity();
m4.axisRotate(modelView, [axisX, axisY, axisZ], angle, modelView);
m4.translate(modeView, [tx, ty, tz], modelView);
m4.scale(modelView, [sx, sy, sz], modelView);
or
var modelView = m4.identity();
modelView = m4.axisRotate(modelView, [axisX, axisY, axisZ], angle);
modelView = m4.translate(modeView, [tx, ty, tz]);
modelView = m4.scale(modelView, [sx, sy, sz]);
or this
var modelView = m4.identity();
modelView = m4.multiply(modelView, m4.axisRotation([axisX, axisY, axisZ], angle));
modelView = m4.multiply(modelView, m4.translation([tx, ty, tz]));
modelView = m4.multiply(modelView, m4.scaling([sx, sy, sz]));
or this
var modelView = m4.identity();
m4.multiply(modelView, m4.axisRotation([axisX, axisY, axisZ], angle), modelView);
m4.multiply(modelView, m4.translation([tx, ty, tz]), modelView);
m4.multiply(modelView, m4.scaling([sx, sy, sz]), modelView);
from twgl.js.
Gotcha. OpenGL does the same thing.
from twgl.js.
As for speed if you check firefox I think you'll find twgl is faster. Hopefully Chrome will fix their code as it should be faster there too
from twgl.js.
I will add the OpenGL pattern makes sense for a matrix stack or a scenegraph. you start at the root (or the projection) and apply down, then you can pop off. If you do things in the opposite order you can't do that.
In other worlds
// house
push
translate(houseT); rotate(houseR); scale(houseS);
// window
push
translate(windowT); rotate(windowR); scale(windowS);
pop
// door
push
translate(doorT); rotate(doorR); scale(doorS);
pop
// backdoor
push
translate(backdoorT); rotate(backdoorR); scale(backdoorS);
// doorknob
push
translate(doorknobT); rotate(doorknobR); scale(doorknobS);
pop
pop
pop
from twgl.js.
Related Issues (20)
- Dynamically changing attribute values, does it require to create bufferinfo everytime
- Last framebuffer's attached texture is empty? HOT 3
- Incorrect sentence structure.
- GPGPU particles example performance HOT 5
- resizeCanvasToDisplaySize in a web worker sets the width and height to 0 HOT 2
- Should not update the number of elements too HOT 1
- Question about simple triangle rendering HOT 1
- Inconsistent `type` type in `createAttribsFromArrays` HOT 8
- Defer checking shader compile status HOT 8
- Unsetting a texture in webgl2 HOT 3
- gl.useProgram(program); HOT 1
- bindTransformFeedbackInfo with offset HOT 3
- Get the jsdoc into the tsd HOT 2
- Incorrect TypeScript types of `createAugmentedTypedArray` HOT 2
- TEXTURE_COMPARE_MODE and sampler2DShadow HOT 4
- twgl-base package.json refers to non-existent `module` file HOT 2
- Cubemap uses only first texture HOT 3
- Rendering objects using drawObjectList causes skybox to not be rendered HOT 6
- `opt_locations` of createProgramInfo is missing from typescript bindings HOT 2
- webgpu support ? HOT 1
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from twgl.js.