Skip to content

Commit b27ab90

Browse files
authored
Support unquantized vertex tables (#3288)
* Remove obsolete unused BingElevation-based terrain. * MeshPointList * Option to quantize positions. * Simplify graphic args pt 1: delete MeshGraphicArgs. * Get stuff (mostly tests) compiling. * Clean up (to an extent) MeshArgs and PolylineArgs. Tests are annoying. * remove obsolete TODO. * Quantized vertex table builders. * unquantized vertex table builders. * Mesh/PolylineArgs.points doesn't need an add method. * Vertex comparison tolerance based on quantization params or chord tolerance. * fix dumb test. * fix a couple tests. * fix vertex comparison. * Clarify feature index is 24 bits and material index is not produced by frontend code. * indentation * ShaderBuilderFlags is an object. We will need max rgba per vertex shortly. * Read vertex table data up front. * Use pre-sampled data for position. * Use pre-sampled data for normals and color index. * Use pre-sampled vertex data everywhere. * Support decoding unquantized vertex position. * Point3dList.range; qparams can be used for deriving range even if positions are not quantized. * Flag specifying whether positions are quantized. * consolidate normal computation. * When reading vertex data conditionalize based on whether positions are quantized. * Decode unquantized polyline/edge endpoints. * PolylineTesselator. * Turn on unquantized positions for decorations. Test failures ensue. * fix 3 tests. the rest of the failures are from rendering. * Test for unquantized vertex table (failing). * Get test passing. * unquantized geometry now renders correctly. * update TODO. Probably won't address. * Define unquantized positions relative to center of range. * Update test. * extract-api * lint.... * please build my code.
1 parent 1b80b21 commit b27ab90

36 files changed

+1082
-638
lines changed

common/api/core-frontend.api.md

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1617,8 +1617,6 @@ export class BingElevationProvider {
16171617
constructor();
16181618
// @internal (undocumented)
16191619
getGeodeticToSeaLevelOffset(point: Point3d, iModel: IModelConnection): Promise<number>;
1620-
// @internal (undocumented)
1621-
getGraphic(latLongRange: Range2d, corners: Point3d[], groundBias: number, texture: RenderTexture, system: RenderSystem): Promise<RenderGraphic | undefined>;
16221620
getHeight(carto: Cartographic, geodetic?: boolean): Promise<any>;
16231621
getHeightAverage(iModel: IModelConnection): Promise<number>;
16241622
getHeightRange(iModel: IModelConnection): Promise<Range1d>;
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
{
2+
"changes": [
3+
{
4+
"packageName": "@itwin/core-frontend",
5+
"comment": "Increase precision for vertex positions when producing decoration graphics, to reduce visual artifacts.",
6+
"type": "none"
7+
}
8+
],
9+
"packageName": "@itwin/core-frontend"
10+
}

core/frontend/src/render/ParticleCollectionBuilder.ts

Lines changed: 20 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
import { Id64String } from "@itwin/core-bentley";
1010
import { Matrix3d, Point2d, Point3d, Range3d, Transform, Vector2d, XAndY, XYAndZ } from "@itwin/core-geometry";
1111
import {
12-
ColorDef, Feature, FeatureTable, PackedFeatureTable, QParams3d, QPoint3dList, RenderTexture,
12+
ColorDef, ColorIndex, Feature, FeatureIndex, FeatureTable, FillFlags, PackedFeatureTable, QParams3d, QPoint3dList, RenderTexture,
1313
} from "@itwin/core-common";
1414
import { Viewport } from "../Viewport";
1515
import { RenderGraphic } from "./RenderGraphic";
@@ -343,19 +343,29 @@ function createQuad(size: XAndY, texture: RenderTexture, transparency: number):
343343
new Point3d(-halfWidth, halfHeight, 0), new Point3d(halfWidth, halfHeight, 0),
344344
];
345345

346-
const quadArgs = new MeshArgs();
347346
const range = new Range3d();
348347
range.low = corners[0];
349348
range.high = corners[3];
350-
quadArgs.points = new QPoint3dList(QParams3d.fromRange(range));
351-
for (const corner of corners)
352-
quadArgs.points.add(corner);
353349

354-
quadArgs.vertIndices = [0, 1, 2, 2, 1, 3];
355-
quadArgs.textureUv = [new Point2d(0, 1), new Point2d(1, 1), new Point2d(0, 0), new Point2d(1, 0)];
356-
quadArgs.texture = texture;
357-
quadArgs.colors.initUniform(ColorDef.white.withTransparency(transparency));
358-
quadArgs.isPlanar = true;
350+
const points = new QPoint3dList(QParams3d.fromRange(range));
351+
for (const corner of corners)
352+
points.add(corner);
353+
354+
const colors = new ColorIndex();
355+
colors.initUniform(ColorDef.white.withTransparency(transparency));
356+
357+
const quadArgs: MeshArgs = {
358+
points,
359+
vertIndices: [0, 1, 2, 2, 1, 3],
360+
fillFlags: FillFlags.None,
361+
isPlanar: true,
362+
colors,
363+
features: new FeatureIndex(),
364+
textureMapping: {
365+
texture,
366+
uvParams: [new Point2d(0, 1), new Point2d(1, 1), new Point2d(0, 0), new Point2d(1, 0)],
367+
},
368+
};
359369

360370
return MeshParams.create(quadArgs);
361371
}

core/frontend/src/render/RenderSystem.ts

Lines changed: 21 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88

99
import { base64StringToUint8Array, Id64String, IDisposable } from "@itwin/core-bentley";
1010
import {
11-
ColorDef, ElementAlignedBox3d, FeatureIndexType, Frustum, Gradient, ImageBuffer, ImageBufferFormat, ImageSource, ImageSourceFormat,
11+
ColorDef, ColorIndex, ElementAlignedBox3d, FeatureIndex, FeatureIndexType, FillFlags, Frustum, Gradient, ImageBuffer, ImageBufferFormat, ImageSource, ImageSourceFormat,
1212
isValidImageSourceFormat, PackedFeatureTable, QParams3d, QPoint3dList, RenderMaterial, RenderTexture, SkyGradient, TextureProps, TextureTransparency,
1313
} from "@itwin/core-common";
1414
import { ClipVector, Matrix3d, Point2d, Point3d, Range2d, Range3d, Transform, Vector2d, XAndY } from "@itwin/core-geometry";
@@ -441,39 +441,40 @@ export abstract class RenderSystem implements IDisposable {
441441
public createBackgroundMapDrape(_drapedTree: TileTreeReference, _mapTree: MapTileTreeReference): RenderTextureDrape | undefined { return undefined; }
442442
/** @internal */
443443
public createTile(tileTexture: RenderTexture, corners: Point3d[], featureIndex?: number): RenderGraphic | undefined {
444-
const rasterTile = new MeshArgs();
445-
446444
// corners
447445
// [0] [1]
448446
// [2] [3]
449447
// Quantize the points according to their range
450-
rasterTile.points = new QPoint3dList(QParams3d.fromRange(Range3d.create(...corners)));
451-
for (let i = 0; i < 4; ++i)
452-
rasterTile.points.add(corners[i]);
448+
const points = new QPoint3dList(QParams3d.fromRange(Range3d.create(...corners)));
449+
for (let i = 0; i < 4; i++)
450+
points.add(corners[i]);
453451

454452
// Now remove the translation from the quantized points and put it into a transform instead.
455453
// This prevents graphical artifacts when quantization origin is large relative to quantization scale.
456454
// ###TODO: Would be better not to create a branch for every tile.
457-
const qorigin = rasterTile.points.params.origin;
455+
const qorigin = points.params.origin;
458456
const transform = Transform.createTranslationXYZ(qorigin.x, qorigin.y, qorigin.z);
459457
qorigin.setZero();
460458

461-
rasterTile.vertIndices = [0, 1, 2, 2, 1, 3];
462-
rasterTile.textureUv = [
463-
new Point2d(0.0, 0.0),
464-
new Point2d(1.0, 0.0),
465-
new Point2d(0.0, 1.0),
466-
new Point2d(1.0, 1.0),
467-
];
468-
469-
rasterTile.texture = tileTexture;
470-
rasterTile.isPlanar = true;
471-
459+
const features = new FeatureIndex();
472460
if (undefined !== featureIndex) {
473-
rasterTile.features.featureID = featureIndex;
474-
rasterTile.features.type = FeatureIndexType.Uniform;
461+
features.featureID = featureIndex;
462+
features.type = FeatureIndexType.Uniform;
475463
}
476464

465+
const rasterTile: MeshArgs = {
466+
points,
467+
vertIndices: [0, 1, 2, 2, 1, 3],
468+
isPlanar: true,
469+
features,
470+
colors: new ColorIndex(),
471+
fillFlags: FillFlags.None,
472+
textureMapping: {
473+
uvParams: [new Point2d(0, 0), new Point2d(1, 0), new Point2d(0, 1), new Point2d(1, 1)],
474+
texture: tileTexture,
475+
},
476+
};
477+
477478
const trimesh = this.createTriMesh(rasterTile);
478479
if (undefined === trimesh)
479480
return undefined;

core/frontend/src/render/primitives/EdgeParams.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -293,7 +293,10 @@ export interface EdgeParams {
293293
export namespace EdgeParams {
294294
export function fromMeshArgs(meshArgs: MeshArgs, maxWidth?: number): EdgeParams | undefined {
295295
const args = meshArgs.edges;
296-
const doJoints = wantJointTriangles(args.width, meshArgs.is2d);
296+
if (!args)
297+
return undefined;
298+
299+
const doJoints = wantJointTriangles(args.width, true === meshArgs.is2d);
297300
const polylines = doJoints ? TesselatedPolyline.fromMesh(meshArgs) : undefined;
298301

299302
let segments: SegmentEdgeParams | undefined;

core/frontend/src/render/primitives/PolylineParams.ts

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,6 @@ class PolylineVertex {
8787

8888
class PolylineTesselator {
8989
private _polylines: PolylineData[];
90-
private _points: QPoint3dList;
9190
private _doJoints: boolean;
9291
private _numIndices = 0;
9392
private _vertIndex: number[] = [];
@@ -96,9 +95,15 @@ class PolylineTesselator {
9695
private _nextParam: number[] = [];
9796
private _position: Point3d[] = [];
9897

99-
public constructor(polylines: PolylineData[], points: QPoint3dList, doJointTriangles: boolean) {
98+
public constructor(polylines: PolylineData[], points: QPoint3dList | Point3d[], doJointTriangles: boolean) {
10099
this._polylines = polylines;
101-
this._points = points;
100+
if (points instanceof QPoint3dList) {
101+
for (const p of points.list)
102+
this._position.push(p.unquantize(points.params));
103+
} else {
104+
this._position = points;
105+
}
106+
102107
this._doJoints = doJointTriangles;
103108
}
104109

@@ -107,16 +112,13 @@ class PolylineTesselator {
107112
}
108113

109114
public static fromMesh(args: MeshArgs): PolylineTesselator | undefined {
110-
if (undefined !== args.edges.polylines.lines && undefined !== args.points)
111-
return new PolylineTesselator(args.edges.polylines.lines, args.points, wantJointTriangles(args.edges.width, args.is2d));
115+
if (undefined !== args.edges?.polylines.lines && undefined !== args.points)
116+
return new PolylineTesselator(args.edges.polylines.lines, args.points, wantJointTriangles(args.edges.width, true === args.is2d));
112117

113118
return undefined;
114119
}
115120

116121
public tesselate(): TesselatedPolyline {
117-
for (const p of this._points.list)
118-
this._position.push(p.unquantize(this._points.params));
119-
120122
this._tesselate();
121123

122124
const vertIndex = VertexIndices.fromArray(this._vertIndex);

core/frontend/src/render/primitives/VertexKey.ts

Lines changed: 35 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -7,25 +7,36 @@
77
*/
88

99
import { assert, compareWithTolerance, IndexMap } from "@itwin/core-bentley";
10-
import { Point2d } from "@itwin/core-geometry";
11-
import { OctEncodedNormal, QPoint3d } from "@itwin/core-common";
10+
import { Point2d, Point3d, XYAndZ } from "@itwin/core-geometry";
11+
import { OctEncodedNormal } from "@itwin/core-common";
1212

1313
/** @internal */
1414
export interface VertexKeyProps {
15-
position: QPoint3d;
15+
position: Point3d;
1616
fillColor: number;
1717
normal?: OctEncodedNormal;
1818
uvParam?: Point2d;
1919
}
2020

21+
function comparePositions(p0: Point3d, p1: Point3d, tolerance: XYAndZ): number {
22+
let diff = compareWithTolerance(p0.x, p1.x, tolerance.x);
23+
if (0 === diff) {
24+
diff = compareWithTolerance(p0.y, p1.y, tolerance.y);
25+
if (0 === diff)
26+
diff = compareWithTolerance(p0.z, p1.z, tolerance.z);
27+
}
28+
29+
return diff;
30+
}
31+
2132
/** @internal */
2233
export class VertexKey {
23-
public readonly position: QPoint3d;
34+
public readonly position: Point3d;
2435
public readonly normal?: OctEncodedNormal;
2536
public readonly uvParam?: Point2d;
2637
public readonly fillColor: number;
2738

28-
public constructor(position: QPoint3d, fillColor: number, normal?: OctEncodedNormal, uvParam?: Point2d) {
39+
public constructor(position: Point3d, fillColor: number, normal?: OctEncodedNormal, uvParam?: Point2d) {
2940
this.position = position.clone();
3041
this.fillColor = fillColor;
3142
this.normal = normal;
@@ -34,7 +45,7 @@ export class VertexKey {
3445

3546
public static create(props: VertexKeyProps): VertexKey { return new VertexKey(props.position, props.fillColor, props.normal, props.uvParam); }
3647

37-
public equals(rhs: VertexKey): boolean {
48+
public equals(rhs: VertexKey, tolerance: XYAndZ): boolean {
3849
if (this.fillColor !== rhs.fillColor)
3950
return false;
4051

@@ -44,24 +55,24 @@ export class VertexKey {
4455
return false;
4556
}
4657

47-
if (!this.position.equals(rhs.position))
58+
if (0 !== comparePositions(this.position, rhs.position, tolerance))
4859
return false;
4960

5061
if (undefined !== this.uvParam) {
5162
assert(undefined !== rhs.uvParam);
52-
return this.uvParam.isAlmostEqual(rhs.uvParam, 0.1);
63+
return this.uvParam.isAlmostEqual(rhs.uvParam, 0.1); // ###TODO surely this is a typo?
5364
}
5465

5566
return true;
5667
}
5768

58-
public compare(rhs: VertexKey): number {
69+
public compare(rhs: VertexKey, tolerance: XYAndZ): number {
5970
if (this === rhs)
6071
return 0;
6172

6273
let diff = this.fillColor - rhs.fillColor;
6374
if (0 === diff) {
64-
diff = this.position.compare(rhs.position);
75+
diff = comparePositions(this.position, rhs.position, tolerance);
6576
if (0 === diff) {
6677
if (undefined !== this.normal) {
6778
assert(undefined !== rhs.normal);
@@ -83,9 +94,22 @@ export class VertexKey {
8394

8495
/** @internal */
8596
export class VertexMap extends IndexMap<VertexKey> {
86-
public constructor() { super((lhs, rhs) => lhs.compare(rhs)); }
97+
private readonly _tolerance: XYAndZ;
98+
99+
public constructor(tolerance: XYAndZ) {
100+
super((lhs, rhs) => lhs.compare(rhs, tolerance));
101+
this._tolerance = tolerance;
102+
}
87103

88104
public insertKey(props: VertexKeyProps, onInsert?: (vk: VertexKey) => any): number {
89105
return this.insert(VertexKey.create(props), onInsert);
90106
}
107+
108+
public arePositionsAlmostEqual(p0: VertexKeyProps, p1: VertexKeyProps): boolean {
109+
return 0 === this.comparePositions(p0, p1);
110+
}
111+
112+
public comparePositions(p0: VertexKeyProps, p1: VertexKeyProps): number {
113+
return comparePositions(p0.position, p1.position, this._tolerance);
114+
}
91115
}

0 commit comments

Comments
 (0)