renderer.ts 8.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233
  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. clear: () => void
  33. render: (scene: Scene, variant: RenderVariant) => void
  34. setViewport: (x: number, y: number, width: number, height: number) => void
  35. setClearColor: (color: Color) => void
  36. setPickingAlphaThreshold: (value: number) => void
  37. getImageData: () => ImageData
  38. dispose: () => void
  39. }
  40. export const DefaultRendererProps = {
  41. clearColor: Color(0x000000),
  42. viewport: Viewport.create(0, 0, 0, 0),
  43. pickingAlphaThreshold: 0.5,
  44. }
  45. export type RendererProps = typeof DefaultRendererProps
  46. namespace Renderer {
  47. export function create(ctx: WebGLContext, camera: Camera, props: Partial<RendererProps> = {}): Renderer {
  48. const { gl } = ctx
  49. let { clearColor, viewport: _viewport, pickingAlphaThreshold } = { ...DefaultRendererProps, ...props }
  50. const viewport = Viewport.clone(_viewport)
  51. const viewportVec4 = Viewport.toVec4(Vec4.zero(), viewport)
  52. // const lightPosition = Vec3.create(0, 0, -100)
  53. const lightColor = Vec3.create(1.0, 1.0, 1.0)
  54. const lightAmbient = Vec3.create(0.5, 0.5, 0.5)
  55. const fogColor = Vec3.create(0.0, 0.0, 0.0)
  56. function setClearColor(color: Color) {
  57. clearColor = color
  58. const [ r, g, b ] = Color.toRgbNormalized(color)
  59. gl.clearColor(r, g, b, 1.0)
  60. Vec3.set(fogColor, r, g, b)
  61. }
  62. setClearColor(clearColor)
  63. const view = Mat4.clone(camera.view)
  64. const invView = Mat4.invert(Mat4.identity(), view)
  65. const modelView = Mat4.clone(camera.view)
  66. const invModelView = Mat4.invert(Mat4.identity(), modelView)
  67. const invProjection = Mat4.invert(Mat4.identity(), camera.projection)
  68. const modelViewProjection = Mat4.mul(Mat4.identity(), modelView, camera.projection)
  69. const invModelViewProjection = Mat4.invert(Mat4.identity(), modelViewProjection)
  70. const globalUniforms: GlobalUniformValues = {
  71. uModel: ValueCell.create(Mat4.identity()),
  72. uView: ValueCell.create(camera.view),
  73. uInvView: ValueCell.create(invView),
  74. uModelView: ValueCell.create(modelView),
  75. uInvModelView: ValueCell.create(invModelView),
  76. uInvProjection: ValueCell.create(invProjection),
  77. uProjection: ValueCell.create(Mat4.clone(camera.projection)),
  78. uModelViewProjection: ValueCell.create(modelViewProjection),
  79. uInvModelViewProjection: ValueCell.create(invModelViewProjection),
  80. uPixelRatio: ValueCell.create(ctx.pixelRatio),
  81. uViewportHeight: ValueCell.create(viewport.height),
  82. uViewport: ValueCell.create(viewportVec4),
  83. uLightColor: ValueCell.create(lightColor),
  84. uLightAmbient: ValueCell.create(lightAmbient),
  85. uFogNear: ValueCell.create(camera.state.fogNear),
  86. uFogFar: ValueCell.create(camera.state.fogFar),
  87. uFogColor: ValueCell.create(fogColor),
  88. uPickingAlphaThreshold: ValueCell.create(pickingAlphaThreshold),
  89. }
  90. let currentProgramId = -1
  91. const renderObject = (r: Renderable<RenderableValues & BaseValues>, variant: RenderVariant) => {
  92. const program = r.getProgram(variant)
  93. if (r.state.visible) {
  94. if (currentProgramId !== program.id) {
  95. program.use()
  96. program.setUniforms(globalUniforms)
  97. currentProgramId = program.id
  98. }
  99. if (r.values.dDoubleSided) {
  100. if (r.values.dDoubleSided.ref.value) {
  101. gl.disable(gl.CULL_FACE)
  102. } else {
  103. gl.enable(gl.CULL_FACE)
  104. }
  105. } else {
  106. // webgl default
  107. gl.disable(gl.CULL_FACE)
  108. }
  109. if (r.values.dFlipSided) {
  110. if (r.values.dFlipSided.ref.value) {
  111. gl.frontFace(gl.CW)
  112. gl.cullFace(gl.FRONT)
  113. } else {
  114. gl.frontFace(gl.CCW)
  115. gl.cullFace(gl.BACK)
  116. }
  117. } else {
  118. // webgl default
  119. gl.frontFace(gl.CCW)
  120. gl.cullFace(gl.BACK)
  121. }
  122. gl.depthMask(r.state.opaque)
  123. r.render(variant)
  124. }
  125. }
  126. const render = (scene: Scene, variant: RenderVariant) => {
  127. ValueCell.update(globalUniforms.uModel, scene.view)
  128. ValueCell.update(globalUniforms.uView, camera.view)
  129. ValueCell.update(globalUniforms.uInvView, Mat4.invert(invView, camera.view))
  130. ValueCell.update(globalUniforms.uModelView, Mat4.mul(modelView, scene.view, camera.view))
  131. ValueCell.update(globalUniforms.uInvModelView, Mat4.invert(invModelView, modelView))
  132. ValueCell.update(globalUniforms.uProjection, camera.projection)
  133. ValueCell.update(globalUniforms.uInvProjection, Mat4.invert(invProjection, camera.projection))
  134. ValueCell.update(globalUniforms.uModelViewProjection, Mat4.mul(modelViewProjection, modelView, camera.projection))
  135. ValueCell.update(globalUniforms.uInvModelViewProjection, Mat4.invert(invModelViewProjection, modelViewProjection))
  136. ValueCell.update(globalUniforms.uFogFar, camera.state.fogFar)
  137. ValueCell.update(globalUniforms.uFogNear, camera.state.fogNear)
  138. currentProgramId = -1
  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. clear: () => {
  149. gl.depthMask(true)
  150. gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT)
  151. },
  152. render,
  153. setClearColor,
  154. setPickingAlphaThreshold: (value: number) => {
  155. pickingAlphaThreshold = value
  156. ValueCell.update(globalUniforms.uPickingAlphaThreshold, pickingAlphaThreshold)
  157. },
  158. setViewport: (x: number, y: number, width: number, height: number) => {
  159. Viewport.set(viewport, x, y, width, height)
  160. gl.viewport(x, y, width, height)
  161. ValueCell.update(globalUniforms.uViewportHeight, height)
  162. ValueCell.update(globalUniforms.uViewport, Vec4.set(viewportVec4, x, y, width, height))
  163. },
  164. getImageData: () => {
  165. const { width, height } = viewport
  166. const buffer = new Uint8Array(width * height * 4)
  167. ctx.unbindFramebuffer()
  168. ctx.readPixels(0, 0, width, height, buffer)
  169. return createImageData(buffer, width, height)
  170. },
  171. get props() {
  172. return {
  173. clearColor,
  174. pickingAlphaThreshold,
  175. viewport
  176. }
  177. },
  178. get stats(): RendererStats {
  179. return {
  180. programCount: ctx.programCache.count,
  181. shaderCount: ctx.shaderCache.count,
  182. bufferCount: ctx.bufferCount,
  183. framebufferCount: ctx.framebufferCount,
  184. renderbufferCount: ctx.renderbufferCount,
  185. textureCount: ctx.textureCount,
  186. vaoCount: ctx.vaoCount,
  187. drawCount: ctx.drawCount,
  188. instanceCount: ctx.instanceCount,
  189. instancedDrawCount: ctx.instancedDrawCount,
  190. }
  191. },
  192. dispose: () => {
  193. // TODO
  194. }
  195. }
  196. }
  197. }
  198. export default Renderer