www.xbdev.net
xbdev - software development
Thursday February 19, 2026
Home | Contact | Support | WebGPU Graphics and Compute ... | WebGPU.. Games, Tutorials, Demos, Projects, and Code.....
     
 

WebGPU..

Games, Tutorials, Demos, Projects, and Code.....

 

Camera Strafe


Moving tangentally to the cameras forward direction (while allowing up/right camera looking).


Rotate and strafe the caera.
Rotate and strafe the caera.


Functions Used: setVertexBuffer(), setIndexBuffer(), drawIndexed(), createBuffer(), getMappedRange(), getContext(), requestAdapter(), getPreferredCanvasFormat(), createCommandEncoder(), beginRenderPass(), setPipeline(), draw(), end(), submit(), getCurrentTexture(), createView(), createShaderModule()


Cursor keys and WSAD strafe the camera - while clicking and draging the mouse cursor over the window rotates the camera view.

We add a couple of small helper functions to the top of the camera file - of course, these can be swapped out for the vector/matrix libraries in the gl-matrix. However, it prevents any external dependencies and doesn't hide away any of the functionality/workings.


// Helper functions
function Crossv1v2 )
{
    
let normal = {};    

    
// Calculate the cross product with the non communitive equation
    
normal.= ((v1.v2.z) - (v1.v2.y));
    
normal.= ((v1.v2.x) - (v1.v2.z));
    
normal.= ((v1.v2.y) - (v1.v2.x));

    
// Return the cross product
    
return normal;                                         
}

function 
Normalize)
{
    
// Get the magnitude of our normal
    
let magnitude Math.sqrtv.x*v.v.y*v.v.z*v.) ;                

    
// Now that we have the magnitude, we can divide our vector by that magnitude.
    // That will make our vector a total length of 1.  
    
v.v.magnitude;
    
v.v.magnitude;    
    
v.v.magnitude;
    
    
// Finally, return our normalized vector
    
return v;                                        
}

function 
Subtractv1v2 )
{
  return { 
x:v1.x-v2.x,
           
y:v1.y-v2.y,
           
z:v1.z-v2.};
}

// A 'static' property in JavaScript is best represented by a property directly on the constructor function itself

function camera() {}

camera.zero     = {x:0y:0z:0};
camera.up       = {x:0y:1z:0};
  
camera.position camera.zero;
camera.view     = {x:0y:0z:-1};
  

  
// This function sets the camera's position and view and up vectors
camera.PositionCamera = function ( positionXpositionYpositionZ// target
                                     
viewX,     viewY,     viewZ,     // position of the camera
                                   
upX,       upY,       upZ)
  {
    
camera.position = {x:positionXy:positionYz:positionZ};
    
camera.view        = {x:viewX,     y:viewY,     z:viewZ};
    
camera.up       = {x:upX,       y:upY,       z:upZ};
  }

  
// This rotates the view around the position using an axis-angle rotation
camera.RotateView = function(angle,  x,  y,  z)
  {
    
// Get the view vector (The direction we are facing)
    
let tmpview = {x:camera.view.x-camera.position.x,
                   
y:camera.view.y-camera.position.y,
                   
z:camera.view.z-camera.position.z};        

    
// Calculate the sine and cosine of the angle once
    
let cosTheta Math.cos(angle);
    
let sinTheta Math.sin(angle);

    
// Find the new x position for the new rotated point
    
camera.view.x  = (cosTheta + (cosTheta) * x)        * tmpview.x;
    
camera.view.+= ((cosTheta) * sinTheta)    * tmpview.y;
    
camera.view.+= ((cosTheta) * sinTheta)    * tmpview.z;

    
// Find the new y position for the new rotated point
    
camera.view.y  = ((cosTheta) * sinTheta)    * tmpview.x;
    
camera.view.+= (cosTheta + (cosTheta) * y)        * tmpview.y;
    
camera.view.+= ((cosTheta) * sinTheta)    * tmpview.z;

    
// Find the new z position for the new rotated point
    
camera.view.z  = ((cosTheta) * sinTheta)    * tmpview.x;
    
camera.view.+= ((cosTheta) * sinTheta)    * tmpview.y;
    
camera.view.+= (cosTheta + (cosTheta) * z)        * tmpview.z;

    
// Add the newly rotated vector to our position to set our new rotated view of our camera.
    
camera.view = {x:camera.view.x+camera.position.x,
                   
y:camera.view.y+camera.position.y,
                   
z:camera.view.z+camera.position.z};
  }


  
// This rotates the position around a given point
camera.RotateAroundPoint = function(centeranglexyz)
  {
    
// To rotate our position around a point, what we need to do is find
    // a vector from our position to the center point we will be rotating around.
    // Once we get this vector, then we rotate it along the specified axis with
    // the specified degree.  Finally the new vector is added center point that we
    // rotated around (center) to become our new position.  

    // Get vector from our position to the center we are rotating around
    
let tmppos = {x:camera.position.x-center.x,
                  
y:camera.position.y-center.y,
                  
z:camera.position.z-center.z}; 

    
// Calculate the sine and cosine of the angle once
    
let cosTheta Math.cos(angle);
    
let sinTheta Math.sin(angle);

    
// Find the new x position for the new rotated point
    
camera.position.x  = (cosTheta + (cosTheta) * x)        * tmppos.x;
    
camera.position.+= ((cosTheta) * sinTheta)    * tmppos.y;
    
camera.position.+= ((cosTheta) * sinTheta)    * tmppos.z;

    
// Find the new y position for the new rotated point
    
camera.position.y  = ((cosTheta) * sinTheta)    * tmppos.x;
    
camera.position.+= (cosTheta + (cosTheta) * y)        * tmppos.y;
    
camera.position.+= ((cosTheta) * sinTheta)    * tmppos.z;

    
// Find the new z position for the new rotated point
    
camera.position.z  = ((cosTheta) * sinTheta)    * tmppos.x;
    
camera.position.+= ((cosTheta) * sinTheta)    * tmppos.y;
    
camera.position.+= (cosTheta + (cosTheta) * z)        * tmppos.z;

    
// Now we just add the newly rotated vector to our position to set
    // our new rotated position of our camera.
    
camera.position = {x:camera.position.x+center.x,
                       
y:camera.position.y+center.y,
                       
z:camera.position.z+center.z};
  }

  
// This will move the camera forward or backward depending on the speed
camera.MoveCamera = function(speed)
  {
    
// Get our view vector (The direciton we are facing)
    
let dir = {x:camera.view.x-camera.position.x,
               
y:camera.view.y-camera.position.y,
               
z:camera.view.z-camera.position.z};
  
    
dir Normalizedir );
    
    
camera.position.+= dir.speed;        // Add our acceleration to our position's X
    
camera.position.+= dir.speed;        // Add our acceleration to our position's Z
    
camera.view.+= dir.speed;            // Add our acceleration to our view's X
    
camera.view.+= dir.speed;            // Add our acceleration to our view's Z
  
}

  
// This strafes the camera left and right depending on the speed (-/+)
camera.StrafeCamera = function(speed)
{
    
// Strafing is quite simple if you understand what the cross product is.
    // If you have 2 vectors (say the up and the view) you can
    // use the cross product formula to get a vector that is 90 degrees from the 2 vectors.

    
let dir = { x:camera.view.camera.position.x,
                
y:camera.view.camera.position.y,
                
z:camera.view.camera.position.};
  
    
// Initialize a variable for the cross product result
    
let vcross Crossdircamera.up );

    
// Normalize the strafe vector
    
camera.strafe Normalizevcross );

    
// Add the strafe vector to our position
    
camera.position.+= camera.strafe.speed;
    
camera.position.+= camera.strafe.speed;

    
// Add the strafe vector to our view
    
camera.view.+= camera.strafe.speed;
    
camera.view.+= camera.strafe.speed;
}

// store the mouse/view information prior to mouse drag/look around
camera.StartViewByMouse = function( mxmy )
{
   
camera.startMousePos = {x:mxy:my };
   
camera.startView     camera.view;
}

camera.MoveViewByMouse = function( mxmy )
{
    
camera.view = {...camera.startView};
  
    
let angleY = (mx camera.startMousePos.x) / 500.0;
    
let angleZ = (my camera.startMousePos.y) / 500.0;

    
let axis CrossSubtract(camera.viewcamera.position), camera.up);
    
axis Normalize(axis);
                
    
// rotate the camera by the remaining angle (1.0f - lastRotX)
    
camera.RotateViewangleZaxis.xaxis.yaxis.z);
  
    
// Always rotate the camera around the y-axis
    
camera.RotateView(angleY010);
}


camera.GetViewMatrix = function()
  {
    
// Give webgpu our camera position, then camera view, then camera up vector
      
let viewMatrix mat4.create();
  
    
mat4.lookAt(viewMatrix
               
Object.values(camera.position), 
               
Object.values(camera.view),  
               
Object.values(camera.up));
  
      return 
viewMatrix;
  }



window.camera camera;




Resources and Links


• WebGPU Lab Example [LINK]
































WebGPU by Example: Fractals, Image Effects, Ray-Tracing, Procedural Geometry, 2D/3D, Particles, Simulations WebGPU Compute graphics and animations using the webgpu api 12 week course kenwright learn webgpu api kenwright programming compute and graphics applications with html5 and webgpu api kenwright real-time 3d graphics with webgpu kenwright webgpu api develompent a quick start guide kenwright webgpu by example 2022 kenwright webgpu gems kenwright webgpu interactive compute and graphics visualization cookbook kenwright wgsl webgpu shading language cookbook kenwright wgsl webgpugems shading language cookbook kenwright



 
Advert (Support Website)

 
 Visitor:
Copyright (c) 2002-2025 xbdev.net - All rights reserved.
Designated articles, tutorials and software are the property of their respective owners.