base.ts 7.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163
  1. /**
  2. * Copyright (c) 2018-2022 mol* contributors, licensed under MIT, See LICENSE file for more info.
  3. *
  4. * @author Alexander Rose <alexander.rose@weirdbyte.de>
  5. */
  6. import { RenderableState } from '../../mol-gl/renderable';
  7. import { ValueCell } from '../../mol-util';
  8. import { BaseValues } from '../../mol-gl/renderable/schema';
  9. import { LocationIterator } from '../util/location-iterator';
  10. import { ParamDefinition as PD } from '../../mol-util/param-definition';
  11. import { TransformData, createIdentityTransform } from './transform-data';
  12. import { Theme } from '../../mol-theme/theme';
  13. import { ColorNames } from '../../mol-util/color/names';
  14. import { NullLocation } from '../../mol-model/location';
  15. import { UniformColorTheme } from '../../mol-theme/color/uniform';
  16. import { UniformSizeTheme } from '../../mol-theme/size/uniform';
  17. import { smoothstep } from '../../mol-math/interpolate';
  18. import { Material } from '../../mol-util/material';
  19. import { Clip } from '../../mol-util/clip';
  20. export const VisualQualityInfo = {
  21. 'custom': {},
  22. 'auto': {},
  23. 'highest': {},
  24. 'higher': {},
  25. 'high': {},
  26. 'medium': {},
  27. 'low': {},
  28. 'lower': {},
  29. 'lowest': {},
  30. };
  31. export type VisualQuality = keyof typeof VisualQualityInfo
  32. export const VisualQualityNames = Object.keys(VisualQualityInfo) as VisualQuality[];
  33. export const VisualQualityOptions = PD.arrayToOptions(VisualQualityNames);
  34. //
  35. export const ColorSmoothingParams = {
  36. smoothColors: PD.MappedStatic('auto', {
  37. auto: PD.Group({}),
  38. on: PD.Group({
  39. resolutionFactor: PD.Numeric(2, { min: 0.5, max: 6, step: 0.1 }),
  40. sampleStride: PD.Numeric(3, { min: 1, max: 12, step: 1 }),
  41. }),
  42. off: PD.Group({})
  43. }),
  44. };
  45. export type ColorSmoothingParams = typeof ColorSmoothingParams
  46. export function hasColorSmoothingProp(props: PD.Values<any>): props is PD.Values<ColorSmoothingParams> {
  47. return !!props.smoothColors;
  48. }
  49. export function getColorSmoothingProps(smoothColors: PD.Values<ColorSmoothingParams>['smoothColors'], preferSmoothing?: boolean, resolution?: number) {
  50. if ((smoothColors.name === 'on' || (smoothColors.name === 'auto' && preferSmoothing)) && resolution && resolution < 3) {
  51. let stride = 3;
  52. if (smoothColors.name === 'on') {
  53. resolution *= smoothColors.params.resolutionFactor;
  54. stride = smoothColors.params.sampleStride;
  55. } else {
  56. // https://graphtoy.com/?f1(x,t)=(2-smoothstep(0,1.1,x))*x&coords=0.7,0.6,1.8
  57. resolution *= 2 - smoothstep(0, 1.1, resolution);
  58. resolution = Math.max(0.5, resolution);
  59. if (resolution > 1.2) stride = 2;
  60. }
  61. return { resolution, stride };
  62. };
  63. }
  64. //
  65. export namespace BaseGeometry {
  66. export const MaterialCategory: PD.Info = { category: 'Material' };
  67. export const ShadingCategory: PD.Info = { category: 'Shading' };
  68. export const CustomQualityParamInfo: PD.Info = {
  69. category: 'Custom Quality',
  70. hideIf: (params: PD.Values<Params>) => typeof params.quality !== 'undefined' && params.quality !== 'custom'
  71. };
  72. export const Params = {
  73. alpha: PD.Numeric(1, { min: 0, max: 1, step: 0.01 }, { label: 'Opacity', isEssential: true, description: 'How opaque/transparent the representation is rendered.' }),
  74. quality: PD.Select<VisualQuality>('auto', VisualQualityOptions, { isEssential: true, description: 'Visual/rendering quality of the representation.' }),
  75. material: Material.getParam(),
  76. clip: PD.Group(Clip.Params),
  77. instanceGranularity: PD.Boolean(false, { description: 'Use instance granularity for marker, transparency, clipping, overpaint, substance data to save memory.' }),
  78. };
  79. export type Params = typeof Params
  80. export type Counts = { drawCount: number, vertexCount: number, groupCount: number, instanceCount: number }
  81. export function createSimple(colorValue = ColorNames.grey, sizeValue = 1, transform?: TransformData) {
  82. if (!transform) transform = createIdentityTransform();
  83. const locationIterator = LocationIterator(1, transform.instanceCount.ref.value, 1, () => NullLocation, false, () => false);
  84. const theme: Theme = {
  85. color: UniformColorTheme({}, { value: colorValue, lightness: 0, saturation: 0 }),
  86. size: UniformSizeTheme({}, { value: sizeValue })
  87. };
  88. return { transform, locationIterator, theme };
  89. }
  90. export function createValues(props: PD.Values<Params>, counts: Counts) {
  91. const clip = Clip.getClip(props.clip);
  92. return {
  93. alpha: ValueCell.create(props.alpha),
  94. uAlpha: ValueCell.create(props.alpha),
  95. uVertexCount: ValueCell.create(counts.vertexCount),
  96. uGroupCount: ValueCell.create(counts.groupCount),
  97. drawCount: ValueCell.create(counts.drawCount),
  98. uMetalness: ValueCell.create(props.material.metalness),
  99. uRoughness: ValueCell.create(props.material.roughness),
  100. uBumpiness: ValueCell.create(props.material.bumpiness),
  101. dLightCount: ValueCell.create(1),
  102. dColorMarker: ValueCell.create(true),
  103. dClipObjectCount: ValueCell.create(clip.objects.count),
  104. dClipVariant: ValueCell.create(clip.variant),
  105. uClipObjectType: ValueCell.create(clip.objects.type),
  106. uClipObjectInvert: ValueCell.create(clip.objects.invert),
  107. uClipObjectPosition: ValueCell.create(clip.objects.position),
  108. uClipObjectRotation: ValueCell.create(clip.objects.rotation),
  109. uClipObjectScale: ValueCell.create(clip.objects.scale),
  110. instanceGranularity: ValueCell.create(props.instanceGranularity),
  111. };
  112. }
  113. export function updateValues(values: BaseValues, props: PD.Values<Params>) {
  114. ValueCell.updateIfChanged(values.alpha, props.alpha); // `uAlpha` is set in renderable.render
  115. ValueCell.updateIfChanged(values.uMetalness, props.material.metalness);
  116. ValueCell.updateIfChanged(values.uRoughness, props.material.roughness);
  117. ValueCell.updateIfChanged(values.uBumpiness, props.material.bumpiness);
  118. const clip = Clip.getClip(props.clip);
  119. ValueCell.updateIfChanged(values.dClipObjectCount, clip.objects.count);
  120. ValueCell.updateIfChanged(values.dClipVariant, clip.variant);
  121. ValueCell.update(values.uClipObjectType, clip.objects.type);
  122. ValueCell.update(values.uClipObjectInvert, clip.objects.invert);
  123. ValueCell.update(values.uClipObjectPosition, clip.objects.position);
  124. ValueCell.update(values.uClipObjectRotation, clip.objects.rotation);
  125. ValueCell.update(values.uClipObjectScale, clip.objects.scale);
  126. ValueCell.updateIfChanged(values.instanceGranularity, props.instanceGranularity);
  127. }
  128. export function createRenderableState(props: Partial<PD.Values<Params>> = {}): RenderableState {
  129. const opaque = props.alpha === undefined ? true : props.alpha === 1;
  130. return {
  131. disposed: false,
  132. visible: true,
  133. alphaFactor: 1,
  134. pickable: true,
  135. colorOnly: false,
  136. opaque,
  137. writeDepth: opaque,
  138. };
  139. }
  140. export function updateRenderableState(state: RenderableState, props: PD.Values<Params>) {
  141. state.opaque = props.alpha * state.alphaFactor >= 1;
  142. state.writeDepth = state.opaque;
  143. }
  144. }