Skip to content

Support unquantized vertex tables #3288

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

Merged
merged 39 commits into from
Mar 3, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
39 commits
Select commit Hold shift + click to select a range
2d50982
Remove obsolete unused BingElevation-based terrain.
pmconne Feb 28, 2022
6c14854
MeshPointList
pmconne Mar 1, 2022
a5380eb
Option to quantize positions.
pmconne Mar 1, 2022
52cd7dc
Simplify graphic args pt 1: delete MeshGraphicArgs.
pmconne Mar 1, 2022
16b7a7b
Get stuff (mostly tests) compiling.
pmconne Mar 1, 2022
9e4930e
Clean up (to an extent) MeshArgs and PolylineArgs. Tests are annoying.
pmconne Mar 1, 2022
b9a938d
remove obsolete TODO.
pmconne Mar 1, 2022
fa8dae5
Quantized vertex table builders.
pmconne Mar 1, 2022
1dcf8fe
unquantized vertex table builders.
pmconne Mar 1, 2022
3821a1f
Mesh/PolylineArgs.points doesn't need an add method.
pmconne Mar 2, 2022
7438195
Vertex comparison tolerance based on quantization params or chord tol…
pmconne Mar 2, 2022
4e5fded
fix dumb test.
pmconne Mar 2, 2022
210171f
fix a couple tests.
pmconne Mar 2, 2022
536bfa4
fix vertex comparison.
pmconne Mar 2, 2022
f437dc5
Clarify feature index is 24 bits and material index is not produced b…
pmconne Mar 2, 2022
587f45f
indentation
pmconne Mar 2, 2022
eb3c209
ShaderBuilderFlags is an object.
pmconne Mar 2, 2022
e0f1c0d
Read vertex table data up front.
pmconne Mar 2, 2022
f49dff9
Use pre-sampled data for position.
pmconne Mar 2, 2022
f95e696
Use pre-sampled data for normals and color index.
pmconne Mar 2, 2022
3768393
Use pre-sampled vertex data everywhere.
pmconne Mar 2, 2022
bff046f
Support decoding unquantized vertex position.
pmconne Mar 2, 2022
6aca2e5
Point3dList.range; qparams can be used for deriving range even if pos…
pmconne Mar 3, 2022
c2dd2ad
Flag specifying whether positions are quantized.
pmconne Mar 3, 2022
8491b7c
consolidate normal computation.
pmconne Mar 3, 2022
270a74a
When reading vertex data conditionalize based on whether positions ar…
pmconne Mar 3, 2022
5c3359d
Decode unquantized polyline/edge endpoints.
pmconne Mar 3, 2022
feea77e
PolylineTesselator.
pmconne Mar 3, 2022
382a08b
Turn on unquantized positions for decorations.
pmconne Mar 3, 2022
c3fb479
fix 3 tests.
pmconne Mar 3, 2022
75d0aa9
Test for unquantized vertex table (failing).
pmconne Mar 3, 2022
4a2f1b0
Get test passing.
pmconne Mar 3, 2022
f78e91a
unquantized geometry now renders correctly.
pmconne Mar 3, 2022
44d7fcd
update TODO. Probably won't address.
pmconne Mar 3, 2022
aff1667
Define unquantized positions relative to center of range.
pmconne Mar 3, 2022
2f2f49a
Update test.
pmconne Mar 3, 2022
c9cd890
extract-api
pmconne Mar 3, 2022
946189c
lint....
pmconne Mar 3, 2022
d2067ff
please build my code.
pmconne Mar 3, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 0 additions & 2 deletions common/api/core-frontend.api.md
Original file line number Diff line number Diff line change
Expand Up @@ -1617,8 +1617,6 @@ export class BingElevationProvider {
constructor();
// @internal (undocumented)
getGeodeticToSeaLevelOffset(point: Point3d, iModel: IModelConnection): Promise<number>;
// @internal (undocumented)
getGraphic(latLongRange: Range2d, corners: Point3d[], groundBias: number, texture: RenderTexture, system: RenderSystem): Promise<RenderGraphic | undefined>;
getHeight(carto: Cartographic, geodetic?: boolean): Promise<any>;
getHeightAverage(iModel: IModelConnection): Promise<number>;
getHeightRange(iModel: IModelConnection): Promise<Range1d>;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"changes": [
{
"packageName": "@itwin/core-frontend",
"comment": "Increase precision for vertex positions when producing decoration graphics, to reduce visual artifacts.",
"type": "none"
}
],
"packageName": "@itwin/core-frontend"
}
30 changes: 20 additions & 10 deletions core/frontend/src/render/ParticleCollectionBuilder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
import { Id64String } from "@itwin/core-bentley";
import { Matrix3d, Point2d, Point3d, Range3d, Transform, Vector2d, XAndY, XYAndZ } from "@itwin/core-geometry";
import {
ColorDef, Feature, FeatureTable, PackedFeatureTable, QParams3d, QPoint3dList, RenderTexture,
ColorDef, ColorIndex, Feature, FeatureIndex, FeatureTable, FillFlags, PackedFeatureTable, QParams3d, QPoint3dList, RenderTexture,
} from "@itwin/core-common";
import { Viewport } from "../Viewport";
import { RenderGraphic } from "./RenderGraphic";
Expand Down Expand Up @@ -343,19 +343,29 @@ function createQuad(size: XAndY, texture: RenderTexture, transparency: number):
new Point3d(-halfWidth, halfHeight, 0), new Point3d(halfWidth, halfHeight, 0),
];

const quadArgs = new MeshArgs();
const range = new Range3d();
range.low = corners[0];
range.high = corners[3];
quadArgs.points = new QPoint3dList(QParams3d.fromRange(range));
for (const corner of corners)
quadArgs.points.add(corner);

quadArgs.vertIndices = [0, 1, 2, 2, 1, 3];
quadArgs.textureUv = [new Point2d(0, 1), new Point2d(1, 1), new Point2d(0, 0), new Point2d(1, 0)];
quadArgs.texture = texture;
quadArgs.colors.initUniform(ColorDef.white.withTransparency(transparency));
quadArgs.isPlanar = true;
const points = new QPoint3dList(QParams3d.fromRange(range));
for (const corner of corners)
points.add(corner);

const colors = new ColorIndex();
colors.initUniform(ColorDef.white.withTransparency(transparency));

const quadArgs: MeshArgs = {
points,
vertIndices: [0, 1, 2, 2, 1, 3],
fillFlags: FillFlags.None,
isPlanar: true,
colors,
features: new FeatureIndex(),
textureMapping: {
texture,
uvParams: [new Point2d(0, 1), new Point2d(1, 1), new Point2d(0, 0), new Point2d(1, 0)],
},
};

return MeshParams.create(quadArgs);
}
Expand Down
41 changes: 21 additions & 20 deletions core/frontend/src/render/RenderSystem.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@

import { base64StringToUint8Array, Id64String, IDisposable } from "@itwin/core-bentley";
import {
ColorDef, ElementAlignedBox3d, FeatureIndexType, Frustum, Gradient, ImageBuffer, ImageBufferFormat, ImageSource, ImageSourceFormat,
ColorDef, ColorIndex, ElementAlignedBox3d, FeatureIndex, FeatureIndexType, FillFlags, Frustum, Gradient, ImageBuffer, ImageBufferFormat, ImageSource, ImageSourceFormat,
isValidImageSourceFormat, PackedFeatureTable, QParams3d, QPoint3dList, RenderMaterial, RenderTexture, SkyGradient, TextureProps, TextureTransparency,
} from "@itwin/core-common";
import { ClipVector, Matrix3d, Point2d, Point3d, Range2d, Range3d, Transform, Vector2d, XAndY } from "@itwin/core-geometry";
Expand Down Expand Up @@ -441,39 +441,40 @@ export abstract class RenderSystem implements IDisposable {
public createBackgroundMapDrape(_drapedTree: TileTreeReference, _mapTree: MapTileTreeReference): RenderTextureDrape | undefined { return undefined; }
/** @internal */
public createTile(tileTexture: RenderTexture, corners: Point3d[], featureIndex?: number): RenderGraphic | undefined {
const rasterTile = new MeshArgs();

// corners
// [0] [1]
// [2] [3]
// Quantize the points according to their range
rasterTile.points = new QPoint3dList(QParams3d.fromRange(Range3d.create(...corners)));
for (let i = 0; i < 4; ++i)
rasterTile.points.add(corners[i]);
const points = new QPoint3dList(QParams3d.fromRange(Range3d.create(...corners)));
for (let i = 0; i < 4; i++)
points.add(corners[i]);

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

rasterTile.vertIndices = [0, 1, 2, 2, 1, 3];
rasterTile.textureUv = [
new Point2d(0.0, 0.0),
new Point2d(1.0, 0.0),
new Point2d(0.0, 1.0),
new Point2d(1.0, 1.0),
];

rasterTile.texture = tileTexture;
rasterTile.isPlanar = true;

const features = new FeatureIndex();
if (undefined !== featureIndex) {
rasterTile.features.featureID = featureIndex;
rasterTile.features.type = FeatureIndexType.Uniform;
features.featureID = featureIndex;
features.type = FeatureIndexType.Uniform;
}

const rasterTile: MeshArgs = {
points,
vertIndices: [0, 1, 2, 2, 1, 3],
isPlanar: true,
features,
colors: new ColorIndex(),
fillFlags: FillFlags.None,
textureMapping: {
uvParams: [new Point2d(0, 0), new Point2d(1, 0), new Point2d(0, 1), new Point2d(1, 1)],
texture: tileTexture,
},
};

const trimesh = this.createTriMesh(rasterTile);
if (undefined === trimesh)
return undefined;
Expand Down
5 changes: 4 additions & 1 deletion core/frontend/src/render/primitives/EdgeParams.ts
Original file line number Diff line number Diff line change
Expand Up @@ -293,7 +293,10 @@ export interface EdgeParams {
export namespace EdgeParams {
export function fromMeshArgs(meshArgs: MeshArgs, maxWidth?: number): EdgeParams | undefined {
const args = meshArgs.edges;
const doJoints = wantJointTriangles(args.width, meshArgs.is2d);
if (!args)
return undefined;

const doJoints = wantJointTriangles(args.width, true === meshArgs.is2d);
const polylines = doJoints ? TesselatedPolyline.fromMesh(meshArgs) : undefined;

let segments: SegmentEdgeParams | undefined;
Expand Down
18 changes: 10 additions & 8 deletions core/frontend/src/render/primitives/PolylineParams.ts
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,6 @@ class PolylineVertex {

class PolylineTesselator {
private _polylines: PolylineData[];
private _points: QPoint3dList;
private _doJoints: boolean;
private _numIndices = 0;
private _vertIndex: number[] = [];
Expand All @@ -96,9 +95,15 @@ class PolylineTesselator {
private _nextParam: number[] = [];
private _position: Point3d[] = [];

public constructor(polylines: PolylineData[], points: QPoint3dList, doJointTriangles: boolean) {
public constructor(polylines: PolylineData[], points: QPoint3dList | Point3d[], doJointTriangles: boolean) {
this._polylines = polylines;
this._points = points;
if (points instanceof QPoint3dList) {
for (const p of points.list)
this._position.push(p.unquantize(points.params));
} else {
this._position = points;
}

this._doJoints = doJointTriangles;
}

Expand All @@ -107,16 +112,13 @@ class PolylineTesselator {
}

public static fromMesh(args: MeshArgs): PolylineTesselator | undefined {
if (undefined !== args.edges.polylines.lines && undefined !== args.points)
return new PolylineTesselator(args.edges.polylines.lines, args.points, wantJointTriangles(args.edges.width, args.is2d));
if (undefined !== args.edges?.polylines.lines && undefined !== args.points)
return new PolylineTesselator(args.edges.polylines.lines, args.points, wantJointTriangles(args.edges.width, true === args.is2d));

return undefined;
}

public tesselate(): TesselatedPolyline {
for (const p of this._points.list)
this._position.push(p.unquantize(this._points.params));

this._tesselate();

const vertIndex = VertexIndices.fromArray(this._vertIndex);
Expand Down
46 changes: 35 additions & 11 deletions core/frontend/src/render/primitives/VertexKey.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,25 +7,36 @@
*/

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

/** @internal */
export interface VertexKeyProps {
position: QPoint3d;
position: Point3d;
fillColor: number;
normal?: OctEncodedNormal;
uvParam?: Point2d;
}

function comparePositions(p0: Point3d, p1: Point3d, tolerance: XYAndZ): number {
let diff = compareWithTolerance(p0.x, p1.x, tolerance.x);
if (0 === diff) {
diff = compareWithTolerance(p0.y, p1.y, tolerance.y);
if (0 === diff)
diff = compareWithTolerance(p0.z, p1.z, tolerance.z);
}

return diff;
}

/** @internal */
export class VertexKey {
public readonly position: QPoint3d;
public readonly position: Point3d;
public readonly normal?: OctEncodedNormal;
public readonly uvParam?: Point2d;
public readonly fillColor: number;

public constructor(position: QPoint3d, fillColor: number, normal?: OctEncodedNormal, uvParam?: Point2d) {
public constructor(position: Point3d, fillColor: number, normal?: OctEncodedNormal, uvParam?: Point2d) {
this.position = position.clone();
this.fillColor = fillColor;
this.normal = normal;
Expand All @@ -34,7 +45,7 @@ export class VertexKey {

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

public equals(rhs: VertexKey): boolean {
public equals(rhs: VertexKey, tolerance: XYAndZ): boolean {
if (this.fillColor !== rhs.fillColor)
return false;

Expand All @@ -44,24 +55,24 @@ export class VertexKey {
return false;
}

if (!this.position.equals(rhs.position))
if (0 !== comparePositions(this.position, rhs.position, tolerance))
return false;

if (undefined !== this.uvParam) {
assert(undefined !== rhs.uvParam);
return this.uvParam.isAlmostEqual(rhs.uvParam, 0.1);
return this.uvParam.isAlmostEqual(rhs.uvParam, 0.1); // ###TODO surely this is a typo?
}

return true;
}

public compare(rhs: VertexKey): number {
public compare(rhs: VertexKey, tolerance: XYAndZ): number {
if (this === rhs)
return 0;

let diff = this.fillColor - rhs.fillColor;
if (0 === diff) {
diff = this.position.compare(rhs.position);
diff = comparePositions(this.position, rhs.position, tolerance);
if (0 === diff) {
if (undefined !== this.normal) {
assert(undefined !== rhs.normal);
Expand All @@ -83,9 +94,22 @@ export class VertexKey {

/** @internal */
export class VertexMap extends IndexMap<VertexKey> {
public constructor() { super((lhs, rhs) => lhs.compare(rhs)); }
private readonly _tolerance: XYAndZ;

public constructor(tolerance: XYAndZ) {
super((lhs, rhs) => lhs.compare(rhs, tolerance));
this._tolerance = tolerance;
}

public insertKey(props: VertexKeyProps, onInsert?: (vk: VertexKey) => any): number {
return this.insert(VertexKey.create(props), onInsert);
}

public arePositionsAlmostEqual(p0: VertexKeyProps, p1: VertexKeyProps): boolean {
return 0 === this.comparePositions(p0, p1);
}

public comparePositions(p0: VertexKeyProps, p1: VertexKeyProps): number {
return comparePositions(p0.position, p1.position, this._tolerance);
}
}
Loading