Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Z scaling #937

Merged
merged 25 commits into from Mar 25, 2021
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
2a001a6
modify model transform keyin to take scaling
MarcNeely Feb 11, 2021
581a421
test
MarcNeely Mar 10, 2021
5a41d6b
fix instancing
MarcNeely Mar 10, 2021
17374c1
Compare forceNoInstancing
pmconne Mar 10, 2021
26f9e49
restore deleted property.
pmconne Mar 10, 2021
48e2f41
Remove unnecessary invalidateScene and requestRedraw calls.
pmconne Mar 10, 2021
e4c3ac1
Cleanup & make work nicer with Z offset
MarcNeely Mar 12, 2021
5a5b2d9
fix rgb axes in measure distance tool
MarcNeely Mar 12, 2021
a742f67
Merge branch 'z-scaling' of https://github.com/imodeljs/imodeljs into…
MarcNeely Mar 12, 2021
023c1fc
Remove debug
MarcNeely Mar 15, 2021
8e2638d
lint & typo
MarcNeely Mar 18, 2021
567b7fe
Merge branch 'master' into z-scaling
MarcNeely Mar 22, 2021
f09107e
Merge branch 'master' into z-scaling
mergify[bot] Mar 22, 2021
1aa841e
Modify tessellation for nonuniform scaling
MarcNeely Mar 22, 2021
9d3b718
Merge branch 'z-scaling' of https://github.com/imodeljs/imodeljs into…
MarcNeely Mar 22, 2021
dbc6969
rush change
MarcNeely Mar 22, 2021
325b952
extract-api
MarcNeely Mar 22, 2021
dbce0b4
Replace use of System.instance with IModelApp.rSys
MarcNeely Mar 23, 2021
2609c68
move scaleFactor calc to TileDrawArgs constructor
MarcNeely Mar 23, 2021
1e78608
Merge branch 'master' into z-scaling
pmconne Mar 25, 2021
a8b328c
Merge branch 'master' into z-scaling
mergify[bot] Mar 25, 2021
b033c23
Merge branch 'master' into z-scaling
mergify[bot] Mar 25, 2021
ba5928b
Merge branch 'master' into z-scaling
mergify[bot] Mar 25, 2021
d071d13
Merge branch 'master' into z-scaling
mergify[bot] Mar 25, 2021
015c99d
Merge branch 'master' into z-scaling
mergify[bot] Mar 25, 2021
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
17 changes: 14 additions & 3 deletions core/frontend/src/AccuSnap.ts
Expand Up @@ -707,9 +707,11 @@ export class AccuSnap implements Decorator {
// If this hit is from a plan projection model, apply the model's elevation to the snap point for display.
let snapPoint = result.snapPoint!;
const elevation = undefined !== thisHit.modelId ? thisHit.viewport.view.getModelElevation(thisHit.modelId) : 0;
if (0 !== elevation) {
if (0 !== elevation || undefined !== thisHit.viewport.view.modelDisplayTransformProvider) {
const adjustedSnapPoint = Point3d.fromJSON(snapPoint);
adjustedSnapPoint.z += elevation;
// Also apply the model display transform if there is one.
thisHit.viewport.transformByModelDisplayTransform(thisHit.modelId, adjustedSnapPoint, false);
snapPoint = adjustedSnapPoint;
}

Expand All @@ -719,14 +721,23 @@ export class AccuSnap implements Decorator {
let transform;
if (0 !== elevation)
transform = Transform.createTranslationXYZ(0, 0, elevation);
if (undefined !== thisHit.modelId && undefined !== thisHit.viewport.view.modelDisplayTransformProvider) {
if (undefined === transform)
transform = Transform.createIdentity();
transform = thisHit.viewport.view.getModelDisplayTransform(thisHit.modelId, transform);
}

snap.setCurvePrimitive(parseCurve(result.curve), transform, result.geomType);
if (undefined !== result.parentGeomType)
snap.parentGeomType = result.parentGeomType;
if (undefined !== result.hitPoint)
if (undefined !== result.hitPoint) {
snap.hitPoint.setFromJSON(result.hitPoint); // Update hitPoint from readPixels with exact point location corrected to surface/edge geometry...
if (undefined !== result.normal)
thisHit.viewport.transformByModelDisplayTransform(thisHit.modelId, snap.hitPoint, false);
}
if (undefined !== result.normal) {
snap.normal = Vector3d.fromJSON(result.normal);
thisHit.viewport.transformNormalByModelDisplayTransform(thisHit.modelId, snap.normal);
}

if (SnapMode.Intersection !== snap.snapMode)
return snap;
Expand Down
37 changes: 33 additions & 4 deletions core/frontend/src/Viewport.ts
Expand Up @@ -309,13 +309,15 @@ export abstract class Viewport implements IDisposable {
}
/** @internal */
public invalidateScene(): void {
console.log(`invalidating Scene...`);
this._sceneValid = false;
this._timePointValid = false;
this.invalidateDecorations();
this._disposeDecorationCache(); // When the scene is invalidated, remove all cached decorations so they get regenerated.
}
/** @internal */
public invalidateRenderPlan(): void {
console.log(`invalidating RenderPlan...`);
this._renderPlanValid = false;
this.invalidateScene();
}
Expand Down Expand Up @@ -2398,8 +2400,10 @@ export abstract class Viewport implements IDisposable {

// If this is a plan projection model, invert the elevation applied to its display transform.
const modelId = pixels.getPixel(x, y).featureTable?.modelId;
if (undefined !== modelId)
if (undefined !== modelId) {
npc.z -= this.view.getModelElevation(modelId);
this.transformByModelDisplayTransform(modelId, npc, true);
}
}

return npc;
Expand Down Expand Up @@ -2471,6 +2475,28 @@ export abstract class Viewport implements IDisposable {
this.view.modelDisplayTransformProvider = provider;
}

/** @internal */
public transformByModelDisplayTransform(modelId: string | undefined, pnt: Point3d, inverse: boolean): void {
if (undefined !== modelId && undefined !== this.view.modelDisplayTransformProvider) {
const transform = this.view.modelDisplayTransformProvider.getModelDisplayTransform(modelId, Transform.createIdentity());
const newPnt = inverse ? transform.multiplyInversePoint3d(pnt) : transform.multiplyPoint3d(pnt);
if (undefined !== newPnt)
pnt.set(newPnt.x, newPnt.y, newPnt.z);
}
}

/** @internal */
public transformNormalByModelDisplayTransform(modelId: string | undefined, normal: Vector3d): void {
if (undefined !== modelId && undefined !== this.view.modelDisplayTransformProvider) {
const transform = this.view.modelDisplayTransformProvider.getModelDisplayTransform(modelId, Transform.createIdentity());
const newVec = transform.matrix.multiplyInverse(normal);
if (undefined !== newVec) {
newVec.normalizeInPlace();
normal.set(newVec.x, newVec.y, newVec.z);
}
}
}

/** An ordered list of names of screen-space post-processing effects to be applied to the image rendered by the Viewport.
* The effects are applied to the image in the order in which they appear in the list. Any names not corresponding to a registered effect are ignored.
* This may have no effect if the Viewport's [[RenderTarget]] does not support screen-space effects.
Expand Down Expand Up @@ -2769,6 +2795,9 @@ export class ScreenViewport extends Viewport {
return result;
}

/** @internal */
public picker = new ElementPicker();

/** Find a point on geometry visible in this Viewport, within a radius of supplied pick point.
* If no geometry is selected, return the point projected to the most appropriate reference plane.
* @param pickPoint Point to search about, in world coordinates
Expand All @@ -2785,14 +2814,14 @@ export class ScreenViewport extends Viewport {
if (undefined === radius)
radius = this.pixelsFromInches(ToolSettings.viewToolPickRadiusInches);

const picker = new ElementPicker();
this.picker.empty();
const locateOpts = new LocateOptions();
locateOpts.allowNonLocatable = (undefined === options || !options.excludeNonLocatable);
locateOpts.allowDecorations = (undefined === options || !options.excludeDecorations);
locateOpts.allowExternalIModels = (undefined === options || !options.excludeExternalIModels);

if (0 !== picker.doPick(this, pickPoint, radius, locateOpts)) {
const hitDetail = picker.getHit(0)!;
if (0 !== this.picker.doPick(this, pickPoint, radius, locateOpts)) {
const hitDetail = this.picker.getHit(0)!;
const hitPoint = hitDetail.getPoint();
if (hitDetail.isModelHit)
return { plane: Plane3dByOriginAndUnitNormal.create(hitPoint, this.view.getUpVector(hitPoint))!, source: DepthPointSource.Model, sourceId: hitDetail.sourceId };
Expand Down
15 changes: 14 additions & 1 deletion core/frontend/src/render/webgl/BranchUniforms.ts
Expand Up @@ -61,6 +61,7 @@ export class BranchUniforms {
private readonly _mvp32 = new Matrix4();
private readonly _m32 = new Matrix4();
private readonly _v32 = new Matrix3();
private readonly _mvn32 = new Matrix3();

// Working state
private readonly _scratchTransform = Transform.createIdentity();
Expand Down Expand Up @@ -150,8 +151,9 @@ export class BranchUniforms {
}

public bindModelViewMatrix(uniform: UniformHandle, geom: CachedGeometry, isViewCoords: boolean): void {
if (this.update(uniform, geom, isViewCoords))
if (this.update(uniform, geom, isViewCoords)) {
uniform.setMatrix4(this._mv32);
}
}

public bindModelViewProjectionMatrix(uniform: UniformHandle, geom: CachedGeometry, isViewCoords: boolean): void {
Expand All @@ -169,6 +171,11 @@ export class BranchUniforms {
uniform.setMatrix3(this._v32);
}

public bindModelViewNTransform(uniform: UniformHandle, geom: CachedGeometry, isViewCoords: boolean) {
if (this.update(uniform, geom, isViewCoords))
uniform.setMatrix3(this._mvn32);
}

private update(uniform: UniformHandle, geometry: CachedGeometry, isViewCoords: boolean): boolean {
const uniforms = this._target.uniforms[isViewCoords ? "viewRect" : "frustum"];
if (!sync(uniforms, this))
Expand Down Expand Up @@ -230,6 +237,12 @@ export class BranchUniforms {
Matrix4d.createTransform(mv, this._mv);
this._mv32.initFromTransform(mv);

const inv = this._mv.createInverse();
if (undefined !== inv) {
const invTr = inv.cloneTransposed();
this._mvn32.initFromMatrix3d(invTr.matrixPart());
}

// Don't bother computing mvp for instanced geometry - it's not used.
if (!this._isInstanced) {
uniforms.projectionMatrix.multiplyMatrixMatrix(this._mv, this._mvp);
Expand Down
4 changes: 2 additions & 2 deletions core/frontend/src/render/webgl/glsl/Edge.ts
Expand Up @@ -32,8 +32,8 @@ const decodeEndPointAndQuadIndices = `
const animateEndPoint = `g_otherPos.xyz += computeAnimationDisplacement(g_otherIndex, u_animDispParams.x, u_animDispParams.y, u_animDispParams.z, u_qAnimDispOrigin, u_qAnimDispScale);`;

const checkForSilhouetteDiscard = `
vec3 n0 = MAT_NORM * octDecodeNormal(a_normals.xy);
vec3 n1 = MAT_NORM * octDecodeNormal(a_normals.zw);
vec3 n0 = normalize(MAT_NORM * octDecodeNormal(a_normals.xy));
vec3 n1 = normalize(MAT_NORM * octDecodeNormal(a_normals.zw));

if (0.0 == MAT_MVP[0].w) {
return n0.z * n1.z > 0.0; // orthographic.
Expand Down
20 changes: 18 additions & 2 deletions core/frontend/src/render/webgl/glsl/Vertex.ts
Expand Up @@ -12,6 +12,7 @@ import { UniformHandle } from "../UniformHandle";
import { Matrix4 } from "../Matrix";
import { RenderPass, TextureUnit } from "../RenderFlags";
import { VariableType, VertexShaderBuilder } from "../ShaderBuilder";
import { System } from "../System";
import { decodeUint16, decodeUint24 } from "./Decode";
import { addInstanceOverrides } from "./Instancing";
import { addLookupTable } from "./LookupTable";
Expand Down Expand Up @@ -113,7 +114,13 @@ export function addModelViewMatrix(vert: VertexShaderBuilder): void {
}

const computeNormalMatrix = `
g_nmx = mat3(MAT_MV);
g_nmx = mat3(u_modelViewN);
g_nmx[0][0] *= u_frustumScale.x;
g_nmx[1][1] *= u_frustumScale.y;
`;

const computeNormalMatrix2 = `
g_nmx = transpose(inverse(mat3(MAT_MV)));
g_nmx[0][0] *= u_frustumScale.x;
g_nmx[1][1] *= u_frustumScale.y;
`;
Expand All @@ -128,7 +135,16 @@ export function addNormalMatrix(vert: VertexShaderBuilder) {
});
});

vert.addInitializer(computeNormalMatrix);
if (false && System.instance.capabilities.isWebGL2)
vert.addInitializer(computeNormalMatrix2);
else {
vert.addUniform("u_modelViewN", VariableType.Mat3, (prog) => {
prog.addGraphicUniform("u_modelViewN", (uniform, params) => {
params.target.uniforms.branch.bindModelViewNTransform(uniform, params.geometry, false);
});
});
vert.addInitializer(computeNormalMatrix);
}
}

const scratchLutParams = new Float32Array(4);
Expand Down
38 changes: 35 additions & 3 deletions core/frontend/src/tile/PrimaryTileTree.ts
Expand Up @@ -7,7 +7,7 @@
*/

import { assert, compareStrings, Id64String } from "@bentley/bentleyjs-core";
import { Range3d, StringifiedClipVector, Transform } from "@bentley/geometry-core";
import { Geometry, Range3d, StringifiedClipVector, Transform } from "@bentley/geometry-core";
import {
BatchType,
compareIModelTileTreeIds,
Expand All @@ -23,20 +23,22 @@ import { IModelConnection } from "../IModelConnection";
import { GeometricModel3dState, GeometricModelState } from "../ModelState";
import { RenderClipVolume } from "../render/RenderClipVolume";
import { SceneContext } from "../ViewContext";
import { ViewState, ViewState3d } from "../ViewState";
import { ModelDisplayTransformProvider, ViewState, ViewState3d } from "../ViewState";
import { SpatialViewState } from "../SpatialViewState";
import { RenderScheduleState } from "../RenderScheduleState";
import { InteractiveEditingSession } from "../InteractiveEditingSession";
import {
IModelTileTree, IModelTileTreeParams, iModelTileTreeParamsFromJSON, TileDrawArgs, TileGraphicType, TileTree, TileTreeOwner, TileTreeReference,
TileTreeSupplier,
} from "./internal";
import { System } from "../render/webgl/System";

interface PrimaryTreeId {
readonly treeId: PrimaryTileTreeId;
readonly modelId: Id64String;
readonly is3d: boolean;
readonly isPlanProjection: boolean;
readonly forceNoInstancing: boolean;
}

class PlanProjectionTileTree extends IModelTileTree {
Expand Down Expand Up @@ -75,10 +77,11 @@ class PrimaryTreeSupplier implements TileTreeSupplier {

const options = {
edgesRequired: treeId.edgesRequired,
allowInstancing: undefined === treeId.animationId && !treeId.enforceDisplayPriority && !treeId.sectionCut,
allowInstancing: undefined === treeId.animationId && !treeId.enforceDisplayPriority && !treeId.sectionCut && !id.forceNoInstancing,
is3d: id.is3d,
batchType: BatchType.Primary,
};
console.log(`=== Creating tile tree id.forceNoInstancing ${id.forceNoInstancing ? "true" : "false"} allowInstancing ${options.allowInstancing ? "true" : "false"}`);

const params = iModelTileTreeParamsFromJSON(props, iModel, id.modelId, options);
if (!id.isPlanProjection)
Expand Down Expand Up @@ -132,6 +135,7 @@ class PrimaryTreeReference extends TileTreeReference {
private _owner: TileTreeOwner;
private readonly _sectionClip?: StringifiedClipVector;
private readonly _sectionCutAppearanceProvider?: FeatureAppearanceProvider;
private _forceNoInstancing: boolean;

public constructor(view: ViewState, model: GeometricModelState, planProjection: boolean, transformNodeId?: number, sectionClip?: StringifiedClipVector) {
super();
Expand All @@ -149,16 +153,42 @@ class PrimaryTreeReference extends TileTreeReference {
});
}

this._forceNoInstancing = false;
if (!System.instance.capabilities.isWebGL2) {
this.checkForceNoInstancing(view.modelDisplayTransformProvider);
view.onModelDisplayTransformProviderChanged.addListener((provider: ModelDisplayTransformProvider | undefined) => {
console.log(`Listener heard a change...`);
this.checkForceNoInstancing(provider);
console.log(` this._forceNoInstancing ${this._forceNoInstancing}`);
});
}

console.log(`PrimaryTreeReference constructor this._forceNoInstancing is ${this._forceNoInstancing}`);
this._id = {
modelId: model.id,
is3d: model.is3d,
treeId: this.createTreeId(view, model.id, transformNodeId),
isPlanProjection: planProjection,
forceNoInstancing: this._forceNoInstancing,
};

this._owner = primaryTreeSupplier.getOwner(this._id, model.iModel);
}

private checkForceNoInstancing(provider: ModelDisplayTransformProvider | undefined) {
this._forceNoInstancing = false;
// If this model has a display transform with a non-uniform scale then instancing needs to be forced off when using WebGL1.
if (undefined !== provider) {
const tf = provider.getModelDisplayTransform(this.model.id, Transform.createIdentity());
const sx = tf.matrix.getColumn(0).magnitudeSquared();
const sy = tf.matrix.getColumn(1).magnitudeSquared();
const sz = tf.matrix.getColumn(2).magnitudeSquared();
console.log(` Scale (${sx}, ${sy}, ${sz})`);
if (Math.abs(sx - sy) > Geometry.smallMetricDistance || Math.abs(sx - sz) > Geometry.smallMetricDistance)
this._forceNoInstancing = true;
}
}

protected getViewFlagOverrides(_tree: TileTree) {
return this._viewFlagOverrides;
}
Expand Down Expand Up @@ -198,11 +228,13 @@ class PrimaryTreeReference extends TileTreeReference {
public get treeOwner(): TileTreeOwner {
const newId = this.createTreeId(this.view, this._id.modelId, this._id.treeId.animationTransformNodeId);
if (0 !== compareIModelTileTreeIds(newId, this._id.treeId)) {
Copy link
Member

@pmconne pmconne Mar 10, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If the only thing that changed is this._forceNoInstancing then you're not going to update your Id.
The viewport already invalidates the scene when the display transform provider changes so you don't have to worry about that - you just need to make sure you compute a correct tree Id.

Probably check this._forceNoInstancing !== this._id.forceNoInstancing.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Check it where, in the listener and then if it changed create a new id? How does that make the tiles reload?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Right here where you are checking compareIModelTileTreeIds.
TileTreeReference.treeOwner is called whenever we want access to the reference's TileTree. We compute an Id here based on the reference's current state, and ask for that tree. If the reference's state changed, we may get back a different tree - e.g., one with instancing disabled.

console.log(`PrimaryTreeReference treeOwner this._forceNoInstancing ${this._forceNoInstancing}`);
this._id = {
modelId: this._id.modelId,
is3d: this._id.is3d,
treeId: newId,
isPlanProjection: this._id.isPlanProjection,
forceNoInstancing: this._forceNoInstancing,
};

this._owner = primaryTreeSupplier.getOwner(this._id, this.model.iModel);
Expand Down