2
$\begingroup$

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.

enter image description here

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
$\endgroup$
  • $\begingroup$ 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. $\endgroup$ – atevm Mar 29 '18 at 11:22
  • 1
    $\begingroup$ I saw that. I have re-edit this time with the correct tags. (We are completely removing the programming tag.) $\endgroup$ – David Mar 29 '18 at 12:46
2
$\begingroup$

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);

    if (frameInd > frameNum)
      frameInd = frameNum;
    else if (frameInd < 1)
      frameInd = 1;

    // invert frameInd
    frameInd = frameNum - 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();

  window.addEventListener("resize", resize);
}

The result:

enter image description here

Two non-uniformly scaled version of the same slider adapted to the window size, changed by Chromium inspector.

The whole project:

You can download the whole source code and the corresponding .blend file.

$\endgroup$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.