How can I implement a FPS view with WebGL inside a browser?

5.9k views Asked by At

I'm using Copperlicht, and I want to create a usable FPS. The demo controls shows why the browser environment makes this a pain.

In order to implement FPS camera control, you need to track the relative mouse position - in other words, its motion, not its absolute screen coordinates. The mouse can leave the browser at any time (rightfully so) and can't be tracked, unless the user initiates a drag event inside the page. Click events change focus and prevent the application from using mouse data as input.

The mouse position can be tracked during drag, but this requires the user to hold down their left mouse button. This isn't good since left clicking is usually used for other things. Holding the button down is also tiring and cumbersome.

The only thing I can think of is automating the middle mouse button. A middle mouse button press keeps focus in the browser, and keeps left/right click events outside the browser window in the browser's focus. Is it possible to cause middle mouse button to stay pressed using JavaScript?

If not, is there a "pure" solution to this ? I'd rather not go to flash or Java or a plugin as an answer.

8

There are 8 answers

0
Nikola Lukic On

Right here right now :

I make one with push/pop matrix with glmatrix 0.9 also version 2.0 webgl & glmatrix . Secret - Must translate to zero , rotate and then translate to map position. You have all parameters for first person controler.

See:opengles 1.1. / webgl 1.0 / glmatrix 0.9 or see this example with full colizion.

WebGl 2 / glmatrix 2 Example's (also First Person controller):

Download from bitBucket

Live example

Out of context :

////////////////////////////////////////////////////////
// Somewhere in draw function  ....
////////////////////////////////////////////////////////

mat4.identity(object.mvMatrix);
this.mvPushMatrix(object.mvMatrix,this.mvMatrixStack);

    ////////////////////////////////////////////////////////
    if (App.camera.FirstPersonController==true){camera.setCamera(object)}

    ////////////////////////////////////////////////////////
    mat4.translate(object.mvMatrix, object.mvMatrix, object.position.worldLocation );
    mat4.rotate(object.mvMatrix, object.mvMatrix, degToRad(object.rotValue), object.rotDirection.RotationVector );

.... End of Draw function

Content of SetCamera :

var camera = new Object();

/* Set defaults                                  */
camera.pitch     = 0;
camera.pitchRate = 0;
camera.yaw       = 0;
camera.yawRate   = 0;
camera.xPos      = 0;
camera.yPos      = 0;
camera.zPos      = 0;
camera.speed     = 0;
camera.yawAmp    = 0.05;
camera.pitchAmp    = 0.007;

keyboardPress = defineKeyBoardObject();

camera.setCamera = function(object) {
    /* Left Key  or A                            */
    if (keyboardPress.getKeyStatus(37) || keyboardPress.getKeyStatus(65) ||  App.camera.leftEdge == true) {

        camera.yawRate = 20;
        if (App.camera.leftEdge == true) camera.yawRate = 10;
    }
    /* Right Key or D                            */
    else if (keyboardPress.getKeyStatus(39) || keyboardPress.getKeyStatus(68) ||  App.camera.rightEdge == true) {

        camera.yawRate = -20;
        if (App.camera.rightEdge == true) camera.yawRate = -10;
    }
    else {
       // camera.yawRate = 0;
    }



    /* Up Key    or W                            */
    if (keyboardPress.getKeyStatus(38) || keyboardPress.getKeyStatus(87)) {
        camera.speed = 0.03;
    }
    /* Down Key  or S                            */
    else if (keyboardPress.getKeyStatus(40) || keyboardPress.getKeyStatus(83)) {
        camera.speed = -0.03;
    }
    else {
        camera.speed = 0;
    }
    /* Page Up
    if (keyboardPress.getKeyStatus(33)) {
        camera.pitchRate = 100;
    }
    /* Page Down
    else if (keyboardPress.getKeyStatus(34)) {
        camera.pitchRate = -100;
    }
    else {
        camera.pitchRate = 0;
    }
    */
    /* Calculate yaw, pitch and roll(x,y,z) */
    if (camera.speed != 0) {

        camera.xPos -= Math.sin(degToRad(camera.yaw)) * camera.speed;
        camera.yPos = 0;
        camera.zPos -= Math.cos(degToRad(camera.yaw)) * camera.speed;

    }
    camera.yaw   += camera.yawRate   * camera.yawAmp   ;
    camera.pitch += camera.pitchRate * camera.pitchAmp ;

    mat4.rotate(object.mvMatrix, object.mvMatrix, degToRad(-camera.pitch), [1, 0, 0]);
    mat4.rotate(object.mvMatrix, object.mvMatrix, degToRad(-camera.yaw), [0, 1, 0]);

   // mat4.translate(object.mvMatrix, object.mvMatrix, [camera.yaw, -camera.pitch, 0]);
     mat4.translate(object.mvMatrix, object.mvMatrix, [-camera.xPos , -camera.yPos  , -camera.zPos ]);

    camera.yawRate   = 0;
    camera.pitchRate = 0;
};

This code allows you to draw 3D objects and folders easily and quickly.Under the principle of one object one line. webgl 3d wourld engine framework zlatnaspirala First person web site look. Used lib : High performance matrix and vector operations for WebGL

5
Chiguireitor On

(this is the only solution i've seen so far could work for my game project, doing an FPS too)

Implement a Plugin for each browser you intend to support. AFAIK, this is the way they solved the problem with "Quake Live".

Chrome / Chromium -> PPAPI

Firefox & Opera -> NPAPI

IE -> ActiveX

Safari -> Safari plugin development

Btw, the link Daniel Baulig gave you has a nice pointer and solves this problem (on the long run).

1
Daniel Baulig On

This thread is a nice reading on this topic. It seems like prototypes for this functionality are at least suggested for Firefox and Chrome.

3
Alexander On

How about making the window fullscreen and then pausing the game if the cursor moves out of the window? I know this doesn't really solve the problem, but it's the best I can think of, without using a plugin of some sort.

0
Omiod On

We need the window to be able to capture the mouse, as it is seen with some browser plugins, maybe in Java. Flash doesn't have this ability, AFAIK.

As a sidenote, when captured to "get the mouse back" you have to press ESC, and this can be annoying when the app doesn't inform the user properly.

1
Johnny DropTables On

I found this example code at http://bitdaddys.com/javascript/example3run.html

 <html>
<head>
<title>JavaScript Example of Mouse Position Tracking</title>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
</head>

<body>
<form name=thisform>
<table border=0>
<tr><td colspan=2>Position Of Cursor</td></tr>
<tr><td>X <input type=text name=x value=""></td>
    <td>Y <input type=text name=y value=""></td>

</tr>
</table>
</form>

<script type=text/javascript>
    var isIE = document.all?true:false;
    if (!isIE) document.captureEvents(Event.MOUSEMOVE);
    document.onmousemove = getMousePosition;
    function getMousePosition(mp) {
      var _x;
      var _y;
      if (!isIE) {
        _x = mp.pageX;
        _y = mp.pageY;
      }
      if (isIE) {
        _x = event.clientX + document.body.scrollLeft;
        _y = event.clientY + document.body.scrollTop;
      }
      document.thisform.x.value=_x;
      document.thisform.y.value=_y;
      return true;
    }
</script>


</body>
</html>
2
Dan Beam On

It's kind of cheating, but going to about:flags in Chrome and enabling "FPS counter" works for me, :) (but it's not doing it for all browsers nor inside your WebGL app).

0
Toji On

At this point in time (Oct 2011) the only way to get real First Person Shooter-style controls is via a browser plugin. Depending on your needs you might also be able to get away with a simple click-and-drag scheme like I'm currently using in my Quake 3 demo, but if you are building an actual game and not a pretty tech demo this is probably not sufficient.

(Note: That's actually what Google did for their GWT port of Quake 2. You have to use the CTRL key to fire, since clicking is used to move your view.)

In the near future, however, we should be receiving a "MouseLock" API that is basically custom-built for this purpose. You can read up on it's progress at Seth Ladd's Blog. Once that comes out we'll have a lot more options for game controls available to us. (Would also help with things like RTS games)