Skip to content

Commit

Permalink
👢 Small updates to code context
Browse files Browse the repository at this point in the history
  • Loading branch information
benc-uk committed Aug 25, 2023
1 parent 9d13ecb commit 2bcf689
Show file tree
Hide file tree
Showing 5 changed files with 85 additions and 66 deletions.
30 changes: 14 additions & 16 deletions dist-bundle/gsots3d.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion dist-bundle/gsots3d.js.map

Large diffs are not rendered by default.

6 changes: 3 additions & 3 deletions examples/demo/main.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ try {
matGlass.opacity = 0.3
matGlass.reflectivity = 0.6
const crystalBall = ctx.createSphereInstance(matGlass, 4, 24, 12)
crystalBall.position = [12, 22, -8]
crystalBall.position = [12, 21, -8]

const matBlueGlass = Material.createSolidColour(0.2, 0.3, 1.0)
matBlueGlass.specular = [0.8, 0.8, 0.8]
Expand Down Expand Up @@ -112,7 +112,7 @@ try {
mellonTx.diffuse = [0.7, 1.4, 0.7]
mellonTx.specular = [1.0, 1.0, 1.0]
mellonTx.shininess = 25
mellon.position = [22, 22, -19]
mellon.position = [22, 21.5, -19]

const crateMat = Material.createBasicTexture('../_textures/crate.png')
crateMat.addSpecularTexture('../_textures/crate-specular.png')
Expand Down Expand Up @@ -244,7 +244,7 @@ ctx.setDynamicEnvmap([0, 15, 0], 256)
ctx.globalLight.enableShadows({
mapSize: 2048,
zoom: 100,
polygonOffset: 0.1,
polygonOffset: 1,
})

ctx.start()
4 changes: 2 additions & 2 deletions examples/dice/main.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ import { Context, Physics, Tuples } from '../../dist-bundle/gsots3d.js'
import * as CANNON from 'https://cdn.jsdelivr.net/npm/cannon-es@0.20.0/dist/cannon-es.min.js'

const ctx = await Context.init()
ctx.start()

ctx.camera.position = [50, 80, 60]
ctx.camera.enableFPControls(0.8, -0.49, 0.0015, 1.8)
ctx.camera.far = 1300
Expand Down Expand Up @@ -78,8 +80,6 @@ window.addEventListener('keydown', (e) => {
}
})

ctx.start()

function addDice() {
const dice = ctx.createModelInstance('dice')
dice.position = [-30 + Math.random() * 60, 70 + Math.random() * 40, -20 + Math.random() * 40]
Expand Down
109 changes: 65 additions & 44 deletions src/core/context.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,19 +40,19 @@ const MAX_LIGHTS = 16
export class Context {
private gl: WebGL2RenderingContext
private started: boolean
private instances: Map<number, Instance> = new Map()
private instancesTrans: Instance[] = []
private instancesParticles: Instance[] = []
private cameras: Map<string, Camera> = new Map()
private instances: Map<number, Instance>
private instancesTrans: Map<number, Instance>
private instancesParticles: Map<number, Instance>
private cameras: Map<string, Camera>
private activeCameraName: string
private envmap?: EnvironmentMap
private _envmap?: EnvironmentMap
private dynamicEnvMap?: DynamicEnvironmentMap

/** Global directional light */
public globalLight: LightDirectional

/** All the dynamic point lights in the scene */
public lights: LightPoint[] = []
public lights: LightPoint[]

/** Main camera for this context */
private _camera: Camera
Expand Down Expand Up @@ -87,12 +87,22 @@ export class Context {
return this.activeCameraName
}

/** Get the current EnvironmentMap for the scene */
get envmap() {
return this._envmap
}

/** Constructor is private, use init() to create a new context */
private constructor(gl: WebGL2RenderingContext) {
this.gl = gl
this.started = false
this.debug = false
this.gamma = 1.0
this.instances = new Map()
this.instancesTrans = new Map()
this.instancesParticles = new Map()
this.cameras = new Map()
this.lights = []

// Main global light
this.globalLight = new LightDirectional()
Expand Down Expand Up @@ -159,13 +169,17 @@ export class Context {
// Call the external update function
this.update(Stats.deltaTime, now)

// RENDERING - Render into the dynamic environment map(s) if any
// -----------------------------------------------------------------------
// RENDER CORE - Render into the dynamic environment map(s) if any
// -----------------------------------------------------------------------
if (this.dynamicEnvMap) {
// This is a rare case of passing the context to the object, but it's needed for the dynamic env map
this.dynamicEnvMap.update(this.gl, this)
}

// RENDERING - Render the shadow map from the global light
// -------------------------------------------------------------
// RENDER CORE - Render the shadow map from the global light
// -------------------------------------------------------------
if (this.globalLight.shadowsEnabled) {
// Switch to front face culling for shadow map, yeah it's weird but it works!
this.gl.cullFace(this.gl.FRONT)
Expand All @@ -185,7 +199,9 @@ export class Context {
this.gl.disable(this.gl.POLYGON_OFFSET_FILL)
}

// RENDERING - Render the scene from active camera into the main framebuffer
// -------------------------------------------------------------------------------------
// RENDER CORE - Render the scene from active camera into the main framebuffer
// -------------------------------------------------------------------------------------
twgl.bindFramebufferInfo(this.gl, null)
this.renderWithCamera(this.camera)

Expand Down Expand Up @@ -223,7 +239,7 @@ export class Context {

// Work out what reflection map to use, if any
// NOTE: This *not* part of the material because it's too hard to dynamically change
let reflectMap: WebGLTexture | null = this.envmap?.texture ?? null
let reflectMap: WebGLTexture | null = this._envmap?.texture ?? null

// As there is only one dynamic reflection envmap, we can use it across all instances
// But ONLY set this when the camera is NOT rendering into it!
Expand All @@ -250,12 +266,16 @@ export class Context {
// u_shadowScatter: this.globalLight.shadowMapOptions?.scatter ?? 0.2,
} as UniformSet

// RENDERING - Draw envmap around the scene first, like a skybox & background
if (this.envmap) {
this.envmap.render(<mat4>uniforms.u_view, <mat4>uniforms.u_proj, camera)
// ------------------------------------------------------------------------------
// RENDER CORE - Draw envmap around the scene first, as a skybox background
// ------------------------------------------------------------------------------
if (this._envmap) {
this._envmap.render(<mat4>uniforms.u_view, <mat4>uniforms.u_proj, camera)
}

// RENDERING - Process lighting
// ------------------------------------------------
// RENDER CORE - Process lighting
// ------------------------------------------------

// Apply global light to the two programs
uniforms.u_lightDirGlobal = this.globalLight.uniforms
Expand All @@ -281,38 +301,50 @@ export class Context {

uniforms.u_lightsPosCount = lightCount

// RENDERING - Draw all opaque instances
// ------------------------------------------------
// RENDER CORE - Draw all standard opaque instances
// ------------------------------------------------
this.gl.enable(this.gl.CULL_FACE)

// eslint-disable-next-line @typescript-eslint/no-unused-vars
for (const [_id, instance] of this.instances) {
instance.render(this.gl, uniforms, programOverride)
}

// RENDERING - Draw all transparent instances
this.gl.disable(this.gl.CULL_FACE)
// ------------------------------------------------
// RENDER CORE - Draw all transparent instances
// ------------------------------------------------

// Sort transparent instances by distance to camera
// Maybe remove this in scenes with lots of transparent instances?
this.instancesTrans.sort((a, b) => {
// TODO: Maybe remove this in scenes with lots of transparent instances?
const instancesTransArray = Array.from(this.instancesTrans.values())
instancesTransArray.sort((a, b) => {
const ad = Tuples.distance(a.position ?? [0, 0, 0], this.camera.position)
const bd = Tuples.distance(b.position ?? [0, 0, 0], this.camera.position)
return bd - ad
})

for (const instance of this.instancesTrans) {
this.gl.disable(this.gl.CULL_FACE)
// eslint-disable-next-line @typescript-eslint/no-unused-vars
for (const instance of instancesTransArray) {
instance.render(this.gl, uniforms, programOverride)
}

// RENDERING - Draw all particle systems
// ------------------------------------------------
// RENDER CORE - Draw all particle systems
// ------------------------------------------------
this.gl.depthMask(false)
for (const instance of this.instancesParticles) {

// eslint-disable-next-line @typescript-eslint/no-unused-vars
for (const [_id, instance] of this.instancesParticles) {
instance.render(this.gl, uniforms, programOverride)
}

this.gl.depthMask(true)
}

/**
* Start the rendering loop
* Start the rendering loop, without calling this nothing will render
*/
start() {
log.info('🚀 Starting main GSOTS render loop!')
Expand All @@ -333,7 +365,7 @@ export class Context {
}

/**
* Resize the canvas to match the size of the element it's in
* Resize the canvas to match the size of the HTML element that contains it
* @param viewportOnly - Only resize the viewport, not the canvas
*/
resize(viewportOnly = false) {
Expand All @@ -354,7 +386,7 @@ export class Context {
*/
private addInstance(instance: Instance, material: Material) {
if (material.opacity !== undefined && material.opacity < 1) {
this.instancesTrans.push(instance)
this.instancesTrans.set(instance.id, instance)
} else {
this.instances.set(instance.id, instance)
}
Expand Down Expand Up @@ -571,7 +603,7 @@ export class Context {
const instance = new Instance(particleSystem)
instance.castShadow = false

this.instancesParticles.push(instance)
this.instancesParticles.set(instance.id, instance)
Stats.instances++

return { instance, particleSystem }
Expand All @@ -583,22 +615,15 @@ export class Context {
* @param textureURLs - Array of 6 texture URLs to use for the map, in the order: +X, -X, +Y, -Y, +Z, -Z
*/
setEnvmap(renderAsBackground = false, ...textureURLs: string[]) {
this.envmap = new EnvironmentMap(this.gl, textureURLs)
this.envmap.renderAsBackground = renderAsBackground
this._envmap = new EnvironmentMap(this.gl, textureURLs)
this._envmap.renderAsBackground = renderAsBackground
}

/**
* Remove any current EnvironmentMap from the scene
*/
removeEnvmap() {
this.envmap = undefined
}

/**
* Get the current EnvironmentMap for the scene
*/
getEnvmap() {
return this.envmap
this._envmap = undefined
}

/**
Expand All @@ -611,22 +636,18 @@ export class Context {
}

/**
* Remove instance from the scene
* Remove instance from the scene, it will no longer be rendered
* @param instance - Instance to remove
*/
removeInstance(instance: Instance) {
if (!instance) return

if (instance.renderable instanceof ParticleSystem) {
for (let i = 0; i < this.instancesParticles.length; i++) {
if (this.instancesParticles[i].id === instance.id) {
this.instancesParticles.splice(i, 1)
return
}
}
this.instancesParticles.delete(instance.id)
return
}

// TODO: Only non-transparent instances are in the map!
this.instances.delete(instance.id)
this.instancesTrans.delete(instance.id)
}
}

0 comments on commit 2bcf689

Please sign in to comment.