altreality Posted August 28, 2015 Share Posted August 28, 2015 Hi,I am building this simple train game where i make a locomotive(or a box that represents one) follow a curving track. Preview here: http://synth2014.github.io/Age-of-Steam/babylon/rk4.html I have only straight and circular segments. Somewhat realistic train movement is achieved by having a front point and a back point for the locomotive. The loco is positioned and oriented using these points. Its parallel to the line joining these points and positioned in the midpoint of the line. These points are marked by the red sphere(front) & grey sphere(back) respectively in the link above The front point is moved along the current curve(straight or circular), then the back point is calculated. The algorithm for that uses sphere intersection with straight lines or circular segments. I use BABYLON.Vector3.RotationFromAxis(xAxis, yAxis, zAxis) to rotate the box representing the locomotive. The code for it is:// forwardVecWS is the line joining the front point and the back point,// and pointing towards the front point. var xAxis = forwardVecWS.clone(); // the new x-axis of the loco // relative to World Space is simply the forward axis var yAxis = new BABYLON.Vector3(0, 0, 0); var zAxis = new BABYLON.Vector3(0, 0, 0); zAxis = BABYLON.Vector3.Cross(xAxis, frontSegment.upAxis).normalize(); yAxis = BABYLON.Vector3.Cross(zAxis, xAxis).normalize(); xAxis = BABYLON.Vector3.Cross(yAxis, zAxis).normalize(); console.debug("x(" + xAxis.x + "," + xAxis.y + "," + xAxis.z + "), y(" + yAxis.x + "," + yAxis.y + "," + yAxis.z + "), z(" + zAxis.x + "," + zAxis.y + "," + zAxis.z + ")");I seem to be calculating the local-axes of the box in world space correctly as can be seen from the developer tools view:GET http://synth2014.github.io/Age-of-Steam/babylon/js/utils.js babylon.2.1.debug.js:4703BJS - [19:29:02]: Babylon.js engine (v2.1.0) launchedbabylon.2.1.debug.js:3072 GET http://synth2014.github.io/Age-of-Steam/babylon/scenes/dummy.babylon.manifest?1440770342473 404 (Not Found)Database.checkManifestFile @ babylon.2.1.debug.js:3072Database @ babylon.2.1.debug.js:3032SceneLoader.Append @ babylon.2.1.debug.js:18734SceneLoader.Load @ babylon.2.1.debug.js:18684startGame @ mainRK4.js:34Integrator.js:37 Verlet: Position: 0.1, velocity:0.1FastLoco.js:466 x(0.9994770317996606,0,0.03233671141195854), y(0,1,0), z(-0.03233671141195854,0,0.9994770317996606)Integrator.js:37 Verlet: Position: 0.1, velocity:0.1FastLoco.js:466 x(0.9994350227871951,0,0.033610046509320576), y(0,1,0), z(-0.03361004650932058,0,0.9994350227871953)Integrator.js:37 Verlet: Position: 0.1, velocity:0.1FastLoco.js:466 x(0.9993905467884464,0,0.03490752053483967), y(0,1,0), z(-0.03490752053483967,0,0.9993905467884464)Integrator.js:37 Verlet: Position: 0.1, velocity:0.1Yet somehow, the box keeps disappearing for some the values. I had faced this earlier if the Vector3 for the axes were not normalized or the frame supplied wasn't orthogonal. From what I can see, thats not the case here. Anyone has any idea what may be going on? The code in question is here: https://github.com/synth2014/Age-of-Steam/blob/gh-pages/babylon/js/FastLoco.js#L451 There are some steps for the calculation that should be irrelevant if the final x,y & z axis values are normalized and the frame is orthogonal. Quote Link to comment Share on other sites More sharing options...
jerome Posted August 28, 2015 Share Posted August 28, 2015 The 3 axis must be normalized, orthogonal and left-handed in the order axis1, axis2, axis3 roller coaster train example here : http://www.babylonjs-playground.com/#1HH4OJ#5 Quote Link to comment Share on other sites More sharing options...
altreality Posted August 28, 2015 Author Share Posted August 28, 2015 Well, I added some code to check the orthogonality and normalization and they seem to be correct: Verlet: Position: 0.1, velocity:0.1FastLoco.js:470 x(0.9994770317996606,0,0.03233671141195854), y(0,1,0), z(-0.03233671141195854,0,0.9994770317996606)FastLoco.js:474 x.z=0, x.y=0, y.z=0FastLoco.js:475 Length x=1, y=1, z=1Integrator.js:37 Verlet: Position: 0.1, velocity:0.1FastLoco.js:470 x(0.9994350227871951,0,0.033610046509320576), y(0,1,0), z(-0.03361004650932058,0,0.9994350227871953)FastLoco.js:474 x.z=0, x.y=0, y.z=0FastLoco.js:475 Length x=0.9999999999999999, y=1, z=1.0000000000000002Integrator.js:37 Verlet: Position: 0.1, velocity:0.1FastLoco.js:470 x(0.9993905467884464,0,0.03490752053483967), y(0,1,0), z(-0.03490752053483967,0,0.9993905467884464)FastLoco.js:474 x.z=0, x.y=0, y.z=0FastLoco.js:475 Length x=1, y=1, z=1Integrator.js:37 Verlet: Position: 0.1, velocity:0.1FastLoco.js:470 x(0.9993435115829765,0,0.03622907474674426), y(0,1,0), z(-0.036229074746744264,0,0.9993435115829767)FastLoco.js:474 x.z=0, x.y=0, y.z=0FastLoco.js:475 Length x=0.9999999999999999, y=1, z=1.0000000000000002Integrator.js:37 Verlet: Position: 0.1, velocity:0.1FastLoco.js:470 x(0.9992938168341208,0,0.037574827173187275), y(0,1,0), z(-0.037574827173187275,0,0.9992938168341208)FastLoco.js:474 x.z=0, x.y=0, y.z=0FastLoco.js:475 Length x=1, y=1, z=1The dot products of the axes with each other are 0. The lengths of each axis is 1(within floating point precision) var xDotz = BABYLON.Vector3.Dot(xAxis, zAxis); var xDoty = BABYLON.Vector3.Dot(xAxis, yAxis); var yDotz = BABYLON.Vector3.Dot(yAxis, zAxis); console.debug("x(" + xAxis.x + "," + xAxis.y + "," + xAxis.z + "), y(" + yAxis.x + "," + yAxis.y + "," + yAxis.z + "), z(" + zAxis.x + "," + zAxis.y + "," + zAxis.z + ")"); console.debug("x.z=" + xDotz + ", x.y=" + xDoty + ", y.z=" + yDotz); console.debug("Length x=" + xAxis.length() + ", y=" + yAxis.length() + ", z=" + zAxis.length()); Quote Link to comment Share on other sites More sharing options...
jerome Posted August 28, 2015 Share Posted August 28, 2015 could you please log the rotation angles returned by RotationFromAxis() in the same time so we could check its values when the loco disappear ? or do a PG ? Quote Link to comment Share on other sites More sharing options...
altreality Posted August 28, 2015 Author Share Posted August 28, 2015 Thanks Jerome. Seems you were spot on. The rotation angles sometimes have a NaN in one of the angles. Updated http://synth2014.github.io/Age-of-Steam/babylon/rk4.html to print out the rotation and position too: Failed to load resource: the server responded with a status of 404 (Not Found)babylon.2.1.debug.js:4703BJS - [23:17:20]: Babylon.js engine (v2.1.0) launchedhttp://synth2014.github.io/Age-of-Steam/babylon/scenes/dummy.babylon.manifest?1440784040518 Failed to load resource: the server responded with a status of 404 (Not Found)Integrator.js:37 Verlet: Position: 0.1, velocity:0.1FastLoco.js:470 x(0.9994770317996606,0,0.03233671141195854), y(0,1,0), z(-0.03233671141195854,0,0.9994770317996606)FastLoco.js:474 x.z=0, x.y=0, y.z=0FastLoco.js:475 Length x=1, y=1, z=1FastLoco.js:482 Rotation x=0, y=-0.032342349615338765, z=NaNFastLoco.js:483 Position(15.050137463756561, 0, 0.3233671188354492)Integrator.js:37 Verlet: Position: 0.1, velocity:0.1FastLoco.js:470 x(0.9994350227871951,0,0.033610046509320576), y(0,1,0), z(-0.03361004650932058,0,0.9994350227871953)FastLoco.js:474 x.z=0, x.y=0, y.z=0FastLoco.js:475 Length x=0.9999999999999999, y=1, z=1.0000000000000002FastLoco.js:482 Rotation x=-1.4901161193847656e-8, y=-0.03361637757690891, z=NaNFastLoco.js:483 Position(15.147261049621582, 0, 0.3361004590988159)Integrator.js:37 Verlet: Position: 0.1, velocity:0.1FastLoco.js:470 x(0.9993905467884464,0,0.03490752053483967), y(0,1,0), z(-0.03490752053483967,0,0.9993905467884464)FastLoco.js:474 x.z=0, x.y=0, y.z=0FastLoco.js:475 Length x=1, y=1, z=1FastLoco.js:482 Rotation x=0, y=-0.0349146137642364, z=-1.4901161193847656e-8FastLoco.js:483 Position(15.244280262470246, 0, 0.34907519817352295)Integrator.js:37 Verlet: Position: 0.1, velocity:0.1FastLoco.js:470 x(0.9993435115829765,0,0.03622907474674426), y(0,1,0), z(-0.036229074746744264,0,0.9993435115829767)FastLoco.js:474 x.z=0, x.y=0, y.z=0FastLoco.js:475 Length x=0.9999999999999999, y=1, z=1.0000000000000002FastLoco.js:482 Rotation x=0, y=-0.036237004818494976, z=NaNFastLoco.js:483 Position(15.341193910209656, 0, 0.36229074001312256)Integrator.js:37 Verlet: Position: 0.1, velocity:0.1FastLoco.js:470 x(0.9992938168341208,0,0.037574827173187275), y(0,1,0), z(-0.037574827173187275,0,0.9992938168341208)FastLoco.js:474 x.z=0, x.y=0, y.z=0FastLoco.js:475 Length x=1, y=1, z=1FastLoco.js:482 Rotation x=NaN, y=-0.03758367457586275, z=NaNFastLoco.js:483 Position(15.438000300746918, 0, 0.37574827671051025)Integrator.js:37 Verlet: Position: 0.1, velocity:0.1FastLoco.js:470 x(0.9992413735216208,0,0.03894454316877913), y(0,1,0), z(-0.03894454316877913,0,0.9992413735216208)FastLoco.js:474 x.z=0, x.y=0, y.z=0FastLoco.js:475 Length x=1, y=1, z=1FastLoco.js:482 Rotation x=0, y=-0.03895439427871502, z=0FastLoco.js:483 Position(15.534699540012358, 0, 0.389445424079895)Integrator.js:37 Verlet: Position: 0.1, velocity:0.1FastLoco.js:470 x(0.9991860780093766,0,0.04033833799551142), y(0,1,0), z(-0.04033833799551142,0,0.9991860780093766)FastLoco.js:474 x.z=0, x.y=0, y.z=0FastLoco.js:475 Length x=1, y=1, z=1FastLoco.js:482 Rotation x=NaN, y=-0.04034928564659717, z=0FastLoco.js:483 Position(15.631288637889863, 0, 0.40338337421417236)Integrator.js:37 Verlet: Position: 0.1, velocity:0.1FastLoco.js:470 x(0.9991278314631757,0,0.041756153985874), y(0,1,0), z(-0.041756153985874,0,0.9991278314631757)FastLoco.js:474 x.z=0, x.y=0, y.z=0FastLoco.js:475 Length x=1, y=1, z=1FastLoco.js:482 Rotation x=0, y=-0.04176829769043192, z=0FastLoco.js:483 Position(15.727766104263305, 0, 0.41756153106689453)Integrator.js:37 Verlet: Position: 0.1, velocity:0.1FastLoco.js:470 x(0.9990665362840676,0,0.04319787121324316), y(0,1,0), z(-0.04319787121324316,0,0.9990665362840676)FastLoco.js:474 x.z=0, x.y=0, y.z=0FastLoco.js:475 Length x=1, y=1, z=1FastLoco.js:482 Rotation x=NaN, y=-0.04321131744913273, z=NaNFastLoco.js:483 Position(15.824132141109466, 0, 0.431978702545166)Integrator.js:37 Verlet: Position: 0.1, velocity:0.1FastLoco.js:470 x(0.9990020884231274,0,0.044663489857264344), y(0,1,0), z(-0.044663489857264344,0,0.9990020884231274)FastLoco.js:474 x.z=0, x.y=0, y.z=0FastLoco.js:475 Length x=1, y=1, z=1FastLoco.js:482 Rotation x=0, y=-0.044678352527951666, z=-1.4901161193847656e-8FastLoco.js:483 Position(15.920383662265778, 0, 0.4466348886489868)Integrator.js:37 Verlet: Position: 0.1, velocity:0.1FastLoco.js:470 x(0.9989343793541373,0,0.046153068634325126), y(0,1,0), z(-0.046153068634325126,0,0.9989343793541373)FastLoco.js:474 x.z=0, x.y=0, y.z=0FastLoco.js:475 Length x=1, y=1, z=1FastLoco.js:482 Rotation x=NaN, y=-0.04616946951298599, z=NaNFastLoco.js:483 Position(16.016519773662566, 0, 0.4615306854248047)Integrator.js:37 Verlet: Position: 0.1, velocity:0.1FastLoco.js:470 x(0.9988633097128881,0,0.047666429585350605), y(0,1,0), z(-0.047666429585350605,0,0.9988633097128881)FastLoco.js:474 x.z=0, x.y=0, y.z=0FastLoco.js:475 Length x=1, y=1, z=1FastLoco.js:482 Rotation x=0, y=-0.04768449845694656, z=0FastLoco.js:483 Position(16.112539283206942, 0, 0.47666430473327637)I wonder why there should be a NaN returned for a valid(as far as I can see), set of axes.Maybe these are some sort of floating point issue. Sometimes z=1.0000000000000002 for example.I don't think that such a small difference should throw off the calculation leading to a NaN though! Setting up a Play Ground here: http://www.babylonjs-playground.com/#1HH4OJ#11Anyone knows how to print debug values in PG? Quote Link to comment Share on other sites More sharing options...
jerome Posted August 28, 2015 Share Posted August 28, 2015 I will have to check accurately these values. Maybe is there a bug due to floating approximations in the algo ... In the PG, you can just do a console.log and everyone can check the values in his own browser Quote Link to comment Share on other sites More sharing options...
jerome Posted August 28, 2015 Share Posted August 28, 2015 Okit seems to be something missing either in the approximation either in the dot product (second case, I guess)probably we need to normalize first the u1 vector here : https://github.com/BabylonJS/Babylon.js/blob/master/src/Math/babylon.math.ts#L1111 altreality 1 Quote Link to comment Share on other sites More sharing options...
altreality Posted August 29, 2015 Author Share Posted August 29, 2015 Thanks Jerome. I will try a temporary fix in that function till its in the mainline. One thing I have noticed with the Cross product function,var cross = Vector3.Cross(u, v);Even if u & v are unit vectors, the cross vector isn't necessarily a unit vector and should be normalized anyway to be safe. ---------------- Hmm, normalizing in that function does not fix the issue. I will check what else is going on there.u1 = new Vector3(x, y, z);u1.normalize();v1 = Vector3.Cross(w, u1); // v1 image of v through rotation around wv1.normalize();cross = Vector3.Cross(u, u1); // returns same direction as w (=local z) if positive angle : cross(source, image)cross.normalize(); Quote Link to comment Share on other sites More sharing options...
jerome Posted August 29, 2015 Share Posted August 29, 2015 Actually I guess the problem is in the dot product. If the dot product isn't in the range [-1, 1], Math.acos(dot) will return NaN, what is happening in your PG. So as u is already normalized, if we normalize u1, then dot(u, u1) should be between -1 and 1 in all cases. The other solution would be to compare parameter axis coordinate values not to zero (limit case, as currently) but to epsilonToZero (almost zero) to avoid near limit cases going bad due to floating computation approximations. I'll check it as monday. altreality 1 Quote Link to comment Share on other sites More sharing options...
altreality Posted August 30, 2015 Author Share Posted August 30, 2015 Thanks Jerome. I can confirm that clamping the 3 dot products does work:dot = (Math.min(1, Math.max(-1, dot)));https://github.com/synth2014/Age-of-Steam/commit/3bceef2305f659914aa494679f306b175d700b35#diff-209db2e32be0b3025625186a20545bc2L836 Updated movement: http://synth2014.github.io/Age-of-Steam/babylon/rk4.html Quote Link to comment Share on other sites More sharing options...
jerome Posted August 30, 2015 Share Posted August 30, 2015 Ok, thank you for the fix :-)I will PR it in the mainstream ... unless you want to do it to get credit of course I was wrong when I said initially that axis1, axis2, axis3 parameters should be normalized when passed to RotationFromAxis(). Axis1, axis2 and axis3 are vectors that belong to the user, they aren't modified by the function but just copied and these copies only are then normalized.So they don't need to be normalized, but they have to be orthogonal and left-handed oriented. altreality 1 Quote Link to comment Share on other sites More sharing options...
altreality Posted August 30, 2015 Author Share Posted August 30, 2015 To submit a change, I just check out the repo, change the proper typescript file and submit a patch? Is there any unit test suite I need to run or a packaging process? Quote Link to comment Share on other sites More sharing options...
jerome Posted August 30, 2015 Share Posted August 30, 2015 no : nothing more than you just saidyou just have to test it in your browser on your own example what was bugged Was the dot product clamping still necessary once each temp vector (cross) was normalized ? Quote Link to comment Share on other sites More sharing options...
altreality Posted August 31, 2015 Author Share Posted August 31, 2015 Thanks.Was the dot product clamping still necessary once each temp vector (cross) was normalized ?Yes, it was. Normalization of the vectors did not work. Quote Link to comment Share on other sites More sharing options...
jerome Posted September 1, 2015 Share Posted September 1, 2015 OkI'm on it There's a weird approximation problem in the Dot product function ... unless it is in the BJS normalize() method or a genuine js approximation problemWith your set of values, if u and u1 are explicitly normalized Vector3.Dot(u, u1) returns here 1.0000000002 what shouldn't be possible ... It shoud be 0.0000009 or 1.0, but not greater than 1.0 that's why you had then to clamp the dot product although it shoudn't be necessary with normalized vectors Well, I guess that I will PR a fix with the clamping stuff before we investigate where the approximation is wrong (dot, normalize, js math) Quote Link to comment Share on other sites More sharing options...
jerome Posted September 1, 2015 Share Posted September 1, 2015 fix PRed altreality 1 Quote Link to comment Share on other sites More sharing options...
RaananW Posted September 1, 2015 Share Posted September 1, 2015 Oh, too much math... merged. Quote Link to comment Share on other sites More sharing options...
jerome Posted September 1, 2015 Share Posted September 1, 2015 After a look at BJS normalize() and dot product, I just couldn't see anything wrong.So these were only javascript math approximations in a bad lucky context. Everything should now be fixed with the usage of WithinEpsilon() comparisons and explicit clamping in the right interval. altreality 1 Quote Link to comment Share on other sites More sharing options...
Recommended Posts
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.