Three.js vs Ammo.js Make player move left and right in FPS mode with dynamic playerPhysicsBody - three.js

I attach to the player(camera) physics body. I have nice working forwand and backward but lft and right always faild in some way.
I dont want kinematic like ussually controls object containe.
I wanna my graphics to follow my physics body.
Here is most important code:
if (this.moveForward == true) {
// WORKS PERFECT IN ANY DIRECTION
this.pos.copy(this.raycaster.ray.direction);
this.pos.multiplyScalar(12);
this.playerBody.userData.physicsBody.setLinearVelocity(
new Ammo.btVector3(this.pos.x,this.pos.y,this.pos.z));
} else if (this.moveBackward == true) {
// WORKS PERFECT IN ANY DIRECTION
this.pos.copy(this.raycaster.ray.direction);
this.pos.multiplyScalar(12);
this.playerBody.userData.physicsBody.setLinearVelocity(
new Ammo.btVector3(-this.pos.x,this.pos.y,-this.pos.z));
} else if (this.moveLeft == true) {
// NOT WORKS PERFECT IN ANY DIRECTION !!!!
this.pos.copy(this.raycaster.ray.direction);
this.pos.multiplyScalar(12);
this.playerBody.userData.physicsBody.setLinearVelocity(
new Ammo.btVector3(this.pos.x, 0, this.pos.y));
} else if (this.moveRight == true) {
// NOT WORKS PERFECT IN ANY DIRECTION !!!!
this.pos.copy(this.raycaster.ray.direction);
this.pos.multiplyScalar(12);
this.playerBody.userData.physicsBody.setLinearVelocity(
new Ammo.btVector3(-this.pos.y, 0, -this.pos.x));
}
I try to combine x,y,z also with -x,-y,-z in different variant but no success.
How can i modify this.raycaster.ray.direction for example angle for Y axion +90 or -90
and make work just like forwand and backward....
Any suggestion ?

i make clone of exist ray.direction vector then i apply new angle with applyAxisAngle. For left -90 for right 90 .
else if (this.moveLeft == true) {
let fixedDirection1 = this.raycaster.ray.direction.clone();
fixedDirection1.applyAxisAngle(
new THREE.Vector3(0,1,0), MathUtils.degToRad(90))
this.pos.copy(fixedDirection1);
this.pos.multiplyScalar(this.config.playerController.movementSpeed.left);
this.playerBody.userData.physicsBody.setLinearVelocity(
new Ammo.btVector3(this.pos.x, 0, this.pos.z));
} else if (this.moveRight == true) {
let fixedDirection1 = this.raycaster.ray.direction.clone();
fixedDirection1.applyAxisAngle(
new THREE.Vector3(0,1,0), MathUtils.degToRad(-90))
this.pos.copy(fixedDirection1);
this.pos.multiplyScalar(this.config.playerController.movementSpeed.right);
this.playerBody.userData.physicsBody.setLinearVelocity(
new Ammo.btVector3(this.pos.x, 0, this.pos.z));
}
Now i have player who walk in all directions.

Related

JavaFX Changing Text Displaying Score to Animation and Setting Back to Score

I am currently making a 2-player game of pong that displays the score of each side. I am looking to display the score throughout the entire game, but when someone scores, I would like a "GOAL!" (letter by letter to a short pause at the end) animation to be set as the text rather than the team's points (just how it shows in some sports shown on tv), and then be set back to the new score after. I am having troubles with this section, here is what I have:
This is my code for displaying the animation(not sure if this is right, haven't been able to test it because it won't display!):
public void displayGoal(int homeOrAway)
{
String str = "GOAL!";
if(homeOrAway == 0)
{
final IntegerProperty i = new SimpleIntegerProperty(0);
Timeline timeline = new Timeline();
KeyFrame keyFrame = new KeyFrame(
Duration.seconds(1),
event -> {
if (i.get() > str.length()) {
timeline.stop();
textHomeScore.setText("" + getHomeScore() + "");
} else {
textHomeScore.setText(str.substring(0, i.get()));
i.set(i.get() + 1);
}
});
timeline.getKeyFrames().add(keyFrame);
timeline.play();
}
else
{
final IntegerProperty i = new SimpleIntegerProperty(0);
Timeline timeline = new Timeline();
KeyFrame keyFrame = new KeyFrame(
Duration.seconds(1),
event -> {
if (i.get() > str.length()) {
timeline.stop();
textAwayScore.setText(""+ getAwayScore() + "");
} else {
textAwayScore.setText(str.substring(0, i.get()));
i.set(i.get() + 1);
}
});
timeline.getKeyFrames().add(keyFrame);
timeline.play();
}
}
textAwayScore and textHomeScore are just normal Texts, not TextFields.
Without this function, the scores display perfectly fine and they count up everytime the ball goes past the paddle. It would be nice to add this animation to whichever side gets the point, so any help to accomplish this is greatly appreciated. If anyone needs any clarification please let me know and I will clarify something! Thank you!

Updating a geometry inside a mesh does nothing

I am using THREE.JS rev 49.
My program needs to update a mesh by changing it's geometry.
Unfortunately the display does not seem to update.
Here is my code :
// theObject is an array of associatives :
// {
// object1: {mesh: undefined/THREE.mesh, mat: THREE.Material, geo: THREE.Geometry}
// object2: {mesh: undefined/THREE.mesh, mat: THREE.Material, geo: THREE.Geometry}
// ...
// }
// In my function, theObject[i].mesh geometry must change to be theObject[i].geo.
for(i in theObjects) {
//*
if ( theObjects[i].mesh == undefined) {
theObjects[i].mesh = new THREE.Mesh(theObjects[i].geo, theObjects[i].mat);
theObjects[i].mesh.geometry.dynamic = true;
theObjects[i].geo.verticesNeedUpdate = true;
scenePostsurgery.add(theObjects[i].mesh);
} else
theObjects[i].mesh.geometry.vertices = theObjects[i].geo.vertices;
}
Do I have to add something else ?
/Oragon
If I understood correctly you are updating vertices here:
else{
theObjects[i].mesh.geometry.vertices = theObjects[i].geo.vertices;
}
Try to change this code to :
else{
theObjects[i].mesh.geometry.dynamic = true;
theObjects[i].mesh.geometry.vertices = theObjects[i].geo.vertices;
theObjects[i].mesh.geometry.verticesNeedUpdate = true;
}
In if(){} you create a mesh and in else{} you update so dynamic = true and verticesNeedUpdate = true you need to set to mesh which is in else{}.
When changing the entire geometry, I think the easiest way is to remove the old one (scene.remove(geometry), then add the new one (scene.add(geometry)). I think the cost of modifying the mesh and geometry parameters and properties is the same as adding a new one, although adding is much easier and saves a lot of headache!

Optimized keyboard controls for XNA game

The code I am using for controlling the four-directional movement of the player's sprite in my 2D game is exhibiting some unwanted affection. I realize that this affection is because the if conditions that are first met will trump the later else ifs... So the directional affection my code shows now is: left > right > up > down.
What kind of affection I want is: the first direction pressed > the second direction pressed > the third direction pressed > the fourth direction pressed.
I also want it to remember what order the keypresses are in untill they're released.
Example:
I hold left, the sprite moves left.
I push up while still holding left, and the sprite immediately moves up.
I release up while still holding left, and the sprite resumes its movement left.
This memory should encompass all four directional keys so that the controls won't feel buggy if the user has "fat fingers".
This is the code I use for movement so far:
if (CurrentKeyboardState.IsKeyDown(Keys.Left) == true)
{
Speed.X = moveSpeed;
Direction.X = moveLeft;
}
else if (CurrentKeyboardState.IsKeyDown(Keys.Right) == true)
{
Speed.X = moveSpeed;
Direction.X = moveRight;
}
else if (CurrentKeyboardState.IsKeyDown(Keys.Up) == true)
{
Speed.Y = moveSpeed;
Direction.Y = moveUp;
}
else if (CurrentKeyboardState.IsKeyDown(Keys.Down) == true)
{
Speed.Y = moveSpeed;
Direction.Y = moveDown;
}
I am thinking I could use a List and just put the direction pressed (left, right, up, down) as strings into the list if it isn't already in the list, and then always check what the latest item in the list is to decide what directio to move. And of course remove the strings when the corresponding keys are released. Would this be a good way of solving it?
Here is my attempt on this:
if (currentKeyboardState.IsKeyDown(Keys.Left))
{
if (!keyDownList.Contains("left"))
{
keyDownList.Add("left");
System.Diagnostics.Debug.WriteLine("left inserted");
}
}
else if (oldKeyboardState.IsKeyDown(Keys.Left))
{
keyDownList.Remove("left");
System.Diagnostics.Debug.WriteLine("left removed");
}
if (currentKeyboardState.IsKeyDown(Keys.Right))
{
if (!keyDownList.Contains("right"))
{
keyDownList.Add("right");
System.Diagnostics.Debug.WriteLine("right added");
}
}
else if (oldKeyboardState.IsKeyDown(Keys.Right))
{
keyDownList.Remove("right");
System.Diagnostics.Debug.WriteLine("right removed");
}
if (currentKeyboardState.IsKeyDown(Keys.Up))
{
if (!keyDownList.Contains("up"))
{
keyDownList.Add("up");
System.Diagnostics.Debug.WriteLine("up added");
}
}
else if (oldKeyboardState.IsKeyDown(Keys.Up))
{
keyDownList.Remove("up");
System.Diagnostics.Debug.WriteLine("up removed");
}
if (currentKeyboardState.IsKeyDown(Keys.Down))
{
if (!keyDownList.Contains("down"))
{
keyDownList.Add("down");
System.Diagnostics.Debug.WriteLine("down added");
}
}
else if (oldKeyboardState.IsKeyDown(Keys.Down))
{
keyDownList.Remove("down");
System.Diagnostics.Debug.WriteLine("down removed");
}
try
{
if (keyDownList[keyDownList.Count-1].Contains("left"))
{
//move left
speed.X = moveSpeed;
direction.X = moveLeft;
}
else if (keyDownList[keyDownList.Count-1].Contains("right"))
{
//move right
speed.X = moveSpeed;
direction.X = moveRight;
}
else if (keyDownList[keyDownList.Count-1].Contains("up"))
{
//move up
speed.Y = moveSpeed;
direction.Y = moveUp;
}
else if (keyDownList[keyDownList.Count-1].Contains("down"))
{
//move down
speed.Y = moveSpeed;
direction.Y = moveDown;
}
}
catch (Exception e)
{
}
I had some problems with it initially, but it seems to work fine now with the exception of it generating exceptions (A first chance exception of type 'System.ArgumentOutOfRangeException' occurred in mscorlib.dll) while my sprite is standing still. Any tips on how to stop that?
I'm not just looking for a solution that works, but for something durable and efficient that feels rock solid and professional, so discussion on the topic is more than welcome.
Durable, efficient, rock solid, etc. it may not be, but what you're saying with your if/else if block there is that you're only interested in one keystate per frame, when I don't think that's the case.
What happens if you try:
if (CurrentKeyboardState.IsKeyDown(Keys.Down) & !CurrentKeyboardState.IsKeyDown(Keys.Up))
{
Speed.Y = moveSpeed;
Direction.Y = moveDown;
}
if (CurrentKeyboardState.IsKeyDown(Keys.Up) & !CurrentKeyboardState.IsKeyDown(Keys.Down))
{
Speed.Y = moveSpeed;
Direction.Y = moveUp;
}
And repeat similar for left and right. By testing mutual exclusivity between opposing directions, you keep yourself from adding to and subtracting from direction in the same frame. Also, by using separate conditions instead of an if/elseif chain, you allow the possibility to process Left + Up in the same frame.

Rotation in Unity3D

This is a simplified code from what I'm trying to do:
var angle = 1.57;
if ( this.transform.rotation.y > angle ){
this.transform.rotation.y--;
} else if ( this.transform.rotation.y < angle ){
this.transform.rotation.y++;
}
I'm used to code in AS3, and if I do that in flash, it works perfectly, though in Unity3D it doesn't, and I'm having a hard time figuring out why, or how could I get that effect.
Can anybody help me? Thanks!
edit:
my object is a rigidbody car with 2 capsule colliders driving in a "bumpy" floor, and at some point he just loses direction precision, and I think its because of it's heirarchical rotation system.
(thanks to kay for the transform.eulerAngles tip)
transform.rotation retrieves a Quaternion. Try transform.rotation.eulerAngles.y instead.
Transform Rotation is used for setting an angle, not turning an object, so you would need to get the rotation, add your change, and then set the new rotation.
Try using transform.rotate instead.
Check the Unity3d scripting reference here:
http://unity3d.com/support/documentation/ScriptReference/Transform.Rotate.html
I see two problems so far. First the hierarchical rotation of Unity. Based on what you are trying to achieve you should manipulate either
transform.localEulerAngles
or
transform.eulerAngles
The second thing is, you can't modify the euler angles this way, as the Vectors are all passed by value:
transform.localEulerAngles.y--;
You have to do it this way:
Vector3 rotation = transform.localEulerAngles;
rotation.y--;
transform.localEulerAngles = rotation;
You need to create a new Quaternion Object
transform.rotation = Quaternion.Euler ( transform.rotation.x, transform.rotation.y++, transform.rotation.z );
You can also use transform.Rotate function.
The above suggestion to use transform.Rotate( ) is probably what you're going to need to do to actually make it rotate, BUT the variables of transform.Rotate( ) are velocity/speed rather than direction, so transform.Rotate( ) will have to use more than one axis if you want an angled rotation. Ex:
class Unity // Example is in C#
{
void Update( )
{
gameObject.transform.Rotate(0, 1, 0);
}
}
This will rotate the object around its y-axis at a speed of 1.
Let me know if this helps - and if it hinders I can explain it differently.
You should try multiplyng your rotation factor with Time.deltaTime
Hope that helps
Peace
Here is my script for GameObject rotation with touch
//
// RotateController.cs
//
// Created by Ramdhan Choudhary on 12/05/13.
//
using UnityEngine;
using System;
public class RotateController
{
private float RotationSpeed = 9.5f;
private const float mFingerDistanceEpsilon = 1.0f;
public float MinDist = 2.0f;
public float MaxDist = 50.0f;
private Transform mMoveObject = null;
private bool isEnabledMoving = false;
//************** Rotation Controller Constructor **************//
public RotateController (Transform goMove)
{
isEnabledMoving = true;
mMoveObject = goMove;
if (mMoveObject == null) {
Debug.LogWarning ("Error! Cannot find object!");
return;
}
}
//************** Handle Object Rotation **************//
public void Update ()
{
if (!isEnabledMoving && mMoveObject != null) {
return;
}
Vector3 camDir = Camera.main.transform.forward;
Vector3 camLeft = Vector3.Cross (camDir, Vector3.down);
// rotate
if (Input.touchCount == 1) {
mMoveObject.Rotate (camLeft, Input.touches [0].deltaPosition.y * RotationSpeed * Time.deltaTime, Space.World);
mMoveObject.Rotate (Vector3.down, Input.touches [0].deltaPosition.x * RotationSpeed * Time.deltaTime, Space.Self);
}
}
}

Creating a 3D free-camera in WebGL - why do neither of these methods work?

EDIT
OK, I've tried a camera using quaternions:
qyaw = [Math.cos(rot[0]/2), 0, Math.sin(rot[0]/2), 0];
qpitch = [Math.cos(rot[1]/2), 0, 0, Math.sin(rot[1]/2)];
rotQuat = quat4.multiply (qpitch, qyaw);
camRot = quat4.toMat4(rotQuat);
camMat = mat4.multiply(camMat,camRot);
and I get exactly the same problem. So I'm guessing it's not gimbal lock. I've tried changing the order I multiply my matrices, but it just goes camera matrix * model view matrix, then object matrix * model view. That's right isn't it?
I'm trying to build a 3d camera in webGL that can move about the world and be rotated around the x and y (right and up) axes.
I'm getting the familiar problem (possibly gimbal lock?) that once one of the axes is rotated, the rotation around the other is screwed up; for example, when you rotate around the Y axis 90degrees, rotation around the x becomes a spin around z.
I appreciate this is a common problem, and there are copious guides to building a camera that avoid this problem, but as far as I can tell, I've implemented two different solutions and I'm still getting the same problem. Frankly, it's doing my head in...
One solution I'm using is this (adapted from http://www.toymaker.info/Games/html/camera.html):
function updateCam(){
yAx = [0,1,0];
xAx = [1,0,0];
zAx = [0,0,1];
mat4.identity(camMat);
xRotMat = mat4.create();
mat4.identity(xRotMat)
mat4.rotate(xRotMat,rot[0],xAx);
mat4.multiplyVec3(xRotMat,zAx);
mat4.multiplyVec3(xRotMat,yAx);
yRotMat = mat4.create();
mat4.identity(yRotMat)
mat4.rotate(yRotMat,rot[1],yAx);
mat4.multiplyVec3(yRotMat,zAx);
mat4.multiplyVec3(yRotMat,xAx);
zRotMat = mat4.create();
mat4.identity(zRotMat)
mat4.rotate(zRotMat,rot[2],zAx);
mat4.multiplyVec3(zRotMat,yAx);
mat4.multiplyVec3(zRotMat,xAx);
camMat[0] = xAx[0];
camMat[1] = yAx[0];
camMat[2] = zAx[0];
//camMat[3] =
camMat[4] = xAx[1]
camMat[5] = yAx[1];
camMat[6] = zAx[1];
//camMat[7] =
camMat[8] = xAx[2]
camMat[9] = yAx[2];
camMat[10]= zAx[2];
//camMat[11]=
camMat[12]= -1* vec3.dot(camPos, xAx);
camMat[13]= -1* vec3.dot(camPos, yAx);
camMat[14]= -1* vec3.dot(camPos, zAx);
//camMat[15]=
var movSpeed = 1.5 * forward;
var movVec= vec3.create(zAx);
vec3.scale(movVec, movSpeed);
vec3.add(camPos, movVec);
movVec= vec3.create(xAx);
movSpeed = 1.5 * strafe;
vec3.scale(movVec, movSpeed);
vec3.add(camPos, movVec);
}
I also tried using this method using
mat4.rotate(camMat, rot[1], yAx);
instead of explicitly building the camera matrix - same result.
My second (actually first...) method looks like this (rot is an array containing the current rotations around x, y and z (z is always zero):
function updateCam(){
mat4.identity(camRot);
mat4.identity(camMat);
camRot = fullRotate(rot);
mat4.set(camRot,camMat);
mat4.translate(camMat, camPos);
}
function fullRotate(angles){
var cosX = Math.cos(angles[0]);
var sinX = Math.sin(angles[0]);
var cosY = Math.cos(angles[1]);
var sinY = Math.sin(angles[1]);
var cosZ = Math.cos(angles[2]);
var sinZ = Math.sin(angles[2]);
rotMatrix = mat4.create([cosZ*cosY, -1*sinZ*cosX + cosZ*sinY*sinX, sinZ*sinX+cosZ*sinY*cosX, 0,
sinZ*cosY, cosZ*cosX + sinZ*sinY*sinX, -1*cosZ*sinX + sinZ*sinY*cosX, 0,
-1*sinY, cosY*sinX, cosY*cosX, 0,
0,0,0,1 ] );
mat4.transpose(rotMatrix);
return (rotMatrix);
}
The code (I've taken out most of the boilerplate gl lighting stuff etc and just left the transformations) to actually draw the scene is:
function drawScene() {
gl.viewport(0, 0, gl.viewportWidth, gl.viewportHeight);
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
mat4.perspective(45, gl.viewportWidth / gl.viewportHeight, 0.1, 2000.0, pMatrix);
mat4.identity(mvMatrix);
for(var i=0; i<planets.length; i++){
if (planets[i].type =="sun"){
currentProgram = perVertexSunProgram;
} else {
currentProgram = perVertexNormalProgram;
}
alpha = planets[i].alphaFlag;
mat4.identity(planets[i].rotMat);
mvPushMatrix();
//all the following puts planets in orbit around a central sun, but it's not really relevant to my current problem
var rot = [0,rotCount*planets[i].orbitSpeed,0];
var planetMat;
planetMat = mat4.create(fullRotate(rot));
mat4.multiply(planets[i].rotMat, planetMat);
mat4.translate(planets[i].rotMat, planets[i].position);
if (planets[i].type == "moon"){
var rot = [0,rotCount*planets[i].moonOrbitSpeed,0];
moonMat = mat4.create(fullRotate(rot));
mat4.multiply(planets[i].rotMat, moonMat);
mat4.translate(planets[i].rotMat, planets[i].moonPosition);
mat4.multiply(planets[i].rotMat, mat4.inverse(moonMat));
}
mat4.multiply(planets[i].rotMat, mat4.inverse(planetMat));
mat4.rotate(planets[i].rotMat, rotCount*planets[i].spinSpd, [0, 1, 0]);
//this bit does the work - multiplying the model view by the camera matrix, then by the matrix of the object we want to render
mat4.multiply(mvMatrix, camMat);
mat4.multiply(mvMatrix, planets[i].rotMat);
gl.useProgram(currentProgram);
setMatrixUniforms();
gl.drawElements(gl.TRIANGLES, planets[i].VertexIndexBuffer.numItems, gl.UNSIGNED_SHORT, 0);
mvPopMatrix();
}
}
However, most of the transformations can be ignored, the same effect cab be seen simply displaying a sphere at world coords 0,0,0.
I thought my two methods - either rotating the axes one at a time as you go, or building up the rotation matrix in one go avoided the problem of doing two rotations one after the other. Any ideas where I'm going wrong?
PS - I'm still very much starting to learn WebGL and 3d maths, so be gentle and talk to me like someone who hadn't heard of a matrix til a couple of months ago... Also, I know quaternions are a good solution to 3d rotation, and that would be my next attempt, however, I think I need to understand why these two methods don't work first...
For the sake of clarification, think about gimbal lock this way: You've played Quake/Unreal/Call of Duty/Any First Person Shooter, right? You know how when you are looking forward and move the mouse side to side your view swings around in a nice wide arc, but if you look straight up or down and move your mouse side to side you basically just spin tightly around a single point? That's gimbal lock. It's something that pretty much any FPS game uses because it happens to mimic what we would do in real life, and thus most people don't usually think of it as a problem.
For something like a space flight sim, however, or (more commonly) skeletal animation that type of effect is undesirable, and so we use things like quaternions to help us get around it. Wether or not you care about gimbal lock for your camera depends on the effect that you are looking to achieve.
I don't think you're experiencing that, however. What it sounds like is that your order of matrix multiplication is messed up, and as a result your view is rotating in a way that you don't expect. I would try playing with the order that you do your X/Y/Z rotations in and see if you can find an order than gives you the desired results.
Now, I hate doing code dumps, but this may be useful to you so here we go: This is the code that I use in most of my newer WebGL projects to manage a free-floating camera. It is gimbal locked, but as I mentioned earlier it doesn't really matter in this case. Basically it just gives you FPS style controls that you can use to fly around your scene.
/**
* A Flying Camera allows free motion around the scene using FPS style controls (WASD + mouselook)
* This type of camera is good for displaying large scenes
*/
var FlyingCamera = Object.create(Object, {
_angles: {
value: null
},
angles: {
get: function() {
return this._angles;
},
set: function(value) {
this._angles = value;
this._dirty = true;
}
},
_position: {
value: null
},
position: {
get: function() {
return this._position;
},
set: function(value) {
this._position = value;
this._dirty = true;
}
},
speed: {
value: 100
},
_dirty: {
value: true
},
_cameraMat: {
value: null
},
_pressedKeys: {
value: null
},
_viewMat: {
value: null
},
viewMat: {
get: function() {
if(this._dirty) {
var mv = this._viewMat;
mat4.identity(mv);
mat4.rotateX(mv, this.angles[0]-Math.PI/2.0);
mat4.rotateZ(mv, this.angles[1]);
mat4.rotateY(mv, this.angles[2]);
mat4.translate(mv, [-this.position[0], -this.position[1], - this.position[2]]);
this._dirty = false;
}
return this._viewMat;
}
},
init: {
value: function(canvas) {
this.angles = vec3.create();
this.position = vec3.create();
this.pressedKeys = new Array(128);
// Initialize the matricies
this.projectionMat = mat4.create();
this._viewMat = mat4.create();
this._cameraMat = mat4.create();
// Set up the appropriate event hooks
var moving = false;
var lastX, lastY;
var self = this;
window.addEventListener("keydown", function(event) {
self.pressedKeys[event.keyCode] = true;
}, false);
window.addEventListener("keyup", function(event) {
self.pressedKeys[event.keyCode] = false;
}, false);
canvas.addEventListener('mousedown', function(event) {
if(event.which == 1) {
moving = true;
}
lastX = event.pageX;
lastY = event.pageY;
}, false);
canvas.addEventListener('mousemove', function(event) {
if (moving) {
var xDelta = event.pageX - lastX;
var yDelta = event.pageY - lastY;
lastX = event.pageX;
lastY = event.pageY;
self.angles[1] += xDelta*0.025;
while (self.angles[1] < 0)
self.angles[1] += Math.PI*2;
while (self.angles[1] >= Math.PI*2)
self.angles[1] -= Math.PI*2;
self.angles[0] += yDelta*0.025;
while (self.angles[0] < -Math.PI*0.5)
self.angles[0] = -Math.PI*0.5;
while (self.angles[0] > Math.PI*0.5)
self.angles[0] = Math.PI*0.5;
self._dirty = true;
}
}, false);
canvas.addEventListener('mouseup', function(event) {
moving = false;
}, false);
return this;
}
},
update: {
value: function(frameTime) {
var dir = [0, 0, 0];
var speed = (this.speed / 1000) * frameTime;
// This is our first person movement code. It's not really pretty, but it works
if(this.pressedKeys['W'.charCodeAt(0)]) {
dir[1] += speed;
}
if(this.pressedKeys['S'.charCodeAt(0)]) {
dir[1] -= speed;
}
if(this.pressedKeys['A'.charCodeAt(0)]) {
dir[0] -= speed;
}
if(this.pressedKeys['D'.charCodeAt(0)]) {
dir[0] += speed;
}
if(this.pressedKeys[32]) { // Space, moves up
dir[2] += speed;
}
if(this.pressedKeys[17]) { // Ctrl, moves down
dir[2] -= speed;
}
if(dir[0] != 0 || dir[1] != 0 || dir[2] != 0) {
var cam = this._cameraMat;
mat4.identity(cam);
mat4.rotateX(cam, this.angles[0]);
mat4.rotateZ(cam, this.angles[1]);
mat4.inverse(cam);
mat4.multiplyVec3(cam, dir);
// Move the camera in the direction we are facing
vec3.add(this.position, dir);
this._dirty = true;
}
}
}
});
This camera assumes that Z is your "Up" axis, which may or may not be true for you. It's also using ECMAScript 5 style objects, but that shouldn't be an issue for any WebGL-enabled browser, and it utilizes my glMatrix library but it looks like you're already using that anyway. Basic usage is pretty simple:
// During your init code
var camera = Object.create(FlyingCamera).init(canvasElement);
// During your draw loop
camera.update(16); // 16ms per-frame == 60 FPS
// Bind a shader, etc, etc...
gl.uniformMatrix4fv(shaderUniformModelViewMat, false, camera.viewMat);
Everything else is handled internally for you, including keyboard and mouse controls. May not fit your needs exactly, but hopefully you can glean what you need to from there. (Note: This is essentially the same as the camera used in my Quake 3 demo, so that should give you an idea of how it works.)
Okay, that's enough babbling from me for one post! Good luck!
It doesn't matter how you build your matrices, using euler angle rotations (like both of your code snippets do) will always result in a transformation that shows the gimble lock problem.
You may want to have a look at https://en.wikipedia.org/wiki/Quaternions_and_spatial_rotation as a starting point for creating transformations that avoid gimble locks.
Try my new project (webGL2 part of visual-js game engine) based on glmatrix 2.0 .
Activate events for camera use : App.camera.FirstPersonController = true;
live examples
For camera important functions :
Camera interaction
App.operation.CameraPerspective = function() {
this.GL.gl.viewport(0, 0, wd, ht);
this.GL.gl.clear(this.GL.gl.COLOR_BUFFER_BIT | this.GL.gl.DEPTH_BUFFER_BIT);
// mat4.identity( world.mvMatrix )
// mat4.translate(world.mvMatrix , world.mvMatrix, [ 10 , 10 , 10] );
/* Field of view, Width height ratio, min distance of viewpoint, max distance of viewpoint, */
mat4.perspective(this.pMatrix, degToRad( App.camera.viewAngle ), (this.GL.gl.viewportWidth / this.GL.gl.viewportHeight), App.camera.nearViewpoint , App.camera.farViewpoint );
};
manifest.js :
var App = {
name : "webgl2 experimental",
version : 0.3,
events : true,
logs : false ,
draw_interval : 10 ,
antialias : false ,
camera : { viewAngle : 45 ,
nearViewpoint : 0.1 ,
farViewpoint : 1000 ,
edgeMarginValue : 100 ,
FirstPersonController : false },
textures : [] , //readOnly in manifest
tools : {}, //readOnly in manifest
download source from :
webGL 2 part of visual-js GE project
Old :
opengles 1.1
https://stackoverflow.com/a/17261523/1513187
Very fast first person controler with glmatrix 0.9 based on http://learningwebgl.com/ examples.

Resources