# Blend4Webs m_trans.set_matrix does not respect linear algebra

I tried to scale an object alongside a specific dimension with the set_matrix function from the transform module in Blend4Web.

# Phenomenon

Here is an example matrix applied by set_matrix

a 0 0 0
0 1 0 0
0 0 1 0
0 0 0 1


Let a be 0.1

Expectation: It should be scaled to 0.1 on X.

Result: It was scaled down approximately 0.8 on X, Y and Z.

Left is the original cube, the right is transformed with the matrix as defined above.

then I assigned different values to a, and find many anomalies, the two most noticeable:

• The transformation is not linear,
• and happens on all 3D axes. (it should be carried out only on X)

The funniest case when a is zero, because in this setting the transformation matrix spans only to 2 dimensions, which should collapse the cube to a square... well it makes it a slightly smaller cube, but at least it collapsed my mind to the null space.

# Reproduction

I made a self contained example in a project, you can extract it into your project folder. This reproduces what I described, the only difference that it changes 2 basis vectors to null vector instead of one.

### Blender file

I changed two things on the default Blend4Web starter file:

• Reseted the cube transformation to the identity. (it is translated on Z by 1 on default scene )
• turned on the physics on the cube object, so it can be transformed.

### Code

The following code was written into the default Blend4Web JavaScript scaffolding, under the place your code here comment

var cube = m_scenes.get_object_by_name("cube");
// The cube object on default b4w scene is transformed by the identity.
var mat = m_trans.get_matrix(cube);
// Create a global function to update the cube transformation matrix
// from the inspector.
updateMatfromWindow(mat, cube);

console.log("identity: ");
mat4_pprint(mat);
mat[0] = 0;
mat[5] = 0;
console.log('collapsing to one dimension');
mat4_pprint(mat);
/**
* after this the cube should disaper. since it transformed by a matrix with a
* zero determinant.
*/
m_trans.set_matrix(cube, mat);


I also added some extra features for testing, so you can update the transformation matrix of the cube from the inspector, using the updateMat(ind, val), function, for example:

updateMat(12, 1) // will translate the cube 1 unit on x.


and a matrix pretty printer function.

My environment:

• NixOS 17.09 “Hummingbird” (GNU/Linux)
• Blender 2.79a
• Blend4Web 17.12.0
• I received an edit to this post, which changed the programming tag to scripting, which is ok, I guess... but added the python tag, which is wrong since the code in question is written in JavaScript (it runs in the browser as a web app, and NOT in Blender). So please at least check out Blend4Web before editing this post. – atevm Mar 29 '18 at 11:22
• I saw that. I have re-edit this time with the correct tags. (We are completely removing the programming tag.) – David Mar 29 '18 at 12:46

As it turned out recent Blend4Web (17.12.0) does not support non-uniform scaling (it will be added with the next release). Which also means: its 4D matrix module does not expose the real transformation entity, which it usess at its deepest abstraction.

# General workaround:

However Blend4Web supports non-uniform scale animations exported from blender, and it is also possible to jump to a specific animation frame. So make a appropriate scale animation and wrote a code which interpolates between its frames.

# Example:

I wrote a window-scaleresponsive input range GUI element with this method, the relevant code snippet should be rather simple for someone with a basic knowledge about the Blend4Web SDK.

function registerSliderResize(railObj, knobObj, frameNum) {

var etalonRatio = 16 / 9;

function resize() {

var ratio = window.innerWidth / window.innerHeight;
var frameInd = Math.floor(ratio / etalonRatio * frameNum);

else if (frameInd < 1)
frameInd = 1;

// invert frameInd

m_anim.apply(railObj, "rail-resize", m_anim.SLOT_0);
m_anim.set_behavior(railObj, m_anim.AB_FINISH_STOP, m_anim.SLOT_0);
m_anim.play(railObj, null, m_anim.SLOT_0);
console.log(frameInd);
m_anim.set_frame(railObj, frameInd, m_anim.SLOT_0);
m_anim.stop(railObj, m_anim.SLOT_0);

m_anim.apply(knobObj, "knob-resize", m_anim.SLOT_0);
m_anim.set_behavior(railObj, m_anim.AB_FINISH_STOP, m_anim.SLOT_0);
m_anim.play(railObj, null, m_anim.SLOT_0);
console.log(frameInd);
m_anim.set_frame(railObj, frameInd, m_anim.SLOT_0);
m_anim.stop(railObj, m_anim.SLOT_0);
};

resize();