@itwin/core-frontend
Version:
iTwin.js frontend components
265 lines (257 loc) • 11.9 kB
JavaScript
"use strict";
/*---------------------------------------------------------------------------------------------
* 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
*/
Object.defineProperty(exports, "__esModule", { value: true });
exports.addAnimation = addAnimation;
const core_bentley_1 = require("@itwin/core-bentley");
const core_common_1 = require("@itwin/core-common");
const RenderFlags_1 = require("../RenderFlags");
const Surface_1 = require("./Surface");
const Vertex_1 = require("./Vertex");
const initialize = `
g_anim_step = vec2(1.0) / u_animLUTParams.xy;
g_anim_center = g_anim_step * 0.5;
`;
// The vertex index is an integer in [0..numVertices].
// The frame index is an integer in [0..numBytesPerVertex/2].
// Therefore each frame index points at 2 bytes within the texture.
// The third component of the return value is 0.0 if the input index points to the first 2 bytes of the texel, or 1.0 if pointing to the second 2 bytes
const computeAnimLUTCoords = `
vec3 computeAnimLUTCoords(float vertIndex, float frameIndex) {
// float baseIndex = (vertIndex * 2.0) + frameIndex;
float baseIndex = (vertIndex * u_animLUTParams.z) + frameIndex;
float halfIndex = baseIndex * 0.5;
float index = floor(halfIndex);
float epsilon = 0.5 / u_animLUTParams.x;
float yId = floor(index / u_animLUTParams.x + epsilon);
float xId = index - u_animLUTParams.x * yId;
vec2 texCoord = g_anim_center + vec2(xId / u_animLUTParams.x, yId / u_animLUTParams.y);
return vec3(texCoord, 2.0 * (halfIndex - index));
}
`;
// Sample 2 bytes at the specified index.
const sampleAnimVec2 = `
vec2 sampleAnimVec2(float vertIndex, float frameIndex) {
vec3 tc = computeAnimLUTCoords(vertIndex, frameIndex);
vec4 texel = floor(TEXTURE(u_animLUT, tc.xy) * 255.0 + 0.5);
return texel.xy * (1.0 - tc.z) + texel.zw * tc.z;
}
`;
// Position is quantized to 6 bytes (2 bytes per component). So we always must sample two adjacent texels. We discard two bytes based on whether the index is even or odd.
const computeAnimationFrameDisplacement = `
vec3 computeAnimationFrameDisplacement(float vertIndex, float frameIndex, vec3 origin, vec3 scale) {
vec3 tc = computeAnimLUTCoords(vertIndex, frameIndex);
vec4 enc1 = floor(TEXTURE(u_animLUT, tc.xy) * 255.0 + 0.5);
tc.x += g_anim_step.x;
vec4 enc2 = floor(TEXTURE(u_animLUT, tc.xy) * 255.0 + 0.5);
vec2 ex = enc1.xy * (1.0 - tc.z) + enc1.zw * tc.z;
vec2 ey = enc1.zw * (1.0 - tc.z) + enc2.xy * tc.z;
vec2 ez = enc2.xy * (1.0 - tc.z) + enc2.zw * tc.z;
vec3 qpos = vec3(decodeUInt16(ex), decodeUInt16(ey), decodeUInt16(ez));
return unquantizePosition(qpos, origin, scale).xyz;
}
`;
const computeAnimationDisplacement = `
vec3 computeAnimationDisplacement(float vertIndex, float frameIndex0, float frameIndex1, float fraction, vec3 origin, vec3 scale) {
if (frameIndex0 < 0.0)
return vec3(0.0, 0.0, 0.0);
vec3 displacement = computeAnimationFrameDisplacement(vertIndex, frameIndex0, origin, scale);
if (fraction > 0.0) {
vec3 displacement1 = computeAnimationFrameDisplacement(vertIndex, frameIndex1, origin, scale);
displacement += fraction * (displacement1 - displacement);
}
return displacement;
}
`;
const adjustRawPosition = `
rawPos.xyz += computeAnimationDisplacement(g_vertexLUTIndex, u_animDispParams.x, u_animDispParams.y, u_animDispParams.z, u_qAnimDispOrigin, u_qAnimDispScale);
return rawPos;
`;
const computeAnimationFrameNormal = `
vec3 computeAnimationFrameNormal(float frameIndex) {
vec2 enc = sampleAnimVec2(g_vertexLUTIndex, frameIndex);
return octDecodeNormal(enc);
}
`;
const computeAnimationNormal = `
vec3 computeAnimationNormal(float frameIndex0, float frameIndex1, float fraction) {
vec3 normal = computeAnimationFrameNormal(frameIndex0);
if (fraction > 0.0) {
vec3 normal1 = computeAnimationFrameNormal(frameIndex1);
normal += fraction * (normal1 - normal);
}
return normal;
}
`;
const computeAnimationFrameParam = `
float computeAnimationFrameParam(float frameIndex, float origin, float scale) {
vec2 enc = sampleAnimVec2(g_vertexLUTIndex, frameIndex);
return clamp((origin + scale * decodeUInt16(enc)), 0.0, 1.0);
}
`;
const computeAnimationParam = `
vec2 computeAnimationParam(float frameIndex0, float frameIndex1, float fraction, float origin, float scale) {
float param = computeAnimationFrameParam(frameIndex0, origin, scale);
if (fraction > 0.0) {
float param1 = computeAnimationFrameParam(frameIndex1, origin, scale);
param += fraction * (param1 - param);
}
return vec2(.5, param);
}
`;
const scratchAnimParams = [
undefined,
undefined,
new Float32Array(2), // origin, scale
new Float32Array(3), // index0, index1, fraction
];
function getAnimParams(size, initialValue) {
const array = scratchAnimParams[size];
if (undefined !== initialValue)
for (let i = 0; i < array.length; i++)
array[i] = initialValue;
return array;
}
function getDisplacementChannel(params) {
const displacement = params.target.analysisStyle?.displacement;
if (!displacement)
return undefined;
const channel = params.geometry.asLUT?.lut.auxChannels?.displacements?.get(displacement.channelName);
return channel ? { channel, displacement } : undefined;
}
function getNormalChannel(params) {
const channelName = params.target.analysisStyle?.normalChannelName;
if (undefined === channelName)
return undefined;
return params.geometry.asLUT?.lut.auxChannels?.normals?.get(channelName);
}
function getScalarChannel(params) {
const scalar = params.target.analysisStyle?.thematic;
if (!scalar)
return undefined;
const channel = params.geometry.asMesh?.lut.auxChannels?.params?.get(scalar.channelName);
return channel ? { channel, scalar } : undefined;
}
function computeAnimParams(params, channel, fraction) {
const { inputs, indices } = channel;
const inputValue = fraction * inputs[inputs.length - 1];
for (let i = 0; i < inputs.length - 1; i++) {
if (inputValue >= inputs[i] && inputValue < inputs[i + 1]) {
params[0] = indices[i];
params[1] = indices[i + 1];
params[2] = inputValue - inputs[i] / (inputs[i + 1] - inputs[i]);
return;
}
}
params[0] = params[1] = indices[inputs.length - 1];
params[2] = 0.0;
}
/** @internal */
function addAnimation(vert, isSurface) {
// Lookup table
vert.addGlobal("g_anim_step", 3 /* VariableType.Vec2 */);
vert.addGlobal("g_anim_center", 3 /* VariableType.Vec2 */);
vert.addInitializer(initialize);
vert.addFunction(Vertex_1.unquantizePosition);
vert.addUniform("u_animLUT", 8 /* VariableType.Sampler2D */, (prog) => {
prog.addGraphicUniform("u_animLUT", (uniform, params) => {
const channels = (params.geometry.asLUT).lut.auxChannels;
(0, core_bentley_1.assert)(undefined !== channels);
channels.texture.bindSampler(uniform, RenderFlags_1.TextureUnit.AuxChannelLUT);
});
});
vert.addUniform("u_animLUTParams", 4 /* VariableType.Vec3 */, (prog) => {
prog.addGraphicUniform("u_animLUTParams", (uniform, params) => {
const geom = params.geometry.asLUT;
(0, core_bentley_1.assert)(undefined !== geom && undefined !== geom.lut.auxChannels);
const tex = geom.lut.auxChannels.texture;
const array = getAnimParams(3);
array[0] = tex.width;
array[1] = tex.height;
array[2] = geom.lut.auxChannels.numBytesPerVertex / 2;
uniform.setUniform3fv(array);
});
});
vert.addFunction(computeAnimLUTCoords);
vert.addFunction(sampleAnimVec2);
// Displacement
vert.addFunction(computeAnimationFrameDisplacement);
vert.addFunction(computeAnimationDisplacement);
vert.set(1 /* VertexShaderComponent.AdjustRawPosition */, adjustRawPosition);
vert.addUniform("u_animDispParams", 4 /* VariableType.Vec3 */, (prog) => {
prog.addGraphicUniform("u_animDispParams", (uniform, params) => {
const animParams = getAnimParams(3, 0.0);
const disp = getDisplacementChannel(params);
if (undefined !== disp)
computeAnimParams(animParams, disp.channel, params.target.analysisFraction);
uniform.setUniform3fv(animParams);
});
});
vert.addUniform("u_qAnimDispScale", 4 /* VariableType.Vec3 */, (prog) => {
prog.addGraphicUniform("u_qAnimDispScale", (uniform, params) => {
const animParams = getAnimParams(3, 0.0);
const disp = getDisplacementChannel(params);
if (undefined !== disp)
for (let i = 0; i < 3; i++)
animParams[i] = disp.channel.qScale[i] * disp.displacement.scale;
uniform.setUniform3fv(animParams);
});
});
vert.addUniform("u_qAnimDispOrigin", 4 /* VariableType.Vec3 */, (prog) => {
prog.addGraphicUniform("u_qAnimDispOrigin", (uniform, params) => {
const animParams = getAnimParams(3, 0.0);
const disp = getDisplacementChannel(params);
if (undefined !== disp)
for (let i = 0; i < 3; i++)
animParams[i] = disp.channel.qOrigin[i] * disp.displacement.scale;
uniform.setUniform3fv(animParams);
});
});
// Normal and param
if (isSurface) {
vert.addFunction(Surface_1.octDecodeNormal);
vert.addFunction(computeAnimationFrameNormal);
vert.addFunction(computeAnimationNormal);
vert.addFunction(computeAnimationFrameParam);
vert.addFunction(computeAnimationParam);
vert.addUniform("u_animNormalParams", 4 /* VariableType.Vec3 */, (prog) => {
prog.addGraphicUniform("u_animNormalParams", (uniform, params) => {
const animParams = getAnimParams(3, -1.0);
const channel = getNormalChannel(params);
if (undefined !== channel)
computeAnimParams(animParams, channel, params.target.analysisFraction);
uniform.setUniform3fv(animParams);
});
});
vert.addUniform("u_animScalarParams", 4 /* VariableType.Vec3 */, (prog) => {
prog.addGraphicUniform("u_animScalarParams", (uniform, params) => {
const scalars = getScalarChannel(params);
const animParams = getAnimParams(3, -1.0);
if (scalars)
computeAnimParams(animParams, scalars.channel, params.target.analysisFraction);
uniform.setUniform3fv(animParams);
});
});
vert.addUniform("u_animScalarQParams", 3 /* VariableType.Vec2 */, (prog) => {
prog.addGraphicUniform("u_animScalarQParams", (uniform, params) => {
const scalars = getScalarChannel(params);
const animParams = getAnimParams(2, 1.0);
if (scalars) {
const range = scalars.scalar.range;
let rangeScale = range.high - range.low;
if (rangeScale === 0)
rangeScale = 1;
animParams[0] = core_common_1.ThematicGradientSettings.margin + (scalars.channel.qOrigin - range.low) / rangeScale;
animParams[1] = core_common_1.ThematicGradientSettings.contentRange * scalars.channel.qScale / rangeScale;
}
uniform.setUniform2fv(animParams);
});
});
}
}
//# sourceMappingURL=Animation.js.map