renderer.ts 8.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230
  1. /**
  2. * Copyright (c) 2018 mol* contributors, licensed under MIT, See LICENSE file for more info.
  3. *
  4. * @author Alexander Rose <alexander.rose@weirdbyte.de>
  5. */
  6. // import { Vec3, Mat4 } from 'mol-math/linear-algebra'
  7. import { Viewport } from 'mol-canvas3d/camera/util';
  8. import { Camera } from 'mol-canvas3d/camera';
  9. import Scene from './scene';
  10. import { WebGLContext, createImageData } from './webgl/context';
  11. import { Mat4, Vec3, Vec4 } from 'mol-math/linear-algebra';
  12. import { Renderable } from './renderable';
  13. import { Color } from 'mol-util/color';
  14. import { ValueCell } from 'mol-util';
  15. import { RenderableValues, GlobalUniformValues, BaseValues } from './renderable/schema';
  16. import { RenderVariant } from './webgl/render-item';
  17. export interface RendererStats {
  18. programCount: number
  19. shaderCount: number
  20. bufferCount: number
  21. framebufferCount: number
  22. renderbufferCount: number
  23. textureCount: number
  24. vaoCount: number
  25. drawCount: number
  26. instanceCount: number
  27. instancedDrawCount: number
  28. }
  29. interface Renderer {
  30. readonly stats: RendererStats
  31. readonly props: RendererProps
  32. render: (scene: Scene, variant: RenderVariant) => void
  33. setViewport: (x: number, y: number, width: number, height: number) => void
  34. setClearColor: (color: Color) => void
  35. setPickingAlphaThreshold: (value: number) => void
  36. getImageData: () => ImageData
  37. dispose: () => void
  38. }
  39. export const DefaultRendererProps = {
  40. clearColor: Color(0x000000),
  41. viewport: Viewport.create(0, 0, 0, 0),
  42. pickingAlphaThreshold: 0.5,
  43. }
  44. export type RendererProps = typeof DefaultRendererProps
  45. namespace Renderer {
  46. export function create(ctx: WebGLContext, camera: Camera, props: Partial<RendererProps> = {}): Renderer {
  47. const { gl } = ctx
  48. let { clearColor, viewport: _viewport, pickingAlphaThreshold } = { ...DefaultRendererProps, ...props }
  49. const viewport = Viewport.clone(_viewport)
  50. const viewportVec4 = Viewport.toVec4(Vec4.zero(), viewport)
  51. // const lightPosition = Vec3.create(0, 0, -100)
  52. const lightColor = Vec3.create(1.0, 1.0, 1.0)
  53. const lightAmbient = Vec3.create(0.5, 0.5, 0.5)
  54. const fogColor = Vec3.create(0.0, 0.0, 0.0)
  55. function setClearColor(color: Color) {
  56. clearColor = color
  57. const [ r, g, b ] = Color.toRgbNormalized(color)
  58. gl.clearColor(r, g, b, 1.0)
  59. }
  60. setClearColor(clearColor)
  61. const view = Mat4.clone(camera.view)
  62. const invView = Mat4.invert(Mat4.identity(), view)
  63. const modelView = Mat4.clone(camera.view)
  64. const invModelView = Mat4.invert(Mat4.identity(), modelView)
  65. const invProjection = Mat4.invert(Mat4.identity(), camera.projection)
  66. const modelViewProjection = Mat4.mul(Mat4.identity(), modelView, camera.projection)
  67. const invModelViewProjection = Mat4.invert(Mat4.identity(), modelViewProjection)
  68. const globalUniforms: GlobalUniformValues = {
  69. uModel: ValueCell.create(Mat4.identity()),
  70. uView: ValueCell.create(camera.view),
  71. uInvView: ValueCell.create(invView),
  72. uModelView: ValueCell.create(modelView),
  73. uInvModelView: ValueCell.create(invModelView),
  74. uInvProjection: ValueCell.create(invProjection),
  75. uProjection: ValueCell.create(Mat4.clone(camera.projection)),
  76. uModelViewProjection: ValueCell.create(modelViewProjection),
  77. uInvModelViewProjection: ValueCell.create(invModelViewProjection),
  78. uPixelRatio: ValueCell.create(ctx.pixelRatio),
  79. uViewportHeight: ValueCell.create(viewport.height),
  80. uViewport: ValueCell.create(viewportVec4),
  81. uLightColor: ValueCell.create(Vec3.clone(lightColor)),
  82. uLightAmbient: ValueCell.create(Vec3.clone(lightAmbient)),
  83. uFogNear: ValueCell.create(camera.state.near),
  84. uFogFar: ValueCell.create(camera.state.far / 50),
  85. uFogColor: ValueCell.create(Vec3.clone(fogColor)),
  86. uPickingAlphaThreshold: ValueCell.create(pickingAlphaThreshold),
  87. }
  88. let currentProgramId = -1
  89. const renderObject = (r: Renderable<RenderableValues & BaseValues>, variant: RenderVariant) => {
  90. const program = r.getProgram(variant)
  91. if (r.state.visible) {
  92. if (currentProgramId !== program.id) {
  93. program.use()
  94. program.setUniforms(globalUniforms)
  95. currentProgramId = program.id
  96. }
  97. if (r.values.dDoubleSided) {
  98. if (r.values.dDoubleSided.ref.value) {
  99. gl.disable(gl.CULL_FACE)
  100. } else {
  101. gl.enable(gl.CULL_FACE)
  102. }
  103. } else {
  104. // webgl default
  105. gl.disable(gl.CULL_FACE)
  106. }
  107. if (r.values.dFlipSided) {
  108. if (r.values.dFlipSided.ref.value) {
  109. gl.frontFace(gl.CW)
  110. gl.cullFace(gl.FRONT)
  111. } else {
  112. gl.frontFace(gl.CCW)
  113. gl.cullFace(gl.BACK)
  114. }
  115. } else {
  116. // webgl default
  117. gl.frontFace(gl.CCW)
  118. gl.cullFace(gl.BACK)
  119. }
  120. gl.depthMask(r.opaque)
  121. r.render(variant)
  122. }
  123. }
  124. const render = (scene: Scene, variant: RenderVariant) => {
  125. ValueCell.update(globalUniforms.uModel, scene.view)
  126. ValueCell.update(globalUniforms.uView, camera.view)
  127. ValueCell.update(globalUniforms.uInvView, Mat4.invert(invView, camera.view))
  128. ValueCell.update(globalUniforms.uModelView, Mat4.mul(modelView, scene.view, camera.view))
  129. ValueCell.update(globalUniforms.uInvModelView, Mat4.invert(invModelView, modelView))
  130. ValueCell.update(globalUniforms.uProjection, camera.projection)
  131. ValueCell.update(globalUniforms.uInvProjection, Mat4.invert(invProjection, camera.projection))
  132. ValueCell.update(globalUniforms.uModelViewProjection, Mat4.mul(modelViewProjection, modelView, camera.projection))
  133. ValueCell.update(globalUniforms.uInvModelViewProjection, Mat4.invert(invModelViewProjection, modelViewProjection))
  134. ValueCell.update(globalUniforms.uFogFar, camera.state.fogFar)
  135. ValueCell.update(globalUniforms.uFogNear, camera.state.fogNear)
  136. currentProgramId = -1
  137. gl.depthMask(true)
  138. gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT)
  139. gl.disable(gl.BLEND)
  140. gl.enable(gl.DEPTH_TEST)
  141. scene.eachOpaque((r) => renderObject(r, variant))
  142. gl.blendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA)
  143. gl.enable(gl.BLEND)
  144. scene.eachTransparent((r) => renderObject(r, variant))
  145. gl.finish()
  146. }
  147. return {
  148. render,
  149. setClearColor,
  150. setPickingAlphaThreshold: (value: number) => {
  151. pickingAlphaThreshold = value
  152. ValueCell.update(globalUniforms.uPickingAlphaThreshold, pickingAlphaThreshold)
  153. },
  154. setViewport: (x: number, y: number, width: number, height: number) => {
  155. Viewport.set(viewport, x, y, width, height)
  156. gl.viewport(x, y, width, height)
  157. ValueCell.update(globalUniforms.uViewportHeight, height)
  158. ValueCell.update(globalUniforms.uViewport, Vec4.set(viewportVec4, x, y, width, height))
  159. },
  160. getImageData: () => {
  161. const { width, height } = viewport
  162. const buffer = new Uint8Array(width * height * 4)
  163. ctx.unbindFramebuffer()
  164. ctx.readPixels(0, 0, width, height, buffer)
  165. return createImageData(buffer, width, height)
  166. },
  167. get props() {
  168. return {
  169. clearColor,
  170. pickingAlphaThreshold,
  171. viewport
  172. }
  173. },
  174. get stats(): RendererStats {
  175. return {
  176. programCount: ctx.programCache.count,
  177. shaderCount: ctx.shaderCache.count,
  178. bufferCount: ctx.bufferCount,
  179. framebufferCount: ctx.framebufferCount,
  180. renderbufferCount: ctx.renderbufferCount,
  181. textureCount: ctx.textureCount,
  182. vaoCount: ctx.vaoCount,
  183. drawCount: ctx.drawCount,
  184. instanceCount: ctx.instanceCount,
  185. instancedDrawCount: ctx.instancedDrawCount,
  186. }
  187. },
  188. dispose: () => {
  189. // TODO
  190. }
  191. }
  192. }
  193. }
  194. export default Renderer