@itwin/core-frontend
Version:
iTwin.js frontend components
169 lines • 7.9 kB
JavaScript
/*---------------------------------------------------------------------------------------------
* Copyright (c) Bentley Systems, Incorporated. All rights reserved.
* See LICENSE.md in the project root for license terms and full copyright notice.
*--------------------------------------------------------------------------------------------*/
/** @packageDocumentation
* @module WebGL
*/
import { assert, dispose } from "@itwin/core-bentley";
import { Gradient, RenderTexture, ThematicDisplayMode, ThematicGradientMode, ThematicGradientTransparencyMode, } from "@itwin/core-common";
import { TextureUnit } from "./RenderFlags";
import { desync, sync } from "./Sync";
import { TextureHandle } from "./Texture";
import { ThematicSensors } from "./ThematicSensors";
import { Angle, Range3d, Vector3d } from "@itwin/core-geometry";
import { System } from "./System";
import { FloatRgba } from "./FloatRGBA";
/** Maintains state for uniforms related to thematic display.
* @internal
*/
export class ThematicUniforms {
_sensors; // NB: This is only used if no distance cutoff is applied (this is shared among all batches)
_texture;
_range = new Float32Array(2);
_colorMix = 0.0;
_axis = new Float32Array(3);
_sunDirection = new Float32Array(3);
_marginColor = new FloatRgba();
_displayMode = new Float32Array(1);
_fragSettings = new Float32Array(4); // gradientMode, distanceCutoff, stepCount, > 0.0 if multiply gradient alpha
_numSensors = 0;
_gradientDimension = _getGradientDimension();
_thematicDisplay;
syncKey = 0;
get _distanceCutoff() { return this._fragSettings[1]; }
get thematicDisplay() {
return this._thematicDisplay;
}
get wantIsoLines() {
if (undefined !== this.thematicDisplay)
return ThematicDisplayMode.Height === this._displayMode[0] && ThematicGradientMode.IsoLines === this.thematicDisplay.gradientSettings.mode;
return false;
}
get wantSlopeMode() {
return (undefined !== this.thematicDisplay) ? ThematicDisplayMode.Slope === this._displayMode[0] : false;
}
get wantHillShadeMode() {
return (undefined !== this.thematicDisplay) ? ThematicDisplayMode.HillShade === this._displayMode[0] : false;
}
get wantGlobalSensorTexture() {
return !(this._distanceCutoff > 0);
}
get bytesUsed() {
return this._sensors ? this._sensors.bytesUsed : 0;
}
_scratchVector = new Vector3d();
_updateAxis(axis, viewMatrix) {
const tAxis = (viewMatrix !== undefined) ? viewMatrix.multiplyVector(axis, this._scratchVector) : axis;
tAxis.normalizeInPlace();
this._axis[0] = tAxis.x;
this._axis[1] = tAxis.y;
this._axis[2] = tAxis.z;
}
_updateSunDirection(sunDir, viewMatrix) {
viewMatrix.multiplyVector(sunDir, this._scratchVector);
this._scratchVector.negate(this._scratchVector);
this._scratchVector.normalizeInPlace();
this._sunDirection[0] = this._scratchVector.x;
this._sunDirection[1] = this._scratchVector.y;
this._sunDirection[2] = this._scratchVector.z;
}
update(target) {
const plan = target.plan;
if (this.thematicDisplay && plan.thematic && this.thematicDisplay.equals(plan.thematic) && this._texture) {
if (undefined !== this._sensors)
this._sensors.update(target.uniforms.frustum.viewMatrix);
if (ThematicDisplayMode.Slope === this.thematicDisplay.displayMode) {
this._updateAxis(this.thematicDisplay.axis, target.uniforms.frustum.viewMatrix);
desync(this);
}
else if (ThematicDisplayMode.HillShade === this.thematicDisplay.displayMode) {
this._updateSunDirection(this.thematicDisplay.sunDirection, target.uniforms.frustum.viewMatrix);
desync(this);
}
return;
}
desync(this);
this._thematicDisplay = plan.thematic;
this._texture = dispose(this._texture);
if (!this.thematicDisplay)
return;
if (ThematicDisplayMode.Slope === this.thematicDisplay.displayMode) {
this._range[0] = Angle.degreesToRadians(this.thematicDisplay.range.low);
this._range[1] = Angle.degreesToRadians(this.thematicDisplay.range.high);
}
else {
this._range[0] = this.thematicDisplay.range.low;
this._range[1] = this.thematicDisplay.range.high;
}
this._colorMix = this.thematicDisplay.gradientSettings.colorMix;
this._updateAxis(this.thematicDisplay.axis, (ThematicDisplayMode.Slope === this.thematicDisplay.displayMode) ? target.uniforms.frustum.viewMatrix : undefined);
if (ThematicDisplayMode.HillShade === this.thematicDisplay.displayMode)
this._updateSunDirection(this.thematicDisplay.sunDirection, target.uniforms.frustum.viewMatrix);
this._marginColor.setColorDef(this.thematicDisplay.gradientSettings.marginColor);
this._displayMode[0] = this.thematicDisplay.displayMode;
this._fragSettings[0] = this.thematicDisplay.gradientSettings.mode;
const sensorSettings = this.thematicDisplay.sensorSettings;
this._fragSettings[1] = (undefined === sensorSettings) ? 0 : this.thematicDisplay.sensorSettings.distanceCutoff;
this._fragSettings[2] = Math.min(this.thematicDisplay.gradientSettings.stepCount, this._gradientDimension);
this._fragSettings[3] = this.thematicDisplay.gradientSettings.transparencyMode === ThematicGradientTransparencyMode.SurfaceOnly ? 0.0 : 1.0;
// If we want sensors and have no distance cutoff, then create a global shared sensor texture.
if (target.wantThematicSensors && !(this._distanceCutoff > 0)) {
this._numSensors = sensorSettings.sensors.length;
this._sensors = dispose(this._sensors);
this._sensors = ThematicSensors.create(target, Range3d.createNull());
}
const symb = Gradient.Symb.createThematic(this.thematicDisplay.gradientSettings);
const image = symb.getThematicImageForRenderer(this._gradientDimension);
this._texture = TextureHandle.createForImageBuffer(image, RenderTexture.Type.ThematicGradient);
}
bindRange(uniform) {
if (!sync(this, uniform))
uniform.setUniform2fv(this._range);
}
bindAxis(uniform) {
if (!sync(this, uniform))
uniform.setUniform3fv(this._axis);
}
bindSunDirection(uniform) {
if (!sync(this, uniform))
uniform.setUniform3fv(this._sunDirection);
}
bindMarginColor(uniform) {
if (!sync(this, uniform))
this._marginColor.bind(uniform);
}
bindDisplayMode(uniform) {
if (!sync(this, uniform))
uniform.setUniform1fv(this._displayMode);
}
bindFragSettings(uniform) {
if (!sync(this, uniform))
uniform.setUniform4fv(this._fragSettings);
}
bindTexture(uniform, unit) {
assert(undefined !== this._texture);
this._texture.bindSampler(uniform, unit);
}
bindNumSensors(uniform) {
if (!sync(this, uniform))
uniform.setUniform1i(this._numSensors);
}
bindSensors(uniform) {
assert(undefined !== this._sensors);
this._sensors.texture.bindSampler(uniform, TextureUnit.ThematicSensors);
}
get isDisposed() {
return undefined === this._texture && undefined === this._sensors;
}
[Symbol.dispose]() {
this._texture = dispose(this._texture);
this._sensors = dispose(this._sensors);
}
}
function _getGradientDimension() {
const preferDimension = 8192;
const maxDimension = System.instance.maxTextureSize;
return (preferDimension > maxDimension) ? maxDimension : preferDimension;
}
//# sourceMappingURL=ThematicUniforms.js.map