-
Notifications
You must be signed in to change notification settings - Fork 250
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
Changes from 6 commits
d098f0f
ae6ccf1
8d2597b
ba956d5
5d3fdf2
f2b9a18
bfbda29
4ac3887
f7dd8a4
81a7f23
0a8988e
3068102
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,133 @@ | ||
'use strict'; | ||
|
||
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 = moveTechniqueRenderStates; | ||
|
||
var defaultBlendEquation = [ | ||
WebGLConstants.FUNC_ADD, | ||
WebGLConstants.FUNC_ADD | ||
]; | ||
|
||
var defaultBlendFactors = [ | ||
WebGLConstants.ONE, | ||
WebGLConstants.ZERO, | ||
WebGLConstants.ONE, | ||
WebGLConstants.ZERO | ||
]; | ||
|
||
function isStateEnabled(renderStates, state) { | ||
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; | ||
} | ||
|
||
/** | ||
* Move glTF 1.0 technique render states to glTF 2.0 materials properties and EXT_blend extension. | ||
* | ||
* @param {Object} gltf A javascript object containing a glTF asset. | ||
* @returns {Object} The updated glTF asset. | ||
* | ||
* @private | ||
*/ | ||
function moveTechniqueRenderStates(gltf) { | ||
var blendingForTechnique = {}; | ||
var materialPropertiesForTechnique = {}; | ||
var techniquesLegacy = gltf.techniques; | ||
if (!defined(techniquesLegacy)) { | ||
return gltf; | ||
} | ||
|
||
ForEach.technique(gltf, function (techniqueLegacy, techniqueIndex) { | ||
var renderStates = techniqueLegacy.states; | ||
if (defined(renderStates)) { | ||
var materialProperties = materialPropertiesForTechnique[techniqueIndex] = {}; | ||
|
||
// If BLEND is enabled, the material should have alpha mode BLEND | ||
if (isStateEnabled(renderStates, WebGLConstants.BLEND)) { | ||
materialProperties.alphaMode = 'BLEND'; | ||
|
||
var blendFunctions = renderStates.functions; | ||
if (defined(blendFunctions) && (defined(blendFunctions.blendEquationSeparate) | ||
|| defined(blendFunctions.blendFuncSeparate))) { | ||
blendingForTechnique[techniqueIndex] = { | ||
blendEquation: defaultValue(blendFunctions.blendEquationSeparate, defaultBlendEquation), | ||
blendFactors: getSupportedBlendFactors(blendFunctions.blendFuncSeparate, defaultBlendFactors) | ||
}; | ||
} | ||
} | ||
|
||
// If CULL_FACE is not enabled, the material should be doubleSided | ||
if (!isStateEnabled(renderStates, WebGLConstants.CULL_FACE)) { | ||
materialProperties.doubleSided = true; | ||
} | ||
|
||
delete techniqueLegacy.states; | ||
} | ||
}); | ||
|
||
if (Object.keys(blendingForTechnique).length > 0) { | ||
if (!defined(gltf.extensions)) { | ||
gltf.extensions = {}; | ||
} | ||
|
||
addExtensionsUsed(gltf, 'EXT_blend'); | ||
} | ||
|
||
ForEach.material(gltf, function (material) { | ||
if (defined(material.technique)) { | ||
var materialProperties = materialPropertiesForTechnique[material.technique]; | ||
ForEach.objectLegacy(materialProperties, function (value, property) { | ||
material[property] = value; | ||
}); | ||
|
||
var blending = blendingForTechnique[material.technique]; | ||
if (defined(blending)) { | ||
if (!defined(material.extensions)) { | ||
material.extensions = {}; | ||
} | ||
|
||
material.extensions.EXT_blend = blending; | ||
} | ||
} | ||
}); | ||
|
||
return gltf; | ||
} |
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() { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Update the name to |
||
it('sets material.doubleSided property if CULL_FACE is not enabled', function () { | ||
var gltfWithUpdatedMaterials = moveTechniqueRenderStates(gltf); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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)); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Maybe use Cesium's There was a problem hiding this comment. Choose a reason for hiding this commentThe 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. There was a problem hiding this comment. Choose a reason for hiding this commentThe 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... There was a problem hiding this comment. Choose a reason for hiding this commentThe 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 There was a problem hiding this comment. Choose a reason for hiding this commentThe 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(); | ||
}); | ||
}); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is
EXT_blend
expected to be the final name, or will it beKHR_blend
? It seems like a bunch of extension proposals have that prefix but I'm not sure whether that's the actual prefix or just a placeholder.