import {
|
combine,
|
GltfLoader,
|
FeatureIdPipelineStage,
|
ShaderBuilder,
|
ShaderDestination,
|
Resource,
|
ResourceCache,
|
_shadersFeatureStageCommon,
|
_shadersFeatureStageFS,
|
_shadersFeatureStageVS,
|
} from "../../../Source/Cesium.js";
|
import createScene from "../../createScene.js";
|
import ShaderBuilderTester from "../../ShaderBuilderTester.js";
|
import waitForLoaderProcess from "../../waitForLoaderProcess.js";
|
|
describe("Scene/ModelExperimental/FeatureIdPipelineStage", function () {
|
var buildingsMetadata =
|
"./Data/Models/GltfLoader/BuildingsMetadata/glTF/buildings-metadata.gltf";
|
var microcosm = "./Data/Models/GltfLoader/Microcosm/glTF/microcosm.gltf";
|
var boxInstanced =
|
"./Data/Models/GltfLoader/BoxInstanced/glTF/box-instanced.gltf";
|
|
var scene;
|
var gltfLoaders = [];
|
|
var defaultShaderBuilder;
|
|
beforeAll(function () {
|
scene = createScene();
|
defaultShaderBuilder = createDefaultShaderBuilder();
|
});
|
|
afterAll(function () {
|
scene.destroyForSpecs();
|
});
|
|
afterEach(function () {
|
var gltfLoadersLength = gltfLoaders.length;
|
for (var i = 0; i < gltfLoadersLength; ++i) {
|
var gltfLoader = gltfLoaders[i];
|
if (!gltfLoader.isDestroyed()) {
|
gltfLoader.destroy();
|
}
|
}
|
gltfLoaders.length = 0;
|
ResourceCache.clearForSpecs();
|
});
|
|
function createDefaultShaderBuilder() {
|
var shaderBuilder = new ShaderBuilder();
|
shaderBuilder.addStruct(
|
FeatureIdPipelineStage.STRUCT_ID_FEATURE,
|
FeatureIdPipelineStage.STRUCT_NAME_FEATURE,
|
ShaderDestination.BOTH
|
);
|
return shaderBuilder;
|
}
|
|
function verifyFeatureStruct(shaderBuilder) {
|
ShaderBuilderTester.expectHasVertexStruct(
|
shaderBuilder,
|
FeatureIdPipelineStage.STRUCT_ID_FEATURE,
|
FeatureIdPipelineStage.STRUCT_NAME_FEATURE,
|
[" int id;", " vec2 st;", " vec4 color;"]
|
);
|
ShaderBuilderTester.expectHasFragmentStruct(
|
shaderBuilder,
|
FeatureIdPipelineStage.STRUCT_ID_FEATURE,
|
FeatureIdPipelineStage.STRUCT_NAME_FEATURE,
|
[" int id;", " vec2 st;", " vec4 color;"]
|
);
|
}
|
|
function verifyFeatureStructFunctions(shaderBuilder) {
|
ShaderBuilderTester.expectHasVertexFunction(
|
shaderBuilder,
|
FeatureIdPipelineStage.FUNCTION_ID_FEATURE_VARYINGS_VS,
|
FeatureIdPipelineStage.FUNCTION_SIGNATURE_UPDATE_FEATURE,
|
[
|
" v_activeFeatureId = float(feature.id);",
|
" v_activeFeatureSt = feature.st;",
|
" v_activeFeatureColor = feature.color;",
|
]
|
);
|
ShaderBuilderTester.expectHasFragmentFunction(
|
shaderBuilder,
|
FeatureIdPipelineStage.FUNCTION_ID_FEATURE_VARYINGS_FS,
|
FeatureIdPipelineStage.FUNCTION_SIGNATURE_UPDATE_FEATURE,
|
[
|
" feature.id = int(v_activeFeatureId);",
|
" feature.st = v_activeFeatureSt;",
|
" feature.color = v_activeFeatureColor;",
|
]
|
);
|
}
|
|
function getOptions(gltfPath, options) {
|
var resource = new Resource({
|
url: gltfPath,
|
});
|
|
return combine(options, {
|
gltfResource: resource,
|
incrementallyLoadTextures: false,
|
});
|
}
|
|
function loadGltf(gltfPath, options) {
|
var gltfLoader = new GltfLoader(getOptions(gltfPath, options));
|
gltfLoaders.push(gltfLoader);
|
gltfLoader.load();
|
|
return waitForLoaderProcess(gltfLoader, scene);
|
}
|
|
function expectUniformMap(uniformMap, expected) {
|
for (var key in expected) {
|
if (expected.hasOwnProperty(key)) {
|
var expectedValue = expected[key];
|
var uniformFunction = uniformMap[key];
|
expect(uniformFunction).toBeDefined();
|
expect(uniformFunction()).toEqual(expectedValue);
|
}
|
}
|
}
|
|
it("processes primitive feature IDs from vertex attribute", function () {
|
var renderResources = {
|
shaderBuilder: defaultShaderBuilder.clone(),
|
model: {
|
featureIdAttributeIndex: 0,
|
},
|
runtimeNode: { node: {} },
|
hasFeatureIds: false,
|
featureTableId: undefined,
|
};
|
|
return loadGltf(buildingsMetadata).then(function (gltfLoader) {
|
var components = gltfLoader.components;
|
var primitive = components.nodes[1].primitives[0];
|
|
var frameState = scene.frameState;
|
var context = frameState.context;
|
// Reset pick objects.
|
context._pickObjects = [];
|
|
FeatureIdPipelineStage.process(renderResources, primitive, frameState);
|
|
expect(renderResources.hasFeatureIds).toBe(true);
|
|
var shaderBuilder = renderResources.shaderBuilder;
|
|
ShaderBuilderTester.expectHasVertexDefines(shaderBuilder, [
|
"HAS_FEATURES",
|
"FEATURE_ID_ATTRIBUTE a_featureId_0",
|
]);
|
|
ShaderBuilderTester.expectHasFragmentDefines(shaderBuilder, [
|
"HAS_FEATURES",
|
]);
|
ShaderBuilderTester.expectHasVaryings(shaderBuilder, [
|
"varying float v_activeFeatureId;",
|
"varying vec2 v_activeFeatureSt;",
|
"varying vec4 v_activeFeatureColor;",
|
]);
|
|
verifyFeatureStruct(shaderBuilder);
|
verifyFeatureStructFunctions(shaderBuilder);
|
|
ShaderBuilderTester.expectVertexLinesEqual(shaderBuilder, [
|
_shadersFeatureStageCommon,
|
_shadersFeatureStageVS,
|
]);
|
|
ShaderBuilderTester.expectFragmentLinesEqual(shaderBuilder, [
|
_shadersFeatureStageCommon,
|
_shadersFeatureStageFS,
|
]);
|
});
|
});
|
|
it("processes primitive implicit feature IDs", function () {
|
var renderResources = {
|
shaderBuilder: defaultShaderBuilder.clone(),
|
model: {
|
featureIdAttributeIndex: 1,
|
_resources: [],
|
},
|
attributeIndex: 4,
|
attributes: [],
|
runtimeNode: { node: {} },
|
hasFeatureIds: false,
|
propertyTableId: undefined,
|
featureIdVertexAttributeSetIndex: 1,
|
};
|
|
return loadGltf(buildingsMetadata).then(function (gltfLoader) {
|
var components = gltfLoader.components;
|
var primitive = components.nodes[1].primitives[0];
|
|
var frameState = scene.frameState;
|
var context = frameState.context;
|
// Reset pick objects.
|
context._pickObjects = [];
|
|
FeatureIdPipelineStage.process(renderResources, primitive, frameState);
|
|
expect(renderResources.hasFeatureIds).toBe(true);
|
|
var shaderBuilder = renderResources.shaderBuilder;
|
|
ShaderBuilderTester.expectHasVertexDefines(shaderBuilder, [
|
"HAS_FEATURES",
|
"FEATURE_ID_ATTRIBUTE a_featureId_1",
|
]);
|
|
ShaderBuilderTester.expectHasFragmentDefines(shaderBuilder, [
|
"HAS_FEATURES",
|
]);
|
|
ShaderBuilderTester.expectHasAttributes(shaderBuilder, undefined, [
|
"attribute float a_featureId_1;",
|
]);
|
ShaderBuilderTester.expectHasVaryings(shaderBuilder, [
|
"varying float v_activeFeatureId;",
|
"varying vec2 v_activeFeatureSt;",
|
"varying vec4 v_activeFeatureColor;",
|
]);
|
|
ShaderBuilderTester.expectVertexLinesEqual(shaderBuilder, [
|
_shadersFeatureStageCommon,
|
_shadersFeatureStageVS,
|
]);
|
|
ShaderBuilderTester.expectFragmentLinesEqual(shaderBuilder, [
|
_shadersFeatureStageCommon,
|
_shadersFeatureStageFS,
|
]);
|
|
verifyFeatureStruct(shaderBuilder);
|
verifyFeatureStructFunctions(shaderBuilder);
|
|
expect(renderResources.featureIdVertexAttributeSetIndex).toEqual(2);
|
|
var vertexBuffer = renderResources.model._resources[0];
|
expect(vertexBuffer.vertexArrayDestroyable).toBe(false);
|
|
var vertexAttribute = renderResources.attributes[0];
|
expect(vertexAttribute.instanceDivisor).toEqual(0);
|
expect(vertexAttribute.vertexBuffer).toBe(vertexBuffer);
|
});
|
});
|
|
it("processes primitive implicit feature ID constant only", function () {
|
var renderResources = {
|
shaderBuilder: defaultShaderBuilder.clone(),
|
model: {
|
featureIdAttributeIndex: 2,
|
_resources: [],
|
},
|
attributeIndex: 4,
|
attributes: [],
|
runtimeNode: { node: {} },
|
hasFeatureIds: false,
|
propertyTableId: undefined,
|
featureIdVertexAttributeSetIndex: 1,
|
};
|
|
return loadGltf(buildingsMetadata).then(function (gltfLoader) {
|
var components = gltfLoader.components;
|
var primitive = components.nodes[1].primitives[0];
|
|
var frameState = scene.frameState;
|
var context = frameState.context;
|
// Reset pick objects.
|
context._pickObjects = [];
|
|
FeatureIdPipelineStage.process(renderResources, primitive, frameState);
|
|
expect(renderResources.hasFeatureIds).toBe(true);
|
|
var shaderBuilder = renderResources.shaderBuilder;
|
|
ShaderBuilderTester.expectHasVertexDefines(shaderBuilder, [
|
"HAS_FEATURES",
|
"FEATURE_ID_ATTRIBUTE a_featureId_1",
|
]);
|
|
ShaderBuilderTester.expectHasFragmentDefines(shaderBuilder, [
|
"HAS_FEATURES",
|
]);
|
|
ShaderBuilderTester.expectHasAttributes(shaderBuilder, undefined, [
|
"attribute float a_featureId_1;",
|
]);
|
ShaderBuilderTester.expectHasVaryings(shaderBuilder, [
|
"varying float v_activeFeatureId;",
|
"varying vec2 v_activeFeatureSt;",
|
"varying vec4 v_activeFeatureColor;",
|
]);
|
|
ShaderBuilderTester.expectVertexLinesEqual(shaderBuilder, [
|
_shadersFeatureStageCommon,
|
_shadersFeatureStageVS,
|
]);
|
|
ShaderBuilderTester.expectFragmentLinesEqual(shaderBuilder, [
|
_shadersFeatureStageCommon,
|
_shadersFeatureStageFS,
|
]);
|
|
verifyFeatureStruct(shaderBuilder);
|
verifyFeatureStructFunctions(shaderBuilder);
|
|
expect(renderResources.featureIdVertexAttributeSetIndex).toEqual(2);
|
|
expect(renderResources.model._resources).toEqual([]);
|
|
var vertexAttribute = renderResources.attributes[0];
|
expect(vertexAttribute.instanceDivisor).toEqual(0);
|
expect(vertexAttribute.buffer).not.toBeDefined();
|
expect(vertexAttribute.value).toBe(3);
|
});
|
});
|
|
it("processes instances feature IDs from vertex attribute", function () {
|
var renderResources = {
|
shaderBuilder: defaultShaderBuilder.clone(),
|
model: {
|
featureIdAttributeIndex: 1,
|
},
|
runtimeNode: {},
|
hasFeatureIds: false,
|
propertyTableId: undefined,
|
};
|
|
return loadGltf(boxInstanced).then(function (gltfLoader) {
|
var components = gltfLoader.components;
|
var node = components.nodes[0];
|
renderResources.runtimeNode.node = node;
|
var primitive = node.primitives[0];
|
|
var frameState = scene.frameState;
|
var context = frameState.context;
|
// Reset pick objects.
|
context._pickObjects = [];
|
|
FeatureIdPipelineStage.process(renderResources, primitive, frameState);
|
|
expect(renderResources.hasFeatureIds).toBe(true);
|
|
var shaderBuilder = renderResources.shaderBuilder;
|
|
ShaderBuilderTester.expectHasVertexDefines(shaderBuilder, [
|
"HAS_FEATURES",
|
"FEATURE_ID_ATTRIBUTE a_instanceFeatureId_0",
|
]);
|
|
ShaderBuilderTester.expectHasFragmentDefines(shaderBuilder, [
|
"HAS_FEATURES",
|
]);
|
|
ShaderBuilderTester.expectHasVaryings(shaderBuilder, [
|
"varying float v_activeFeatureId;",
|
"varying vec2 v_activeFeatureSt;",
|
"varying vec4 v_activeFeatureColor;",
|
]);
|
|
verifyFeatureStruct(shaderBuilder);
|
verifyFeatureStructFunctions(shaderBuilder);
|
|
ShaderBuilderTester.expectVertexLinesEqual(shaderBuilder, [
|
_shadersFeatureStageCommon,
|
_shadersFeatureStageVS,
|
]);
|
|
ShaderBuilderTester.expectFragmentLinesEqual(shaderBuilder, [
|
_shadersFeatureStageCommon,
|
_shadersFeatureStageFS,
|
]);
|
});
|
});
|
|
it("processes instance implicit feature IDs", function () {
|
var renderResources = {
|
shaderBuilder: defaultShaderBuilder.clone(),
|
model: {
|
featureIdAttributeIndex: 0,
|
_resources: [],
|
},
|
attributeIndex: 4,
|
attributes: [],
|
runtimeNode: { node: {} },
|
hasFeatureIds: false,
|
propertyTableId: undefined,
|
featureIdVertexAttributeSetIndex: 1,
|
};
|
|
return loadGltf(boxInstanced).then(function (gltfLoader) {
|
var components = gltfLoader.components;
|
var node = components.nodes[0];
|
renderResources.runtimeNode.node = node;
|
var primitive = node.primitives[0];
|
|
var frameState = scene.frameState;
|
var context = frameState.context;
|
// Reset pick objects.
|
context._pickObjects = [];
|
|
FeatureIdPipelineStage.process(renderResources, primitive, frameState);
|
|
expect(renderResources.hasFeatureIds).toBe(true);
|
|
var shaderBuilder = renderResources.shaderBuilder;
|
|
ShaderBuilderTester.expectHasVertexDefines(shaderBuilder, [
|
"HAS_FEATURES",
|
"FEATURE_ID_ATTRIBUTE a_instanceFeatureId_1",
|
]);
|
|
ShaderBuilderTester.expectHasFragmentDefines(shaderBuilder, [
|
"HAS_FEATURES",
|
]);
|
|
ShaderBuilderTester.expectHasAttributes(shaderBuilder, undefined, [
|
"attribute float a_instanceFeatureId_1;",
|
]);
|
ShaderBuilderTester.expectHasVaryings(shaderBuilder, [
|
"varying float v_activeFeatureId;",
|
"varying vec2 v_activeFeatureSt;",
|
"varying vec4 v_activeFeatureColor;",
|
]);
|
|
verifyFeatureStruct(shaderBuilder);
|
verifyFeatureStructFunctions(shaderBuilder);
|
|
ShaderBuilderTester.expectVertexLinesEqual(shaderBuilder, [
|
_shadersFeatureStageCommon,
|
_shadersFeatureStageVS,
|
]);
|
|
ShaderBuilderTester.expectFragmentLinesEqual(shaderBuilder, [
|
_shadersFeatureStageCommon,
|
_shadersFeatureStageFS,
|
]);
|
|
expect(renderResources.featureIdVertexAttributeSetIndex).toEqual(2);
|
|
var vertexBuffer = renderResources.model._resources[0];
|
expect(vertexBuffer.vertexArrayDestroyable).toBe(false);
|
|
var vertexAttribute = renderResources.attributes[0];
|
expect(vertexAttribute.instanceDivisor).toEqual(1);
|
expect(vertexAttribute.vertexBuffer).toBe(vertexBuffer);
|
});
|
});
|
|
it("processes feature IDs from texture", function () {
|
var renderResources = {
|
attributeIndex: 1,
|
hasFeatureIds: false,
|
shaderBuilder: defaultShaderBuilder.clone(),
|
model: {
|
featureIdTextureIndex: 0,
|
},
|
uniformMap: {},
|
};
|
|
return loadGltf(microcosm).then(function (gltfLoader) {
|
var components = gltfLoader.components;
|
var primitive = components.nodes[0].primitives[0];
|
|
var frameState = scene.frameState;
|
var context = frameState.context;
|
// Reset pick objects.
|
context._pickObjects = [];
|
|
FeatureIdPipelineStage.process(renderResources, primitive, frameState);
|
expect(renderResources.hasFeatureIds).toBe(true);
|
|
var shaderBuilder = renderResources.shaderBuilder;
|
ShaderBuilderTester.expectHasVertexDefines(shaderBuilder, [
|
"HAS_FEATURES",
|
]);
|
|
ShaderBuilderTester.expectHasFragmentDefines(shaderBuilder, [
|
"HAS_FEATURES",
|
"FEATURE_ID_TEXTURE u_featureIdTexture_0",
|
"FEATURE_ID_TEXCOORD v_texCoord_0",
|
"FEATURE_ID_CHANNEL r",
|
]);
|
|
ShaderBuilderTester.expectHasFragmentUniforms(shaderBuilder, [
|
"uniform sampler2D u_featureIdTexture_0;",
|
]);
|
|
var expectedUniforms = {
|
u_featureIdTexture_0:
|
primitive.featureIdTextures[0].textureReader.texture,
|
};
|
|
expectUniformMap(renderResources.uniformMap, expectedUniforms);
|
});
|
});
|
});
|