Skip to content

Commit 09d7454

Browse files
committed
support 2.5D/2D projection by default when the option projectTo2D is not set
add the options.customGeometryStageVS Whether to override the default VS geometry stage, to let the user define its own VS geometry stage.
1 parent b2f7722 commit 09d7454

File tree

3 files changed

+106
-3
lines changed

3 files changed

+106
-3
lines changed

packages/engine/Source/Scene/Model/GeometryPipelineStage.js

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -184,13 +184,30 @@ GeometryPipelineStage.process = function (
184184
);
185185
}
186186

187+
shaderBuilder.addUniform("vec3", "u_ellipsoidRadii");
188+
shaderBuilder.addUniform("vec3", "u_ellipsoidRadiiSquared");
189+
190+
const ellipsoid = frameState.mapProjection.ellipsoid;
191+
const uniformMap = renderResources.uniformMap;
192+
193+
uniformMap.u_ellipsoidRadii = function () {
194+
return ellipsoid.radii;
195+
};
196+
uniformMap.u_ellipsoidRadiiSquared = function () {
197+
return ellipsoid.radiiSquared;
198+
};
199+
187200
handleBitangents(shaderBuilder, primitive.attributes);
188201

189202
if (primitive.primitiveType === PrimitiveType.POINTS) {
190203
shaderBuilder.addDefine("PRIMITIVE_TYPE_POINTS");
191204
}
192205

193-
shaderBuilder.addVertexLines(GeometryStageVS);
206+
if (model._customGeometryStageVS) {
207+
shaderBuilder.addVertexLines(model._customGeometryStageVS);
208+
} else {
209+
shaderBuilder.addVertexLines(GeometryStageVS);
210+
}
194211
shaderBuilder.addFragmentLines(GeometryStageFS);
195212
};
196213

packages/engine/Source/Scene/Model/Model.js

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -166,6 +166,7 @@ import ModelImagery from "./ModelImagery.js";
166166
* @privateParam {boolean} [options.showCreditsOnScreen=false] Whether to display the credits of this model on screen.
167167
* @privateParam {SplitDirection} [options.splitDirection=SplitDirection.NONE] The {@link SplitDirection} split to apply to this model.
168168
* @privateParam {boolean} [options.projectTo2D=false] Whether to accurately project the model's positions in 2D. If this is true, the model will be projected accurately to 2D, but it will use more memory to do so. If this is false, the model will use less memory and will still render in 2D / CV mode, but its positions may be inaccurate. This disables minimumPixelSize and prevents future modification to the model matrix. This also cannot be set after the model has loaded.
169+
* @privateParam {boolean} [options.customGeometryStageVS] Whether to override the default VS geometry stage, to let the user define its own VS geometry stage.
169170
* @privateParam {boolean} [options.enablePick=false] Whether to allow CPU picking with <code>pick</code> when not using WebGL 2 or above. If using WebGL 2 or above, this option will be ignored. If using WebGL 1 and this is true, the <code>pick</code> operation will work correctly, but it will use more memory to do so. If running with WebGL 1 and this is false, the model will use less memory, but <code>pick</code> will always return <code>undefined</code>. This cannot be set after the model has loaded.
170171
* @privateParam {string|number} [options.featureIdLabel="featureId_0"] Label of the feature ID set to use for picking and styling. For EXT_mesh_features, this is the feature ID's label property, or "featureId_N" (where N is the index in the featureIds array) when not specified. EXT_feature_metadata did not have a label field, so such feature ID sets are always labeled "featureId_N" where N is the index in the list of all feature Ids, where feature ID attributes are listed before feature ID textures. If featureIdLabel is an integer N, it is converted to the string "featureId_N" automatically. If both per-primitive and per-instance feature IDs are present, the instance feature IDs take priority.
171172
* @privateParam {string|number} [options.instanceFeatureIdLabel="instanceFeatureId_0"] Label of the instance feature ID set used for picking and styling. If instanceFeatureIdLabel is set to an integer N, it is converted to the string "instanceFeatureId_N" automatically. If both per-primitive and per-instance feature IDs are present, the instance feature IDs take priority.
@@ -479,6 +480,7 @@ function Model(options) {
479480
this._sceneMode = undefined;
480481
this._projectTo2D = options.projectTo2D ?? false;
481482
this._enablePick = options.enablePick ?? false;
483+
this._customGeometryStageVS = options.customGeometryStageVS;
482484

483485
this._fogRenderable = undefined;
484486

@@ -3055,6 +3057,7 @@ Model.fromGltfAsync = async function (options) {
30553057
loadIndicesForWireframe: options.enableDebugWireframe,
30563058
loadPrimitiveOutline: options.enableShowOutline,
30573059
loadForClassification: defined(options.classificationType),
3060+
customGeometryStageVS: options.customGeometryStageVS,
30583061
};
30593062

30603063
const basePath = options.basePath ?? "";
@@ -3321,6 +3324,7 @@ function makeModelOptions(loader, modelType, options) {
33213324
showCreditsOnScreen: options.showCreditsOnScreen,
33223325
splitDirection: options.splitDirection,
33233326
projectTo2D: options.projectTo2D,
3327+
customGeometryStageVS: options.customGeometryStageVS,
33243328
enablePick: options.enablePick,
33253329
featureIdLabel: options.featureIdLabel,
33263330
instanceFeatureIdLabel: options.instanceFeatureIdLabel,

packages/engine/Source/Shaders/Model/GeometryStageVS.glsl

Lines changed: 84 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,100 @@
1+
vec3 projectToGeographic(vec3 cartographic)
2+
{
3+
float lon = cartographic.y;
4+
float lat = cartographic.x;
5+
float altitude = cartographic.z;
6+
7+
float plate_x = u_ellipsoidRadii.x * lat;
8+
float plate_y = u_ellipsoidRadii.x * lon;
9+
10+
return vec3(altitude, plate_x, plate_y);
11+
}
12+
13+
vec3 cartesianToCartographic(vec3 cartesian) {
14+
// Correct the incoming (y, z, x) coordinate order to standard ECEF (x, y, z).
15+
vec3 ecef = vec3(cartesian.z, cartesian.x, cartesian.y);
16+
17+
// Check if the ellipsoid is a sphere, which allows for a much faster, direct calculation.
18+
bool isSphere = (u_ellipsoidRadii.x == u_ellipsoidRadii.y) && (u_ellipsoidRadii.x == u_ellipsoidRadii.z);
19+
20+
if (isSphere) {
21+
float mag = length(ecef);
22+
// Avoid division by zero at the center
23+
if (mag < czm_epsilon6) {
24+
return vec3(0.0, 0.0, -u_ellipsoidRadii.x);
25+
}
26+
float longitude = atan(ecef.y, ecef.x);
27+
float latitude = asin(ecef.z / mag);
28+
float height = mag - u_ellipsoidRadii.x;
29+
return vec3(longitude, latitude, height);
30+
}
31+
32+
// --- Ellipsoidal Calculation (Iterative Method) ---
33+
34+
// The vector from the center to the point on the XY plane
35+
vec2 p = ecef.xy;
36+
float pLength = length(p);
37+
38+
// If the point is near the Z-axis, the calculation is straightforward
39+
if (pLength < czm_epsilon6) {
40+
// Longitude is undefined at the poles, but 0.0 is a standard convention.
41+
float longitude = 0.0;
42+
float latitude = (ecef.z >= 0.0) ? czm_pi / 2.0 : -czm_pi / 2.0;
43+
float height = abs(ecef.z) - u_ellipsoidRadii.z;
44+
return vec3(longitude, latitude, height);
45+
}
46+
47+
// Key ellipsoid parameters
48+
float a = u_ellipsoidRadii.x;
49+
float c = u_ellipsoidRadii.z;
50+
float a2 = u_ellipsoidRadiiSquared.x;
51+
float c2 = u_ellipsoidRadiiSquared.z;
52+
float e2 = (a2 - c2) / a2; // First eccentricity squared
53+
54+
// Initial guess for latitude is the geocentric latitude
55+
float latitude = atan(ecef.z, pLength);
56+
float N; // Radius of curvature in the prime vertical
57+
58+
// Iteratively refine the latitude. 3-4 iterations are sufficient for high precision.
59+
for (int i = 0; i < 4; ++i) {
60+
float sinLat = sin(latitude);
61+
N = a / sqrt(1.0 - e2 * sinLat * sinLat);
62+
latitude = atan((ecef.z + N * e2 * sinLat) / pLength);
63+
}
64+
65+
// With the final latitude, calculate longitude and height
66+
float longitude = atan(ecef.y, ecef.x);
67+
float sinLat = sin(latitude);
68+
float cosLat = cos(latitude);
69+
N = a / sqrt(1.0 - e2 * sinLat * sinLat);
70+
float height = (pLength / cosLat) - N;
71+
72+
return vec3(longitude, latitude, height);
73+
}
74+
175
vec4 geometryStage(inout ProcessedAttributes attributes, mat4 modelView, mat3 normal)
276
{
377
vec4 computedPosition;
478

579
// Compute positions in different coordinate systems
680
vec3 positionMC = attributes.positionMC;
781
v_positionMC = positionMC;
8-
v_positionEC = (modelView * vec4(positionMC, 1.0)).xyz;
982

1083
#if defined(USE_2D_POSITIONS) || defined(USE_2D_INSTANCING)
1184
vec3 position2D = attributes.position2D;
1285
vec3 positionEC = (u_modelView2D * vec4(position2D, 1.0)).xyz;
1386
computedPosition = czm_projection * vec4(positionEC, 1.0);
1487
#else
15-
computedPosition = czm_projection * vec4(v_positionEC, 1.0);
88+
if(czm_morphTime != 1.){
89+
vec3 cartographic = cartesianToCartographic(positionMC);
90+
vec3 position = projectToGeographic(cartographic);
91+
92+
vec3 positionEC = (czm_view * vec4(position, 1.0)).xyz;
93+
computedPosition = czm_projection * vec4(positionEC, 1.0);
94+
}else{
95+
v_positionEC = (modelView * vec4(positionMC, 1.0)).xyz;
96+
computedPosition = czm_projection * vec4(v_positionEC, 1.0);
97+
}
1698
#endif
1799

18100
// Sometimes the custom shader and/or style needs this

0 commit comments

Comments
 (0)