0

I want to move an object based on its own direction. The object has a translation vector and a rotation vector(degrees). I can call a method move and give it a direction and the units the object should be moved(speed if you so wish). If I give this method the direction "FORWARD" than it should move in the direction the object is currently facing.

I have this code currently:

/*
 * MIT License
 * 
 * Copyright (c) 2017 Ralph Niemitz
 * 
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 * 
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 * 
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */
package de.ralleytn.engine.lunatic;

import javax.vecmath.Vector3f;

/**
 * Merges rotation with translation and adds translation based on rotation.
 * @author Ralph Niemitz/RalleYTN(ralph.niemitz@gmx.de)
 * @version 1.0.0
 * @since 1.0.0
 */
public interface Movable extends Translatable, Rotatable {

    /**
     * Moves the object into the given direction based on its own rotation.
     * @param direction the direction in which the object should be moved
     * @param units the number of units it should be moved
     * @since 1.0.0
     */
    public default void move(Direction direction, float units) {

        float nUnits = -units;
        Vector3f rotation = this.getRotation();

        if(direction == Direction.LEFT) {

            float rY = (float)Math.toRadians(rotation.y);
            float rZ = (float)Math.toRadians(rotation.z);

            float x = (float)Math.cos(rY) * nUnits;
            float y = (float)Math.sin(rZ) * units;
            float z = (float)Math.sin(rY) * nUnits;

            this.translate(x, y, z);

        } else if(direction == Direction.RIGHT) {

            // float rX = (float)Math.toRadians(rotation.x);
            float rY = (float)Math.toRadians(rotation.y);
            float rZ = (float)Math.toRadians(rotation.z);

            float x = (float)Math.cos(rY) * units;
            float y = (float)Math.sin(rZ) * nUnits;
            float z = (float)Math.sin(rY) * units;

            this.translate(x, y, z);

        } else if(direction == Direction.FORWARD) {

            float rX = (float)Math.toRadians(rotation.x);
            float rY = (float)Math.toRadians(rotation.y - 90.0F);

            float x = (float)Math.cos(rY) * units;
            float y = (float)Math.sin(rX) * nUnits;
            float z = (float)Math.sin(rY) * units;

            this.translate(x, y, z);

        } else if(direction == Direction.BACKWARD) {

            float rX = (float)Math.toRadians(rotation.x);
            float rY = (float)Math.toRadians(rotation.y - 90.0F);

            float x = (float)Math.cos(rY) * nUnits;
            float y = (float)Math.sin(rX) * units;
            float z = (float)Math.sin(rY) * nUnits;

            this.translate(x, y, z);

        } else if(direction == Direction.UP) {

            float rX = (float)Math.toRadians(rotation.x);
            float rZ = (float)Math.toRadians(rotation.z);

            float x = (float)Math.sin(rZ) * nUnits;
            float y = (float)Math.cos(rX) * units;
            float z = (float)Math.sin(rX) * nUnits;

            this.translate(x, y, z);

        } else if(direction == Direction.DOWN) {

            float rX = (float)Math.toRadians(rotation.x);
            float rZ = (float)Math.toRadians(rotation.z);

            float x = (float)Math.sin(rZ) * units;
            float y = (float)Math.cos(rX) * nUnits;
            float z = (float)Math.sin(rX) * units;

            this.translate(x, y, z);
        }
    }
}

It doesn't really work how I want it to. I'm fairly new to 3D so I don't have that much knowledge. All the solutions I've seen so far are for Unity and C# which doesn't really help me.

I'm using the javax.vecmath package if that is important.

RalleYTN
  • 138
  • 10
  • see [Understanding 4x4 homogenous transform matrices](https://stackoverflow.com/a/28084380/2521214) especially the last 3 links in there ... – Spektre Nov 27 '17 at 07:53

1 Answers1

0

There is different ways of accomplishing what you are asking.

One of them should be to maintain a forward vector, and a representation of your rotation in your Object instance. the forward vector should maybe be initialized with vec3(0, 0, 1);

I don't know what is Vector3f rotation = this.getRotation(); If it's Euler angle (yaw, pitch and roll), you should maybe avoid doing the trigonometry on your self and use some predefined functions wich can compute a rotation matrix based on those angles here

You can start with only Rx and Ry in the beguining and use some methods like: glRotatef(value, 0, 1, 0); for Ry

glRotatef(value, 1, 0, 0); for Rx

Now each time you accomplish a rotation you should update those rotations value. you start with the rotation Matrix, and then you apply this rotation matrix to your InitialForwardvector.

m_rotation = Matrix4f.identity().rotateX(Rx).rotateY(Ry);
m_forward  = m_rotation * vec3(0, 0, 1);

Now when you judge its time to translate

vec3 translationVector = speed * m_forward;
this.translate(translationVector.x, translationVector.y, translationVector.z);

If you want to go left you can compute the left vector by adding 90° to the yaw of your rotation matrix. I am not sure it's what you want sometimes in videoGame it's better to only move on the XZ plane.

Matrix4f rotation = Matrix4f.identity().rotateX(Rx /* maybe 0 */).rotateY(Ry + 1.57);
m_left = m_rotation * vec3(0, 0, 1);

You can also compute your initial left vector, remove the code above and use the same rotation Matrix but applied to your left vector, you will have better performance. Just try to have your initLeftVector perpendicular with your initialForward one.

vec3 initialLeft = vec3(1, 0, 0);
m_left = m_rotation * initialLeft;
Paltoquet
  • 1,184
  • 1
  • 10
  • 18
  • I really want to avoid using deprecated methods like glRotatef(). I work with OpenGL4.6 and the programmable Pipeline (Shaders and stuff). Yes the rotation is euler. and javax.vecmath doesn't have much functionality. I even saw myself forced to copy some legacy LWJGL2 code because some things just didnt work. – RalleYTN Nov 27 '17 at 09:10
  • I still dont fully understand how these forward, left etc, vectors work. And its not about moving the camera but objects in a 3D world based on their rotation on all axis. Do you have some articles describing what exactly they are and how to calculate them properly. the article you linked just showed me the basics of transformation and projection which I already applied. – RalleYTN Nov 27 '17 at 09:28
  • It would be good if all your object have its own Model Matrix where all its transformation are located. Each object should have its own rotation matrix and a initialForwardVector. This way you can compute their forward direction in WorldSpace and translate in the same space before camera. I am a beguiner my self, but a good concept used in a variety of games is a SceneGraph where object inherit transformation from others https://www.opengl.org/discussion_boards/showthread.php/177194-What-is-a-scene-graph – Paltoquet Nov 27 '17 at 10:07
  • Question: where is the speed? I have to multiply the speed with the delta to get smooth movement. I cannot see it in this forward vector thingy – RalleYTN Nov 27 '17 at 12:52
  • and what exactly is now. vec3(0,0,1) and Ry + 1.57. that just looks like magic numbers. wasn't vec3(0,0,1) supposed to be the forward vector, why is that in the calculation for left. do I really have to rotate the entire matrix just to get the directions. just calculating the matrix with rotation on XYZ already costs me 2 FPS. – RalleYTN Nov 27 '17 at 13:10
  • Yep you are right, `vec3(0, 0, 1)`is your initial forward vector, something like at the beguining of my scene this object is currently looking in the z direction. For the 1.57 it's equal to 90° in radian pi/2. m_rotation is the rotation which you will apply to your initTargetVector to compute the new facing direction, now you can assume (depend on your case) that the x axis is m_forward but rotated 90° on the y axis. Now if you want better performance you should change the use of matrix to quaternions, which are better to store rotations and cleaner for this case. – Paltoquet Nov 27 '17 at 13:49
  • why does moving an object have to be a science for itself? – RalleYTN Nov 27 '17 at 14:32
  • It's important to see the big picture. You handle 3 type of coordinates. In our case World coordinate and Camera. Inside world coordinate you can translate your objects where ever you like. But you have to define the amount. Each of your object should have a facing direction,leftDirection and rightDirection. When thoose are set it become really easy to put code like: `myObjectPosition = myObjectPosition + this.left * speed;`I think you should have started only with the basic yax, roll and pitch could have come later on. http://www.opengl-tutorial.org/beginners-tutorials/tutorial-3-matrices/. – Paltoquet Nov 27 '17 at 15:01