You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1118 lines
32 KiB
JavaScript
1118 lines
32 KiB
JavaScript
import combine from "../Core/combine.js";
|
|
import defaultValue from "../Core/defaultValue.js";
|
|
import defined from "../Core/defined.js";
|
|
import NearFarScalar from "../Core/NearFarScalar.js";
|
|
import Rectangle from "../Core/Rectangle.js";
|
|
import DrawCommand from "../Renderer/DrawCommand.js";
|
|
import Pass from "../Renderer/Pass.js";
|
|
import RenderState from "../Renderer/RenderState.js";
|
|
import ShaderSource from "../Renderer/ShaderSource.js";
|
|
import BlendingState from "./BlendingState.js";
|
|
import CullFace from "./CullFace.js";
|
|
import SceneMode from "./SceneMode.js";
|
|
|
|
var DerivedCommandType = {
|
|
OPAQUE_FRONT_FACE: 0,
|
|
OPAQUE_BACK_FACE: 1,
|
|
DEPTH_ONLY_FRONT_FACE: 2,
|
|
DEPTH_ONLY_BACK_FACE: 3,
|
|
DEPTH_ONLY_FRONT_AND_BACK_FACE: 4,
|
|
TRANSLUCENT_FRONT_FACE: 5,
|
|
TRANSLUCENT_BACK_FACE: 6,
|
|
TRANSLUCENT_FRONT_FACE_MANUAL_DEPTH_TEST: 7,
|
|
TRANSLUCENT_BACK_FACE_MANUAL_DEPTH_TEST: 8,
|
|
PICK_FRONT_FACE: 9,
|
|
PICK_BACK_FACE: 10,
|
|
DERIVED_COMMANDS_MAXIMUM_LENGTH: 11,
|
|
};
|
|
|
|
var derivedCommandsMaximumLength =
|
|
DerivedCommandType.DERIVED_COMMANDS_MAXIMUM_LENGTH;
|
|
|
|
var DerivedCommandNames = [
|
|
"opaqueFrontFaceCommand",
|
|
"opaqueBackFaceCommand",
|
|
"depthOnlyFrontFaceCommand",
|
|
"depthOnlyBackFaceCommand",
|
|
"depthOnlyFrontAndBackFaceCommand",
|
|
"translucentFrontFaceCommand",
|
|
"translucentBackFaceCommand",
|
|
"translucentFrontFaceManualDepthTestCommand",
|
|
"translucentBackFaceManualDepthTestCommand",
|
|
"pickFrontFaceCommand",
|
|
"pickBackFaceCommand",
|
|
];
|
|
|
|
/**
|
|
* @private
|
|
*/
|
|
function GlobeTranslucencyState() {
|
|
this._frontFaceAlphaByDistance = new NearFarScalar(0.0, 1.0, 0.0, 1.0);
|
|
this._backFaceAlphaByDistance = new NearFarScalar(0.0, 1.0, 0.0, 1.0);
|
|
|
|
this._frontFaceTranslucent = false;
|
|
this._backFaceTranslucent = false;
|
|
this._requiresManualDepthTest = false;
|
|
this._sunVisibleThroughGlobe = false;
|
|
this._environmentVisible = false;
|
|
this._useDepthPlane = false;
|
|
this._numberOfTextureUniforms = 0;
|
|
this._globeTranslucencyFramebuffer = undefined;
|
|
this._rectangle = Rectangle.clone(Rectangle.MAX_VALUE);
|
|
|
|
this._derivedCommandKey = 0;
|
|
this._derivedCommandsDirty = false;
|
|
this._derivedCommandPacks = undefined;
|
|
|
|
this._derivedCommandTypes = new Array(derivedCommandsMaximumLength);
|
|
this._derivedBlendCommandTypes = new Array(derivedCommandsMaximumLength);
|
|
this._derivedPickCommandTypes = new Array(derivedCommandsMaximumLength);
|
|
this._derivedCommandTypesToUpdate = new Array(derivedCommandsMaximumLength);
|
|
|
|
this._derivedCommandsLength = 0;
|
|
this._derivedBlendCommandsLength = 0;
|
|
this._derivedPickCommandsLength = 0;
|
|
this._derivedCommandsToUpdateLength = 0;
|
|
}
|
|
|
|
Object.defineProperties(GlobeTranslucencyState.prototype, {
|
|
frontFaceAlphaByDistance: {
|
|
get: function () {
|
|
return this._frontFaceAlphaByDistance;
|
|
},
|
|
},
|
|
backFaceAlphaByDistance: {
|
|
get: function () {
|
|
return this._backFaceAlphaByDistance;
|
|
},
|
|
},
|
|
translucent: {
|
|
get: function () {
|
|
return this._frontFaceTranslucent;
|
|
},
|
|
},
|
|
sunVisibleThroughGlobe: {
|
|
get: function () {
|
|
return this._sunVisibleThroughGlobe;
|
|
},
|
|
},
|
|
environmentVisible: {
|
|
get: function () {
|
|
return this._environmentVisible;
|
|
},
|
|
},
|
|
useDepthPlane: {
|
|
get: function () {
|
|
return this._useDepthPlane;
|
|
},
|
|
},
|
|
numberOfTextureUniforms: {
|
|
get: function () {
|
|
return this._numberOfTextureUniforms;
|
|
},
|
|
},
|
|
rectangle: {
|
|
get: function () {
|
|
return this._rectangle;
|
|
},
|
|
},
|
|
});
|
|
|
|
GlobeTranslucencyState.prototype.update = function (scene) {
|
|
var globe = scene.globe;
|
|
if (!defined(globe) || !globe.show) {
|
|
this._frontFaceTranslucent = false;
|
|
this._backFaceTranslucent = false;
|
|
this._sunVisibleThroughGlobe = true;
|
|
this._environmentVisible = true;
|
|
this._useDepthPlane = false;
|
|
return;
|
|
}
|
|
|
|
this._frontFaceAlphaByDistance = updateAlphaByDistance(
|
|
globe.translucency.enabled,
|
|
globe.translucency.frontFaceAlpha,
|
|
globe.translucency.frontFaceAlphaByDistance,
|
|
this._frontFaceAlphaByDistance
|
|
);
|
|
this._backFaceAlphaByDistance = updateAlphaByDistance(
|
|
globe.translucency.enabled,
|
|
globe.translucency.backFaceAlpha,
|
|
globe.translucency.backFaceAlphaByDistance,
|
|
this._backFaceAlphaByDistance
|
|
);
|
|
|
|
this._frontFaceTranslucent = isFaceTranslucent(
|
|
globe.translucency.enabled,
|
|
this._frontFaceAlphaByDistance,
|
|
globe
|
|
);
|
|
this._backFaceTranslucent = isFaceTranslucent(
|
|
globe.translucency.enabled,
|
|
this._backFaceAlphaByDistance,
|
|
globe
|
|
);
|
|
|
|
this._requiresManualDepthTest = requiresManualDepthTest(this, scene, globe);
|
|
|
|
this._sunVisibleThroughGlobe = isSunVisibleThroughGlobe(this, scene);
|
|
this._environmentVisible = isEnvironmentVisible(this, scene);
|
|
this._useDepthPlane = useDepthPlane(this, scene);
|
|
this._numberOfTextureUniforms = getNumberOfTextureUniforms(this);
|
|
|
|
this._rectangle = Rectangle.clone(
|
|
globe.translucency.rectangle,
|
|
this._rectangle
|
|
);
|
|
|
|
gatherDerivedCommandRequirements(this, scene);
|
|
};
|
|
|
|
function updateAlphaByDistance(enabled, alpha, alphaByDistance, result) {
|
|
if (!enabled) {
|
|
result.nearValue = 1.0;
|
|
result.farValue = 1.0;
|
|
return result;
|
|
}
|
|
|
|
if (!defined(alphaByDistance)) {
|
|
result.nearValue = alpha;
|
|
result.farValue = alpha;
|
|
return result;
|
|
}
|
|
|
|
NearFarScalar.clone(alphaByDistance, result);
|
|
result.nearValue *= alpha;
|
|
result.farValue *= alpha;
|
|
return result;
|
|
}
|
|
|
|
function isFaceTranslucent(translucencyEnabled, alphaByDistance, globe) {
|
|
return (
|
|
translucencyEnabled &&
|
|
(globe.baseColor.alpha < 1.0 ||
|
|
alphaByDistance.nearValue < 1.0 ||
|
|
alphaByDistance.farValue < 1.0)
|
|
);
|
|
}
|
|
|
|
function isSunVisibleThroughGlobe(state, scene) {
|
|
// The sun is visible through the globe if the front and back faces are translucent when above ground
|
|
// or if front faces are translucent when below ground
|
|
var frontTranslucent = state._frontFaceTranslucent;
|
|
var backTranslucent = state._backFaceTranslucent;
|
|
return frontTranslucent && (scene.cameraUnderground || backTranslucent);
|
|
}
|
|
|
|
function isEnvironmentVisible(state, scene) {
|
|
// The environment is visible if the camera is above ground or underground with translucency
|
|
return !scene.cameraUnderground || state._frontFaceTranslucent;
|
|
}
|
|
|
|
function useDepthPlane(state, scene) {
|
|
// Use the depth plane when the camera is above ground and the globe is opaque
|
|
return !scene.cameraUnderground && !state._frontFaceTranslucent;
|
|
}
|
|
|
|
function requiresManualDepthTest(state, scene, globe) {
|
|
return (
|
|
state._frontFaceTranslucent &&
|
|
!state._backFaceTranslucent &&
|
|
!globe.depthTestAgainstTerrain &&
|
|
scene.mode !== SceneMode.SCENE2D &&
|
|
scene.context.depthTexture
|
|
);
|
|
}
|
|
|
|
function getNumberOfTextureUniforms(state) {
|
|
var numberOfTextureUniforms = 0;
|
|
|
|
if (state._frontFaceTranslucent) {
|
|
++numberOfTextureUniforms; // classification texture
|
|
}
|
|
|
|
if (state._requiresManualDepthTest) {
|
|
++numberOfTextureUniforms; // czm_globeDepthTexture for manual depth testing
|
|
}
|
|
|
|
return numberOfTextureUniforms;
|
|
}
|
|
|
|
function gatherDerivedCommandRequirements(state, scene) {
|
|
state._derivedCommandsLength = getDerivedCommandTypes(
|
|
state,
|
|
scene,
|
|
false,
|
|
false,
|
|
state._derivedCommandTypes
|
|
);
|
|
|
|
state._derivedBlendCommandsLength = getDerivedCommandTypes(
|
|
state,
|
|
scene,
|
|
true,
|
|
false,
|
|
state._derivedBlendCommandTypes
|
|
);
|
|
|
|
state._derivedPickCommandsLength = getDerivedCommandTypes(
|
|
state,
|
|
scene,
|
|
false,
|
|
true,
|
|
state._derivedPickCommandTypes
|
|
);
|
|
|
|
var i;
|
|
|
|
var derivedCommandKey = 0;
|
|
for (i = 0; i < state._derivedCommandsLength; ++i) {
|
|
derivedCommandKey |= 1 << state._derivedCommandTypes[i];
|
|
}
|
|
for (i = 0; i < state._derivedBlendCommandsLength; ++i) {
|
|
derivedCommandKey |= 1 << state._derivedBlendCommandTypes[i];
|
|
}
|
|
for (i = 0; i < state._derivedPickCommandsLength; ++i) {
|
|
derivedCommandKey |= 1 << state._derivedPickCommandTypes[i];
|
|
}
|
|
|
|
var derivedCommandsToUpdateLength = 0;
|
|
for (i = 0; i < derivedCommandsMaximumLength; ++i) {
|
|
if ((derivedCommandKey & (1 << i)) > 0) {
|
|
state._derivedCommandTypesToUpdate[derivedCommandsToUpdateLength++] = i;
|
|
}
|
|
}
|
|
state._derivedCommandsToUpdateLength = derivedCommandsToUpdateLength;
|
|
|
|
var derivedCommandsDirty = derivedCommandKey !== state._derivedCommandKey;
|
|
state._derivedCommandKey = derivedCommandKey;
|
|
state._derivedCommandsDirty = derivedCommandsDirty;
|
|
|
|
if (!defined(state._derivedCommandPacks) && state._frontFaceTranslucent) {
|
|
state._derivedCommandPacks = createDerivedCommandPacks();
|
|
}
|
|
}
|
|
|
|
function getDerivedCommandTypes(
|
|
state,
|
|
scene,
|
|
isBlendCommand,
|
|
isPickCommand,
|
|
types
|
|
) {
|
|
var length = 0;
|
|
|
|
var frontTranslucent = state._frontFaceTranslucent;
|
|
var backTranslucent = state._backFaceTranslucent;
|
|
|
|
if (!frontTranslucent) {
|
|
// Don't use derived commands if the globe is opaque
|
|
return length;
|
|
}
|
|
|
|
var cameraUnderground = scene.cameraUnderground;
|
|
var requiresManualDepthTest = state._requiresManualDepthTest;
|
|
|
|
var translucentFrontFaceCommandType = isPickCommand
|
|
? DerivedCommandType.PICK_FRONT_FACE
|
|
: requiresManualDepthTest
|
|
? DerivedCommandType.TRANSLUCENT_FRONT_FACE_MANUAL_DEPTH_TEST
|
|
: DerivedCommandType.TRANSLUCENT_FRONT_FACE;
|
|
|
|
var translucentBackFaceCommandType = isPickCommand
|
|
? DerivedCommandType.PICK_BACK_FACE
|
|
: requiresManualDepthTest
|
|
? DerivedCommandType.TRANSLUCENT_BACK_FACE_MANUAL_DEPTH_TEST
|
|
: DerivedCommandType.TRANSLUCENT_BACK_FACE;
|
|
|
|
if (scene.mode === SceneMode.SCENE2D) {
|
|
types[length++] = DerivedCommandType.DEPTH_ONLY_FRONT_FACE;
|
|
types[length++] = translucentFrontFaceCommandType;
|
|
return length;
|
|
}
|
|
|
|
if (backTranslucent) {
|
|
// Push depth-only command for classification. Blend commands do not need to write depth.
|
|
// Push translucent commands for front and back faces.
|
|
if (!isBlendCommand) {
|
|
types[length++] = DerivedCommandType.DEPTH_ONLY_FRONT_AND_BACK_FACE;
|
|
}
|
|
if (cameraUnderground) {
|
|
types[length++] = translucentFrontFaceCommandType;
|
|
types[length++] = translucentBackFaceCommandType;
|
|
} else {
|
|
types[length++] = translucentBackFaceCommandType;
|
|
types[length++] = translucentFrontFaceCommandType;
|
|
}
|
|
} else {
|
|
// Push opaque command for the face that appears in back.
|
|
// Push depth-only command and translucent command for the face that appears in front.
|
|
// eslint-disable-next-line no-lonely-if
|
|
if (cameraUnderground) {
|
|
if (!isBlendCommand) {
|
|
types[length++] = DerivedCommandType.DEPTH_ONLY_BACK_FACE;
|
|
}
|
|
types[length++] = DerivedCommandType.OPAQUE_FRONT_FACE;
|
|
types[length++] = translucentBackFaceCommandType;
|
|
} else {
|
|
if (!isBlendCommand) {
|
|
types[length++] = DerivedCommandType.DEPTH_ONLY_FRONT_FACE;
|
|
}
|
|
types[length++] = DerivedCommandType.OPAQUE_BACK_FACE;
|
|
types[length++] = translucentFrontFaceCommandType;
|
|
}
|
|
}
|
|
|
|
return length;
|
|
}
|
|
|
|
function removeDefine(defines, defineToRemove) {
|
|
var index = defines.indexOf(defineToRemove);
|
|
if (index > -1) {
|
|
defines.splice(index, 1);
|
|
}
|
|
}
|
|
|
|
function hasDefine(defines, define) {
|
|
return defines.indexOf(define) > -1;
|
|
}
|
|
|
|
function getOpaqueFrontFaceShaderProgram(vs, fs) {
|
|
removeDefine(vs.defines, "TRANSLUCENT");
|
|
removeDefine(fs.defines, "TRANSLUCENT");
|
|
}
|
|
|
|
function getOpaqueBackFaceShaderProgram(vs, fs) {
|
|
removeDefine(vs.defines, "GROUND_ATMOSPHERE");
|
|
removeDefine(fs.defines, "GROUND_ATMOSPHERE");
|
|
removeDefine(vs.defines, "FOG");
|
|
removeDefine(fs.defines, "FOG");
|
|
removeDefine(vs.defines, "TRANSLUCENT");
|
|
removeDefine(fs.defines, "TRANSLUCENT");
|
|
}
|
|
|
|
function getDepthOnlyShaderProgram(vs, fs) {
|
|
if (
|
|
hasDefine(fs.defines, "TILE_LIMIT_RECTANGLE") ||
|
|
hasDefine(fs.defines, "ENABLE_CLIPPING_PLANES")
|
|
) {
|
|
// Need to execute the full shader if discard is called
|
|
return;
|
|
}
|
|
|
|
var depthOnlyShader =
|
|
"void main() \n" + "{ \n" + " gl_FragColor = vec4(1.0); \n" + "} \n";
|
|
|
|
fs.sources = [depthOnlyShader];
|
|
}
|
|
|
|
function getTranslucentShaderProgram(vs, fs) {
|
|
var sources = fs.sources;
|
|
var length = sources.length;
|
|
for (var i = 0; i < length; ++i) {
|
|
sources[i] = ShaderSource.replaceMain(
|
|
sources[i],
|
|
"czm_globe_translucency_main"
|
|
);
|
|
}
|
|
|
|
var globeTranslucencyMain =
|
|
"\n\n" +
|
|
"uniform sampler2D u_classificationTexture; \n" +
|
|
"void main() \n" +
|
|
"{ \n" +
|
|
" vec2 st = gl_FragCoord.xy / czm_viewport.zw; \n" +
|
|
"#ifdef MANUAL_DEPTH_TEST \n" +
|
|
" float logDepthOrDepth = czm_unpackDepth(texture2D(czm_globeDepthTexture, st)); \n" +
|
|
" if (logDepthOrDepth != 0.0) \n" +
|
|
" { \n" +
|
|
" vec4 eyeCoordinate = czm_windowToEyeCoordinates(gl_FragCoord.xy, logDepthOrDepth); \n" +
|
|
" float depthEC = eyeCoordinate.z / eyeCoordinate.w; \n" +
|
|
" if (v_positionEC.z < depthEC) \n" +
|
|
" { \n" +
|
|
" discard; \n" +
|
|
" } \n" +
|
|
" } \n" +
|
|
"#endif \n" +
|
|
" czm_globe_translucency_main(); \n" +
|
|
" vec4 classificationColor = texture2D(u_classificationTexture, st); \n" +
|
|
" if (classificationColor.a > 0.0) \n" +
|
|
" { \n" +
|
|
" // Reverse premultiplication process to get the correct composited result of the classification primitives \n" +
|
|
" classificationColor.rgb /= classificationColor.a; \n" +
|
|
" } \n" +
|
|
" gl_FragColor = classificationColor * vec4(classificationColor.aaa, 1.0) + gl_FragColor * (1.0 - classificationColor.a); \n" +
|
|
"} \n";
|
|
|
|
sources.push(globeTranslucencyMain);
|
|
}
|
|
|
|
function getTranslucentBackFaceShaderProgram(vs, fs) {
|
|
getTranslucentShaderProgram(vs, fs);
|
|
removeDefine(vs.defines, "GROUND_ATMOSPHERE");
|
|
removeDefine(fs.defines, "GROUND_ATMOSPHERE");
|
|
removeDefine(vs.defines, "FOG");
|
|
removeDefine(fs.defines, "FOG");
|
|
}
|
|
|
|
function getTranslucentFrontFaceManualDepthTestShaderProgram(vs, fs) {
|
|
getTranslucentShaderProgram(vs, fs);
|
|
vs.defines.push("GENERATE_POSITION");
|
|
fs.defines.push("MANUAL_DEPTH_TEST");
|
|
}
|
|
|
|
function getTranslucentBackFaceManualDepthTestShaderProgram(vs, fs) {
|
|
getTranslucentBackFaceShaderProgram(vs, fs);
|
|
vs.defines.push("GENERATE_POSITION");
|
|
fs.defines.push("MANUAL_DEPTH_TEST");
|
|
}
|
|
|
|
function getPickShaderProgram(vs, fs) {
|
|
var pickShader =
|
|
"uniform sampler2D u_classificationTexture; \n" +
|
|
"void main() \n" +
|
|
"{ \n" +
|
|
" vec2 st = gl_FragCoord.xy / czm_viewport.zw; \n" +
|
|
" vec4 pickColor = texture2D(u_classificationTexture, st); \n" +
|
|
" if (pickColor == vec4(0.0)) \n" +
|
|
" { \n" +
|
|
" discard; \n" +
|
|
" } \n" +
|
|
" gl_FragColor = pickColor; \n" +
|
|
"} \n";
|
|
|
|
fs.sources = [pickShader];
|
|
}
|
|
|
|
function getDerivedShaderProgram(
|
|
context,
|
|
shaderProgram,
|
|
derivedShaderProgram,
|
|
shaderProgramDirty,
|
|
getShaderProgramFunction,
|
|
cacheName
|
|
) {
|
|
if (!defined(getShaderProgramFunction)) {
|
|
return shaderProgram;
|
|
}
|
|
|
|
if (!shaderProgramDirty && defined(derivedShaderProgram)) {
|
|
return derivedShaderProgram;
|
|
}
|
|
|
|
var shader = context.shaderCache.getDerivedShaderProgram(
|
|
shaderProgram,
|
|
cacheName
|
|
);
|
|
if (!defined(shader)) {
|
|
var attributeLocations = shaderProgram._attributeLocations;
|
|
var vs = shaderProgram.vertexShaderSource.clone();
|
|
var fs = shaderProgram.fragmentShaderSource.clone();
|
|
vs.defines = defined(vs.defines) ? vs.defines.slice(0) : [];
|
|
fs.defines = defined(fs.defines) ? fs.defines.slice(0) : [];
|
|
|
|
getShaderProgramFunction(vs, fs);
|
|
|
|
shader = context.shaderCache.createDerivedShaderProgram(
|
|
shaderProgram,
|
|
cacheName,
|
|
{
|
|
vertexShaderSource: vs,
|
|
fragmentShaderSource: fs,
|
|
attributeLocations: attributeLocations,
|
|
}
|
|
);
|
|
}
|
|
|
|
return shader;
|
|
}
|
|
|
|
function getOpaqueFrontFaceRenderState(renderState) {
|
|
renderState.cull.face = CullFace.BACK;
|
|
renderState.cull.enabled = true;
|
|
}
|
|
|
|
function getOpaqueBackFaceRenderState(renderState) {
|
|
renderState.cull.face = CullFace.FRONT;
|
|
renderState.cull.enabled = true;
|
|
}
|
|
|
|
function getDepthOnlyFrontFaceRenderState(renderState) {
|
|
renderState.cull.face = CullFace.BACK;
|
|
renderState.cull.enabled = true;
|
|
renderState.colorMask = {
|
|
red: false,
|
|
green: false,
|
|
blue: false,
|
|
alpha: false,
|
|
};
|
|
}
|
|
|
|
function getDepthOnlyBackFaceRenderState(renderState) {
|
|
renderState.cull.face = CullFace.FRONT;
|
|
renderState.cull.enabled = true;
|
|
renderState.colorMask = {
|
|
red: false,
|
|
green: false,
|
|
blue: false,
|
|
alpha: false,
|
|
};
|
|
}
|
|
|
|
function getDepthOnlyFrontAndBackFaceRenderState(renderState) {
|
|
renderState.cull.enabled = false;
|
|
renderState.colorMask = {
|
|
red: false,
|
|
green: false,
|
|
blue: false,
|
|
alpha: false,
|
|
};
|
|
}
|
|
|
|
function getTranslucentFrontFaceRenderState(renderState) {
|
|
renderState.cull.face = CullFace.BACK;
|
|
renderState.cull.enabled = true;
|
|
renderState.depthMask = false;
|
|
renderState.blending = BlendingState.ALPHA_BLEND;
|
|
}
|
|
|
|
function getTranslucentBackFaceRenderState(renderState) {
|
|
renderState.cull.face = CullFace.FRONT;
|
|
renderState.cull.enabled = true;
|
|
renderState.depthMask = false;
|
|
renderState.blending = BlendingState.ALPHA_BLEND;
|
|
}
|
|
|
|
function getPickFrontFaceRenderState(renderState) {
|
|
renderState.cull.face = CullFace.BACK;
|
|
renderState.cull.enabled = true;
|
|
renderState.blending.enabled = false;
|
|
}
|
|
|
|
function getPickBackFaceRenderState(renderState) {
|
|
renderState.cull.face = CullFace.FRONT;
|
|
renderState.cull.enabled = true;
|
|
renderState.blending.enabled = false;
|
|
}
|
|
|
|
function getDerivedRenderState(
|
|
renderState,
|
|
derivedRenderState,
|
|
renderStateDirty,
|
|
getRenderStateFunction,
|
|
cache
|
|
) {
|
|
if (!defined(getRenderStateFunction)) {
|
|
return renderState;
|
|
}
|
|
|
|
if (!renderStateDirty && defined(derivedRenderState)) {
|
|
return derivedRenderState;
|
|
}
|
|
|
|
var cachedRenderState = cache[renderState.id];
|
|
if (!defined(cachedRenderState)) {
|
|
var rs = RenderState.getState(renderState);
|
|
getRenderStateFunction(rs);
|
|
cachedRenderState = RenderState.fromCache(rs);
|
|
cache[renderState.id] = cachedRenderState;
|
|
}
|
|
|
|
return cachedRenderState;
|
|
}
|
|
|
|
function getTranslucencyUniformMap(state) {
|
|
return {
|
|
u_classificationTexture: function () {
|
|
return state._globeTranslucencyFramebuffer.classificationTexture;
|
|
},
|
|
};
|
|
}
|
|
|
|
function getDerivedUniformMap(
|
|
state,
|
|
uniformMap,
|
|
derivedUniformMap,
|
|
uniformMapDirty,
|
|
getDerivedUniformMapFunction
|
|
) {
|
|
if (!defined(getDerivedUniformMapFunction)) {
|
|
return uniformMap;
|
|
}
|
|
|
|
if (!uniformMapDirty && defined(derivedUniformMap)) {
|
|
return derivedUniformMap;
|
|
}
|
|
|
|
return combine(uniformMap, getDerivedUniformMapFunction(state), false);
|
|
}
|
|
|
|
function DerivedCommandPack(options) {
|
|
this.pass = options.pass;
|
|
this.pickOnly = options.pickOnly;
|
|
this.getShaderProgramFunction = options.getShaderProgramFunction;
|
|
this.getRenderStateFunction = options.getRenderStateFunction;
|
|
this.getUniformMapFunction = options.getUniformMapFunction;
|
|
this.renderStateCache = {};
|
|
}
|
|
|
|
function createDerivedCommandPacks() {
|
|
return [
|
|
// opaqueFrontFaceCommand
|
|
new DerivedCommandPack({
|
|
pass: Pass.GLOBE,
|
|
pickOnly: false,
|
|
getShaderProgramFunction: getOpaqueFrontFaceShaderProgram,
|
|
getRenderStateFunction: getOpaqueFrontFaceRenderState,
|
|
getUniformMapFunction: undefined,
|
|
}),
|
|
// opaqueBackFaceCommand
|
|
new DerivedCommandPack({
|
|
pass: Pass.GLOBE,
|
|
pickOnly: false,
|
|
getShaderProgramFunction: getOpaqueBackFaceShaderProgram,
|
|
getRenderStateFunction: getOpaqueBackFaceRenderState,
|
|
getUniformMapFunction: undefined,
|
|
}),
|
|
// depthOnlyFrontFaceCommand
|
|
new DerivedCommandPack({
|
|
pass: Pass.GLOBE,
|
|
pickOnly: false,
|
|
getShaderProgramFunction: getDepthOnlyShaderProgram,
|
|
getRenderStateFunction: getDepthOnlyFrontFaceRenderState,
|
|
getUniformMapFunction: undefined,
|
|
}),
|
|
// depthOnlyBackFaceCommand
|
|
new DerivedCommandPack({
|
|
pass: Pass.GLOBE,
|
|
pickOnly: false,
|
|
getShaderProgramFunction: getDepthOnlyShaderProgram,
|
|
getRenderStateFunction: getDepthOnlyBackFaceRenderState,
|
|
getUniformMapFunction: undefined,
|
|
}),
|
|
// depthOnlyFrontAndBackFaceCommand
|
|
new DerivedCommandPack({
|
|
pass: Pass.GLOBE,
|
|
pickOnly: false,
|
|
getShaderProgramFunction: getDepthOnlyShaderProgram,
|
|
getRenderStateFunction: getDepthOnlyFrontAndBackFaceRenderState,
|
|
getUniformMapFunction: undefined,
|
|
}),
|
|
// translucentFrontFaceCommand
|
|
new DerivedCommandPack({
|
|
pass: Pass.TRANSLUCENT,
|
|
pickOnly: false,
|
|
getShaderProgramFunction: getTranslucentShaderProgram,
|
|
getRenderStateFunction: getTranslucentFrontFaceRenderState,
|
|
getUniformMapFunction: getTranslucencyUniformMap,
|
|
}),
|
|
// translucentBackFaceCommand
|
|
new DerivedCommandPack({
|
|
pass: Pass.TRANSLUCENT,
|
|
pickOnly: false,
|
|
getShaderProgramFunction: getTranslucentBackFaceShaderProgram,
|
|
getRenderStateFunction: getTranslucentBackFaceRenderState,
|
|
getUniformMapFunction: getTranslucencyUniformMap,
|
|
}),
|
|
// translucentFrontFaceManualDepthTestCommand
|
|
new DerivedCommandPack({
|
|
pass: Pass.TRANSLUCENT,
|
|
pickOnly: false,
|
|
getShaderProgramFunction: getTranslucentFrontFaceManualDepthTestShaderProgram,
|
|
getRenderStateFunction: getTranslucentFrontFaceRenderState,
|
|
getUniformMapFunction: getTranslucencyUniformMap,
|
|
}),
|
|
// translucentBackFaceManualDepthTestCommand
|
|
new DerivedCommandPack({
|
|
pass: Pass.TRANSLUCENT,
|
|
pickOnly: false,
|
|
getShaderProgramFunction: getTranslucentBackFaceManualDepthTestShaderProgram,
|
|
getRenderStateFunction: getTranslucentBackFaceRenderState,
|
|
getUniformMapFunction: getTranslucencyUniformMap,
|
|
}),
|
|
// pickFrontFaceCommand
|
|
new DerivedCommandPack({
|
|
pass: Pass.TRANSLUCENT,
|
|
pickOnly: true,
|
|
getShaderProgramFunction: getPickShaderProgram,
|
|
getRenderStateFunction: getPickFrontFaceRenderState,
|
|
getUniformMapFunction: getTranslucencyUniformMap,
|
|
}),
|
|
// pickBackFaceCommand
|
|
new DerivedCommandPack({
|
|
pass: Pass.TRANSLUCENT,
|
|
pickOnly: true,
|
|
getShaderProgramFunction: getPickShaderProgram,
|
|
getRenderStateFunction: getPickBackFaceRenderState,
|
|
getUniformMapFunction: getTranslucencyUniformMap,
|
|
}),
|
|
];
|
|
}
|
|
|
|
var derivedCommandNames = new Array(derivedCommandsMaximumLength);
|
|
var derivedCommandPacks = new Array(derivedCommandsMaximumLength);
|
|
|
|
GlobeTranslucencyState.prototype.updateDerivedCommands = function (
|
|
command,
|
|
frameState
|
|
) {
|
|
var derivedCommandTypes = this._derivedCommandTypesToUpdate;
|
|
var derivedCommandsLength = this._derivedCommandsToUpdateLength;
|
|
|
|
if (derivedCommandsLength === 0) {
|
|
return;
|
|
}
|
|
|
|
for (var i = 0; i < derivedCommandsLength; ++i) {
|
|
derivedCommandPacks[i] = this._derivedCommandPacks[derivedCommandTypes[i]];
|
|
derivedCommandNames[i] = DerivedCommandNames[derivedCommandTypes[i]];
|
|
}
|
|
|
|
updateDerivedCommands(
|
|
this,
|
|
command,
|
|
derivedCommandsLength,
|
|
derivedCommandTypes,
|
|
derivedCommandNames,
|
|
derivedCommandPacks,
|
|
frameState
|
|
);
|
|
};
|
|
|
|
function updateDerivedCommands(
|
|
state,
|
|
command,
|
|
derivedCommandsLength,
|
|
derivedCommandTypes,
|
|
derivedCommandNames,
|
|
derivedCommandPacks,
|
|
frameState
|
|
) {
|
|
var derivedCommandsObject = command.derivedCommands.globeTranslucency;
|
|
var derivedCommandsDirty = state._derivedCommandsDirty;
|
|
|
|
if (
|
|
command.dirty ||
|
|
!defined(derivedCommandsObject) ||
|
|
derivedCommandsDirty
|
|
) {
|
|
command.dirty = false;
|
|
|
|
if (!defined(derivedCommandsObject)) {
|
|
derivedCommandsObject = {};
|
|
command.derivedCommands.globeTranslucency = derivedCommandsObject;
|
|
}
|
|
|
|
var frameNumber = frameState.frameNumber;
|
|
|
|
var uniformMapDirtyFrame = defaultValue(
|
|
derivedCommandsObject.uniformMapDirtyFrame,
|
|
0
|
|
);
|
|
var shaderProgramDirtyFrame = defaultValue(
|
|
derivedCommandsObject.shaderProgramDirtyFrame,
|
|
0
|
|
);
|
|
var renderStateDirtyFrame = defaultValue(
|
|
derivedCommandsObject.renderStateDirtyFrame,
|
|
0
|
|
);
|
|
|
|
var uniformMapDirty =
|
|
derivedCommandsObject.uniformMap !== command.uniformMap;
|
|
|
|
var shaderProgramDirty =
|
|
derivedCommandsObject.shaderProgramId !== command.shaderProgram.id;
|
|
|
|
var renderStateDirty =
|
|
derivedCommandsObject.renderStateId !== command.renderState.id;
|
|
|
|
if (uniformMapDirty) {
|
|
derivedCommandsObject.uniformMapDirtyFrame = frameNumber;
|
|
}
|
|
if (shaderProgramDirty) {
|
|
derivedCommandsObject.shaderProgramDirtyFrame = frameNumber;
|
|
}
|
|
if (renderStateDirty) {
|
|
derivedCommandsObject.renderStateDirtyFrame = frameNumber;
|
|
}
|
|
|
|
derivedCommandsObject.uniformMap = command.uniformMap;
|
|
derivedCommandsObject.shaderProgramId = command.shaderProgram.id;
|
|
derivedCommandsObject.renderStateId = command.renderState.id;
|
|
|
|
for (var i = 0; i < derivedCommandsLength; ++i) {
|
|
var derivedCommandPack = derivedCommandPacks[i];
|
|
var derivedCommandType = derivedCommandTypes[i];
|
|
var derivedCommandName = derivedCommandNames[i];
|
|
var derivedCommand = derivedCommandsObject[derivedCommandName];
|
|
|
|
var derivedUniformMap;
|
|
var derivedShaderProgram;
|
|
var derivedRenderState;
|
|
|
|
if (defined(derivedCommand)) {
|
|
derivedUniformMap = derivedCommand.uniformMap;
|
|
derivedShaderProgram = derivedCommand.shaderProgram;
|
|
derivedRenderState = derivedCommand.renderState;
|
|
} else {
|
|
derivedUniformMap = undefined;
|
|
derivedShaderProgram = undefined;
|
|
derivedRenderState = undefined;
|
|
}
|
|
|
|
derivedCommand = DrawCommand.shallowClone(command, derivedCommand);
|
|
derivedCommandsObject[derivedCommandName] = derivedCommand;
|
|
|
|
var derivedUniformMapDirtyFrame = defaultValue(
|
|
derivedCommand.derivedCommands.uniformMapDirtyFrame,
|
|
0
|
|
);
|
|
var derivedShaderProgramDirtyFrame = defaultValue(
|
|
derivedCommand.derivedCommands.shaderProgramDirtyFrame,
|
|
0
|
|
);
|
|
var derivedRenderStateDirtyFrame = defaultValue(
|
|
derivedCommand.derivedCommands.renderStateDirtyFrame,
|
|
0
|
|
);
|
|
|
|
var derivedUniformMapDirty =
|
|
uniformMapDirty || derivedUniformMapDirtyFrame < uniformMapDirtyFrame;
|
|
var derivedShaderProgramDirty =
|
|
shaderProgramDirty ||
|
|
derivedShaderProgramDirtyFrame < shaderProgramDirtyFrame;
|
|
var derivedRenderStateDirty =
|
|
renderStateDirty ||
|
|
derivedRenderStateDirtyFrame < renderStateDirtyFrame;
|
|
|
|
if (derivedUniformMapDirty) {
|
|
derivedCommand.derivedCommands.uniformMapDirtyFrame = frameNumber;
|
|
}
|
|
if (derivedShaderProgramDirty) {
|
|
derivedCommand.derivedCommands.shaderProgramDirtyFrame = frameNumber;
|
|
}
|
|
if (derivedRenderStateDirty) {
|
|
derivedCommand.derivedCommands.renderStateDirtyFrame = frameNumber;
|
|
}
|
|
|
|
derivedCommand.derivedCommands.type = derivedCommandType;
|
|
derivedCommand.pass = derivedCommandPack.pass;
|
|
derivedCommand.pickOnly = derivedCommandPack.pickOnly;
|
|
derivedCommand.uniformMap = getDerivedUniformMap(
|
|
state,
|
|
command.uniformMap,
|
|
derivedUniformMap,
|
|
derivedUniformMapDirty,
|
|
derivedCommandPack.getUniformMapFunction
|
|
);
|
|
derivedCommand.shaderProgram = getDerivedShaderProgram(
|
|
frameState.context,
|
|
command.shaderProgram,
|
|
derivedShaderProgram,
|
|
derivedShaderProgramDirty,
|
|
derivedCommandPack.getShaderProgramFunction,
|
|
derivedCommandName
|
|
);
|
|
derivedCommand.renderState = getDerivedRenderState(
|
|
command.renderState,
|
|
derivedRenderState,
|
|
derivedRenderStateDirty,
|
|
derivedCommandPack.getRenderStateFunction,
|
|
derivedCommandPack.renderStateCache
|
|
);
|
|
}
|
|
}
|
|
}
|
|
|
|
GlobeTranslucencyState.prototype.pushDerivedCommands = function (
|
|
command,
|
|
isBlendCommand,
|
|
frameState
|
|
) {
|
|
var picking = frameState.passes.pick;
|
|
if (picking && isBlendCommand) {
|
|
// No need to push blend commands in the pick pass
|
|
return;
|
|
}
|
|
|
|
var derivedCommandTypes = this._derivedCommandTypes;
|
|
var derivedCommandsLength = this._derivedCommandsLength;
|
|
|
|
if (picking) {
|
|
derivedCommandTypes = this._derivedPickCommandTypes;
|
|
derivedCommandsLength = this._derivedPickCommandsLength;
|
|
} else if (isBlendCommand) {
|
|
derivedCommandTypes = this._derivedBlendCommandTypes;
|
|
derivedCommandsLength = this._derivedBlendCommandsLength;
|
|
}
|
|
|
|
if (derivedCommandsLength === 0) {
|
|
// No derived commands to push so just push the globe command
|
|
frameState.commandList.push(command);
|
|
return;
|
|
}
|
|
|
|
// Push derived commands
|
|
var derivedCommands = command.derivedCommands.globeTranslucency;
|
|
for (var i = 0; i < derivedCommandsLength; ++i) {
|
|
var derivedCommandName = DerivedCommandNames[derivedCommandTypes[i]];
|
|
frameState.commandList.push(derivedCommands[derivedCommandName]);
|
|
}
|
|
};
|
|
|
|
function executeCommandsMatchingType(
|
|
commands,
|
|
commandsLength,
|
|
executeCommandFunction,
|
|
scene,
|
|
context,
|
|
passState,
|
|
types
|
|
) {
|
|
for (var i = 0; i < commandsLength; ++i) {
|
|
var command = commands[i];
|
|
var type = command.derivedCommands.type;
|
|
if (!defined(types) || types.indexOf(type) > -1) {
|
|
executeCommandFunction(command, scene, context, passState);
|
|
}
|
|
}
|
|
}
|
|
|
|
function executeCommands(
|
|
commands,
|
|
commandsLength,
|
|
executeCommandFunction,
|
|
scene,
|
|
context,
|
|
passState
|
|
) {
|
|
for (var i = 0; i < commandsLength; ++i) {
|
|
executeCommandFunction(commands[i], scene, context, passState);
|
|
}
|
|
}
|
|
|
|
var opaqueTypes = [
|
|
DerivedCommandType.OPAQUE_FRONT_FACE,
|
|
DerivedCommandType.OPAQUE_BACK_FACE,
|
|
];
|
|
var depthOnlyTypes = [
|
|
DerivedCommandType.DEPTH_ONLY_FRONT_FACE,
|
|
DerivedCommandType.DEPTH_ONLY_BACK_FACE,
|
|
DerivedCommandType.DEPTH_ONLY_FRONT_AND_BACK_FACE,
|
|
];
|
|
|
|
GlobeTranslucencyState.prototype.executeGlobeCommands = function (
|
|
frustumCommands,
|
|
executeCommandFunction,
|
|
globeTranslucencyFramebuffer,
|
|
scene,
|
|
passState
|
|
) {
|
|
var context = scene.context;
|
|
var globeCommands = frustumCommands.commands[Pass.GLOBE];
|
|
var globeCommandsLength = frustumCommands.indices[Pass.GLOBE];
|
|
|
|
if (globeCommandsLength === 0) {
|
|
return;
|
|
}
|
|
|
|
this._globeTranslucencyFramebuffer = globeTranslucencyFramebuffer;
|
|
globeTranslucencyFramebuffer.clearClassification(context, passState);
|
|
|
|
// Render opaque commands like normal
|
|
executeCommandsMatchingType(
|
|
globeCommands,
|
|
globeCommandsLength,
|
|
executeCommandFunction,
|
|
scene,
|
|
context,
|
|
passState,
|
|
opaqueTypes
|
|
);
|
|
};
|
|
|
|
GlobeTranslucencyState.prototype.executeGlobeClassificationCommands = function (
|
|
frustumCommands,
|
|
executeCommandFunction,
|
|
globeTranslucencyFramebuffer,
|
|
scene,
|
|
passState
|
|
) {
|
|
var context = scene.context;
|
|
var globeCommands = frustumCommands.commands[Pass.GLOBE];
|
|
var globeCommandsLength = frustumCommands.indices[Pass.GLOBE];
|
|
var classificationCommands =
|
|
frustumCommands.commands[Pass.TERRAIN_CLASSIFICATION];
|
|
var classificationCommandsLength =
|
|
frustumCommands.indices[Pass.TERRAIN_CLASSIFICATION];
|
|
|
|
if (globeCommandsLength === 0 || classificationCommandsLength === 0) {
|
|
return;
|
|
}
|
|
|
|
var frontTranslucent = this._frontFaceTranslucent;
|
|
var backTranslucent = this._backFaceTranslucent;
|
|
|
|
if (!frontTranslucent || !backTranslucent) {
|
|
// Render classification on opaque faces like normal
|
|
executeCommands(
|
|
classificationCommands,
|
|
classificationCommandsLength,
|
|
executeCommandFunction,
|
|
scene,
|
|
context,
|
|
passState
|
|
);
|
|
}
|
|
|
|
if (!frontTranslucent && !backTranslucent) {
|
|
// No translucent commands to render. Skip translucent classification.
|
|
return;
|
|
}
|
|
|
|
this._globeTranslucencyFramebuffer = globeTranslucencyFramebuffer;
|
|
|
|
var originalGlobeDepthTexture = context.uniformState.globeDepthTexture;
|
|
var originalFramebuffer = passState.framebuffer;
|
|
|
|
// Render to internal framebuffer and get the first depth peel
|
|
passState.framebuffer =
|
|
globeTranslucencyFramebuffer.classificationFramebuffer;
|
|
|
|
executeCommandsMatchingType(
|
|
globeCommands,
|
|
globeCommandsLength,
|
|
executeCommandFunction,
|
|
scene,
|
|
context,
|
|
passState,
|
|
depthOnlyTypes
|
|
);
|
|
|
|
if (context.depthTexture) {
|
|
// Pack depth into separate texture for ground polylines and textured ground primitives
|
|
var packedDepthTexture = globeTranslucencyFramebuffer.packDepth(
|
|
context,
|
|
passState
|
|
);
|
|
context.uniformState.globeDepthTexture = packedDepthTexture;
|
|
}
|
|
|
|
// Render classification on translucent faces
|
|
executeCommands(
|
|
classificationCommands,
|
|
classificationCommandsLength,
|
|
executeCommandFunction,
|
|
scene,
|
|
context,
|
|
passState
|
|
);
|
|
|
|
// Unset temporary state
|
|
context.uniformState.globeDepthTexture = originalGlobeDepthTexture;
|
|
passState.framebuffer = originalFramebuffer;
|
|
};
|
|
|
|
export default GlobeTranslucencyState;
|