renderer.ts 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165
  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-view/camera/util';
  8. import { Camera } from 'mol-view/camera/base';
  9. import Scene from './scene';
  10. import { Context, createImageData } from './webgl/context';
  11. import { Mat4, Vec3 } 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 } from './renderable/schema';
  16. export interface RendererStats {
  17. programCount: number
  18. shaderCount: number
  19. bufferCount: number
  20. textureCount: number
  21. vaoCount: number
  22. }
  23. interface Renderer {
  24. render: (scene: Scene, pick: boolean) => void
  25. setViewport: (viewport: Viewport) => void
  26. setClearColor: (color: Color) => void
  27. getImageData: () => ImageData
  28. stats: RendererStats
  29. dispose: () => void
  30. }
  31. function getPixelRatio() {
  32. return (typeof window !== 'undefined') ? window.devicePixelRatio : 1
  33. }
  34. export const DefaultRendererProps = {
  35. clearColor: 0x000000 as Color,
  36. viewport: Viewport.create(0, 0, 0, 0)
  37. }
  38. export type RendererProps = Partial<typeof DefaultRendererProps>
  39. namespace Renderer {
  40. export function create(ctx: Context, camera: Camera, props: RendererProps = {}): Renderer {
  41. const { gl } = ctx
  42. let { clearColor, viewport: _viewport } = { ...DefaultRendererProps, ...props }
  43. const model = Mat4.identity()
  44. const viewport = Viewport.clone(_viewport)
  45. const pixelRatio = getPixelRatio()
  46. // const lightPosition = Vec3.create(0, 0, -100)
  47. const lightColor = Vec3.create(1.0, 1.0, 1.0)
  48. const lightAmbient = Vec3.create(0.5, 0.5, 0.5)
  49. function setClearColor(color: Color) {
  50. const [ r, g, b ] = Color.toRgbNormalized(color)
  51. gl.clearColor(r, g, b, 1.0)
  52. }
  53. setClearColor(clearColor)
  54. const globalUniforms: GlobalUniformValues = {
  55. uModel: ValueCell.create(Mat4.clone(model)),
  56. uView: ValueCell.create(Mat4.clone(camera.view)),
  57. uProjection: ValueCell.create(Mat4.clone(camera.projection)),
  58. uPixelRatio: ValueCell.create(pixelRatio),
  59. uViewportHeight: ValueCell.create(viewport.height),
  60. uLightColor: ValueCell.create(Vec3.clone(lightColor)),
  61. uLightAmbient: ValueCell.create(Vec3.clone(lightAmbient))
  62. }
  63. let currentProgramId = -1
  64. const renderObject = (r: Renderable<RenderableValues>, pick: boolean) => {
  65. const program = pick ? r.pickProgram : r.drawProgram
  66. if (r.state.visible) {
  67. if (currentProgramId !== program.id) {
  68. program.use()
  69. program.setUniforms(globalUniforms)
  70. currentProgramId = program.id
  71. }
  72. if (r.values.dDoubleSided.ref.value) {
  73. gl.disable(gl.CULL_FACE)
  74. } else {
  75. gl.enable(gl.CULL_FACE)
  76. }
  77. if (r.values.dFlipSided.ref.value) {
  78. gl.frontFace(gl.CW)
  79. gl.cullFace(gl.FRONT)
  80. } else {
  81. gl.frontFace(gl.CCW)
  82. gl.cullFace(gl.BACK)
  83. }
  84. gl.depthMask(r.state.depthMask)
  85. if (pick) {
  86. r.pick()
  87. } else {
  88. r.draw()
  89. }
  90. }
  91. }
  92. const render = (scene: Scene, pick: boolean) => {
  93. ValueCell.update(globalUniforms.uView, camera.view)
  94. ValueCell.update(globalUniforms.uProjection, camera.projection)
  95. currentProgramId = -1
  96. gl.depthMask(true)
  97. gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT)
  98. gl.disable(gl.BLEND)
  99. gl.enable(gl.DEPTH_TEST)
  100. scene.eachOpaque((r) => renderObject(r, pick))
  101. gl.blendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA)
  102. gl.enable(gl.BLEND)
  103. scene.eachTransparent((r) => renderObject(r, pick))
  104. gl.finish()
  105. }
  106. return {
  107. render,
  108. setClearColor,
  109. setViewport: (newViewport: Viewport) => {
  110. Viewport.copy(viewport, newViewport)
  111. gl.viewport(viewport.x, viewport.y, viewport.width, viewport.height)
  112. ValueCell.update(globalUniforms.uViewportHeight, viewport.height)
  113. },
  114. getImageData: () => {
  115. const { width, height } = viewport
  116. const buffer = new Uint8Array(width * height * 4)
  117. ctx.unbindFramebuffer()
  118. ctx.readPixels(0, 0, width, height, buffer)
  119. return createImageData(buffer, width, height)
  120. },
  121. get stats(): RendererStats {
  122. return {
  123. programCount: ctx.programCache.count,
  124. shaderCount: ctx.shaderCache.count,
  125. bufferCount: ctx.bufferCount,
  126. textureCount: ctx.textureCount,
  127. vaoCount: ctx.vaoCount,
  128. }
  129. },
  130. dispose: () => {
  131. // TODO
  132. }
  133. }
  134. }
  135. }
  136. export default Renderer