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

Update technique render states and support for KHR_blend #387

Merged
merged 12 commits into from
Jul 11, 2018
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,59 @@ var Cesium = require('cesium');
var addExtensionsUsed = require('./addExtensionsUsed');
var ForEach = require('./ForEach');

var defaultValue = Cesium.defaultValue;
var defined = Cesium.defined;
var WebGLConstants = Cesium.WebGLConstants;

module.exports = updateMaterialProperties;
module.exports = moveTechniqueRenderStates;

var defaultBlendEquation = [
WebGLConstants.FUNC_ADD,
WebGLConstants.FUNC_ADD
];

var defaultBlendFactors = [
WebGLConstants.ONE,
WebGLConstants.ZERO,
WebGLConstants.ONE,
WebGLConstants.ZERO
];

function isStateEnabled(renderStates, state) {
return (renderStates.enable.indexOf(state) > -1);
var enabled = renderStates.enable;
if (!defined(enabled)) {
return false;
}

return (enabled.indexOf(state) > -1);
}

var supportedBlendFactors = [
WebGLConstants.ZERO,
WebGLConstants.ONE,
WebGLConstants.SRC_COLOR,
WebGLConstants.ONE_MINUS_SRC_COLOR,
WebGLConstants.SRC_ALPHA,
WebGLConstants.ONE_MINUS_SRC_ALPHA,
WebGLConstants.DST_ALPHA,
WebGLConstants.ONE_MINUS_DST_ALPHA,
WebGLConstants.DST_COLOR,
WebGLConstants.ONE_MINUS_DST_COLOR
];

// If any of the blend factors are not supported, return the default
function getSupportedBlendFactors(value, defaultValue) {
if (!defined(value)) {
return defaultValue;
}

for (var i = 0; i < 4; i++) {
if (supportedBlendFactors.indexOf(value[i]) === -1) {
return defaultValue;
}
}

return value;
}

/**
Expand All @@ -21,7 +67,7 @@ function isStateEnabled(renderStates, state) {
*
* @private
*/
function updateMaterialProperties(gltf) {
function moveTechniqueRenderStates(gltf) {
var blendingForTechnique = {};
var materialPropertiesForTechnique = {};
var techniquesLegacy = gltf.techniques;
Expand All @@ -35,14 +81,15 @@ function updateMaterialProperties(gltf) {
var materialProperties = materialPropertiesForTechnique[techniqueIndex] = {};

// If BLEND is enabled, the material should have alpha mode BLEND
// and save the blend functions to the EXT_blend extension
if (isStateEnabled(renderStates, WebGLConstants.BLEND)
|| defined(renderStates.blendEquationSeparate) || defined(renderStates.blendFuncSeparate)) {
if (isStateEnabled(renderStates, WebGLConstants.BLEND)) {
materialProperties.alphaMode = 'BLEND';
if (defined(renderStates.functions)) {

var blendFunctions = renderStates.functions;
if (defined(blendFunctions) && (defined(blendFunctions.blendEquationSeparate)
|| defined(blendFunctions.blendFuncSeparate))) {
blendingForTechnique[techniqueIndex] = {
blendEquation: renderStates.functions.blendEquationSeparate,
blendFactors: renderStates.functions.blendFuncSeparate
blendEquation: defaultValue(blendFunctions.blendEquationSeparate, defaultBlendEquation),
blendFactors: getSupportedBlendFactors(blendFunctions.blendFuncSeparate, defaultBlendFactors)
};
}
}
Expand All @@ -52,7 +99,7 @@ function updateMaterialProperties(gltf) {
materialProperties.doubleSided = true;
}

delete techniqueLegacy.state;
delete techniqueLegacy.states;
}
});

Expand Down
8 changes: 4 additions & 4 deletions lib/updateVersion.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,9 @@ var findAccessorMinMax = require('./findAccessorMinMax');
var ForEach = require('./ForEach');
var getAccessorByteStride = require('./getAccessorByteStride');
var numberOfComponentsForType = require('./numberOfComponentsForType');
var removeUnusedElements = require('./removeUnusedElements');
var moveTechniqueRenderStates = require('./moveTechniqueRenderStates');
var moveTechniquesToExtension = require('./moveTechniquesToExtension');
var updateMaterialProperties = require('./updateMaterialProperties');
var removeUnusedElements = require('./removeUnusedElements');

var Cartesian3 = Cesium.Cartesian3;
var clone = Cesium.clone;
Expand Down Expand Up @@ -842,8 +842,8 @@ function glTF10to20(gltf) {
underscoreApplicationSpecificSemantics(gltf);
// Clamp camera parameters
clampCameraParameters(gltf);
// Update material properties and add blending functions to EXT_blend extension, removing technique render states
updateMaterialProperties(gltf);
// Move legacy technique render states to material properties and add EXT_blend extension blending functions
moveTechniqueRenderStates(gltf);
// Add material techniques to KHR_techniques_webgl extension, removing shaders, programs, and techniques
moveTechniquesToExtension(gltf);
// Remove empty arrays
Expand Down
219 changes: 219 additions & 0 deletions specs/lib/moveTechniqueRenderStatesSpec.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,219 @@
'use strict';
var Cesium = require('cesium');
var moveTechniqueRenderStates = require('../../lib/moveTechniqueRenderStates');

var WebGLConstants = Cesium.WebGLConstants;

var gltf = {
programs: {
program_0: {
attributes: [
'a_normal',
'a_position',
'a_texcoord0'
],
fragmentShader: 'BoxTextured0FS',
vertexShader: 'BoxTextured0VS'
}
},
shaders: {
BoxTextured0FS: {
type: WebGLConstants.FRAGMENT_SHADER,
uri: 'BoxTextured0FS.glsl'
},
BoxTextured0VS: {
type: WebGLConstants.VERTEX_SHADER,
uri: 'BoxTextured0VS.glsl'
}
},
techniques: {
technique0: {
states: {
enable: [
WebGLConstants.DEPTH_TEST,
WebGLConstants.BLEND,
WebGLConstants.CULL_FACE
]
}
}
},
materials: [
{
technique: 'technique0'
}
]
};

describe('updateMaterialProperties', function() {
Copy link
Contributor

Choose a reason for hiding this comment

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

Update the name to moveTechniqueToRenderStates.

it('sets material.doubleSided property if CULL_FACE is not enabled', function () {
var gltfWithUpdatedMaterials = moveTechniqueRenderStates(gltf);
Copy link
Contributor

Choose a reason for hiding this comment

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

gltf should be cloned first.

Copy link
Contributor

@lilleyse lilleyse Jun 29, 2018

Choose a reason for hiding this comment

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

This may also be causing intermittent failures when tests are run in random order, which I think jasmine does now?

var material = gltfWithUpdatedMaterials.materials[0];
expect(material.doubleSided).toBeUndefined();

var gltfDoubleSided = JSON.parse(JSON.stringify(gltf));
Copy link
Contributor

Choose a reason for hiding this comment

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

Maybe use Cesium's clone function instead. clone(gltf, true).

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I was having issues with the depth of the cloning when it came to arrays (even when using the deep clone argument). This was much more reliable.

Copy link
Contributor

Choose a reason for hiding this comment

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

Is that a Cesium bug? I don't think that should be happening...

Copy link
Contributor Author

Choose a reason for hiding this comment

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

The documentation isn't partially clear on what the behavior should be: https://cesiumjs.org/Cesium/Build/Documentation/clone.html

Copy link
Contributor

Choose a reason for hiding this comment

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

Alright, if this way works consistently then let's go with it.

gltfDoubleSided.techniques.technique0.states = {
enable : [
WebGLConstants.DEPTH_TEST,
WebGLConstants.BLEND
]
};

gltfWithUpdatedMaterials = moveTechniqueRenderStates(gltfDoubleSided);
material = gltfWithUpdatedMaterials.materials[0];
expect(material.doubleSided).toBe(true);
});

it('sets alphaMode and moves technique render state blending functions to material EXT_blend extension', function() {
var gltfWithBlendFunctions = JSON.parse(JSON.stringify(gltf));

gltfWithBlendFunctions.techniques.technique0.states = {
enable: [
WebGLConstants.DEPTH_TEST,
WebGLConstants.BLEND,
WebGLConstants.CULL_FACE
],
functions: {
blendEquationSeparate: [
WebGLConstants.FUNC_ADD,
WebGLConstants.FUNC_ADD
],
blendFuncSeparate: [
WebGLConstants.ONE,
WebGLConstants.ONE_MINUS_SRC_ALPHA,
WebGLConstants.ONE,
WebGLConstants.ONE_MINUS_SRC_ALPHA
]
}
};

var gltfWithBlendExtension = moveTechniqueRenderStates(gltfWithBlendFunctions);
expect(gltfWithBlendExtension.extensionsUsed.indexOf('EXT_blend')).toBeGreaterThan(-1);
expect(gltfWithBlendExtension.extensionsRequired).toBeUndefined();

var material = gltfWithBlendExtension.materials[0];
expect(material.alphaMode).toBe('BLEND');
expect(material.extensions).toBeDefined();
var materialBlending = material.extensions.EXT_blend;
expect(materialBlending).toBeDefined();
expect(materialBlending.blendEquation).toEqual([
WebGLConstants.FUNC_ADD,
WebGLConstants.FUNC_ADD
]);
expect(materialBlending.blendFactors).toEqual([
WebGLConstants.ONE,
WebGLConstants.ONE_MINUS_SRC_ALPHA,
WebGLConstants.ONE,
WebGLConstants.ONE_MINUS_SRC_ALPHA
]);
});

it('provides defaults for extension properties if not provided', function () {
var gltfWithBlendFunctions = JSON.parse(JSON.stringify(gltf));
gltfWithBlendFunctions.techniques.technique0.states = {
enable: [
WebGLConstants.DEPTH_TEST,
WebGLConstants.BLEND,
WebGLConstants.CULL_FACE
],
functions: {
blendFuncSeparate: [
WebGLConstants.ONE,
WebGLConstants.ONE_MINUS_SRC_ALPHA,
WebGLConstants.ONE,
WebGLConstants.ONE_MINUS_SRC_ALPHA
]
}
};

var gltfWithBlendExtension = moveTechniqueRenderStates(gltfWithBlendFunctions);
var materialBlending = gltfWithBlendExtension.materials[0].extensions.EXT_blend;
expect(materialBlending).toBeDefined();
expect(materialBlending.blendEquation).toEqual([
WebGLConstants.FUNC_ADD,
WebGLConstants.FUNC_ADD
]);
expect(materialBlending.blendFactors).toEqual([
WebGLConstants.ONE,
WebGLConstants.ONE_MINUS_SRC_ALPHA,
WebGLConstants.ONE,
WebGLConstants.ONE_MINUS_SRC_ALPHA
]);

gltfWithBlendFunctions.techniques.technique0.states = {
enable: [
WebGLConstants.DEPTH_TEST,
WebGLConstants.BLEND,
WebGLConstants.CULL_FACE
],
functions: {
blendEquationSeparate: [
WebGLConstants.FUNC_ADD,
WebGLConstants.FUNC_ADD
]
}
};

gltfWithBlendExtension = moveTechniqueRenderStates(gltfWithBlendFunctions);
materialBlending = gltfWithBlendExtension.materials[0].extensions.EXT_blend;
expect(materialBlending).toBeDefined();
expect(materialBlending.blendEquation).toEqual([
WebGLConstants.FUNC_ADD,
WebGLConstants.FUNC_ADD
]);
expect(materialBlending.blendFactors).toEqual([
WebGLConstants.ONE,
WebGLConstants.ZERO,
WebGLConstants.ONE,
WebGLConstants.ZERO
]);
});

it('falls back to default blending factors if unsupported factor is found', function () {
var gltfWithBlendFunctions = JSON.parse(JSON.stringify(gltf));
gltfWithBlendFunctions.techniques.technique0.states = {
enable: [
WebGLConstants.DEPTH_TEST,
WebGLConstants.BLEND,
WebGLConstants.CULL_FACE
],
functions : {
blendFuncSeparate: [
WebGLConstants.SRC_ALPHA_SATURATE,
WebGLConstants.ONE_MINUS_SRC_ALPHA,
WebGLConstants.SRC_ALPHA_SATURATE,
WebGLConstants.ONE_MINUS_SRC_ALPHA
]
}
};

var gltfWithBlendExtension = moveTechniqueRenderStates(gltfWithBlendFunctions);

var materialBlending = gltfWithBlendExtension.materials[0].extensions.EXT_blend;
expect(materialBlending).toBeDefined();
expect(materialBlending.blendFactors).toEqual([
WebGLConstants.ONE,
WebGLConstants.ZERO,
WebGLConstants.ONE,
WebGLConstants.ZERO
]);
});

it('does not set alphaMode or add EXT_blend if no blending is found in render states', function () {
var gltfWithoutBlending = JSON.parse(JSON.stringify(gltf));
delete gltfWithoutBlending.techniques.technique0.states;
gltfWithoutBlending.techniques.technique0.states = {
enable: [
WebGLConstants.DEPTH_TEST,
WebGLConstants.CULL_FACE
]
};

var updatedGltf = moveTechniqueRenderStates(gltfWithoutBlending);
expect(updatedGltf.extensionsUsed).toBeUndefined();
expect(updatedGltf.extensionsRequired).toBeUndefined();

var material = updatedGltf.materials[0];
expect(material.alphaMode).toBeUndefined();
expect(material.extensions).toBeUndefined();
});
});
Loading