|
@@ -15,6 +15,8 @@ import { Color } from 'mol-util/color';
|
|
|
import { ValueCell } from 'mol-util';
|
|
|
import { RenderableValues, GlobalUniformValues, BaseValues } from './renderable/schema';
|
|
|
import { GraphicsRenderVariant } from './webgl/render-item';
|
|
|
+import { ParamDefinition as PD } from 'mol-util/param-definition';
|
|
|
+import { deepClone } from 'mol-util/object';
|
|
|
|
|
|
export interface RendererStats {
|
|
|
programCount: number
|
|
@@ -33,44 +35,35 @@ export interface RendererStats {
|
|
|
|
|
|
interface Renderer {
|
|
|
readonly stats: RendererStats
|
|
|
- readonly props: RendererProps
|
|
|
+ readonly props: Readonly<RendererProps>
|
|
|
|
|
|
clear: () => void
|
|
|
render: (scene: Scene, variant: GraphicsRenderVariant) => void
|
|
|
+ setProps: (props: Partial<RendererProps>) => 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 const RendererParams = {
|
|
|
+ backgroundColor: PD.Color(Color(0x000000)),
|
|
|
+ pickingAlphaThreshold: PD.Numeric(0.5, { min: 0.0, max: 1.0, step: 0.01 }, { description: 'The minimum opacity value needed for an object to be pickable.' }),
|
|
|
+
|
|
|
+ lightIntensity: PD.Numeric(0.8, { min: 0.0, max: 1.0, step: 0.01 }),
|
|
|
+ ambientIntensity: PD.Numeric(0.4, { min: 0.0, max: 1.0, step: 0.01 }),
|
|
|
+
|
|
|
+ metalness: PD.Numeric(0.0, { min: 0.0, max: 1.0, step: 0.01 }),
|
|
|
+ roughness: PD.Numeric(0.4, { min: 0.0, max: 1.0, step: 0.01 }),
|
|
|
+ reflectivity: PD.Numeric(0.5, { min: 0.0, max: 1.0, step: 0.01 }),
|
|
|
}
|
|
|
-export type RendererProps = typeof DefaultRendererProps
|
|
|
+export type RendererProps = PD.Values<typeof RendererParams>
|
|
|
|
|
|
namespace Renderer {
|
|
|
export function create(ctx: WebGLContext, camera: Camera, props: Partial<RendererProps> = {}): Renderer {
|
|
|
const { gl, state, stats } = ctx
|
|
|
- let { clearColor, viewport: _viewport, pickingAlphaThreshold } = { ...DefaultRendererProps, ...props }
|
|
|
-
|
|
|
- const viewport = Viewport.clone(_viewport)
|
|
|
- const viewportVec4 = Viewport.toVec4(Vec4.zero(), viewport)
|
|
|
+ const p = deepClone({ ...PD.getDefaultValues(RendererParams), ...props })
|
|
|
|
|
|
- // 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 viewport = Viewport()
|
|
|
|
|
|
const view = Mat4.clone(camera.view)
|
|
|
const invView = Mat4.invert(Mat4.identity(), view)
|
|
@@ -93,20 +86,34 @@ namespace Renderer {
|
|
|
|
|
|
uPixelRatio: ValueCell.create(ctx.pixelRatio),
|
|
|
uViewportHeight: ValueCell.create(viewport.height),
|
|
|
- uViewport: ValueCell.create(viewportVec4),
|
|
|
+ uViewport: ValueCell.create(Viewport.toVec4(Vec4(), viewport)),
|
|
|
|
|
|
- uLightColor: ValueCell.create(lightColor),
|
|
|
- uLightAmbient: ValueCell.create(lightAmbient),
|
|
|
+ uLightIntensity: ValueCell.create(p.lightIntensity),
|
|
|
+ uAmbientIntensity: ValueCell.create(p.ambientIntensity),
|
|
|
+
|
|
|
+ uMetalness: ValueCell.create(p.metalness),
|
|
|
+ uRoughness: ValueCell.create(p.roughness),
|
|
|
+ uReflectivity: ValueCell.create(p.reflectivity),
|
|
|
|
|
|
uCameraPosition: ValueCell.create(Vec3.clone(camera.state.position)),
|
|
|
uFogNear: ValueCell.create(camera.state.fogNear),
|
|
|
uFogFar: ValueCell.create(camera.state.fogFar),
|
|
|
- uFogColor: ValueCell.create(fogColor),
|
|
|
+ uFogColor: ValueCell.create(Color.toVec3Normalized(Vec3(), p.backgroundColor)),
|
|
|
|
|
|
- uPickingAlphaThreshold: ValueCell.create(pickingAlphaThreshold),
|
|
|
+ uPickingAlphaThreshold: ValueCell.create(p.pickingAlphaThreshold),
|
|
|
}
|
|
|
const globalUniformList = Object.entries(globalUniforms)
|
|
|
|
|
|
+ const [ bgRed, bgGreen, bgBlue ] = Color.toRgbNormalized(p.backgroundColor)
|
|
|
+ gl.clearColor(bgRed, bgGreen, bgBlue, 1.0)
|
|
|
+
|
|
|
+ if (props.backgroundColor !== undefined && props.backgroundColor !== p.backgroundColor) {
|
|
|
+ p.backgroundColor = props.backgroundColor
|
|
|
+ const [ r, g, b ] = Color.toRgbNormalized(p.backgroundColor)
|
|
|
+ gl.clearColor(r, g, b, 1.0)
|
|
|
+ ValueCell.update(globalUniforms.uFogColor, Vec3.set(globalUniforms.uFogColor.ref.value, r, g, b))
|
|
|
+ }
|
|
|
+
|
|
|
let globalUniformsNeedUpdate = true
|
|
|
const renderObject = (r: Renderable<RenderableValues & BaseValues>, variant: GraphicsRenderVariant) => {
|
|
|
const program = r.getProgram(variant)
|
|
@@ -207,31 +214,59 @@ namespace Renderer {
|
|
|
},
|
|
|
render,
|
|
|
|
|
|
- setClearColor,
|
|
|
- setPickingAlphaThreshold: (value: number) => {
|
|
|
- pickingAlphaThreshold = value
|
|
|
- ValueCell.update(globalUniforms.uPickingAlphaThreshold, pickingAlphaThreshold)
|
|
|
+ setProps: (props: Partial<RendererProps>) => {
|
|
|
+ if (props.pickingAlphaThreshold !== undefined && props.pickingAlphaThreshold !== p.pickingAlphaThreshold) {
|
|
|
+ p.pickingAlphaThreshold = props.pickingAlphaThreshold
|
|
|
+ ValueCell.update(globalUniforms.uPickingAlphaThreshold, p.pickingAlphaThreshold)
|
|
|
+ }
|
|
|
+ if (props.backgroundColor !== undefined && props.backgroundColor !== p.backgroundColor) {
|
|
|
+ p.backgroundColor = props.backgroundColor
|
|
|
+ const [ r, g, b ] = Color.toRgbNormalized(p.backgroundColor)
|
|
|
+ gl.clearColor(r, g, b, 1.0)
|
|
|
+ ValueCell.update(globalUniforms.uFogColor, Vec3.set(globalUniforms.uFogColor.ref.value, r, g, b))
|
|
|
+ }
|
|
|
+ if (props.lightIntensity !== undefined && props.lightIntensity !== p.lightIntensity) {
|
|
|
+ p.lightIntensity = props.lightIntensity
|
|
|
+ ValueCell.update(globalUniforms.uLightIntensity, p.lightIntensity)
|
|
|
+ }
|
|
|
+ if (props.ambientIntensity !== undefined && props.ambientIntensity !== p.ambientIntensity) {
|
|
|
+ p.ambientIntensity = props.ambientIntensity
|
|
|
+ ValueCell.update(globalUniforms.uAmbientIntensity, p.ambientIntensity)
|
|
|
+ }
|
|
|
+
|
|
|
+ if (props.metalness !== undefined && props.metalness !== p.metalness) {
|
|
|
+ p.metalness = props.metalness
|
|
|
+ ValueCell.update(globalUniforms.uMetalness, p.metalness)
|
|
|
+ }
|
|
|
+ if (props.roughness !== undefined && props.roughness !== p.roughness) {
|
|
|
+ p.roughness = props.roughness
|
|
|
+ ValueCell.update(globalUniforms.uRoughness, p.roughness)
|
|
|
+ }
|
|
|
+ if (props.reflectivity !== undefined && props.reflectivity !== p.reflectivity) {
|
|
|
+ p.reflectivity = props.reflectivity
|
|
|
+ ValueCell.update(globalUniforms.uReflectivity, p.reflectivity)
|
|
|
+ }
|
|
|
},
|
|
|
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))
|
|
|
+ if (x !== viewport.x || y !== viewport.y || width !== viewport.width || height !== viewport.height) {
|
|
|
+ Viewport.set(viewport, x, y, width, height)
|
|
|
+ ValueCell.update(globalUniforms.uViewportHeight, height)
|
|
|
+ ValueCell.update(globalUniforms.uViewport, Vec4.set(globalUniforms.uViewport.ref.value, x, y, width, height))
|
|
|
+ }
|
|
|
},
|
|
|
getImageData: () => {
|
|
|
- const { width, height } = viewport
|
|
|
- const buffer = new Uint8Array(width * height * 4)
|
|
|
+ const { x, y, width, height } = viewport
|
|
|
+ const dw = width - x
|
|
|
+ const dh = height - y
|
|
|
+ const buffer = new Uint8Array(dw * dh * 4)
|
|
|
ctx.unbindFramebuffer()
|
|
|
- ctx.readPixels(0, 0, width, height, buffer)
|
|
|
- return createImageData(buffer, width, height)
|
|
|
+ ctx.readPixels(x, y, width, height, buffer)
|
|
|
+ return createImageData(buffer, dw, dh)
|
|
|
},
|
|
|
|
|
|
get props() {
|
|
|
- return {
|
|
|
- clearColor,
|
|
|
- pickingAlphaThreshold,
|
|
|
- viewport
|
|
|
- }
|
|
|
+ return p
|
|
|
},
|
|
|
get stats(): RendererStats {
|
|
|
return {
|