diff --git a/src/apps/docking-viewer/viewport.tsx b/src/apps/docking-viewer/viewport.tsx index 2e954753cfd76fd15f1fa0aad1f75b01d7fc1111..35aa2ef00556f68095ab1af91754accd709ae413 100644 --- a/src/apps/docking-viewer/viewport.tsx +++ b/src/apps/docking-viewer/viewport.tsx @@ -26,7 +26,6 @@ function shinyStyle(plugin: PluginContext) { return PluginCommands.Canvas3D.SetSettings(plugin, { settings: { renderer: { ...plugin.canvas3d!.props.renderer, - style: { name: 'plastic', params: {} }, }, postprocessing: { ...plugin.canvas3d!.props.postprocessing, @@ -40,7 +39,6 @@ function occlusionStyle(plugin: PluginContext) { return PluginCommands.Canvas3D.SetSettings(plugin, { settings: { renderer: { ...plugin.canvas3d!.props.renderer, - style: { name: 'flat', params: {} } }, postprocessing: { ...plugin.canvas3d!.props.postprocessing, @@ -94,8 +92,8 @@ export const StructurePreset = StructureRepresentationPresetProvider({ const { update, builder, typeParams } = StructureRepresentationPresetProvider.reprBuilder(plugin, params); const representations = { - ligand: builder.buildRepresentation(update, components.ligand, { type: 'ball-and-stick', typeParams: { ...typeParams, sizeFactor: 0.35 }, color: 'element-symbol', colorParams: { carbonColor: { name: 'element-symbol', params: {} } } }, { tag: 'ligand' }), - polymer: builder.buildRepresentation(update, components.polymer, { type: 'cartoon', typeParams: { ...typeParams }, color: 'chain-id', colorParams: { palette: (plugin.customState as any).colorPalette } }, { tag: 'polymer' }), + ligand: builder.buildRepresentation(update, components.ligand, { type: 'ball-and-stick', typeParams: { ...typeParams, roughness: 0.2, sizeFactor: 0.35 }, color: 'element-symbol', colorParams: { carbonColor: { name: 'element-symbol', params: {} } } }, { tag: 'ligand' }), + polymer: builder.buildRepresentation(update, components.polymer, { type: 'cartoon', typeParams: { ...typeParams, roughness: 0.2 }, color: 'chain-id', colorParams: { palette: (plugin.customState as any).colorPalette } }, { tag: 'polymer' }), }; await update.commit({ revertOnError: true }); @@ -121,8 +119,8 @@ export const IllustrativePreset = StructureRepresentationPresetProvider({ const { update, builder, typeParams } = StructureRepresentationPresetProvider.reprBuilder(plugin, params); const representations = { - ligand: builder.buildRepresentation(update, components.ligand, { type: 'spacefill', typeParams: { ...typeParams }, color: 'element-symbol', colorParams: { carbonColor: { name: 'element-symbol', params: {} } } }, { tag: 'ligand' }), - polymer: builder.buildRepresentation(update, components.polymer, { type: 'spacefill', typeParams: { ...typeParams }, color: 'illustrative', colorParams: { palette: (plugin.customState as any).colorPalette } }, { tag: 'polymer' }), + ligand: builder.buildRepresentation(update, components.ligand, { type: 'spacefill', typeParams: { ...typeParams, ignoreLight: true }, color: 'element-symbol', colorParams: { carbonColor: { name: 'element-symbol', params: {} } } }, { tag: 'ligand' }), + polymer: builder.buildRepresentation(update, components.polymer, { type: 'spacefill', typeParams: { ...typeParams, ignoreLight: true }, color: 'illustrative', colorParams: { palette: (plugin.customState as any).colorPalette } }, { tag: 'polymer' }), }; await update.commit({ revertOnError: true }); @@ -149,8 +147,8 @@ const SurfacePreset = StructureRepresentationPresetProvider({ const { update, builder, typeParams } = StructureRepresentationPresetProvider.reprBuilder(plugin, params); const representations = { - ligand: builder.buildRepresentation(update, components.ligand, { type: 'ball-and-stick', typeParams: { ...typeParams, sizeFactor: 0.26 }, color: 'element-symbol', colorParams: { carbonColor: { name: 'element-symbol', params: {} } } }, { tag: 'ligand' }), - polymer: builder.buildRepresentation(update, components.polymer, { type: 'molecular-surface', typeParams: { ...typeParams, quality: 'custom', resolution: 0.5, doubleSided: true }, color: 'partial-charge' }, { tag: 'polymer' }), + ligand: builder.buildRepresentation(update, components.ligand, { type: 'ball-and-stick', typeParams: { ...typeParams, roughness: 0.2, sizeFactor: 0.26 }, color: 'element-symbol', colorParams: { carbonColor: { name: 'element-symbol', params: {} } } }, { tag: 'ligand' }), + polymer: builder.buildRepresentation(update, components.polymer, { type: 'molecular-surface', typeParams: { ...typeParams, roughness: 0.2, quality: 'custom', resolution: 0.5, doubleSided: true }, color: 'partial-charge' }, { tag: 'polymer' }), }; await update.commit({ revertOnError: true }); @@ -177,8 +175,8 @@ const PocketPreset = StructureRepresentationPresetProvider({ const { update, builder, typeParams } = StructureRepresentationPresetProvider.reprBuilder(plugin, params); const representations = { - ligand: builder.buildRepresentation(update, components.ligand, { type: 'ball-and-stick', typeParams: { ...typeParams, sizeFactor: 0.26 }, color: 'element-symbol', colorParams: { carbonColor: { name: 'element-symbol', params: {} } } }, { tag: 'ligand' }), - surroundings: builder.buildRepresentation(update, components.surroundings, { type: 'molecular-surface', typeParams: { ...typeParams, includeParent: true, quality: 'custom', resolution: 0.2, doubleSided: true }, color: 'partial-charge' }, { tag: 'surroundings' }), + ligand: builder.buildRepresentation(update, components.ligand, { type: 'ball-and-stick', typeParams: { ...typeParams, roughness: 0.2, sizeFactor: 0.26 }, color: 'element-symbol', colorParams: { carbonColor: { name: 'element-symbol', params: {} } } }, { tag: 'ligand' }), + surroundings: builder.buildRepresentation(update, components.surroundings, { type: 'molecular-surface', typeParams: { ...typeParams, roughness: 0.2, includeParent: true, quality: 'custom', resolution: 0.2, doubleSided: true }, color: 'partial-charge' }, { tag: 'surroundings' }), }; await update.commit({ revertOnError: true }); @@ -206,10 +204,10 @@ const InteractionsPreset = StructureRepresentationPresetProvider({ const { update, builder, typeParams } = StructureRepresentationPresetProvider.reprBuilder(plugin, params); const representations = { - ligand: builder.buildRepresentation(update, components.ligand, { type: 'ball-and-stick', typeParams: { ...typeParams, sizeFactor: 0.3 }, color: 'element-symbol', colorParams: { carbonColor: { name: 'element-symbol', params: {} } } }, { tag: 'ligand' }), - ballAndStick: builder.buildRepresentation(update, components.surroundings, { type: 'ball-and-stick', typeParams: { ...typeParams, sizeFactor: 0.1, sizeAspectRatio: 1 }, color: 'element-symbol', colorParams: { carbonColor: { name: 'element-symbol', params: {} } } }, { tag: 'ball-and-stick' }), - interactions: builder.buildRepresentation(update, components.interactions, { type: InteractionsRepresentationProvider, typeParams: { ...typeParams }, color: InteractionTypeColorThemeProvider }, { tag: 'interactions' }), - label: builder.buildRepresentation(update, components.surroundings, { type: 'label', typeParams: { ...typeParams, background: false, borderWidth: 0.1 }, color: 'uniform', colorParams: { value: Color(0x000000) } }, { tag: 'label' }), + ligand: builder.buildRepresentation(update, components.ligand, { type: 'ball-and-stick', typeParams: { ...typeParams, roughness: 0.2, sizeFactor: 0.3 }, color: 'element-symbol', colorParams: { carbonColor: { name: 'element-symbol', params: {} } } }, { tag: 'ligand' }), + ballAndStick: builder.buildRepresentation(update, components.surroundings, { type: 'ball-and-stick', typeParams: { ...typeParams, roughness: 0.2, sizeFactor: 0.1, sizeAspectRatio: 1 }, color: 'element-symbol', colorParams: { carbonColor: { name: 'element-symbol', params: {} } } }, { tag: 'ball-and-stick' }), + interactions: builder.buildRepresentation(update, components.interactions, { type: InteractionsRepresentationProvider, typeParams: { ...typeParams, roughness: 0.2 }, color: InteractionTypeColorThemeProvider }, { tag: 'interactions' }), + label: builder.buildRepresentation(update, components.surroundings, { type: 'label', typeParams: { ...typeParams, roughness: 0.2, background: false, borderWidth: 0.1 }, color: 'uniform', colorParams: { value: Color(0x000000) } }, { tag: 'label' }), }; await update.commit({ revertOnError: true }); diff --git a/src/extensions/geo-export/controls.ts b/src/extensions/geo-export/controls.ts index 90c30ef9a7c5607a7e53eef7434c33b0f1ed7aaa..da1f4aef40c46949bf92cddce7b4509de160e1af 100644 --- a/src/extensions/geo-export/controls.ts +++ b/src/extensions/geo-export/controls.ts @@ -4,7 +4,6 @@ * @author Sukolsak Sakshuwong <sukolsak@stanford.edu> */ -import { getStyle } from '../../mol-gl/renderer'; import { Box3D } from '../../mol-math/geometry'; import { PluginComponent } from '../../mol-plugin-state/component'; import { PluginContext } from '../../mol-plugin/context'; @@ -46,13 +45,12 @@ export class GeometryControls extends PluginComponent { const renderObjects = this.plugin.canvas3d?.getRenderObjects()!; const filename = this.getFilename(); - const style = getStyle(this.plugin.canvas3d?.props.renderer.style!); const boundingSphere = this.plugin.canvas3d?.boundingSphereVisible!; const boundingBox = Box3D.fromSphere3D(Box3D(), boundingSphere); let renderObjectExporter: GlbExporter | ObjExporter | StlExporter | UsdzExporter; switch (this.behaviors.params.value.format) { case 'glb': - renderObjectExporter = new GlbExporter(style, boundingBox); + renderObjectExporter = new GlbExporter(boundingBox); break; case 'obj': renderObjectExporter = new ObjExporter(filename, boundingBox); @@ -61,7 +59,7 @@ export class GeometryControls extends PluginComponent { renderObjectExporter = new StlExporter(boundingBox); break; case 'usdz': - renderObjectExporter = new UsdzExporter(style, boundingBox, boundingSphere.radius); + renderObjectExporter = new UsdzExporter(boundingBox, boundingSphere.radius); break; default: throw new Error('Unsupported format.'); } diff --git a/src/extensions/geo-export/glb-exporter.ts b/src/extensions/geo-export/glb-exporter.ts index 74bca43b05d1919b9fda7b014f5182dabe0152ba..a9ebea606642576c4e33128c28f2849613747cfc 100644 --- a/src/extensions/geo-export/glb-exporter.ts +++ b/src/extensions/geo-export/glb-exporter.ts @@ -2,10 +2,10 @@ * Copyright (c) 2021 mol* contributors, licensed under MIT, See LICENSE file for more info. * * @author Sukolsak Sakshuwong <sukolsak@stanford.edu> + * @author Alexander Rose <alexander.rose@weirdbyte.de> */ import { BaseValues } from '../../mol-gl/renderable/schema'; -import { Style } from '../../mol-gl/renderer'; import { asciiWrite } from '../../mol-io/common/ascii'; import { IsNativeEndianLittle, flipByteOrder } from '../../mol-io/common/binary'; import { Box3D } from '../../mol-math/geometry'; @@ -38,6 +38,8 @@ export class GlbExporter extends MeshExporter<GlbData> { readonly fileExtension = 'glb'; private nodes: Record<string, any>[] = []; private meshes: Record<string, any>[] = []; + private materials: Record<string, any>[] = []; + private materialMap = new Map<string, number>(); private accessors: Record<string, any>[] = []; private bufferViews: Record<string, any>[] = []; private binaryBuffer: ArrayBuffer[] = []; @@ -157,6 +159,21 @@ export class GlbExporter extends MeshExporter<GlbData> { return this.addBuffer(colorBuffer, UNSIGNED_BYTE, 'VEC4', vertexCount, ARRAY_BUFFER, undefined, undefined, true); } + private addMaterial(metalness: number, roughness: number) { + const hash = `${metalness}|${roughness}`; + if (!this.materialMap.has(hash)) { + this.materialMap.set(hash, this.materials.length); + this.materials.push({ + pbrMetallicRoughness: { + baseColorFactor: [1, 1, 1, 1], + metallicFactor: metalness, + roughnessFactor: roughness + } + }); + } + return this.materialMap.get(hash)!; + } + protected async addMeshWithColors(input: AddMeshInput) { const { mesh, values, isGeoTexture, webgl, ctx } = input; @@ -166,6 +183,10 @@ export class GlbExporter extends MeshExporter<GlbData> { const dTransparency = values.dTransparency.ref.value; const aTransform = values.aTransform.ref.value; const instanceCount = values.uInstanceCount.ref.value; + const metalness = values.uMetalness.ref.value; + const roughness = values.uRoughness.ref.value; + + const material = this.addMaterial(metalness, roughness); let interpolatedColors: Uint8Array | undefined; if (colorType === 'volume' || colorType === 'volumeInstance') { @@ -214,7 +235,7 @@ export class GlbExporter extends MeshExporter<GlbData> { COLOR_0: colorAccessorIndex! }, indices: indexAccessorIndex, - material: 0 + material }] }); } @@ -248,13 +269,7 @@ export class GlbExporter extends MeshExporter<GlbData> { }], bufferViews: this.bufferViews, accessors: this.accessors, - materials: [{ - pbrMetallicRoughness: { - baseColorFactor: [1, 1, 1, 1], - metallicFactor: this.style.metalness, - roughnessFactor: this.style.roughness - } - }] + materials: this.materials }; const createChunk = (chunkType: number, data: ArrayBuffer[], byteLength: number, padChar: number): [ArrayBuffer[], number] => { @@ -303,7 +318,7 @@ export class GlbExporter extends MeshExporter<GlbData> { return new Blob([(await this.getData()).glb], { type: 'model/gltf-binary' }); } - constructor(private style: Style, boundingBox: Box3D) { + constructor(boundingBox: Box3D) { super(); const tmpV = Vec3(); Vec3.add(tmpV, boundingBox.min, boundingBox.max); diff --git a/src/extensions/geo-export/usdz-exporter.ts b/src/extensions/geo-export/usdz-exporter.ts index 46a638e2075c553e69e1fa21b14857bc1fd89535..a50621517f51bc855e4718a3a3e6e7f34f6ce67c 100644 --- a/src/extensions/geo-export/usdz-exporter.ts +++ b/src/extensions/geo-export/usdz-exporter.ts @@ -2,9 +2,9 @@ * Copyright (c) 2021 mol* contributors, licensed under MIT, See LICENSE file for more info. * * @author Sukolsak Sakshuwong <sukolsak@stanford.edu> + * @author Alexander Rose <alexander.rose@weirdbyte.de> */ -import { Style } from '../../mol-gl/renderer'; import { asciiWrite } from '../../mol-io/common/ascii'; import { Box3D } from '../../mol-math/geometry'; import { Vec3, Mat3, Mat4 } from '../../mol-math/linear-algebra'; @@ -31,17 +31,16 @@ export class UsdzExporter extends MeshExporter<UsdzData> { readonly fileExtension = 'usdz'; private meshes: string[] = []; private materials: string[] = []; - private materialSet = new Set<number>(); + private materialMap = new Map<string, number>(); private centerTransform: Mat4; - private static getMaterialKey(color: Color, alpha: number) { - return color * 256 + Math.round(alpha * 255); - } + private addMaterial(color: Color, alpha: number, metalness: number, roughness: number): number { + const hash = `${color}|${alpha}|${metalness}|${roughness}`; + if (this.materialMap.has(hash)) return this.materialMap.get(hash)!; + + const materialKey = this.materialMap.size; + this.materialMap.set(hash, materialKey); - private addMaterial(color: Color, alpha: number) { - const materialKey = UsdzExporter.getMaterialKey(color, alpha); - if (this.materialSet.has(materialKey)) return; - this.materialSet.add(materialKey); const [r, g, b] = Color.toRgbNormalized(color); this.materials.push(` def Material "material${materialKey}" @@ -52,12 +51,13 @@ def Material "material${materialKey}" uniform token info:id = "UsdPreviewSurface" color3f inputs:diffuseColor = (${r},${g},${b}) float inputs:opacity = ${alpha} - float inputs:metallic = ${this.style.metalness} - float inputs:roughness = ${this.style.roughness} + float inputs:metallic = ${metalness} + float inputs:roughness = ${roughness} token outputs:surface } } `); + return materialKey; } protected async addMeshWithColors(input: AddMeshInput) { @@ -75,6 +75,8 @@ def Material "material${materialKey}" const tTransparency = values.tTransparency.ref.value; const aTransform = values.aTransform.ref.value; const instanceCount = values.uInstanceCount.ref.value; + const metalness = values.uMetalness.ref.value; + const roughness = values.uRoughness.ref.value; let interpolatedColors: Uint8Array | undefined; if (colorType === 'volume' || colorType === 'volumeInstance') { @@ -141,9 +143,7 @@ def Material "material${materialKey}" alpha *= 1 - transparency; } - this.addMaterial(color, alpha); - - const materialKey = UsdzExporter.getMaterialKey(color, alpha); + const materialKey = this.addMaterial(color, alpha, metalness, roughness); let faceIndices = faceIndicesByMaterial.get(materialKey); if (faceIndices === undefined) { faceIndices = []; @@ -215,7 +215,7 @@ def Mesh "mesh${this.meshes.length}" return new Blob([usdz], { type: 'model/vnd.usdz+zip' }); } - constructor(private style: Style, boundingBox: Box3D, radius: number) { + constructor(boundingBox: Box3D, radius: number) { super(); const t = Mat4(); // scale the model so that it fits within 1 meter diff --git a/src/mol-geo/geometry/base.ts b/src/mol-geo/geometry/base.ts index c9364acccf82581c0f92f3317bb47ea63466becf..6ae9113ff920c7946983b3f3156a7f68c4785ce2 100644 --- a/src/mol-geo/geometry/base.ts +++ b/src/mol-geo/geometry/base.ts @@ -1,5 +1,5 @@ /** - * Copyright (c) 2018 mol* contributors, licensed under MIT, See LICENSE file for more info. + * Copyright (c) 2018-2021 mol* contributors, licensed under MIT, See LICENSE file for more info. * * @author Alexander Rose <alexander.rose@weirdbyte.de> */ @@ -34,18 +34,21 @@ export const VisualQualityOptions = PD.arrayToOptions(VisualQualityNames); // export namespace BaseGeometry { - export const Params = { - alpha: PD.Numeric(1, { min: 0, max: 1, step: 0.01 }, { label: 'Opacity', isEssential: true, description: 'How opaque/transparent the representation is rendered.' }), - quality: PD.Select<VisualQuality>('auto', VisualQualityOptions, { isEssential: true, description: 'Visual/rendering quality of the representation.' }), - }; - export type Params = typeof Params - + export const MaterialCategory: PD.Info = { category: 'Material' }; export const ShadingCategory: PD.Info = { category: 'Shading' }; export const CustomQualityParamInfo: PD.Info = { category: 'Custom Quality', hideIf: (params: PD.Values<Params>) => typeof params.quality !== 'undefined' && params.quality !== 'custom' }; + export const Params = { + alpha: PD.Numeric(1, { min: 0, max: 1, step: 0.01 }, { label: 'Opacity', isEssential: true, description: 'How opaque/transparent the representation is rendered.' }), + quality: PD.Select<VisualQuality>('auto', VisualQualityOptions, { isEssential: true, description: 'Visual/rendering quality of the representation.' }), + metalness: PD.Numeric(0.0, { min: 0.0, max: 1.0, step: 0.01 }, MaterialCategory), + roughness: PD.Numeric(1.0, { min: 0.0, max: 1.0, step: 0.01 }, MaterialCategory), + }; + export type Params = typeof Params + export type Counts = { drawCount: number, vertexCount: number, groupCount: number, instanceCount: number } export function createSimple(colorValue = ColorNames.grey, sizeValue = 1, transform?: TransformData) { @@ -65,11 +68,16 @@ export namespace BaseGeometry { uVertexCount: ValueCell.create(counts.vertexCount), uGroupCount: ValueCell.create(counts.groupCount), drawCount: ValueCell.create(counts.drawCount), + uMetalness: ValueCell.create(props.metalness), + uRoughness: ValueCell.create(props.roughness), + dLightCount: ValueCell.create(1), }; } export function updateValues(values: BaseValues, props: PD.Values<Params>) { ValueCell.updateIfChanged(values.alpha, props.alpha); // `uAlpha` is set in renderable.render + ValueCell.updateIfChanged(values.uMetalness, props.metalness); + ValueCell.updateIfChanged(values.uRoughness, props.roughness); } export function createRenderableState(props: Partial<PD.Values<Params>> = {}): RenderableState { diff --git a/src/mol-gl/_spec/renderer.spec.ts b/src/mol-gl/_spec/renderer.spec.ts index c07e61bc5a9d490ba34cae3e20a6f04188af0ee1..8a28ce6285c645783b0a0482308694064008b499 100644 --- a/src/mol-gl/_spec/renderer.spec.ts +++ b/src/mol-gl/_spec/renderer.spec.ts @@ -73,6 +73,9 @@ function createPoints() { uGroupCount: ValueCell.create(3), uInvariantBoundingSphere: ValueCell.create(Vec4.ofSphere(invariantBoundingSphere.ref.value)), + uMetalness: ValueCell.create(0.0), + uRoughness: ValueCell.create(1.0), + alpha: ValueCell.create(1.0), drawCount: ValueCell.create(3), instanceCount: ValueCell.create(1), @@ -86,6 +89,8 @@ function createPoints() { uSizeFactor: ValueCell.create(1), dPointSizeAttenuation: ValueCell.create(true), dPointStyle: ValueCell.create('square'), + + dLightCount: ValueCell.create(1), }; const state: RenderableState = { disposed: false, diff --git a/src/mol-gl/renderable/schema.ts b/src/mol-gl/renderable/schema.ts index 11e8fe217a9f9b35f43cf5c15fbab5ac505d7f77..33d1726bc74ebc17c59c9b45166f3caacd141e81 100644 --- a/src/mol-gl/renderable/schema.ts +++ b/src/mol-gl/renderable/schema.ts @@ -141,17 +141,10 @@ export const GlobalUniformSchema = { uClipObjectRotation: UniformSpec('v4[]'), uClipObjectScale: UniformSpec('v3[]'), - uLightDirection: UniformSpec('v3'), - uLightColor: UniformSpec('v3'), + uLightDirection: UniformSpec('v3[]'), + uLightColor: UniformSpec('v3[]'), uAmbientColor: UniformSpec('v3'), - // all the following could in principle be per object - // as a kind of 'material' parameter set - // would need to test performance implications - uMetalness: UniformSpec('f'), - uRoughness: UniformSpec('f'), - uReflectivity: UniformSpec('f'), - uPickingAlphaThreshold: UniformSpec('f'), uInteriorDarkening: UniformSpec('f'), @@ -249,12 +242,22 @@ export const ClippingSchema = { export type ClippingSchema = typeof ClippingSchema export type ClippingValues = Values<ClippingSchema> +export const MaterialSchema = { + uMetalness: UniformSpec('f'), + uRoughness: UniformSpec('f'), +} as const; +export type MaterialSchema = typeof MaterialSchema +export type MaterialValues = Values<MaterialSchema> + export const BaseSchema = { ...ColorSchema, ...MarkerSchema, ...OverpaintSchema, ...TransparencySchema, ...ClippingSchema, + ...MaterialSchema, + + dLightCount: DefineSpec('number'), aInstance: AttributeSpec('float32', 1, 1), /** diff --git a/src/mol-gl/renderer.ts b/src/mol-gl/renderer.ts index 01df14c7ad41c26695549328c807a8413725e7c8..ce3c3bc034d14be2a56bb7f84c995afea2fdf067 100644 --- a/src/mol-gl/renderer.ts +++ b/src/mol-gl/renderer.ts @@ -70,7 +70,6 @@ interface Renderer { export const RendererParams = { backgroundColor: PD.Color(Color(0x000000), { description: 'Background color of the 3D canvas' }), - // the following are general 'material' parameters 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.' }), interiorDarkening: PD.Numeric(0.5, { min: 0.0, max: 1.0, step: 0.01 }), @@ -85,25 +84,19 @@ export const RendererParams = { xrayEdgeFalloff: PD.Numeric(1, { min: 0.0, max: 3.0, step: 0.1 }), - lightInclination: PD.Numeric(180, { min: 0, max: 180, step: 1 }), - lightAzimuth: PD.Numeric(0, { min: 0, max: 360, step: 1 }), - lightColor: PD.Color(Color.fromNormalizedRgb(1.0, 1.0, 1.0)), + light: PD.ObjectList({ + inclination: PD.Numeric(180, { min: 0, max: 180, step: 1 }), + azimuth: PD.Numeric(0, { min: 0, max: 360, step: 1 }), + color: PD.Color(Color.fromNormalizedRgb(1.0, 1.0, 1.0)), + intensity: PD.Numeric(0.6, { min: 0.0, max: 1.0, step: 0.01 }), + }, o => Color.toHexString(o.color), { defaultValue: [{ + inclination: 180, + azimuth: 0, + color: Color.fromNormalizedRgb(1.0, 1.0, 1.0), + intensity: 0.6 + }] }), ambientColor: PD.Color(Color.fromNormalizedRgb(1.0, 1.0, 1.0)), - - style: PD.MappedStatic('matte', { - custom: PD.Group({ - lightIntensity: PD.Numeric(0.6, { 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(1.0, { min: 0.0, max: 1.0, step: 0.01 }), - reflectivity: PD.Numeric(0.5, { min: 0.0, max: 1.0, step: 0.01 }), - }, { isExpanded: true }), - flat: PD.Group({}), - matte: PD.Group({}), - glossy: PD.Group({}), - metallic: PD.Group({}), - plastic: PD.Group({}), - }, { label: 'Lighting', description: 'Style in which the 3D scene is rendered/lighted' }), + ambientIntensity: PD.Numeric(0.4, { min: 0.0, max: 1.0, step: 0.01 }), clip: PD.Group({ variant: PD.Select('instance', PD.arrayToOptions<Clipping.Variant>(['instance', 'pixel'])), @@ -121,44 +114,27 @@ export const RendererParams = { }; export type RendererProps = PD.Values<typeof RendererParams> -export type Style = { - lightIntensity: number - ambientIntensity: number - metalness: number - roughness: number - reflectivity: number +type Light = { + count: number + direction: number[] + color: number[] } -export function getStyle(props: RendererProps['style']): Style { - switch (props.name) { - case 'custom': - return props.params as Style; - case 'flat': - return { - lightIntensity: 0, ambientIntensity: 1, - metalness: 0, roughness: 0.4, reflectivity: 0.5 - }; - case 'matte': - return { - lightIntensity: 0.7, ambientIntensity: 0.3, - metalness: 0, roughness: 1, reflectivity: 0.5 - }; - case 'glossy': - return { - lightIntensity: 0.7, ambientIntensity: 0.3, - metalness: 0, roughness: 0.4, reflectivity: 0.5 - }; - case 'metallic': - return { - lightIntensity: 0.7, ambientIntensity: 0.7, - metalness: 0.6, roughness: 0.6, reflectivity: 0.5 - }; - case 'plastic': - return { - lightIntensity: 0.7, ambientIntensity: 0.3, - metalness: 0, roughness: 0.2, reflectivity: 0.5 - }; +const tmpDir = Vec3(); +const tmpColor = Vec3(); +function getLight(props: RendererProps['light'], light?: Light): Light { + const { direction, color } = light || { + direction: (new Array(5 * 3)).fill(0), + color: (new Array(5 * 3)).fill(0), + }; + for (let i = 0, il = props.length; i < il; ++i) { + const p = props[i]; + Vec3.directionFromSpherical(tmpDir, degToRad(p.inclination), degToRad(p.azimuth), 1); + Vec3.toArray(tmpDir, direction, i * 3); + Vec3.scale(tmpColor, Color.toVec3Normalized(tmpColor, p.color), p.intensity); + Vec3.toArray(tmpColor, color, i * 3); } + return { count: props.length, direction, color }; } type Clip = { @@ -200,7 +176,7 @@ namespace Renderer { export function create(ctx: WebGLContext, props: Partial<RendererProps> = {}): Renderer { const { gl, state, stats, extensions: { fragDepth } } = ctx; const p = PD.merge(RendererParams, PD.getDefaultValues(RendererParams), props); - const style = getStyle(p.style); + const light = getLight(p.light); const clip = getClip(p.clip); const viewport = Viewport(); @@ -225,13 +201,8 @@ namespace Renderer { const cameraDir = Vec3(); const viewOffset = Vec2(); - const lightDirection = Vec3(); - Vec3.directionFromSpherical(lightDirection, degToRad(p.lightInclination), degToRad(p.lightAzimuth), 1); - - const lightColor = Color.toVec3Normalized(Vec3(), p.lightColor); - Vec3.scale(lightColor, lightColor, style.lightIntensity); - const ambientColor = Color.toVec3Normalized(Vec3(), p.ambientColor); - Vec3.scale(ambientColor, ambientColor, style.ambientIntensity); + const ambientColor = Vec3(); + Vec3.scale(ambientColor, Color.toArrayNormalized(p.ambientColor, ambientColor, 0), p.ambientIntensity); const globalUniforms: GlobalUniformValues = { uModel: ValueCell.create(Mat4.identity()), @@ -270,15 +241,10 @@ namespace Renderer { uClipObjectRotation: ValueCell.create(clip.objects.rotation), uClipObjectScale: ValueCell.create(clip.objects.scale), - uLightDirection: ValueCell.create(lightDirection), - uLightColor: ValueCell.create(lightColor), + uLightDirection: ValueCell.create(light.direction), + uLightColor: ValueCell.create(light.color), uAmbientColor: ValueCell.create(ambientColor), - // the following 3 are general 'material' uniforms - uMetalness: ValueCell.create(style.metalness), - uRoughness: ValueCell.create(style.roughness), - uReflectivity: ValueCell.create(style.reflectivity), - uPickingAlphaThreshold: ValueCell.create(p.pickingAlphaThreshold), uInteriorDarkening: ValueCell.create(p.interiorDarkening), @@ -318,6 +284,10 @@ namespace Renderer { definesNeedUpdate = true; } } + if (r.values.dLightCount.ref.value !== light.count) { + ValueCell.update(r.values.dLightCount, light.count); + definesNeedUpdate = true; + } if (definesNeedUpdate) r.update(); const program = r.getProgram(variant); @@ -696,44 +666,21 @@ namespace Renderer { ValueCell.update(globalUniforms.uXrayEdgeFalloff, p.xrayEdgeFalloff); } - if (props.lightInclination !== undefined && props.lightInclination !== p.lightInclination) { - p.lightInclination = props.lightInclination; - Vec3.directionFromSpherical(lightDirection, degToRad(p.lightInclination), degToRad(p.lightAzimuth), 1); - ValueCell.update(globalUniforms.uLightDirection, lightDirection); - } - if (props.lightAzimuth !== undefined && props.lightAzimuth !== p.lightAzimuth) { - p.lightAzimuth = props.lightAzimuth; - Vec3.directionFromSpherical(lightDirection, degToRad(p.lightInclination), degToRad(p.lightAzimuth), 1); - ValueCell.update(globalUniforms.uLightDirection, lightDirection); - } - - if (props.lightColor !== undefined && props.lightColor !== p.lightColor) { - p.lightColor = props.lightColor; - Color.toVec3Normalized(lightColor, p.lightColor); - Vec3.scale(lightColor, lightColor, style.lightIntensity); - ValueCell.update(globalUniforms.uLightColor, lightColor); + if (props.light !== undefined && !deepEqual(props.light, p.light)) { + p.light = props.light; + Object.assign(light, getLight(props.light, light)); + ValueCell.update(globalUniforms.uLightDirection, light.direction); + ValueCell.update(globalUniforms.uLightColor, light.color); } if (props.ambientColor !== undefined && props.ambientColor !== p.ambientColor) { p.ambientColor = props.ambientColor; - Color.toVec3Normalized(ambientColor, p.ambientColor); - Vec3.scale(ambientColor, ambientColor, style.ambientIntensity); + Vec3.scale(ambientColor, Color.toArrayNormalized(p.ambientColor, ambientColor, 0), p.ambientIntensity); ValueCell.update(globalUniforms.uAmbientColor, ambientColor); } - - if (props.style !== undefined) { - p.style = props.style; - Object.assign(style, getStyle(props.style)); - - Color.toVec3Normalized(lightColor, p.lightColor); - Vec3.scale(lightColor, lightColor, style.lightIntensity); - ValueCell.update(globalUniforms.uLightColor, lightColor); - Color.toVec3Normalized(ambientColor, p.ambientColor); - Vec3.scale(ambientColor, ambientColor, style.ambientIntensity); + if (props.ambientIntensity !== undefined && props.ambientIntensity !== p.ambientIntensity) { + p.ambientIntensity = props.ambientIntensity; + Vec3.scale(ambientColor, Color.toArrayNormalized(p.ambientColor, ambientColor, 0), p.ambientIntensity); ValueCell.update(globalUniforms.uAmbientColor, ambientColor); - - ValueCell.updateIfChanged(globalUniforms.uMetalness, style.metalness); - ValueCell.updateIfChanged(globalUniforms.uRoughness, style.roughness); - ValueCell.updateIfChanged(globalUniforms.uReflectivity, style.reflectivity); } if (props.clip !== undefined && !deepEqual(props.clip, p.clip)) { diff --git a/src/mol-gl/shader-code.ts b/src/mol-gl/shader-code.ts index c18e2f12eca6e8a926f4389c92ec3e3957d59faa..2402d9782df99a95c07f70823fc555cc153d4926 100644 --- a/src/mol-gl/shader-code.ts +++ b/src/mol-gl/shader-code.ts @@ -134,6 +134,7 @@ function loopReplacer(match: string, start: string, end: string, snippet: string } function replaceCounts(str: string, defines: ShaderDefines) { + if (defines.dLightCount) str = str.replace(/dLightCount/g, `${defines.dLightCount.ref.value}`); if (defines.dClipObjectCount) str = str.replace(/dClipObjectCount/g, `${defines.dClipObjectCount.ref.value}`); return str; } diff --git a/src/mol-gl/shader/chunks/apply-light-color.glsl.ts b/src/mol-gl/shader/chunks/apply-light-color.glsl.ts index 29b0f1f3f2e1a91c0dd4de9666e36069c183c3cd..c648194ef18e150f98b73d7fa7b3bf5a8ee6d0ec 100644 --- a/src/mol-gl/shader/chunks/apply-light-color.glsl.ts +++ b/src/mol-gl/shader/chunks/apply-light-color.glsl.ts @@ -4,7 +4,7 @@ * @author Alexander Rose <alexander.rose@weirdbyte.de> * * adapted from three.js (https://github.com/mrdoob/three.js/) - * which under the MIT License, Copyright © 2010-2019 three.js authors + * which under the MIT License, Copyright © 2010-2021 three.js authors */ export const apply_light_color = ` @@ -14,21 +14,25 @@ export const apply_light_color = ` // - vec3 normal // - float uMetalness // - float uRoughness -// - float uReflectivity -// - float uLightIntensity -// - float uAmbientIntensity +// - vec3 uLightColor +// - vec3 uAmbientColor // outputs // - sets gl_FragColor vec4 color = material; -ReflectedLight reflectedLight = ReflectedLight(vec3(0.0), vec3(0.0), vec3(0.0)); +ReflectedLight reflectedLight = ReflectedLight(vec3(0.0), vec3(0.0), vec3(0.0), vec3(0.0)); PhysicalMaterial physicalMaterial; physicalMaterial.diffuseColor = color.rgb * (1.0 - uMetalness); -physicalMaterial.specularRoughness = clamp(uRoughness, 0.04, 1.0); -physicalMaterial.specularColor = mix(vec3(0.16 * pow2(uReflectivity)), color.rgb, uMetalness); +vec3 dxy = max(abs(dFdx(normal)), abs(dFdy(normal))); +float geometryRoughness = max(max(dxy.x, dxy.y), dxy.z); +physicalMaterial.roughness = max(uRoughness, 0.0525); +physicalMaterial.roughness += geometryRoughness; +physicalMaterial.roughness = min(physicalMaterial.roughness, 1.0); +physicalMaterial.specularColor = mix(vec3( 0.04 ), color.rgb, uMetalness); +physicalMaterial.specularF90 = 1.0; GeometricContext geometry; geometry.position = -vViewPosition; @@ -36,15 +40,24 @@ geometry.normal = normal; geometry.viewDir = normalize(vViewPosition); IncidentLight directLight; -directLight.direction = uLightDirection; -directLight.color = uLightColor; +#pragma unroll_loop_start +for (int i = 0; i < dLightCount; ++i) { + directLight.direction = normalize(uLightDirection[i]); + directLight.color = uLightColor[i] * PI; // * PI for punctual light + RE_Direct_Physical(directLight, geometry, physicalMaterial, reflectedLight); +} +#pragma unroll_loop_end -RE_Direct_Physical(directLight, geometry, physicalMaterial, reflectedLight); - -vec3 irradiance = uAmbientColor * PI; +vec3 irradiance = uAmbientColor * PI; // * PI for punctual light RE_IndirectDiffuse_Physical(irradiance, geometry, physicalMaterial, reflectedLight); -vec3 outgoingLight = reflectedLight.directDiffuse + reflectedLight.indirectDiffuse + reflectedLight.directSpecular; +// indirect specular only metals +vec3 radiance = uAmbientColor * uMetalness; +vec3 iblIrradiance = uAmbientColor * uMetalness; +vec3 clearcoatRadiance = vec3(0.0); +RE_IndirectSpecular_Physical(radiance, iblIrradiance, clearcoatRadiance, geometry, physicalMaterial, reflectedLight); + +vec3 outgoingLight = reflectedLight.directDiffuse + reflectedLight.indirectDiffuse + reflectedLight.directSpecular + reflectedLight.indirectSpecular; gl_FragColor = vec4(outgoingLight, color.a); diff --git a/src/mol-gl/shader/chunks/light-frag-params.glsl.ts b/src/mol-gl/shader/chunks/light-frag-params.glsl.ts index dad65065a7fbdee525de03cefed080b9418214e2..2a98598937e43bb41476fbc80babcf61dbc6d5ee 100644 --- a/src/mol-gl/shader/chunks/light-frag-params.glsl.ts +++ b/src/mol-gl/shader/chunks/light-frag-params.glsl.ts @@ -4,12 +4,12 @@ * @author Alexander Rose <alexander.rose@weirdbyte.de> * * adapted from three.js (https://github.com/mrdoob/three.js/) - * which under the MIT License, Copyright © 2010-2019 three.js authors + * which under the MIT License, Copyright © 2010-2021 three.js authors */ export const light_frag_params = ` -uniform vec3 uLightDirection; -uniform vec3 uLightColor; +uniform vec3 uLightDirection[dLightCount]; +uniform vec3 uLightColor[dLightCount]; uniform vec3 uAmbientColor; uniform float uReflectivity; @@ -18,8 +18,9 @@ uniform float uRoughness; struct PhysicalMaterial { vec3 diffuseColor; - float specularRoughness; + float roughness; vec3 specularColor; + float specularF90; }; struct IncidentLight { @@ -31,6 +32,7 @@ struct ReflectedLight { vec3 directDiffuse; vec3 directSpecular; vec3 indirectDiffuse; + vec3 indirectSpecular; }; struct GeometricContext { @@ -39,20 +41,23 @@ struct GeometricContext { vec3 viewDir; }; -vec3 F_Schlick(const in vec3 specularColor, const in float dotLH) { +vec3 BRDF_Lambert(const in vec3 diffuseColor) { + return RECIPROCAL_PI * diffuseColor; +} + +vec3 F_Schlick(const in vec3 f0, const in float f90, const in float dotVH) { // Original approximation by Christophe Schlick '94 - // float fresnel = pow( 1.0 - dotLH, 5.0 ); + // float fresnel = pow( 1.0 - dotVH, 5.0 ); // Optimized variant (presented by Epic at SIGGRAPH '13) // https://cdn2.unrealengine.com/Resources/files/2013SiggraphPresentationsNotes-26915738.pdf - float fresnel = exp2((-5.55473 * dotLH - 6.98316) * dotLH); - return (1.0 - specularColor) * fresnel + specularColor; + float fresnel = exp2((-5.55473 * dotVH - 6.98316) * dotVH); + return f0 * (1.0 - fresnel) + (f90 * fresnel); } // Moving Frostbite to Physically Based Rendering 3.0 - page 12, listing 2 // https://seblagarde.files.wordpress.com/2015/07/course_notes_moving_frostbite_to_pbr_v32.pdf -float G_GGX_SmithCorrelated(const in float alpha, const in float dotNL, const in float dotNV) { +float V_GGX_SmithCorrelated(const in float alpha, const in float dotNL, const in float dotNV) { float a2 = pow2(alpha); - // dotNL and dotNV are explicitly swapped. This is not a mistake. float gv = dotNL * sqrt(a2 + (1.0 - a2) * pow2(dotNV)); float gl = dotNV * sqrt(a2 + (1.0 - a2) * pow2(dotNL)); return 0.5 / max(gv + gl, EPSILON); @@ -67,47 +72,68 @@ float D_GGX(const in float alpha, const in float dotNH) { return RECIPROCAL_PI * a2 / pow2(denom); } -vec3 BRDF_Diffuse_Lambert(const in vec3 diffuseColor) { - return RECIPROCAL_PI * diffuseColor; -} - -// GGX Distribution, Schlick Fresnel, GGX-Smith Visibility -vec3 BRDF_Specular_GGX(const in IncidentLight incidentLight, const in GeometricContext geometry, const in vec3 specularColor, const in float roughness) { +// GGX Distribution, Schlick Fresnel, GGX_SmithCorrelated Visibility +vec3 BRDF_GGX(const in vec3 lightDir, const in vec3 viewDir, const in vec3 normal, const in vec3 f0, const in float f90, const in float roughness) { float alpha = pow2(roughness); // UE4's roughness - vec3 halfDir = normalize(incidentLight.direction + geometry.viewDir); - - float dotNL = saturate(dot(geometry.normal, incidentLight.direction)); - float dotNV = saturate(dot(geometry.normal, geometry.viewDir)); - float dotNH = saturate(dot(geometry.normal, halfDir)); - float dotLH = saturate(dot(incidentLight.direction, halfDir)); - - vec3 F = F_Schlick(specularColor, dotLH); - float G = G_GGX_SmithCorrelated(alpha, dotNL, dotNV); + vec3 halfDir = normalize( lightDir + viewDir); + float dotNL = saturate(dot(normal, lightDir)); + float dotNV = saturate(dot(normal, viewDir)); + float dotNH = saturate(dot(normal, halfDir)); + float dotVH = saturate(dot(viewDir, halfDir)); + vec3 F = F_Schlick(f0, f90, dotVH); + float V = V_GGX_SmithCorrelated(alpha, dotNL, dotNV); float D = D_GGX(alpha, dotNH); - return F * (G * D); + return F * (V * D); } -// ref: https://www.unrealengine.com/blog/physically-based-shading-on-mobile - environmentBRDF for GGX on mobile -vec3 BRDF_Specular_GGX_Environment(const in GeometricContext geometry, const in vec3 specularColor, const in float roughness) { - float dotNV = saturate(dot(geometry.normal, geometry.viewDir)); +// Analytical approximation of the DFG LUT, one half of the +// split-sum approximation used in indirect specular lighting. +// via 'environmentBRDF' from "Physically Based Shading on Mobile" +// https://www.unrealengine.com/blog/physically-based-shading-on-mobile +vec2 DFGApprox(const in vec3 normal, const in vec3 viewDir, const in float roughness) { + float dotNV = saturate(dot(normal, viewDir)); const vec4 c0 = vec4(-1, -0.0275, -0.572, 0.022); const vec4 c1 = vec4(1, 0.0425, 1.04, -0.04); vec4 r = roughness * c0 + c1; float a004 = min(r.x * r.x, exp2(-9.28 * dotNV)) * r.x + r.y; - vec2 AB = vec2(-1.04, 1.04) * a004 + r.zw; - return specularColor * AB.x + AB.y; + vec2 fab = vec2(-1.04, 1.04) * a004 + r.zw; + return fab; +} + +// Fdez-Agüera's "Multiple-Scattering Microfacet Model for Real-Time Image Based Lighting" +// Approximates multiscattering in order to preserve energy. +// http://www.jcgt.org/published/0008/01/03/ +void computeMultiscattering(const in vec3 normal, const in vec3 viewDir, const in vec3 specularColor, const in float specularF90, const in float roughness, inout vec3 singleScatter, inout vec3 multiScatter) { + vec2 fab = DFGApprox(normal, viewDir, roughness); + vec3 FssEss = specularColor * fab.x + specularF90 * fab.y; + float Ess = fab.x + fab.y; + float Ems = 1.0 - Ess; + vec3 Favg = specularColor + (1.0 - specularColor) * 0.047619; // 1/21 + vec3 Fms = FssEss * Favg / (1.0 - Ems * Favg); + singleScatter += FssEss; + multiScatter += Fms * Ems; } void RE_Direct_Physical(const in IncidentLight directLight, const in GeometricContext geometry, const in PhysicalMaterial material, inout ReflectedLight reflectedLight) { float dotNL = saturate(dot(geometry.normal, directLight.direction)); vec3 irradiance = dotNL * directLight.color; - irradiance *= PI; // punctual light - - reflectedLight.directSpecular += irradiance * BRDF_Specular_GGX(directLight, geometry, material.specularColor, material.specularRoughness); - reflectedLight.directDiffuse += irradiance * BRDF_Diffuse_Lambert(material.diffuseColor); + reflectedLight.directSpecular += irradiance * BRDF_GGX(directLight.direction, geometry.viewDir, geometry.normal, material.specularColor, material.specularF90, material.roughness); + reflectedLight.directDiffuse += irradiance * BRDF_Lambert(material.diffuseColor); } void RE_IndirectDiffuse_Physical(const in vec3 irradiance, const in GeometricContext geometry, const in PhysicalMaterial material, inout ReflectedLight reflectedLight) { - reflectedLight.indirectDiffuse += irradiance * BRDF_Diffuse_Lambert(material.diffuseColor); + reflectedLight.indirectDiffuse += irradiance * BRDF_Lambert(material.diffuseColor); +} + +void RE_IndirectSpecular_Physical( const in vec3 radiance, const in vec3 irradiance, const in vec3 clearcoatRadiance, const in GeometricContext geometry, const in PhysicalMaterial material, inout ReflectedLight reflectedLight) { + // Both indirect specular and indirect diffuse light accumulate here + vec3 singleScattering = vec3(0.0); + vec3 multiScattering = vec3(0.0); + vec3 cosineWeightedIrradiance = irradiance * RECIPROCAL_PI; + computeMultiscattering(geometry.normal, geometry.viewDir, material.specularColor, material.specularF90, material.roughness, singleScattering, multiScattering); + vec3 diffuse = material.diffuseColor * (1.0 - ( singleScattering + multiScattering)); + reflectedLight.indirectSpecular += radiance * singleScattering; + reflectedLight.indirectSpecular += multiScattering * cosineWeightedIrradiance; + reflectedLight.indirectDiffuse += diffuse * cosineWeightedIrradiance; } `; \ No newline at end of file diff --git a/src/mol-plugin-ui/viewport/simple-settings.tsx b/src/mol-plugin-ui/viewport/simple-settings.tsx index 60d9b4412409388b8926185920f8d1588e6e3cf3..369be53db09802babd5d5bda894f4b5db6478ea9 100644 --- a/src/mol-plugin-ui/viewport/simple-settings.tsx +++ b/src/mol-plugin-ui/viewport/simple-settings.tsx @@ -55,12 +55,9 @@ const SimpleSettingsParams = { color: PD.Color(Color(0xFCFBF9), { label: 'Background', description: 'Custom background color' }), transparent: PD.Boolean(false) }, { pivot: 'color' }), - lighting: PD.Group({ - renderStyle: Canvas3DParams.renderer.params.style, - occlusion: Canvas3DParams.postprocessing.params.occlusion, - outline: Canvas3DParams.postprocessing.params.outline, - fog: Canvas3DParams.cameraFog, - }, { pivot: 'renderStyle' }), + occlusion: Canvas3DParams.postprocessing.params.occlusion, + outline: Canvas3DParams.postprocessing.params.outline, + fog: Canvas3DParams.cameraFog, clipping: PD.Group<any>({ ...Canvas3DParams.cameraClipping.params, ...(Canvas3DParams.renderer.params.clip as any).params as any @@ -104,12 +101,9 @@ const SimpleSettingsMapping = ParamMapping({ color: renderer.backgroundColor, transparent: canvas.transparentBackground }, - lighting: { - renderStyle: renderer.style, - occlusion: canvas.postprocessing.occlusion, - outline: canvas.postprocessing.outline, - fog: canvas.cameraFog - }, + occlusion: canvas.postprocessing.occlusion, + outline: canvas.postprocessing.outline, + fog: canvas.cameraFog, clipping: { ...canvas.cameraClipping, ...canvas.renderer.clip @@ -123,10 +117,9 @@ const SimpleSettingsMapping = ParamMapping({ canvas.camera = s.camera; canvas.transparentBackground = s.background.transparent; canvas.renderer.backgroundColor = s.background.color; - canvas.renderer.style = s.lighting.renderStyle; - canvas.postprocessing.occlusion = s.lighting.occlusion; - canvas.postprocessing.outline = s.lighting.outline; - canvas.cameraFog = s.lighting.fog; + canvas.postprocessing.occlusion = s.occlusion; + canvas.postprocessing.outline = s.outline; + canvas.cameraFog = s.fog; canvas.cameraClipping = { radius: s.clipping.radius, far: s.clipping.far,