浏览代码

render loop tweaks

Alexander Rose 6 年之前
父节点
当前提交
5ffaf15dcb
共有 5 个文件被更改,包括 48 次插入39 次删除
  1. 15 20
      src/mol-canvas3d/canvas3d.ts
  2. 11 6
      src/mol-gl/renderer.ts
  3. 4 0
      src/mol-gl/webgl/context.ts
  4. 14 7
      src/mol-gl/webgl/program.ts
  5. 4 6
      src/mol-gl/webgl/uniform.ts

+ 15 - 20
src/mol-canvas3d/canvas3d.ts

@@ -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 }
         }

+ 11 - 6
src/mol-gl/renderer.ts

@@ -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)

+ 4 - 0
src/mol-gl/webgl/context.ts

@@ -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,

+ 14 - 7
src/mol-gl/webgl/program.ts

@@ -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 => {

+ 4 - 6
src/mol-gl/webgl/uniform.ts

@@ -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 }
     }
 }