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

Point Cloud Attenuation in ModelExperimental #9998

Merged
merged 24 commits into from
Jan 12, 2022
Merged
Show file tree
Hide file tree
Changes from 9 commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
9b7e46e
Stub out attenuation pipeline stage
ptrgags Dec 16, 2021
4292d62
Grab pointCloudShading from model or tileset
ptrgags Dec 17, 2021
49f4fd2
Merge branch 'pnts-loader' into attenuation
ptrgags Jan 6, 2022
dd6fb50
export default for pipeline stage
ptrgags Jan 6, 2022
162e5a8
Merge branch 'main' into attenuation
ptrgags Jan 6, 2022
2a002f2
add attenuation to the shader
ptrgags Jan 7, 2022
aff7893
Merge branch 'main' into attenuation
ptrgags Jan 7, 2022
717e778
Add documentation comments
ptrgags Jan 10, 2022
91d84aa
Start adding unit tests for attenuation
ptrgags Jan 10, 2022
aeb1d9e
Refactor pipeline configuration
ptrgags Jan 10, 2022
3be5e39
Move attenuation check to pipeline configuration
ptrgags Jan 10, 2022
d49d787
Update attenuation tests
ptrgags Jan 10, 2022
7b832c8
Add specs for depth multiplier
ptrgags Jan 11, 2022
cd59f1c
Start testing geometric error
ptrgags Jan 11, 2022
16d7927
Unit test geometric error
ptrgags Jan 11, 2022
5e7d9ff
Forward point cloud shading from tileset
ptrgags Jan 11, 2022
2fc05d9
Default maximumAttenuation to max screenspace error
ptrgags Jan 11, 2022
0c84b40
Add pointCloudShading settings to fromGltf
ptrgags Jan 11, 2022
efee47d
PR feedback
ptrgags Jan 12, 2022
0bdcbce
Prevent tileset.pointCloudShading from being set to undefined
ptrgags Jan 12, 2022
4e460c8
Move MSSE handling to uniform callback
ptrgags Jan 12, 2022
d055289
update CHANGES.md
ptrgags Jan 12, 2022
08ce79d
Fix unit test
ptrgags Jan 12, 2022
95b495c
Fix typo
ptrgags Jan 12, 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
12 changes: 12 additions & 0 deletions Source/Scene/ModelExperimental/ModelExperimentalPrimitive.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,17 @@ import Check from "../../Core/Check.js";
import CustomShaderMode from "./CustomShaderMode.js";
import defaultValue from "../../Core/defaultValue.js";
import defined from "../../Core/defined.js";
import PrimitiveType from "../../Core/PrimitiveType.js";
import FeatureIdPipelineStage from "./FeatureIdPipelineStage.js";
import CPUStylingPipelineStage from "./CPUStylingPipelineStage.js";
import DequantizationPipelineStage from "./DequantizationPipelineStage.js";
import GeometryPipelineStage from "./GeometryPipelineStage.js";
import LightingPipelineStage from "./LightingPipelineStage.js";
import MaterialPipelineStage from "./MaterialPipelineStage.js";
import ModelExperimentalType from "./ModelExperimentalType.js";
import ModelExperimentalUtility from "./ModelExperimentalUtility.js";
import PickingPipelineStage from "./PickingPipelineStage.js";
import PointCloudAttenuationPipelineStage from "./PointCloudAttenuationPipelineStage.js";
import VertexAttributeSemantic from "../VertexAttributeSemantic.js";

/**
Expand Down Expand Up @@ -117,9 +120,18 @@ function initialize(runtimePrimitive) {
var hasQuantization = ModelExperimentalUtility.hasQuantizedAttributes(
primitive.attributes
);
var is3DTiles = ModelExperimentalType.is3DTiles(model.type);
var hasPointCloudShading = is3DTiles || defined(model.pointCloudShading);

pipelineStages.push(GeometryPipelineStage);

if (
hasPointCloudShading &&
ptrgags marked this conversation as resolved.
Show resolved Hide resolved
primitive.primitiveType === PrimitiveType.POINTS
) {
pipelineStages.push(PointCloudAttenuationPipelineStage);
ptrgags marked this conversation as resolved.
Show resolved Hide resolved
}

if (hasQuantization) {
pipelineStages.push(DequantizationPipelineStage);
}
Expand Down
120 changes: 120 additions & 0 deletions Source/Scene/ModelExperimental/PointCloudAttenuationPipelineStage.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
import Cartesian3 from "../../Core/Cartesian3.js";
import defaultValue from "../../Core/defaultValue.js";
import defined from "../../Core/defined.js";
import OrthographicFrustum from "../../Core/OrthographicFrustum.js";

import ShaderDestination from "../../Renderer/ShaderDestination.js";
import PointCloudAttenuationStageVS from "../../Shaders/ModelExperimental/PointCloudAttenuationStageVS.js";
import SceneMode from "../SceneMode.js";
import ModelExperimentalType from "./ModelExperimentalType.js";

/**
* Stage to handle point cloud attenuation.
*
* @namespace PointCloudAttenuationPipelineStage
*
* @private
*/
var PointCloudAttenuationPipelineStage = {};
PointCloudAttenuationPipelineStage.name = "PointCloudAttenuationPipelineStage"; // Helps with debugging

var scratchAttenuationUniform = new Cartesian3();

/**
* This stage does the following:
* <ul>
* <li>Add vertex shader code to compute attenuation and update gl_PointSize</li>
* <li>Updates the uniform map to pass in the point cloud attenuation parameters</li>
* </ul>
* @param {PrimitiveRenderResources} renderResources The render resources for this primitive
* @param {ModelComponents.primitive} primitive The primitive
* @param {FrameState} frameState The frame state
*
* @private
*/
PointCloudAttenuationPipelineStage.process = function (
renderResources,
primitive,
frameState
) {
var shaderBuilder = renderResources.shaderBuilder;
shaderBuilder.addVertexLines([PointCloudAttenuationStageVS]);
shaderBuilder.addDefine(
"USE_POINT_CLOUD_ATTENUATION",
undefined,
ShaderDestination.VERTEX
);

var model = renderResources.model;
var pointCloudShading;
var content;
if (ModelExperimentalType.is3DTiles(model.type)) {
content = model.content;
pointCloudShading = content.tileset.pointCloudShading;
} else {
pointCloudShading = model.pointCloudShading;
ptrgags marked this conversation as resolved.
Show resolved Hide resolved
}

shaderBuilder.addUniform(
"vec3",
"model_pointCloudAttenuation",
ShaderDestination.VERTEX
);
renderResources.uniformMap.model_pointCloudAttenuation = function () {
var scratch = scratchAttenuationUniform;

// attenuation.x = pointSize
scratch.x = pointCloudShading.attenuation
? defaultValue(pointCloudShading.maximumAttenuation, 1.0)
: 1.0;
scratch.x *= frameState.pixelRatio;

if (pointCloudShading.attenuation) {
ptrgags marked this conversation as resolved.
Show resolved Hide resolved
var context = frameState.context;
var frustum = frameState.camera.frustum;
var depthMultiplier;

// Attenuation is maximumAttenuation in 2D/ortho
if (
frameState.mode === SceneMode.SCENE2D ||
frustum instanceof OrthographicFrustum
) {
depthMultiplier = Number.POSITIVE_INFINITY;
} else {
depthMultiplier =
context.drawingBufferHeight /
frameState.camera.frustum.sseDenominator;
}

// attenuation.y = geometricError
var geometricError = getGeometricError(pointCloudShading, content);
scratch.y = geometricError * pointCloudShading.geometricErrorScale;

// attenuation.z = depth multiplier
scratch.z = depthMultiplier;
}

return scratch;
};
};

function getGeometricError(pointCloudShading, content) {
if (defined(content)) {
var geometricError = content._tile.geometricError;

if (geometricError > 0) {
return geometricError;
}
}

if (defined(pointCloudShading) && defined(pointCloudShading.baseResolution)) {
return pointCloudShading.baseResolution;
}

// TODO: Waiting on another PR which has updates to the model matrix.
// estimate the geometric error. Originally it was done as
// cbrt(boundingVolume.volume() / pointsLength)
return 0.79;
}

export default PointCloudAttenuationPipelineStage;
2 changes: 2 additions & 0 deletions Source/Shaders/ModelExperimental/ModelExperimentalVS.glsl
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,8 @@ void main()
#ifdef PRIMITIVE_TYPE_POINTS
#ifdef HAS_CUSTOM_VERTEX_SHADER
gl_PointSize = vsOutput.pointSize;
#elif defined(USE_POINT_CLOUD_ATTENUATION)
gl_PointSize = pointCloudAttenuationStage(v_positionEC);
#else
gl_PointSize = 1.0;
#endif
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
float pointCloudAttenuationStage(vec3 positionEC) {
// Variables are packed into a single vector to minimize gl.uniformXXX() calls
float pointSize = model_pointCloudAttenuation.x;
float geometricError = model_pointCloudAttenuation.y;
float depthMultiplier = model_pointCloudAttenuation.z;
float depth = -positionEC.z;
return min((geometricError / depth) * depthMultiplier, pointSize);
}
2 changes: 1 addition & 1 deletion Specs/Scene/ModelExperimental/MaterialPipelineStageSpec.js
Original file line number Diff line number Diff line change
Expand Up @@ -655,5 +655,5 @@ describe(
});
});
},
"WEBGL"
"WebGL"
);
91 changes: 90 additions & 1 deletion Specs/Scene/ModelExperimental/ModelExperimentalPrimitiveSpec.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,10 @@ import {
GeometryPipelineStage,
LightingPipelineStage,
MaterialPipelineStage,
ModelExperimentalType,
PickingPipelineStage,
PointCloudAttenuationPipelineStage,
PrimitiveType,
VertexAttributeSemantic,
BatchTexturePipelineStage,
ModelExperimentalPrimitive,
Expand All @@ -22,6 +25,7 @@ describe("Scene/ModelExperimental/ModelExperimentalPrimitive", function () {
};
var mockNode = {};
var mockModel = {
type: ModelExperimentalType.GLTF,
allowPicking: true,
featureIdAttributeIndex: 0,
};
Expand All @@ -34,7 +38,7 @@ describe("Scene/ModelExperimental/ModelExperimentalPrimitive", function () {
function verifyExpectedStages(stages, expectedStages) {
expect(stages.length, expectedStages.stages);
for (var i = 0; i < stages.length; i++) {
expect(expectedStages[i].name).toEqual(stages[i].name);
expect(stages[i].name).toEqual(expectedStages[i].name);
}
}

Expand Down Expand Up @@ -101,6 +105,7 @@ describe("Scene/ModelExperimental/ModelExperimentalPrimitive", function () {
primitive: mockPrimitive,
node: mockNode,
model: {
type: ModelExperimentalType.GLTF,
allowPicking: false,
content: {},
},
Expand Down Expand Up @@ -154,6 +159,7 @@ describe("Scene/ModelExperimental/ModelExperimentalPrimitive", function () {
},
node: {},
model: {
type: ModelExperimentalType.GLTF,
allowPicking: true,
featureIdAttributeIndex: 1,
content: {},
Expand Down Expand Up @@ -181,6 +187,7 @@ describe("Scene/ModelExperimental/ModelExperimentalPrimitive", function () {
},
node: {},
model: {
type: ModelExperimentalType.GLTF,
allowPicking: true,
featureIdTextureIndex: 1,
content: {},
Expand Down Expand Up @@ -224,6 +231,7 @@ describe("Scene/ModelExperimental/ModelExperimentalPrimitive", function () {
primitive: mockPrimitive,
node: mockNode,
model: {
type: ModelExperimentalType.GLTF,
content: {},
customShader: new CustomShader({
vertexShaderText: emptyVertexShader,
Expand All @@ -248,6 +256,7 @@ describe("Scene/ModelExperimental/ModelExperimentalPrimitive", function () {
primitive: mockPrimitive,
node: mockNode,
model: {
type: ModelExperimentalType.GLTF,
content: {},
customShader: new CustomShader({
mode: CustomShaderMode.REPLACE_MATERIAL,
Expand All @@ -272,6 +281,7 @@ describe("Scene/ModelExperimental/ModelExperimentalPrimitive", function () {
primitive: mockPrimitive,
node: mockNode,
model: {
type: ModelExperimentalType.GLTF,
content: {},
customShader: new CustomShader({
mode: CustomShaderMode.REPLACE_MATERIAL,
Expand All @@ -290,4 +300,83 @@ describe("Scene/ModelExperimental/ModelExperimentalPrimitive", function () {

verifyExpectedStages(primitive.pipelineStages, expectedStages);
});

it("configures point cloud attenuation stage for 3D Tiles point clouds", function () {
var primitive = new ModelExperimentalPrimitive({
primitive: {
featureIdAttributes: [],
featureIdTextures: [],
attributes: [],
primitiveType: PrimitiveType.POINTS,
},
node: mockNode,
model: {
type: ModelExperimentalType.TILE_PNTS,
featureIdAttributeIndex: 0,
},
});

var expectedStages = [
GeometryPipelineStage,
PointCloudAttenuationPipelineStage,
MaterialPipelineStage,
LightingPipelineStage,
AlphaPipelineStage,
];

verifyExpectedStages(primitive.pipelineStages, expectedStages);
});

it("configures point cloud attenuation stage for point clouds", function () {
var primitive = new ModelExperimentalPrimitive({
primitive: {
featureIdAttributes: [],
featureIdTextures: [],
attributes: [],
primitiveType: PrimitiveType.POINTS,
},
node: mockNode,
model: {
type: ModelExperimentalType.GLTF,
featureIdAttributeIndex: 0,
pointCloudShading: {},
},
});

var expectedStages = [
GeometryPipelineStage,
PointCloudAttenuationPipelineStage,
MaterialPipelineStage,
LightingPipelineStage,
AlphaPipelineStage,
];

verifyExpectedStages(primitive.pipelineStages, expectedStages);
});

it("skips point cloud attenuation if point cloud shading is not set", function () {
var primitive = new ModelExperimentalPrimitive({
primitive: {
featureIdAttributes: [],
featureIdTextures: [],
attributes: [],
primitiveType: PrimitiveType.POINTS,
},
node: mockNode,
model: {
type: ModelExperimentalType.GLTF,
featureIdAttributeIndex: 0,
pointCloudShading: undefined,
},
});

var expectedStages = [
GeometryPipelineStage,
MaterialPipelineStage,
LightingPipelineStage,
AlphaPipelineStage,
];

verifyExpectedStages(primitive.pipelineStages, expectedStages);
});
});
Loading