diff --git a/Apps/Sandcastle/gallery/3D Models.html b/Apps/Sandcastle/gallery/3D Models.html
index 3f6c292772c0..a772afc586db 100644
--- a/Apps/Sandcastle/gallery/3D Models.html
+++ b/Apps/Sandcastle/gallery/3D Models.html
@@ -48,6 +48,13 @@
+
+ Blend Alpha |
+
+
+
+ |
+
@@ -66,7 +73,8 @@
// The viewModel tracks the state of our mini application.
var viewModel = {
blendAmount : 0.0,
- blendColor : 0.0
+ blendColor : 0.0,
+ blendAlpha : 1.0
};
// Convert the viewModel members into knockout observables.
Cesium.knockout.track(viewModel);
@@ -83,7 +91,13 @@
Cesium.knockout.getObservable(viewModel, 'blendColor').subscribe(
function(newValue) {
- entity.model.blendColor = Cesium.Color.fromHsl(newValue, 1.0, 0.5);
+ entity.model.blendColor = Cesium.Color.fromHsl(newValue, 1.0, 0.5, viewModel.blendAlpha);
+ }
+);
+
+Cesium.knockout.getObservable(viewModel, 'blendAlpha').subscribe(
+ function(newValue) {
+ entity.model.blendColor = Cesium.Color.fromHsl(viewModel.blendColor, 1.0, 0.5, newValue);
}
);
@@ -106,7 +120,7 @@
minimumPixelSize : 128,
maximumScale : 20000,
blendAmount : viewModel.blendAmount,
- blendColor : Cesium.Color.fromHsl(viewModel.blendColor, 1.0, 0.5)
+ blendColor : Cesium.Color.fromHsl(viewModel.blendColor, 1.0, 0.5, viewModel.blendAlpha)
}
});
viewer.trackedEntity = entity;
diff --git a/Apps/Sandcastle/gallery/development/3D Models.html b/Apps/Sandcastle/gallery/development/3D Models.html
index dbd8409deea8..dbc7680fcd9c 100644
--- a/Apps/Sandcastle/gallery/development/3D Models.html
+++ b/Apps/Sandcastle/gallery/development/3D Models.html
@@ -48,6 +48,13 @@
+
+ Blend Alpha |
+
+
+
+ |
+
@@ -65,7 +72,8 @@
// The viewModel tracks the state of our mini application.
var viewModel = {
blendAmount : 0.0,
- blendColor : 0.0
+ blendColor : 0.0,
+ blendAlpha : 1.0
};
// Convert the viewModel members into knockout observables.
@@ -83,7 +91,13 @@
Cesium.knockout.getObservable(viewModel, 'blendColor').subscribe(
function(newValue) {
- model.blendColor = Cesium.Color.fromHsl(newValue, 1.0, 0.5);
+ entity.model.blendColor = Cesium.Color.fromHsl(newValue, 1.0, 0.5, viewModel.blendAlpha);
+ }
+);
+
+Cesium.knockout.getObservable(viewModel, 'blendAlpha').subscribe(
+ function(newValue) {
+ entity.model.blendColor = Cesium.Color.fromHsl(viewModel.blendColor, 1.0, 0.5, newValue);
}
);
@@ -106,7 +120,7 @@
model.readyPromise.then(function(model) {
model.blendAmount = viewModel.blendAmount;
- model.blendColor = Cesium.Color.fromHsl(viewModel.blendColor, 1.0, 0.5);
+ model.blendColor = Cesium.Color.fromHsl(viewModel.blendColor, 1.0, viewModel.blendAlpha);
// Play and loop all animations at half-speed
model.activeAnimations.addAll({
speedup : 0.5,
diff --git a/Source/Scene/Model.js b/Source/Scene/Model.js
index 78485264bc56..f9e602d44424 100644
--- a/Source/Scene/Model.js
+++ b/Source/Scene/Model.js
@@ -1739,15 +1739,28 @@ define([
return shader;
}
- function modifyShaderForBlendColor(shader) {
+ function hasPremultipliedAlpha(model) {
+ var gltf = model.gltf;
+ return defined(gltf.asset) ? defaultValue(gltf.asset.premultipliedAlpha, false) : false;
+ }
+
+ function modifyShaderForBlendColor(shader, premultipliedAlpha) {
shader = ShaderSource.replaceMain(shader, 'gltf_blend_main');
shader +=
'uniform vec4 gltf_blendColor; \n' +
'uniform float gltf_blendAmount; \n' +
'void main() \n' +
'{ \n' +
- ' gltf_blend_main(); \n' +
+ ' gltf_blend_main(); \n';
+
+ // Un-premultiply the alpha so that blending is correct.
+ if (premultipliedAlpha) {
+ shader += ' gl_FragColor.rgb /= gl_FragColor.a; \n';
+ }
+
+ shader +=
' gl_FragColor.rgb = mix(gl_FragColor.rgb, gltf_blendColor.rgb, gltf_blendAmount); \n' +
+ ' gl_FragColor.a *= gltf_blendColor.a; \n' +
'} \n';
return shader;
}
@@ -1783,7 +1796,8 @@ define([
vs = modifyShaderForQuantizedAttributes(vs, id, model, context);
}
- var blendFS = modifyShaderForBlendColor(fs);
+ var premultipliedAlpha = hasPremultipliedAlpha(model);
+ var blendFS = modifyShaderForBlendColor(fs, premultipliedAlpha);
var drawVS = modifyShader(vs, id, model._vertexShaderLoaded);
var drawFS = modifyShader(blendFS, id, model._fragmentShaderLoaded);
@@ -2319,6 +2333,16 @@ define([
var polygonOffset = defaultValue(statesFunctions.polygonOffset, [0.0, 0.0]);
var scissor = defaultValue(statesFunctions.scissor, [0.0, 0.0, 0.0, 0.0]);
+ // Change the render state to use traditional alpha blending instead of premultiplied alpha blending
+ if (booleanStates[WebGLConstants.BLEND] && hasPremultipliedAlpha(model)) {
+ if ((blendFuncSeparate[0] === WebGLConstants.ONE) && (blendFuncSeparate[1] === WebGLConstants.ONE_MINUS_SRC_ALPHA)) {
+ blendFuncSeparate[0] = WebGLConstants.SRC_ALPHA;
+ blendFuncSeparate[1] = WebGLConstants.ONE_MINUS_SRC_ALPHA;
+ blendFuncSeparate[2] = WebGLConstants.ONE;
+ blendFuncSeparate[3] = WebGLConstants.ONE_MINUS_SRC_ALPHA;
+ }
+ }
+
rendererRenderStates[id] = RenderState.fromCache({
frontFace : defined(statesFunctions.frontFace) ? statesFunctions.frontFace[0] : WebGLConstants.CCW,
cull : {