3D Physics with ZgeBullet

Use of external libraries (DLLs) from ZGE.

Moderator: Moderators

User avatar
Ats
Posts: 933
Joined: Fri Sep 28, 2012 10:05 am
Contact:

Re: 3D Physics with ZgeBullet

Post by Ats »

I have a technical question regarding the update of the bullet simulation.

I always used it like this:

Code: Select all

float t = App.DeltaTime;
zbtStepSimulation(t, 0, 0);
But the documentation is talking about:
@fn void zbtStepSimulation(
float timeStep, int maxSubSteps, float fixedTimeStep)
@brief Proceed the simulation over time step.
@details By default, the @a timeStep is subdivided in constant sub-steps of each
@a fixedTimeStep. In order to keep the simulation real-time, the maximum
number of sub-steps can be clamped to @a maxSubSteps. You can disable
subdividing the time step/sub-stepping by passing @a maxSubSteps=0, but in
that case you have to keep the timeStep constant.
@param timeStep duration of simulation step in seconds
@param maxSubSteps if > 0, it will interpolate motion between fixedTimeStep's
@param fixedTimeStep fixed time step
So I tried this, thinking it would be less demanding than what I used to do:

Code: Select all

// Define a fixed time step for substeps (e.g., 1/60th of a second)
float fixedTimeStep = 1.0f / 60.0f;  // 60Hz

// Calculate the number of substeps needed
int maxSubSteps = (t / fixedTimeStep) + 1;

// Limit maxSubSteps to a reasonable number to avoid performance issues
if (maxSubSteps > 10) maxSubSteps = 10;

// Update the physics simulation
zbtStepSimulation(t, maxSubSteps, fixedTimeStep);
It is working perfectly on PC, but it is utterly broken on Android, leading to random collisions with nothing in the way.
Is there something wrong with what I do, or maybe some technical issue on Android?
User avatar
Ats
Posts: 933
Joined: Fri Sep 28, 2012 10:05 am
Contact:

Re: 3D Physics with ZgeBullet

Post by Ats »

I tested every setting from rado1's ZGEBullet examples:

Demo 1:
float t = App.DeltaTime;
zbtStepSimulation(t, 0, 0);

Demo 2:
float t = App.DeltaTime;
zbtStepSimulation(t, 3, t/2);

Demo 3:
float t = App.DeltaTime;
zbtStepSimulation(t, 1, t);

Demo 4:
zbtStepSimulation(App.DeltaTime, 0, 0);

zbtStepSimulation(t, 0, 0) is only working on PC. On Android, the plane is passing through walls.
zbtStepSimulation(t, 1, t) works on both systems.

Edit:
Simulation on Android still behave weirdly at times... :?
zbtStepSimulation(t, 1, t*0.5) is working better on Android.
User avatar
zakkwylde
Posts: 31
Joined: Sun Feb 24, 2008 1:38 am
Location: France

Re: 3D Physics with ZgeBullet

Post by zakkwylde »

Hi guys,

I have been working on a sample code provided by one of our very helpful friends here but i have been stumped literally for years. Even AI cannot comprehend how to fix this.
This demo (attached) is a camera using quaternions to rotate above a structure. I have been trying to get the camera to move in the direction it is facing but even though it can move, it is never in the direction i want. Can anyone take a shot at this and see if some magic rubs off here?

Thanks![attachment=0]Quart0.zgeproj[/attachment]
Attachments
Quart0.zgeproj
Quaternions demo
(10.64 KiB) Downloaded 33 times
User avatar
Kjell
Posts: 1985
Joined: Sat Feb 23, 2008 11:15 pm

Re: 3D Physics with ZgeBullet

Post by Kjell »

Hi zakkwylde,
zakkwylde wrote: Fri Feb 20, 2026 8:44 amI have been trying to get the camera to move in the direction it is facing but even though it can move, it is never in the direction i want.
Below is a simple* example.

*I ended up converting the quaternion matrix to euler-angles ( instead of manipulating the modelView matrix directly ) in an attempt to make things easy to understand .. just keep in mind that ZGE converts the euler-angles back to a matrix internally again, so this is a bit wasteful performance-wise.

Code: Select all

<?xml version="1.0" encoding="iso-8859-1" ?>
<ZApplication Name="App" Caption="ZGameEditor application" LightPosition="0 1 0" FileVersion="2">
  <OnLoaded>
    <ZLibrary Comment="Quaternion">
      <Source>
<![CDATA[//

vec3 applyQuaternion(vec3 v, vec4 q)
{
  float x, y, z, w;

  x = q.w*v.x+q.y*v.z-q.z*v.y;
  y = q.w*v.y+q.z*v.x-q.x*v.z;
  z = q.w*v.z+q.x*v.y-q.y*v.x;

  w = -q.x*v.x-q.y*v.y-q.z*v.z;

  return vector3
  (
    x*q.w-w*q.x-y*q.z+z*q.y,
    y*q.w-w*q.y-z*q.x+x*q.z,
    z*q.w-w*q.z-x*q.y+y*q.x
  );
}

vec4 invertQuaternion(vec4 q)
{
  return vector4(-q.x, -q.y, -q.z, q.w);
}

vec4 multiplyQuaternion(vec4 a, vec4 b)
{
  return vector4
  (
    a.x*b.w+a.w*b.x+a.y*b.z-a.z*b.y,
    a.y*b.w+a.w*b.y+a.z*b.x-a.x*b.z,
    a.z*b.w+a.w*b.z+a.x*b.y-a.y*b.x,
    a.w*b.w-a.x*b.x-a.y*b.y-a.z*b.z
  );
}

//

vec4 axisAngleToQuaternion(vec3 axis, float angle)
{
  float a, s;

  a = angle*0.5;
  s = sin(a);

  return vector4(axis.x*s, axis.y*s, axis.z*s, cos(a));
}

//

mat4 quaternionToMatrix(vec4 q)
{
  float x2, y2, z2, xx, xy, xz, yy, yz, zz, wx, wy, wz;

  x2 = q.x*2;
  y2 = q.y*2;
  z2 = q.z*2;

  xx = q.x*x2; xy = q.x*y2; xz = q.x*z2;
  yy = q.y*y2; yz = q.y*z2; zz = q.z*z2;
  wx = q.w*x2; wy = q.w*y2; wz = q.w*z2;

  mat4 m;

  m[0,0] = 1-(yy+zz);
  m[0,1] = xy+wz;
  m[0,2] = xz-wy;
  m[0,3] = 0;

  m[1,0] = xy-wz;
  m[1,1] = 1-(xx+zz);
  m[1,2] = yz+wx;
  m[1,3] = 0;

  m[2,0] = xz+wy;
  m[2,1] = yz-wx;
  m[2,2] = 1-(xx+yy);
  m[2,3] = 0;

  m[3,0] = 0;
  m[3,1] = 0;
  m[3,2] = 0;
  m[3,3] = 1;

  return m;
}

//

vec3 matrixToEuler(mat4 m, int order)
{
  vec3 v;

  switch(order)
  {
    case 0x7: // XYZ
      v.x = atan2(m[1,2], m[2,2])/PI*0.5;
      v.y = asin(-clamp(m[0,2], -1, 1))/PI*0.5;
      v.z = atan2(m[0,1], m[0,0])/PI*0.5;
      break;

    case 0xF: // ZYX
      v.x = atan2(-m[2,1], m[2,2])/PI*0.5;
      v.y = asin(clamp(m[2,0], -1, 1))/PI*0.5;
      v.z = atan2(-m[1,0], m[0,0])/PI*0.5;
      break;
  }

  return v;
}]]>
      </Source>
    </ZLibrary>
    <ZExpression>
      <Expression>
<![CDATA[//

CameraOffset = vector3(0, 0.5, 5);]]>
      </Expression>
    </ZExpression>
    <SpawnModel Model="Ship" Position="0 8 0"/>
  </OnLoaded>
  <OnUpdate>
    <Repeat Name="AxisRepeat" Count="3">
      <OnIteration>
        <ZExpression>
          <Expression>
<![CDATA[//

int i = AxisRepeat.Iteration;

//

Axis[i] = 0;

//

AxisPositive.CharCode = AxisMap[i,0];
AxisNegative.CharCode = AxisMap[i,1];]]>
          </Expression>
        </ZExpression>
        <KeyPress Name="AxisPositive" CharCode="68">
          <OnPressed>
            <ZExpression>
              <Expression>
<![CDATA[//

Axis[AxisRepeat.Iteration]++;]]>
              </Expression>
            </ZExpression>
          </OnPressed>
        </KeyPress>
        <KeyPress Name="AxisNegative" CharCode="65">
          <OnPressed>
            <ZExpression>
              <Expression>
<![CDATA[//

Axis[AxisRepeat.Iteration]--;]]>
              </Expression>
            </ZExpression>
          </OnPressed>
        </KeyPress>
      </OnIteration>
    </Repeat>
    <KeyPress Name="Key" Keys="12">
      <OnKeyDown>
        <ZExpression>
          <Expression>
<![CDATA[//

if(Key.KeyIndex)
{
  CameraOffset = vector3(0, 0.5, 5);
}
else
{
  CameraOffset = vector3(0, 0, 0);
}]]>
          </Expression>
        </ZExpression>
      </OnKeyDown>
    </KeyPress>
  </OnUpdate>
  <OnRender>
    <UseMaterial Material="TerrainMaterial"/>
    <RenderMesh Mesh="TerrainMesh"/>
  </OnRender>
  <Content>
    <Array Name="Axis" SizeDim1="4"/>
    <Array Name="AxisMap" Type="4" Dimensions="1" SizeDim1="3" SizeDim2="2" Persistent="255">
      <Values>
<![CDATA[789C535755D37071040003820120]]>
      </Values>
    </Array>
    <Variable Name="CameraOffset" Type="7"/>
    <Model Name="Ship">
      <Definitions>
        <Variable Name="ShipQuaternion" Type="8"/>
      </Definitions>
      <OnSpawn>
        <ZExpression>
          <Expression>
<![CDATA[//

ShipQuaternion = vector4(0, 0, 0, 1);]]>
          </Expression>
        </ZExpression>
      </OnSpawn>
      <OnUpdate>
        <ZExpression>
          <Expression>
<![CDATA[//

float dt, x, y, z;

//

dt = App.DeltaTime;

x = -Axis[1]*dt;
y = -Axis[2]*dt;
z = -Axis[0]*dt;

// Steering

vec4 qx, qy, qz, q;

qx = axisAngleToQuaternion(vector3(1, 0, 0), x);
qy = axisAngleToQuaternion(vector3(0, 1, 0), y);
qz = axisAngleToQuaternion(vector3(0, 0, 1), z);

q = multiplyQuaternion(qz, qy);
q = multiplyQuaternion(qx, q);

ShipQuaternion = multiplyQuaternion(ShipQuaternion, q);
Ship.Rotation = matrixToEuler(quaternionToMatrix(ShipQuaternion), 0x7);

// Movement

vec3 v = applyQuaternion(vector3(0, 0, -8), ShipQuaternion);

Ship.Position.X += v.x*dt;
Ship.Position.Y += v.y*dt;
Ship.Position.Z += v.z*dt;

// Camera

App.CameraRotation = matrixToEuler(quaternionToMatrix(invertQuaternion(ShipQuaternion)), 0xF);

vec3 o = applyQuaternion(CameraOffset, ShipQuaternion);

App.CameraPosition.X = Ship.Position.X+o.x;
App.CameraPosition.Y = Ship.Position.Y+o.y;
App.CameraPosition.Z = Ship.Position.Z+o.z;]]>
          </Expression>
        </ZExpression>
      </OnUpdate>
      <OnRender>
        <Condition>
          <Expression>
<![CDATA[//

return CameraOffset.Z;]]>
          </Expression>
          <OnTrue>
            <UseMaterial Material="ShipMaterial"/>
            <RenderMesh Mesh="ShipMesh"/>
          </OnTrue>
        </Condition>
      </OnRender>
    </Model>
    <Mesh Name="ShipMesh">
      <Producers>
        <MeshImport HasVertexColors="1">
          <MeshData>
<![CDATA[789CD5923F68535118C5AFFF103A084E2EC649A4253A640BA5605B22018B105A692D165248846296486A33682A151751120DA8F4CF835774B0201D149B0E62105F9A621E423010084587D2D1423A8884CAB587C3C7ED5AEA13E5F11D0EBF73EEF7EE83F74E297571675CF755B1ADFEFCFD6278BEE8BA67BB7FB48F9CEF5F3ED6FDF9493A74C1826EAC4E4F4723C532097DDC4A878418BFB14A2561B36F2C1A49954E27D2216AC19E8AA743971CC30B36537212A686A44AFE5C47E25BAC96A43AD670D69FA382407B5B48A9A649E258D4E1ACD1DE163650CD36129CDABD995CF680945E4623E5CDE38F95827624943AF5C8B1CA9BC24198929330158214DB94AA25E1CF5D414A221E4DE9D0F3141584CD5BF7279C4005FAE6973FF76926B805FDB27C6F02A4961412DC62073C50614AC20D68F214B7052A668FA4DCC6B30F674E8C37F327CB5ACF7F87AFD6E93F3CD577AA75127640A4693AE4D5FA541CCDF520387C334FD23786949C0AC2B499674AC2341BBB11F6359482C27FBC4E928D0D0C0A9774609029142909D3C95970ADC5FB1AE2D1246107449AA643EE6BB45E647ADE7EEDB25F9FD17A7236D3A335097D971D1E11425F583084FEE6A239455F58C036E9C073FFCFAB209D43F0997E3449E83B87B04D3AF04BA386D0A7AE9953F44BA366333DF7F36EBCB37C0B3994F7E44EBE4BEE80947BB85FA903EAA03AB4E787278FA8C3FBF47FF3BDFFCBC33B63448FEEFA16C36DA5B497B37DD9DBB97D77CED37157D6FEE8ACADB89ECE83B9679ECEF6B8FAA766E727DED3FC060DFA76D3]]>
          </MeshData>
        </MeshImport>
      </Producers>
    </Mesh>
    <Material Name="ShipMaterial" Shading="1"/>
    <Mesh Name="TerrainMesh">
      <Producers>
        <MeshBox XCount="15" YCount="15" Grid2DOnly="255"/>
        <MeshExpression Scale="64 4 64" VertexColors="255">
          <Expression>
<![CDATA[//

V.Z = -V.Y;
V.Y = rnd();

C.R = 0;
C.G = V.Y;
C.B = 1;]]>
          </Expression>
        </MeshExpression>
      </Producers>
    </Mesh>
    <Material Name="TerrainMaterial"/>
  </Content>
</ZApplication>
You can control the ship using the arrow and A/D keys, and switch between 1st and 3rd-person camera using the 1/2 keys.

K
User avatar
zakkwylde
Posts: 31
Joined: Sun Feb 24, 2008 1:38 am
Location: France

Re: 3D Physics with ZgeBullet

Post by zakkwylde »

Kjell,

Thank you for solving a years long mystery. So we have to still switch to euler for camera postioning. But wouldn't this cause gimbal lock? I didnt see any abnormalities at extreme angles, was rather smooth in 6DOF.

Also, this code only works on the latest ZGE version, not usable on v5.0b that i was on. On that ver. i was able to get the code compiled correctly but the simulation only showed a static terrain and no movement. Wonder why the difference?

Real thankful for you showing the way, now i can get out of the forest :D


Cheers!

Zakkwylde
User avatar
Kjell
Posts: 1985
Joined: Sat Feb 23, 2008 11:15 pm

Re: 3D Physics with ZgeBullet

Post by Kjell »

Hi zakkwylde,
zakkwylde wrote: Tue Feb 24, 2026 12:34 pmSo we have to still switch to euler for camera postioning.
No, converting to euler isn't needed. In case you prefer not to .. simply remove the matrixToEuler conversions, store the results of quaternionToMatrix as mat4 variables and apply them using setMatrix just like i did in previous examples. Just keep in mind you can't use the built-in Camera.Rotation/Position and Model.Rotation properties that way.
zakkwylde wrote: Tue Feb 24, 2026 12:34 pmBut wouldn't this cause gimbal lock?
Nope, all rotation calculations are done using quaternions. Euler angles are perfectly capable of representing any orientation, but once you use them in 6DOF rotation calculations you'll encounter gimbal lock.
zakkwylde wrote: Tue Feb 24, 2026 12:34 pmAlso, this code only works on the latest ZGE version, not usable on v5.0b that i was on. On that ver. i was able to get the code compiled correctly but the simulation only showed a static terrain and no movement. Wonder why the difference?
No idea .. hard to tell without knowing what exact build you're using.

K
Post Reply