123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257 |
- /**
- * Copyright (c) 2018 mol* contributors, licensed under MIT, See LICENSE file for more info.
- *
- * @author Alexander Rose <alexander.rose@weirdbyte.de>
- */
- // import { Vec3, Mat4 } from 'mol-math/linear-algebra'
- import { Viewport } from 'mol-canvas3d/camera/util';
- import { Camera } from 'mol-canvas3d/camera';
- import Scene from './scene';
- import { WebGLContext, createImageData } from './webgl/context';
- import { Mat4, Vec3, Vec4 } from 'mol-math/linear-algebra';
- import { Renderable } from './renderable';
- import { Color } from 'mol-util/color';
- import { ValueCell } from 'mol-util';
- import { RenderableValues, GlobalUniformValues, BaseValues } from './renderable/schema';
- import { RenderVariant } from './webgl/render-item';
- export interface RendererStats {
- programCount: number
- shaderCount: number
- bufferCount: number
- framebufferCount: number
- renderbufferCount: number
- textureCount: number
- vaoCount: number
- drawCount: number
- instanceCount: number
- instancedDrawCount: number
- }
- interface Renderer {
- readonly stats: RendererStats
- readonly props: RendererProps
- clear: () => void
- render: (scene: Scene, variant: RenderVariant) => void
- setViewport: (x: number, y: number, width: number, height: number) => void
- setClearColor: (color: Color) => void
- setPickingAlphaThreshold: (value: number) => void
- getImageData: () => ImageData
- dispose: () => void
- }
- export const DefaultRendererProps = {
- clearColor: Color(0x000000),
- viewport: Viewport.create(0, 0, 0, 0),
- pickingAlphaThreshold: 0.5,
- }
- export type RendererProps = typeof DefaultRendererProps
- namespace Renderer {
- export function create(ctx: WebGLContext, camera: Camera, props: Partial<RendererProps> = {}): Renderer {
- const { gl } = ctx
- let { clearColor, viewport: _viewport, pickingAlphaThreshold } = { ...DefaultRendererProps, ...props }
- const viewport = Viewport.clone(_viewport)
- const viewportVec4 = Viewport.toVec4(Vec4.zero(), viewport)
- // const lightPosition = Vec3.create(0, 0, -100)
- const lightColor = Vec3.create(1.0, 1.0, 1.0)
- const lightAmbient = Vec3.create(0.5, 0.5, 0.5)
- const fogColor = Vec3.create(0.0, 0.0, 0.0)
- function setClearColor(color: Color) {
- clearColor = color
- const [ r, g, b ] = Color.toRgbNormalized(color)
- gl.clearColor(r, g, b, 1.0)
- Vec3.set(fogColor, r, g, b)
- }
- setClearColor(clearColor)
- const view = Mat4.clone(camera.view)
- const invView = Mat4.invert(Mat4.identity(), view)
- const modelView = Mat4.clone(camera.view)
- const invModelView = Mat4.invert(Mat4.identity(), modelView)
- const invProjection = Mat4.invert(Mat4.identity(), camera.projection)
- const modelViewProjection = Mat4.mul(Mat4.identity(), modelView, camera.projection)
- const invModelViewProjection = Mat4.invert(Mat4.identity(), modelViewProjection)
- const globalUniforms: GlobalUniformValues = {
- uModel: ValueCell.create(Mat4.identity()),
- uView: ValueCell.create(camera.view),
- uInvView: ValueCell.create(invView),
- uModelView: ValueCell.create(modelView),
- uInvModelView: ValueCell.create(invModelView),
- uInvProjection: ValueCell.create(invProjection),
- uProjection: ValueCell.create(Mat4.clone(camera.projection)),
- uModelViewProjection: ValueCell.create(modelViewProjection),
- uInvModelViewProjection: ValueCell.create(invModelViewProjection),
- uPixelRatio: ValueCell.create(ctx.pixelRatio),
- uViewportHeight: ValueCell.create(viewport.height),
- uViewport: ValueCell.create(viewportVec4),
- uLightColor: ValueCell.create(lightColor),
- uLightAmbient: ValueCell.create(lightAmbient),
- uCameraPosition: ValueCell.create(Vec3.clone(camera.state.position)),
- uFogNear: ValueCell.create(camera.state.fogNear),
- uFogFar: ValueCell.create(camera.state.fogFar),
- uFogColor: ValueCell.create(fogColor),
- uPickingAlphaThreshold: ValueCell.create(pickingAlphaThreshold),
- }
- let globalUniformsNeedUpdate = true
- const renderObject = (r: Renderable<RenderableValues & BaseValues>, variant: RenderVariant) => {
- const program = r.getProgram(variant)
- if (r.state.visible) {
- if (ctx.currentProgramId !== program.id) {
- globalUniformsNeedUpdate = true
- }
- program.use()
- if (globalUniformsNeedUpdate) {
- program.setUniforms(globalUniforms)
- globalUniformsNeedUpdate = false
- }
- if (r.values.dDoubleSided) {
- if (r.values.dDoubleSided.ref.value) {
- gl.disable(gl.CULL_FACE)
- } else {
- gl.enable(gl.CULL_FACE)
- }
- } else {
- // webgl default
- gl.disable(gl.CULL_FACE)
- }
- if (r.values.dFlipSided) {
- if (r.values.dFlipSided.ref.value) {
- gl.frontFace(gl.CW)
- gl.cullFace(gl.FRONT)
- } else {
- gl.frontFace(gl.CCW)
- gl.cullFace(gl.BACK)
- }
- } else {
- // webgl default
- gl.frontFace(gl.CCW)
- gl.cullFace(gl.BACK)
- }
- r.render(variant)
- }
- }
- const render = (scene: Scene, variant: RenderVariant) => {
- ValueCell.update(globalUniforms.uModel, scene.view)
- ValueCell.update(globalUniforms.uView, camera.view)
- ValueCell.update(globalUniforms.uInvView, Mat4.invert(invView, camera.view))
- ValueCell.update(globalUniforms.uModelView, Mat4.mul(modelView, scene.view, camera.view))
- ValueCell.update(globalUniforms.uInvModelView, Mat4.invert(invModelView, modelView))
- ValueCell.update(globalUniforms.uProjection, camera.projection)
- ValueCell.update(globalUniforms.uInvProjection, Mat4.invert(invProjection, camera.projection))
- ValueCell.update(globalUniforms.uModelViewProjection, Mat4.mul(modelViewProjection, modelView, camera.projection))
- ValueCell.update(globalUniforms.uInvModelViewProjection, Mat4.invert(invModelViewProjection, modelViewProjection))
- ValueCell.update(globalUniforms.uCameraPosition, camera.state.position)
- ValueCell.update(globalUniforms.uFogFar, camera.state.fogFar)
- ValueCell.update(globalUniforms.uFogNear, camera.state.fogNear)
- globalUniformsNeedUpdate = true
- 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) {
- 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)
- for (let i = 0, il = renderables.length; i < il; ++i) {
- const r = renderables[i]
- gl.depthMask(r.values.uAlpha.ref.value === 1.0)
- 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()
- }
- return {
- clear: () => {
- gl.depthMask(true)
- gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT)
- },
- render,
- setClearColor,
- setPickingAlphaThreshold: (value: number) => {
- pickingAlphaThreshold = value
- ValueCell.update(globalUniforms.uPickingAlphaThreshold, pickingAlphaThreshold)
- },
- setViewport: (x: number, y: number, width: number, height: number) => {
- Viewport.set(viewport, x, y, width, height)
- gl.viewport(x, y, width, height)
- ValueCell.update(globalUniforms.uViewportHeight, height)
- ValueCell.update(globalUniforms.uViewport, Vec4.set(viewportVec4, x, y, width, height))
- },
- getImageData: () => {
- const { width, height } = viewport
- const buffer = new Uint8Array(width * height * 4)
- ctx.unbindFramebuffer()
- ctx.readPixels(0, 0, width, height, buffer)
- return createImageData(buffer, width, height)
- },
- get props() {
- return {
- clearColor,
- pickingAlphaThreshold,
- viewport
- }
- },
- get stats(): RendererStats {
- return {
- programCount: ctx.programCache.count,
- shaderCount: ctx.shaderCache.count,
- bufferCount: ctx.bufferCount,
- framebufferCount: ctx.framebufferCount,
- renderbufferCount: ctx.renderbufferCount,
- textureCount: ctx.textureCount,
- vaoCount: ctx.vaoCount,
- drawCount: ctx.drawCount,
- instanceCount: ctx.instanceCount,
- instancedDrawCount: ctx.instancedDrawCount,
- }
- },
- dispose: () => {
- // TODO
- }
- }
- }
- }
- export default Renderer
|