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

render loop improvements, sort renderables

parent 5f19513f
No related branches found
No related tags found
No related merge requests found
...@@ -10,6 +10,9 @@ import { RenderVariant, RenderItem } from './webgl/render-item'; ...@@ -10,6 +10,9 @@ import { RenderVariant, RenderItem } from './webgl/render-item';
import { Sphere3D } from 'mol-math/geometry'; import { Sphere3D } from 'mol-math/geometry';
import { Vec3 } from 'mol-math/linear-algebra'; import { Vec3 } from 'mol-math/linear-algebra';
import { ValueCell } from 'mol-util'; import { ValueCell } from 'mol-util';
import { idFactory } from 'mol-util/id-factory';
const getNextRenderableId = idFactory()
export type RenderableState = { export type RenderableState = {
visible: boolean visible: boolean
...@@ -18,10 +21,12 @@ export type RenderableState = { ...@@ -18,10 +21,12 @@ export type RenderableState = {
} }
export interface Renderable<T extends RenderableValues> { export interface Renderable<T extends RenderableValues> {
readonly id: number
readonly values: T readonly values: T
readonly state: RenderableState readonly state: RenderableState
readonly boundingSphere: Sphere3D readonly boundingSphere: Sphere3D
readonly invariantBoundingSphere: Sphere3D readonly invariantBoundingSphere: Sphere3D
readonly z: number
render: (variant: RenderVariant) => void render: (variant: RenderVariant) => void
getProgram: (variant: RenderVariant) => Program getProgram: (variant: RenderVariant) => Program
...@@ -34,6 +39,7 @@ export function createRenderable<T extends Values<RenderableSchema>>(renderItem: ...@@ -34,6 +39,7 @@ export function createRenderable<T extends Values<RenderableSchema>>(renderItem:
const invariantBoundingSphere: Sphere3D = Sphere3D.create(Vec3.zero(), 0) const invariantBoundingSphere: Sphere3D = Sphere3D.create(Vec3.zero(), 0)
return { return {
id: getNextRenderableId(),
values, values,
state, state,
get boundingSphere () { get boundingSphere () {
...@@ -48,6 +54,9 @@ export function createRenderable<T extends Values<RenderableSchema>>(renderItem: ...@@ -48,6 +54,9 @@ export function createRenderable<T extends Values<RenderableSchema>>(renderItem:
} }
return invariantBoundingSphere return invariantBoundingSphere
}, },
get z () {
return boundingSphere.center[2]
},
render: (variant: RenderVariant) => { render: (variant: RenderVariant) => {
if (values.uPickable) { if (values.uPickable) {
......
...@@ -107,10 +107,9 @@ namespace Renderer { ...@@ -107,10 +107,9 @@ namespace Renderer {
} }
let globalUniformsNeedUpdate = true let globalUniformsNeedUpdate = true
const renderObject = (r: Renderable<RenderableValues & BaseValues>, variant: RenderVariant, opaque: boolean) => { const renderObject = (r: Renderable<RenderableValues & BaseValues>, variant: RenderVariant) => {
if (r.state.opaque !== opaque) return
const program = r.getProgram(variant) const program = r.getProgram(variant)
if (r.state.visible) { if (r.state.visible) {
if (ctx.currentProgramId !== program.id) { if (ctx.currentProgramId !== program.id) {
globalUniformsNeedUpdate = true globalUniformsNeedUpdate = true
} }
...@@ -146,8 +145,6 @@ namespace Renderer { ...@@ -146,8 +145,6 @@ namespace Renderer {
gl.cullFace(gl.BACK) gl.cullFace(gl.BACK)
} }
gl.depthMask(r.state.opaque)
r.render(variant) r.render(variant)
} }
} }
...@@ -170,16 +167,30 @@ namespace Renderer { ...@@ -170,16 +167,30 @@ namespace Renderer {
const { renderables } = scene const { renderables } = scene
gl.disable(gl.BLEND) if (variant === 'draw') {
gl.enable(gl.DEPTH_TEST) gl.disable(gl.BLEND)
for (let i = 0, il = renderables.length; i < il; ++i) { gl.enable(gl.DEPTH_TEST)
renderObject(renderables[i], variant, true) gl.depthMask(true)
} for (let i = 0, il = renderables.length; i < il; ++i) {
const r = renderables[i]
if (r.state.opaque) renderObject(r, variant)
}
gl.blendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA) gl.blendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA)
gl.enable(gl.BLEND) gl.enable(gl.BLEND)
for (let i = 0, il = renderables.length; i < il; ++i) { gl.depthMask(false)
renderObject(renderables[i], variant, false) for (let i = 0, il = renderables.length; i < il; ++i) {
const r = renderables[i]
if (!r.state.opaque) renderObject(r, variant)
}
} else {
// picking
gl.disable(gl.BLEND)
gl.enable(gl.DEPTH_TEST)
gl.depthMask(true)
for (let i = 0, il = renderables.length; i < il; ++i) {
renderObject(renderables[i], variant)
}
} }
gl.finish() gl.finish()
......
...@@ -35,6 +35,21 @@ function calculateBoundingSphere(renderables: Renderable<RenderableValues & Base ...@@ -35,6 +35,21 @@ function calculateBoundingSphere(renderables: Renderable<RenderableValues & Base
return boundingSphere; return boundingSphere;
} }
function renderableSort(a: Renderable<any>, b: Renderable<any>) {
const drawProgramIdA = a.getProgram('draw').id
const drawProgramIdB = b.getProgram('draw').id
if (drawProgramIdA !== drawProgramIdB) {
return drawProgramIdA - drawProgramIdB; // sort by program id to minimize gl state changes
} else if (a.z !== b.z) {
return a.state.opaque
? a.z - b.z // when opaque draw closer elements first to minimize overdraw
: b.z - a.z // when transparent draw elements last to maximize partial visibility
} else {
return a.id - b.id;
}
}
interface Scene extends Object3D { interface Scene extends Object3D {
readonly count: number readonly count: number
readonly renderables: ReadonlyArray<Renderable<RenderableValues & BaseValues>> readonly renderables: ReadonlyArray<Renderable<RenderableValues & BaseValues>>
...@@ -70,11 +85,11 @@ namespace Scene { ...@@ -70,11 +85,11 @@ namespace Scene {
} }
if (!keepBoundingSphere) boundingSphereDirty = true if (!keepBoundingSphere) boundingSphereDirty = true
}, },
add: (o: RenderObject) => { add: (o: RenderObject) => {
if (!renderableMap.has(o)) { if (!renderableMap.has(o)) {
const renderable = createRenderable(ctx, o) const renderable = createRenderable(ctx, o)
renderables.push(renderable) renderables.push(renderable)
renderables.sort(renderableSort)
renderableMap.set(o, renderable) renderableMap.set(o, renderable)
boundingSphereDirty = true boundingSphereDirty = true
} else { } else {
...@@ -86,6 +101,7 @@ namespace Scene { ...@@ -86,6 +101,7 @@ namespace Scene {
if (renderable) { if (renderable) {
renderable.dispose() renderable.dispose()
renderables.splice(renderables.indexOf(renderable), 1) renderables.splice(renderables.indexOf(renderable), 1)
renderables.sort(renderableSort)
renderableMap.delete(o) renderableMap.delete(o)
boundingSphereDirty = true boundingSphereDirty = true
} }
......
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