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';
import { Sphere3D } from 'mol-math/geometry';
import { Vec3 } from 'mol-math/linear-algebra';
import { ValueCell } from 'mol-util';
import { idFactory } from 'mol-util/id-factory';
const getNextRenderableId = idFactory()
export type RenderableState = {
visible: boolean
......@@ -18,10 +21,12 @@ export type RenderableState = {
}
export interface Renderable<T extends RenderableValues> {
readonly id: number
readonly values: T
readonly state: RenderableState
readonly boundingSphere: Sphere3D
readonly invariantBoundingSphere: Sphere3D
readonly z: number
render: (variant: RenderVariant) => void
getProgram: (variant: RenderVariant) => Program
......@@ -34,6 +39,7 @@ export function createRenderable<T extends Values<RenderableSchema>>(renderItem:
const invariantBoundingSphere: Sphere3D = Sphere3D.create(Vec3.zero(), 0)
return {
id: getNextRenderableId(),
values,
state,
get boundingSphere () {
......@@ -48,6 +54,9 @@ export function createRenderable<T extends Values<RenderableSchema>>(renderItem:
}
return invariantBoundingSphere
},
get z () {
return boundingSphere.center[2]
},
render: (variant: RenderVariant) => {
if (values.uPickable) {
......
......@@ -107,8 +107,7 @@ namespace Renderer {
}
let globalUniformsNeedUpdate = true
const renderObject = (r: Renderable<RenderableValues & BaseValues>, variant: RenderVariant, opaque: boolean) => {
if (r.state.opaque !== opaque) return
const renderObject = (r: Renderable<RenderableValues & BaseValues>, variant: RenderVariant) => {
const program = r.getProgram(variant)
if (r.state.visible) {
if (ctx.currentProgramId !== program.id) {
......@@ -146,8 +145,6 @@ namespace Renderer {
gl.cullFace(gl.BACK)
}
gl.depthMask(r.state.opaque)
r.render(variant)
}
}
......@@ -170,16 +167,30 @@ namespace Renderer {
const { renderables } = scene
if (variant === 'draw') {
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, true)
const r = renderables[i]
if (r.state.opaque) renderObject(r, variant)
}
gl.blendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA)
gl.enable(gl.BLEND)
gl.depthMask(false)
for (let i = 0, il = renderables.length; i < il; ++i) {
renderObject(renderables[i], variant, false)
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()
......
......@@ -35,6 +35,21 @@ function calculateBoundingSphere(renderables: Renderable<RenderableValues & Base
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 {
readonly count: number
readonly renderables: ReadonlyArray<Renderable<RenderableValues & BaseValues>>
......@@ -70,11 +85,11 @@ namespace Scene {
}
if (!keepBoundingSphere) boundingSphereDirty = true
},
add: (o: RenderObject) => {
if (!renderableMap.has(o)) {
const renderable = createRenderable(ctx, o)
renderables.push(renderable)
renderables.sort(renderableSort)
renderableMap.set(o, renderable)
boundingSphereDirty = true
} else {
......@@ -86,6 +101,7 @@ namespace Scene {
if (renderable) {
renderable.dispose()
renderables.splice(renderables.indexOf(renderable), 1)
renderables.sort(renderableSort)
renderableMap.delete(o)
boundingSphereDirty = true
}
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment