Global to local rotation

All topics about ZGameEditor goes here.

Moderator: Moderators

Post Reply
User avatar
Ats
Posts: 603
Joined: Fri Sep 28, 2012 10:05 am
Contact:

Global to local rotation

Post by Ats »

Hi, I've been trying to rotate a model from the world viewpoint for hours instead of rotating from his local axes. I've read a lot of stuff about quaternions but I didn't managed to get something working. I was able to get the same result the other way around, by rotating the camera instead of rotating the model, but then I would have more problems with the other things around.

Here's my test. I removed all the commented lines of unsatisfying tests... Can you help me with the magical mathematical lines?

Code: Select all

<?xml version="1.0" encoding="iso-8859-1" ?>
<ZApplication Name="App" Caption="Capture" CameraPosition="0 0 0" FileVersion="2">
  <OnLoaded>
    <SpawnModel Model="ModelViewer" Position="0 0 -20"/>
  </OnLoaded>
  <Content>
    <Model Name="ModelViewer">
      <Definitions>
        <Variable Name="ViewerVelocity" Type="6"/>
        <Variable Name="ButtonUp" Type="4"/>
        <Variable Name="ButtonDown" Type="4"/>
        <Variable Name="ButtonLeft" Type="4"/>
        <Variable Name="ButtonRight" Type="4"/>
      </Definitions>
      <OnSpawn>
        <ZExpression>
          <Expression>
<![CDATA[CurrentModel.Rotation.X = 0.15;
CurrentModel.Rotation.Y = 0;
CurrentModel.Rotation.Z = 0;
CurrentModel.RotationVelocity = 0;]]>
          </Expression>
        </ZExpression>
      </OnSpawn>
      <OnUpdate>
        <ZExpression>
          <Expression>
<![CDATA[ButtonUp = 0;
ButtonDown = 0;
ButtonLeft = 0;
ButtonRight = 0;]]>
          </Expression>
        </ZExpression>
        <KeyPress Comment="UP" Keys="^8wW">
          <OnPressed>
            <ZExpression Expression="ButtonUp = 1;"/>
          </OnPressed>
        </KeyPress>
        <KeyPress Comment="DOWN" Keys="_2sS">
          <OnPressed>
            <ZExpression Expression="ButtonDown = 1;"/>
          </OnPressed>
        </KeyPress>
        <KeyPress Comment="LEFT" Keys="<4aA">
          <OnPressed>
            <ZExpression Expression="ButtonLeft = 1;"/>
          </OnPressed>
        </KeyPress>
        <KeyPress Comment="RIGHT" Keys=">6dD">
          <OnPressed>
            <ZExpression Expression="ButtonRight = 1;"/>
          </OnPressed>
        </KeyPress>
        <ZExpression>
          <Expression>
<![CDATA[if(ButtonUp && ViewerVelocity.X < 1) ViewerVelocity.X += 0.6 * App.DeltaTime;
if(ButtonDown && ViewerVelocity.X > -1) ViewerVelocity.X -= 0.6 * App.DeltaTime;
if(ButtonLeft && ViewerVelocity.Y > -1) ViewerVelocity.Y -= 0.6 * App.DeltaTime;
if(ButtonRight && ViewerVelocity.Y < 1) ViewerVelocity.Y += 0.6 * App.DeltaTime;

if(!ButtonUp && !ButtonDown && !ButtonLeft && !ButtonRight){
  if (ViewerVelocity.X < 0) ViewerVelocity.X += 0.6 * App.DeltaTime;
  if (ViewerVelocity.X > 0) ViewerVelocity.X -= 0.6 * App.DeltaTime;
  if (ViewerVelocity.Y < 0) ViewerVelocity.Y += 0.6 * App.DeltaTime;
  if (ViewerVelocity.Y > 0) ViewerVelocity.Y -= 0.6 * App.DeltaTime;
  if (ViewerVelocity.X > -0.01 && ViewerVelocity.X < 0.01) ViewerVelocity.X = 0;
  if (ViewerVelocity.Y > -0.01 && ViewerVelocity.Y < 0.01) ViewerVelocity.Y = 0;
}


// Local Rotation

CurrentModel.RotationVelocity.X = -1*ViewerVelocity.X;
CurrentModel.RotationVelocity.Y = -1*ViewerVelocity.Y;

// Global Rotation

float cosAngle = cos(ViewerVelocity.X);
float sinAngle = sin(ViewerVelocity.Y);]]>
          </Expression>
        </ZExpression>
      </OnUpdate>
      <OnRender>
        <RenderMesh Mesh="MissileMesh"/>
      </OnRender>
    </Model>
    <Mesh Name="MissileMesh">
      <Producers>
        <MeshBox Scale="0.3 0.3 3"/>
        <MeshExpression VertexColors="255">
          <Expression>
<![CDATA[//V : current vertex
//N : current normal (turn off AutoNormals when modifying normals)
//C : current color (turn on VertexColors)
//TexCoord : current texture coordinate (turn on HasTexCoords)

c.R=0.8;
c.G=0.8;
c.B=0.8;]]>
          </Expression>
        </MeshExpression>
        <MeshBox Comment="flaps right" Scale="0.1 1 1"/>
        <MeshExpression VertexColors="255">
          <Expression>
<![CDATA[//V : current vertex
//N : current normal (turn off AutoNormals when modifying normals)
//C : current color (turn on VertexColors)
//TexCoord : current texture coordinate (turn on HasTexCoords)

c.R=1;
c.G=0.2;
c.B=0.2;]]>
          </Expression>
        </MeshExpression>
        <MeshTransform Position="0 0 1.5" Rotation="0.88 0 0"/>
        <MeshCombine/>
        <MeshBox Comment="flaps left" Scale="0.1 1 1"/>
        <MeshExpression VertexColors="255">
          <Expression>
<![CDATA[//V : current vertex
//N : current normal (turn off AutoNormals when modifying normals)
//C : current color (turn on VertexColors)
//TexCoord : current texture coordinate (turn on HasTexCoords)

c.R=1;
c.G=0.2;
c.B=0.2;]]>
          </Expression>
        </MeshExpression>
        <MeshTransform Position="0 0 1.5" Rotation="0.88 0 0.25"/>
        <MeshCombine/>
        <MeshSphere Scale="0.4 0.4 0.8" ZSamples="3" RadialSamples="4"/>
        <MeshExpression VertexColors="255">
          <Expression>
<![CDATA[//V : current vertex
//N : current normal (turn off AutoNormals when modifying normals)
//C : current color (turn on VertexColors)
//TexCoord : current texture coordinate (turn on HasTexCoords)

c.R=1;
c.G=0.2;
c.B=0.2;]]>
          </Expression>
        </MeshExpression>
        <MeshTransform Scale="1 1 2" Position="0 0 -3" Rotation="0 0 0.125"/>
        <MeshCombine/>
      </Producers>
    </Mesh>
  </Content>
</ZApplication>
User avatar
Kjell
Posts: 1876
Joined: Sat Feb 23, 2008 11:15 pm

Re: Global to local rotation

Post by Kjell »

Hi Ats,
Ats wrote:I've been trying to rotate a model from the world viewpoint for hours instead of rotating from his local axes.
The easiest way to do that is as follows ( use the arrow keys to rotate ) .. no quaternions needed :wink:

Code: Select all

<?xml version="1.0" encoding="iso-8859-1" ?>
<ZApplication Name="App" Caption="ZGameEditor application" FileVersion="2">
  <OnLoaded>
    <SpawnModel Model="Font" SpawnStyle="1"/>
  </OnLoaded>
  <OnUpdate>
    <Repeat Name="AxisRepeat" Count="2" WhileExp="//">
      <OnIteration>
        <ZExpression>
          <Expression>
<![CDATA[//

int i = AxisRepeat.Iteration;

//

Axis[i] = 0;

//

AxisPositive.CharCode = i ? 0x26 : 0x27;
AxisNegative.CharCode = i ? 0x28 : 0x25;]]>
          </Expression>
        </ZExpression>
        <KeyPress Name="AxisPositive" CharCode="38">
          <OnPressed>
            <ZExpression>
              <Expression>
<![CDATA[//

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

Axis[AxisRepeat.Iteration]--;]]>
              </Expression>
            </ZExpression>
          </OnPressed>
        </KeyPress>
        <ZExpression>
          <Expression>
<![CDATA[//

if(Axis[0] && Axis[1])
{
  Axis[0] *= 0.7071;
  Axis[1] *= 0.7071;
}]]>
          </Expression>
        </ZExpression>
      </OnIteration>
    </Repeat>
  </OnUpdate>
  <Content>
    <Array Name="Axis" SizeDim1="2"/>
    <Variable Name="Matrix" Type="5"/>
    <Model Name="Font">
      <OnSpawn>
        <ZExpression>
          <Expression>
<![CDATA[//

for(int i=0; i<4; i++)
{
  for(int j=0; j<4; j++)
  {
    Matrix[i,j] = i == j ? 1 : 0;
  }
}]]>
          </Expression>
        </ZExpression>
      </OnSpawn>
      <OnRender>
        <ZExpression>
          <Expression>
<![CDATA[//

mat4 m;

//

float a, c, s;

if(Axis[0])
{
  a = Axis[0]*4*App.DeltaTime;
  s = sin(a);
  c = cos(a);

  m[0,0] = c;   m[1,0] = 0; m[2,0] = s; m[3,0] = 0;
  m[0,1] = 0;   m[1,1] = 1; m[2,1] = 0; m[3,1] = 0;
  m[0,2] = 0-s; m[1,2] = 0; m[2,2] = c; m[3,2] = 0;
  m[0,3] = 0;   m[1,3] = 0; m[2,3] = 0; m[3,3] = 1;

  Matrix = m * Matrix;
}

if(Axis[1])
{
  a = Axis[1]*4*App.DeltaTime;
  s = sin(a);
  c = cos(a);

  m[0,0] = 1; m[1,0] = 0;   m[2,0] = 0; m[3,0] = 0;
  m[0,1] = 0; m[1,1] = c;   m[2,1] = s; m[3,1] = 0;
  m[0,2] = 0; m[1,2] = 0-s; m[2,2] = c; m[3,2] = 0;
  m[0,3] = 0; m[1,3] = 0;   m[2,3] = 0; m[3,3] = 1;

  Matrix = m * Matrix;
}

//

getMatrix(0, m);
m = m * Matrix;
setMatrix(0, m);]]>
          </Expression>
        </ZExpression>
        <RenderMesh Mesh="FontMesh"/>
      </OnRender>
    </Model>
    <Mesh Name="FontMesh">
      <Producers>
        <MeshImport HasVertexColors="1">
          <MeshData>
<![CDATA[78DAE55041AE0151102C8C88217CCEE018120E613589BBB884F37C3B9BC98F0547B0B1B1E511AD4BE98CCDE41F4077BA5EA75F4F55BD99029880B1F92578F9399F032BD6EC58A4AD7908198090E7B1109E96668B83F0BCE684F8A2057788A725C01DE279CD89306DC9210C5E7DF91F7FBDB7CF8ECC5291A2D4E544AEE4303415C11C3CD20D0F9FAFE066F8A95E24CFE1BFFA03F1BECAA7A28B0186B85813911992257BBC72881F8C91A3E795A3ED7775B9B3BDFD1979828B3C19C43342DF55346F78022DCFECDD27BB1B776FD6768DBE97E64271557D0B7767BC5AC7F7F25A3F6559DA37D51320A5CB2E]]>
          </MeshData>
        </MeshImport>
      </Producers>
    </Mesh>
  </Content>
</ZApplication>
K
User avatar
Ats
Posts: 603
Joined: Fri Sep 28, 2012 10:05 am
Contact:

Re: Global to local rotation

Post by Ats »

Wow. Thanks Kjell, that's exactly what I was trying to do. I'll try to add some momentum to the rotation as an exercise to understand what's going on in your code :lol:

By the way, using Axis instead of ButtonLeft/Right is clever to avoid pressing both opposite direction at the same time, among other things. I'll change my game to use it like that. (Edit: maybe not finaly, I also have to test press/release to avoid key repeat )

Also, is there some reasons why you rotate the model in OnRender instead of using Rotation in OnUpdate? Performance maybe?
I ask because I have a lot of little objetcs that turn around themselves in the game.
Once again, many thanks ! Only one last big problem and I'll be ready to publish the first beta :D
User avatar
Kjell
Posts: 1876
Joined: Sat Feb 23, 2008 11:15 pm

Re: Global to local rotation

Post by Kjell »

Hi Ats,
Ats wrote:By the way, using Axis instead of ButtonLeft/Right is clever to avoid pressing both opposite direction at the same time, among other things. I'll change my game to use it like that. (Edit: maybe not finaly, I also have to test press/release to avoid key repeat )
Check the example in this post on how to do the Axis approach with "press" / "release" events.
Ats wrote:Also, is there some reasons why you rotate the model in OnRender instead of using Rotation in OnUpdate?
To be honest, it's "cleaner" to do the matrix generation in OnUpdate and only the application ( the last 3 lines ) in OnRender. Anyway, the reason why it's in OnRender is because i'm manipulating the modelViewMatrix of the model directly, which can only be done in OnRender.
Ats wrote:I ask because I have a lot of little objetcs that turn around themselves in the game.
Maybe you should explain what you're working on .. unless it's some kind of puzzle game where you rotate a bunch of objects you might not need this approach at all.

K
Post Reply