This engine is all open source, feel free to take it, change it and use it as you wish. if you want, contact me, I'm a beginner in the world of rendering, so all suggestions are welcome. if this library was useful, please, consider making a donation. Thanks and good use.
this engine is intended to be more like a library, very lightweight, without the use of any additional external libraries. Also, the engine's purpose is to be beginner friendly, something like microsoft make code arcade (see here). This repository is intended to be either a documentation and a sort of book of journeys (check here), for the once who wants to learn how to program an engine, from how webgl and webgpu works to the game algorithms.
-tree
-interface
-clearColor
-culling
-append
-setAttributes
-remove
-draw
-drawXYGrid
-drawXZGrid
-drawYZGrid
-removeGrids
-globalCamera
-DrawOpt
-DrawableImageOptions
-SkeletalAnimationOptions
-BonesOpt
-Point3D
-Point2D
graph TD;
WEBGL-->RENDERER
WEBGPU-->RENDERER
indexDB_SAVING_SYSTEM --> GAME
MOBILE_SUPPORT --> GAME
RENDERER --> GAME
PHYSICS_ENGINE --> GAME
OBSERVABLE --> GAME
EVENT_SYSTEM --> GAME
GAME --> SAVINGS
GAME --> MOBILE_API
GAME --> ENTITIES
GAME --> EVENT_HANDLER
ENTITIES --> PARTICLES_SYSTEM
ENTITIES --> SPRITE_3D
ENTITIES --> TILES
TILES --> TILE_MAP
SPRITE_3D --> SPRITE_2D
EVENT_SYSTEM --> OBSERVABLE
game library
├─ .DS_Store
├─ .vscode
│ └─ settings.json
├─ controller
│ ├─ canvasDelegate.ts
│ ├─ debug.ts
│ ├─ gameController.ts
│ ├─ loadData.ts
│ └─ loopController.ts
├─ entities
├─ icon.webp
├─ index.d.ts
├─ index.html
├─ main.ts
├─ material for getting started.md
├─ pipeline.jpg
├─ prova.png
├─ readme.md
├─ rendering
│ ├─ .DS_Store
│ ├─ GLRenderer.ts
│ ├─ GPURenderer.ts
│ ├─ codeDelegates
│ │ ├─ GLcode.ts
│ │ └─ GPUcode.ts
│ ├─ matrix
│ │ ├─ camera.ts
│ │ ├─ matrices.ts
│ │ └─ viewMatrix.ts
│ ├─ programSetterDelegate.ts
│ ├─ rendererModel.ts
│ ├─ shaders
│ │ ├─ GLShaders.ts
│ │ ├─ GPUShader.ts
│ │ └─ shaderModel.ts
│ ├─ shapes.ts
│ ├─ tree.ts
│ └─ types.ts
├─ src
│ ├─ controller
│ │ ├─ canvasDelegate.js
│ │ ├─ debug.js
│ │ ├─ gameController.js
│ │ ├─ loadData.js
│ │ └─ loopController.js
│ ├─ entities
│ │ └─ entity.js
│ ├─ main.js
│ └─ rendering
│ ├─ GLRenderer.js
│ ├─ GPUrenderer.js
│ ├─ codeDelegates
│ │ ├─ GLcode.js
│ │ └─ GPUcode.js
│ ├─ generics.js
│ ├─ matrix
│ │ ├─ camera.js
│ │ ├─ matrices.js
│ │ └─ viewMatrix.js
│ ├─ programSetterDelegate.js
│ ├─ rendererModel.js
│ ├─ shaders
│ │ ├─ GLShaders.js
│ │ ├─ GPUShader.js
│ │ └─ shaderModel.js
│ ├─ shapes.js
│ ├─ tree.js
│ └─ types.js
├─ tsconfig.json
└─ vertex.txt
import { Load } from './controller/loadData.js';
import { GameController } from './controller/gameController.js';
const game = await GameController.get();
const img = await Load.image( 'pipeline.jpg' );
const image = game.$renderer.create({
indices: [
0,1,2,
0,2,3,
],
vertices: [
-1, 1, 0,
-1, -1, 0,
1, -1, 0,
1, 1, 0,
],
imageData: {
image: img,
textureCoords: [
1, 1,
0, 1,
0, 0,
1, 0,
]
},,
perspective: true
})
game.$renderer.append( 'img', image ).setAttributes('img', {
translation: {x: 0, y: 0, z: -5},
scale: 0.5
})
const f = ()=>{
game.$renderer.draw();
requestAnimationFrame(f)
}
f();
get(): Promise<GameController>
this method returns the instance of the class (singleton). it creates (and append to the dom) the canvas in which all will be rendered
public readonly renderer: Renderer
is used to create and draw objects ( see the example or renderer methods). can be an instance of WebGLRenderer or WebGPURenderer (if available)
public readonly debug: Debug
instance of class Debug. it contains utility methods for debugging.
import { Shapes } from './rendering/shapes.js';
import { Renderer } from './rendering/GPURenderer.js'; // './rendering/GLRenderer.js';
const color = [...] //your colors data
const renderer = new Renderer( myCanvas );
await renderer.init(); // initialize the renderer
const myCube = renderer.create({
...Shapes.cube( 0.1 ),
color,
perspective: true // use Perspective in your object
});
renderer.append( 'cube', myCube );
const f = ()=>{
// if you want to make dynamic your object use renderer.setAttributes('myCube', { opt... })
renderer.draw();
requestAnimationFrame(f);
}
f();
interface Renderer {
clearColor: Color;
culling: boolean;
init(): Promise<Renderer>;
create( opt: DrawableElementAttributes ): RenderFunction;
append( name: string, func: RenderFunction ): Renderer;
remove( name: string ): RenderFunction | undefined;
setAttributes( name: string, attributes: DrawOpt ): Renderer;
draw(): void;
}
public clearColor: Color;
color used to clear the screen
public culling: boolean;
set culling if enabled
create( DrawableElementAttributes ): RenderFunction
accept DrawableElementAttributes as parameter and create new instance of RenderFunction, that represents the way in which the render will draw your object on the canvas.
append( string, RenderFunction ): Renderer;
accept string and RenderFunction as parameter. Start rendering what RenderFunction represents. the string is an identifier for that specific object.
setAttributes( string, DrawOpt ): Renderer;
accept string and DrawOpt as parameter. Changes the values of the object (specified by the string accepted as first argument) attributes on rendering. if not necessary, don't call this function.
remove( string ): RenderFunction | undefined;
remove the object named with the string passed as first argument. return the RenderFunction deleted.
draw(): void;
draw all the objects actually attached to the renderer
constructor( GameController ): Debug
drawXYGrid( Color ): void
draw a grid of the color specified (default to red) parallel to the z axis
drawXZGrid( Color ): void
draw a grid of the color specified (default to red) parallel to the y axis
drawYZGrid( Color ): void
draw a grid of the color specified (default to red) parallel to the x axis
removeGrids(): void
remove all the grids currently on the screen
globalCamera(): void
add commands to move a debug camera
type DrawOpt = Partial<{
angle: number;
/**
* 'x' 'y' or 'z'
* @use Axis in generics.ts as enum to represent the different axis
*/
axis: Axis;
/**
* whether or not to convert angle to radiants
*/
toRad: boolean;
/**
* the rotation matrix 3d, so a 4x4 matrix ( you can use Matrix.rotate to get once)
* @see Matrix in matrix.ts
*/
rotationMatrix: number[];
/**
* the translation matrix 3d, so a 4x4 matrix ( you can use Matrix.translate to get once)
* @see Matrix in matrix.ts
*/
translationMatrix: number[];
/**
* 3d vector that translate (moves) the element in the space
*/
translation: Point3D;
/**
* projection matrix
* @TODO add someway of projection matrix generation in Matrix
*/
projectionMatrix: number[];
/**
* the scale to use for reduce/enlarge objects
*/
scale: number | Point3D;
/**
* the scale matrix 3d, so a 4x4 matrix ( you can use Matrix.scale to get once)
* @see Matrix in matrix.ts
*/
scaleMatrix: number[];
camera: Camera;
transformationMatrix: number[];
/**
* vectors that indicate where the actual frame and costume of image atlas (sprite sheet) you want to draw
*/
animationVector: [number, number];
bumpScale: number;
bones: Partial<BonesOpt>
}>;
type DrawableElementOptions = {
color: number[];
indices: number[];
staticColor: Color;
static: boolean;
perspective: boolean;
imageData: DrawableImageOptions;
primitive: Primitives;
bonesData: SkeletalAnimationOptions;
}
type DrawableImageOptions = {
// coordinates of the texture in the space
textureCoords: number[];
//image to use
image: ImageBitmap;
//if you want to animate your image
animate?: boolean;
// image used for displacement mapping
displacementMap?: ImageBitmap;
}
type SkeletalAnimationOptions = {
bones: number;
weights: number[];
indices: number[];
root: number;
}
type BonesOpt = {
angle: number[];
translate: Point3D[];
}
type Point3D = {
x: number,
y: number,
z: number,
}
type Point2D = {
x: number,
y: number,
}
- done: "already implemented"
- on-going: "actually working at..."
- coming soon: "the next step"
- ideally: "if possible, in the future will be supported"
checklist | feature | status |
---|---|---|
global game object | on-going | |
✔️ | webgpu texture | done |
✔️ | webgpu dynamic bindings definition ( create an array of all the bindings) | done |
✔️ | webgpu uniforms | done |
✔️ | webgl texture | done |
✔️ | webgl uniforms | done |
implement lights | coming soon | |
✔️ | implement skeletal animations on webgpu | done |
✔️ | implement skeletal animations on webgl | done |
✔️ | implement a fallback system with possibility of require specific api for the renderer | done |
this section contains all the material used to study rendering (by me), and that I'd thought could be helpful for the beginners
-WebGL Fundamentals
-Mozilla docs
-WebGPU Step By Step
-Raw WebGPU
-code labs google tutorial
-Mozilla docs
-WebGPU Fundamentals
-WebGL skeletal animation
-Skeletal Animation: from math to code
-Skeletal Animation
-WebGPU API for C++
-WebGPU for Metal developers
-Render grass