Skip to content
Snippets Groups Projects
Commit 5ffaf15d authored by Alexander Rose's avatar Alexander Rose
Browse files

render loop tweaks

parent 739d7614
No related branches found
No related tags found
No related merge requests found
......@@ -118,10 +118,9 @@ namespace Canvas3D {
const groupPickTarget = createRenderTarget(webgl, pickWidth, pickHeight)
let pickDirty = true
let isPicking = false
let isIdentifying = false
let isUpdating = false
let drawPending = false
let lastRenderTime = -1
const debugHelper = new BoundingSphereHelper(webgl, scene, p.debug)
......@@ -148,8 +147,9 @@ namespace Canvas3D {
})
if (changed) {
scene.update(true)
const prevPickDirty = pickDirty
draw(true)
pickDirty = false // picking buffers should not have changed
pickDirty = prevPickDirty // picking buffers should not have changed
}
}
......@@ -175,7 +175,7 @@ namespace Canvas3D {
}
function render(variant: 'pick' | 'draw', force: boolean) {
if (isPicking || isUpdating) return false
if (isIdentifying || isUpdating) return false
let didRender = false
controls.update()
......@@ -205,7 +205,6 @@ namespace Canvas3D {
debugHelper.syncVisibility()
renderer.render(debugHelper.scene, 'draw')
}
lastRenderTime = now()
pickDirty = true
break;
}
......@@ -235,25 +234,21 @@ namespace Canvas3D {
const t = now();
camera.transition.tick(t);
draw(false)
if (t - lastRenderTime > 1000 / 12 /** picking at 12 fps */ && pickDirty) {
// TODO would it not be better to call pick in identify?
// because currently for example highlighting something
// sets pickDirty = true that is not true
// there should definitely be a better "dirty" mechanism
pick();
}
window.requestAnimationFrame(animate)
}
function pick() {
render('pick', pickDirty)
pickDirty = false
if (pickDirty) {
render('pick', true)
pickDirty = false
}
}
async function identify(x: number, y: number): Promise<PickingId | undefined> {
if (pickDirty || isPicking) return;
if (isIdentifying) return
isPicking = true
pick() // must be called before setting `isIdentifying = true`
isIdentifying = true
x *= webgl.pixelRatio
y *= webgl.pixelRatio
......@@ -268,21 +263,21 @@ namespace Canvas3D {
// await webgl.readPixelsAsync(xp, yp, 1, 1, buffer)
webgl.readPixels(xp, yp, 1, 1, buffer)
const objectId = decodeIdRGB(buffer[0], buffer[1], buffer[2])
if (objectId === -1) { isPicking = false; return; }
if (objectId === -1) { isIdentifying = false; return; }
instancePickTarget.bind()
// await webgl.readPixelsAsync(xp, yp, 1, 1, buffer)
webgl.readPixels(xp, yp, 1, 1, buffer)
const instanceId = decodeIdRGB(buffer[0], buffer[1], buffer[2])
if (instanceId === -1) { isPicking = false; return; }
if (instanceId === -1) { isIdentifying = false; return; }
groupPickTarget.bind()
// await webgl.readPixelsAsync(xp, yp, 1, 1, buffer)
webgl.readPixels(xp, yp, 1, 1, buffer)
const groupId = decodeIdRGB(buffer[0], buffer[1], buffer[2])
if (groupId === -1) { isPicking = false; return; }
if (groupId === -1) { isIdentifying = false; return; }
isPicking = false
isIdentifying = false
return { objectId, instanceId, groupId }
}
......
......@@ -106,15 +106,19 @@ namespace Renderer {
uPickingAlphaThreshold: ValueCell.create(pickingAlphaThreshold),
}
let currentProgramId = -1
let globalUniformsNeedUpdate = true
const renderObject = (r: Renderable<RenderableValues & BaseValues>, variant: RenderVariant, opaque: boolean) => {
if (r.state.opaque !== opaque) return
const program = r.getProgram(variant)
if (r.state.visible) {
if (currentProgramId !== program.id) {
program.use()
if (r.state.visible) {
if (ctx.currentProgramId !== program.id) {
globalUniformsNeedUpdate = true
}
program.use()
if (globalUniformsNeedUpdate) {
program.setUniforms(globalUniforms)
currentProgramId = program.id
globalUniformsNeedUpdate = false
}
if (r.values.dDoubleSided) {
......@@ -162,8 +166,9 @@ namespace Renderer {
ValueCell.update(globalUniforms.uFogFar, camera.state.fogFar)
ValueCell.update(globalUniforms.uFogNear, camera.state.fogNear)
globalUniformsNeedUpdate = true
const { renderables } = scene
currentProgramId = -1
gl.disable(gl.BLEND)
gl.enable(gl.DEPTH_TEST)
......
......@@ -135,6 +135,8 @@ export interface WebGLContext {
readonly programCache: ProgramCache
readonly framebufferCache: FramebufferCache
currentProgramId: number
bufferCount: number
framebufferCount: number
renderbufferCount: number
......@@ -260,6 +262,8 @@ export function createContext(gl: GLRenderingContext): WebGLContext {
programCache,
framebufferCache,
currentProgramId: -1,
bufferCount: 0,
framebufferCount: 0,
renderbufferCount: 0,
......
......@@ -6,7 +6,7 @@
import { ShaderCode, DefineValues, addShaderDefines } from '../shader-code'
import { WebGLContext } from './context';
import { getUniformUpdaters, getTextureUniformUpdaters, UniformValues } from './uniform';
import { getUniformUpdaters, getTextureUniformUpdaters, UniformValues, UniformUpdater } from './uniform';
import { AttributeBuffers } from './buffer';
import { TextureId, Textures } from './texture';
import { createReferenceCache, ReferenceCache } from 'mol-util/reference-cache';
......@@ -60,6 +60,7 @@ export function createProgram(ctx: WebGLContext, props: ProgramProps): Program {
if (program === null) {
throw new Error('Could not create WebGL program')
}
const programId = getNextProgramId()
const shaderCode = addShaderDefines(ctx, defineValues, _shaderCode)
const vertShaderRef = shaderCache.get(ctx, { type: 'vert', source: shaderCode.vert })
......@@ -76,21 +77,27 @@ export function createProgram(ctx: WebGLContext, props: ProgramProps): Program {
const attributeLocations = getAttributeLocations(ctx, program, schema)
const textureUniformUpdaters = getTextureUniformUpdaters(ctx, program, schema)
const _uniformUpdaters: [string, UniformUpdater][] = []
Object.keys(uniformUpdaters).forEach(k => {
_uniformUpdaters.push([k, uniformUpdaters[k]])
})
let destroyed = false
return {
id: getNextProgramId(),
id: programId,
use: () => {
Object.keys(uniformUpdaters).forEach(k => uniformUpdaters[k].clear())
Object.keys(textureUniformUpdaters).forEach(k => textureUniformUpdaters[k].clear())
// console.log('use', programId)
ctx.currentProgramId = programId
gl.useProgram(program)
},
setUniforms: (uniformValues: UniformValues) => {
Object.keys(uniformValues).forEach(k => {
for (let i = 0, il = _uniformUpdaters.length; i < il; ++i) {
const [k, uu] = _uniformUpdaters[i]
const uv = uniformValues[k]
if (uv !== undefined) uniformUpdaters[k].set(uv.ref.value)
})
if (uv !== undefined) uu.set(uv.ref.value)
}
},
bindAttributes: (attribueBuffers: AttributeBuffers) => {
Object.keys(attribueBuffers).forEach(k => {
......
......@@ -6,7 +6,7 @@
import { Mat3, Mat4, Vec2, Vec3, Vec4 } from 'mol-math/linear-algebra'
import { WebGLContext } from './context';
import { ValueCell } from 'mol-util';
import { ValueCell, arrayEqual } from 'mol-util';
import { RenderableSchema } from '../renderable/schema';
export type UniformKindValue = {
......@@ -51,14 +51,12 @@ function createUniformUpdater(ctx: WebGLContext, program: WebGLProgram, name: st
let _value: UniformType | undefined = undefined
return {
set: value => {
if (_value !== value) {
if (_value !== value || (Array.isArray(_value) && Array.isArray(value) && arrayEqual(_value, value))) {
setter(value)
_value = value
_value = value
}
},
clear: () => {
_value = undefined
}
clear: () => { _value = undefined }
}
}
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment