deeptwins-cesium-engine 0.1.1 → 0.1.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/Source/Core/defaultValue.js +20 -0
- package/Source/Shaders/BufferPointMaterialFS.js +30 -0
- package/Source/Shaders/BufferPointMaterialVS.js +60 -0
- package/Source/Shaders/BufferPolygonMaterialFS.js +15 -0
- package/Source/Shaders/BufferPolygonMaterialVS.js +41 -0
- package/Source/Shaders/BufferPolylineMaterialFS.js +15 -0
- package/Source/Shaders/BufferPolylineMaterialVS.js +65 -0
- package/Source/Shaders/CubeMapPanoramaVS.js +13 -0
- package/Source/Shaders/Model/ConstantLodStageFS.js +62 -0
- package/Source/Shaders/Model/ConstantLodStageVS.js +13 -0
- package/Source/Shaders/Model/EdgeDetectionStageFS.js +60 -0
- package/Source/Shaders/Model/EdgeVisibilityStageFS.js +70 -0
- package/Source/Shaders/Model/EdgeVisibilityStageVS.js +99 -0
- package/Source/Shaders/PrimitiveGaussianSplatFS.js +20 -0
- package/Source/Shaders/PrimitiveGaussianSplatVS.js +197 -0
- package/Source/Shaders/Voxels/IntersectPlane.js +82 -0
- package/Source/Shaders/Voxels/convertLocalToBoxUv.js +31 -0
- package/Source/Shaders/Voxels/convertLocalToCylinderUv.js +97 -0
- package/Source/Shaders/Voxels/convertLocalToEllipsoidUv.js +185 -0
- package/index.js +244 -161
- package/package.json +1 -1
|
@@ -0,0 +1,197 @@
|
|
|
1
|
+
//This file is automatically rebuilt by the Cesium build process.
|
|
2
|
+
export default "//\n\
|
|
3
|
+
// Vertex shader for Gaussian splats.\n\
|
|
4
|
+
\n\
|
|
5
|
+
// The splats are rendered as quads in view space. Splat attributes are loaded from a texture with precomputed 3D covariance.\n\
|
|
6
|
+
\n\
|
|
7
|
+
// Passes local quad coordinates and color to the fragment shader for Gaussian evaluation. \n\
|
|
8
|
+
//\n\
|
|
9
|
+
// Discards splats outside the view frustum or with negligible screen size.\n\
|
|
10
|
+
//\n\
|
|
11
|
+
#if defined(HAS_SPHERICAL_HARMONICS)\n\
|
|
12
|
+
const uint coefficientCount[3] = uint[3](3u,8u,15u);\n\
|
|
13
|
+
const float SH_C1 = 0.48860251;\n\
|
|
14
|
+
const float SH_C2[5] = float[5](\n\
|
|
15
|
+
1.092548430,\n\
|
|
16
|
+
-1.09254843,\n\
|
|
17
|
+
0.315391565,\n\
|
|
18
|
+
-1.09254843,\n\
|
|
19
|
+
0.546274215\n\
|
|
20
|
+
);\n\
|
|
21
|
+
\n\
|
|
22
|
+
const float SH_C3[7] = float[7](\n\
|
|
23
|
+
-0.59004358,\n\
|
|
24
|
+
2.890611442,\n\
|
|
25
|
+
-0.45704579,\n\
|
|
26
|
+
0.373176332,\n\
|
|
27
|
+
-0.45704579,\n\
|
|
28
|
+
1.445305721,\n\
|
|
29
|
+
-0.59004358\n\
|
|
30
|
+
);\n\
|
|
31
|
+
\n\
|
|
32
|
+
//Retrieve SH coefficient. Currently RG32UI format\n\
|
|
33
|
+
uvec2 loadSHCoeff(uint splatID, int index) {\n\
|
|
34
|
+
ivec2 shTexSize = textureSize(u_sphericalHarmonicsTexture, 0);\n\
|
|
35
|
+
uint dims = coefficientCount[uint(u_sphericalHarmonicsDegree)-1u];\n\
|
|
36
|
+
uint splatsPerRow = uint(shTexSize.x) / dims;\n\
|
|
37
|
+
uint shIndex = (splatID%splatsPerRow) * dims + uint(index);\n\
|
|
38
|
+
ivec2 shPosCoord = ivec2(shIndex, splatID / splatsPerRow);\n\
|
|
39
|
+
return texelFetch(u_sphericalHarmonicsTexture, shPosCoord, 0).rg;\n\
|
|
40
|
+
}\n\
|
|
41
|
+
\n\
|
|
42
|
+
//Unpack RG32UI half float coefficients to vec3\n\
|
|
43
|
+
vec3 halfToVec3(uvec2 packed) {\n\
|
|
44
|
+
return vec3(unpackHalf2x16(packed.x), unpackHalf2x16(packed.y).x);\n\
|
|
45
|
+
}\n\
|
|
46
|
+
\n\
|
|
47
|
+
vec3 loadAndExpandSHCoeff(uint splatID, int index) {\n\
|
|
48
|
+
uvec2 coeff = loadSHCoeff(splatID, index);\n\
|
|
49
|
+
return halfToVec3(coeff);\n\
|
|
50
|
+
}\n\
|
|
51
|
+
\n\
|
|
52
|
+
vec3 evaluateSH(uint splatID, vec3 viewDir) {\n\
|
|
53
|
+
vec3 result = vec3(0.0);\n\
|
|
54
|
+
int coeffIndex = 0;\n\
|
|
55
|
+
float x = viewDir.x, y = viewDir.y, z = viewDir.z;\n\
|
|
56
|
+
\n\
|
|
57
|
+
if (u_sphericalHarmonicsDegree >= 1.) {\n\
|
|
58
|
+
vec3 sh1 = loadAndExpandSHCoeff(splatID, coeffIndex++);\n\
|
|
59
|
+
vec3 sh2 = loadAndExpandSHCoeff(splatID, coeffIndex++);\n\
|
|
60
|
+
vec3 sh3 = loadAndExpandSHCoeff(splatID, coeffIndex++);\n\
|
|
61
|
+
result += -SH_C1 * y * sh1 + SH_C1 * z * sh2 - SH_C1 * x * sh3;\n\
|
|
62
|
+
\n\
|
|
63
|
+
if (u_sphericalHarmonicsDegree >= 2.) {\n\
|
|
64
|
+
float xx = x * x;\n\
|
|
65
|
+
float yy = y * y;\n\
|
|
66
|
+
float zz = z * z;\n\
|
|
67
|
+
float xy = x * y;\n\
|
|
68
|
+
float yz = y * z;\n\
|
|
69
|
+
float xz = x * z;\n\
|
|
70
|
+
\n\
|
|
71
|
+
vec3 sh4 = loadAndExpandSHCoeff(splatID, coeffIndex++);\n\
|
|
72
|
+
vec3 sh5 = loadAndExpandSHCoeff(splatID, coeffIndex++);\n\
|
|
73
|
+
vec3 sh6 = loadAndExpandSHCoeff(splatID, coeffIndex++);\n\
|
|
74
|
+
vec3 sh7 = loadAndExpandSHCoeff(splatID, coeffIndex++);\n\
|
|
75
|
+
vec3 sh8 = loadAndExpandSHCoeff(splatID, coeffIndex++);\n\
|
|
76
|
+
result += SH_C2[0] * xy * sh4 +\n\
|
|
77
|
+
SH_C2[1] * yz * sh5 +\n\
|
|
78
|
+
SH_C2[2] * (2.0f * zz - xx - yy) * sh6 +\n\
|
|
79
|
+
SH_C2[3] * xz * sh7 +\n\
|
|
80
|
+
SH_C2[4] * (xx - yy) * sh8;\n\
|
|
81
|
+
\n\
|
|
82
|
+
if (u_sphericalHarmonicsDegree >= 3.) {\n\
|
|
83
|
+
vec3 sh9 = loadAndExpandSHCoeff(splatID, coeffIndex++);\n\
|
|
84
|
+
vec3 sh10 = loadAndExpandSHCoeff(splatID, coeffIndex++);\n\
|
|
85
|
+
vec3 sh11 = loadAndExpandSHCoeff(splatID, coeffIndex++);\n\
|
|
86
|
+
vec3 sh12 = loadAndExpandSHCoeff(splatID, coeffIndex++);\n\
|
|
87
|
+
vec3 sh13 = loadAndExpandSHCoeff(splatID, coeffIndex++);\n\
|
|
88
|
+
vec3 sh14 = loadAndExpandSHCoeff(splatID, coeffIndex++);\n\
|
|
89
|
+
vec3 sh15 = loadAndExpandSHCoeff(splatID, coeffIndex++);\n\
|
|
90
|
+
result += SH_C3[0] * y * (3.0f * xx - yy) * sh9 +\n\
|
|
91
|
+
SH_C3[1] * xy * z * sh10 +\n\
|
|
92
|
+
SH_C3[2] * y * (4.0f * zz - xx - yy) * sh11 +\n\
|
|
93
|
+
SH_C3[3] * z * (2.0f * zz - 3.0f * xx - 3.0f * yy) * sh12 +\n\
|
|
94
|
+
SH_C3[4] * x * (4.0f * zz - xx - yy) * sh13 +\n\
|
|
95
|
+
SH_C3[5] * z * (xx - yy) * sh14 +\n\
|
|
96
|
+
SH_C3[6] * x * (xx - 3.0f * yy) * sh15;\n\
|
|
97
|
+
}\n\
|
|
98
|
+
}\n\
|
|
99
|
+
}\n\
|
|
100
|
+
return result;\n\
|
|
101
|
+
}\n\
|
|
102
|
+
#endif\n\
|
|
103
|
+
\n\
|
|
104
|
+
// Transforms and projects splat covariance into screen space and extracts the major and minor axes of the Gaussian ellipsoid\n\
|
|
105
|
+
// which is used to calculate the vertex position in clip space.\n\
|
|
106
|
+
vec4 calcCovVectors(vec3 viewPos, mat3 Vrk) {\n\
|
|
107
|
+
vec4 t = vec4(viewPos, 1.0);\n\
|
|
108
|
+
vec2 focal = vec2(czm_projection[0][0] * czm_viewport.z, czm_projection[1][1] * czm_viewport.w);\n\
|
|
109
|
+
\n\
|
|
110
|
+
vec2 J1 = focal / t.z;\n\
|
|
111
|
+
vec2 J2 = -focal * vec2(t.x, t.y) / (t.z * t.z);\n\
|
|
112
|
+
mat3 J = mat3(\n\
|
|
113
|
+
J1.x, 0.0, J2.x,\n\
|
|
114
|
+
0.0, J1.y, J2.y,\n\
|
|
115
|
+
0.0, 0.0, 0.0\n\
|
|
116
|
+
);\n\
|
|
117
|
+
\n\
|
|
118
|
+
mat3 R = mat3(czm_modelView);\n\
|
|
119
|
+
\n\
|
|
120
|
+
//transform our covariance into view space\n\
|
|
121
|
+
//ensures orientation is correct\n\
|
|
122
|
+
mat3 Vrk_view = R * Vrk * transpose(R);\n\
|
|
123
|
+
mat3 cov = transpose(J) * Vrk_view * J;\n\
|
|
124
|
+
\n\
|
|
125
|
+
float diagonal1 = cov[0][0] + .3;\n\
|
|
126
|
+
float offDiagonal = cov[0][1];\n\
|
|
127
|
+
float diagonal2 = cov[1][1] + .3;\n\
|
|
128
|
+
\n\
|
|
129
|
+
float mid = 0.5 * (diagonal1 + diagonal2);\n\
|
|
130
|
+
float radius = length(vec2((diagonal1 - diagonal2) * 0.5, offDiagonal));\n\
|
|
131
|
+
float lambda1 = mid + radius;\n\
|
|
132
|
+
float lambda2 = max(mid - radius, 0.1);\n\
|
|
133
|
+
\n\
|
|
134
|
+
vec2 diagonalVector = normalize(vec2(offDiagonal, lambda1 - diagonal1));\n\
|
|
135
|
+
\n\
|
|
136
|
+
return vec4(\n\
|
|
137
|
+
min(sqrt(2.0 * lambda1), 1024.0) * diagonalVector,\n\
|
|
138
|
+
min(sqrt(2.0 * lambda2), 1024.0) * vec2(diagonalVector.y, -diagonalVector.x)\n\
|
|
139
|
+
);\n\
|
|
140
|
+
}\n\
|
|
141
|
+
\n\
|
|
142
|
+
highp vec4 discardVec = vec4(0.0, 0.0, 2.0, 1.0);\n\
|
|
143
|
+
\n\
|
|
144
|
+
void main() {\n\
|
|
145
|
+
uint texIdx = uint(a_splatIndex);\n\
|
|
146
|
+
// u_splatRowMask and u_splatRowShift encode the row width of the splat\n\
|
|
147
|
+
// attribute texture. The texture width is always maximumTextureSize, which\n\
|
|
148
|
+
// varies by GPU, so these are passed as uniforms rather than constants.\n\
|
|
149
|
+
// rowMask = maximumTextureSize/2 - 1\n\
|
|
150
|
+
// rowShift = log2(maximumTextureSize/2)\n\
|
|
151
|
+
uint rowMask = uint(u_splatRowMask);\n\
|
|
152
|
+
uint rowShift = uint(u_splatRowShift);\n\
|
|
153
|
+
ivec2 posCoord = ivec2(int((texIdx & rowMask) << 1), int(texIdx >> rowShift));\n\
|
|
154
|
+
vec4 splatPosition = vec4( uintBitsToFloat(uvec4(texelFetch(u_splatAttributeTexture, posCoord, 0))) );\n\
|
|
155
|
+
\n\
|
|
156
|
+
vec4 splatViewPos = czm_modelView * vec4(splatPosition.xyz, 1.0);\n\
|
|
157
|
+
vec4 clipPosition = czm_projection * splatViewPos;\n\
|
|
158
|
+
\n\
|
|
159
|
+
float clip = 1.2 * clipPosition.w;\n\
|
|
160
|
+
if (clipPosition.z < -clip || clipPosition.x < -clip || clipPosition.x > clip ||\n\
|
|
161
|
+
clipPosition.y < -clip || clipPosition.y > clip) {\n\
|
|
162
|
+
gl_Position = vec4(0.0, 0.0, 2.0, 1.0);\n\
|
|
163
|
+
return;\n\
|
|
164
|
+
}\n\
|
|
165
|
+
\n\
|
|
166
|
+
ivec2 covCoord = ivec2(int(((texIdx & rowMask) << 1) | 1u), int(texIdx >> rowShift));\n\
|
|
167
|
+
uvec4 covariance = uvec4(texelFetch(u_splatAttributeTexture, covCoord, 0));\n\
|
|
168
|
+
\n\
|
|
169
|
+
gl_Position = clipPosition;\n\
|
|
170
|
+
\n\
|
|
171
|
+
vec2 u1 = unpackHalf2x16(covariance.x) ;\n\
|
|
172
|
+
vec2 u2 = unpackHalf2x16(covariance.y);\n\
|
|
173
|
+
vec2 u3 = unpackHalf2x16(covariance.z);\n\
|
|
174
|
+
mat3 Vrk = mat3(u1.x, u1.y, u2.x, u1.y, u2.y, u3.x, u2.x, u3.x, u3.y);\n\
|
|
175
|
+
\n\
|
|
176
|
+
vec4 covVectors = calcCovVectors(splatViewPos.xyz, Vrk);\n\
|
|
177
|
+
\n\
|
|
178
|
+
if (dot(covVectors.xy, covVectors.xy) < 4.0 && dot(covVectors.zw, covVectors.zw) < 4.0) {\n\
|
|
179
|
+
gl_Position = discardVec;\n\
|
|
180
|
+
return;\n\
|
|
181
|
+
}\n\
|
|
182
|
+
\n\
|
|
183
|
+
vec2 corner = vec2((gl_VertexID << 1) & 2, gl_VertexID & 2) - 1.;\n\
|
|
184
|
+
\n\
|
|
185
|
+
gl_Position += vec4((corner.x * covVectors.xy + corner.y * covVectors.zw) / czm_viewport.zw * gl_Position.w, 0, 0);\n\
|
|
186
|
+
gl_Position.z = clamp(gl_Position.z, -abs(gl_Position.w), abs(gl_Position.w));\n\
|
|
187
|
+
\n\
|
|
188
|
+
v_vertPos = corner ;\n\
|
|
189
|
+
v_splatColor = vec4(covariance.w & 0xffu, (covariance.w >> 8) & 0xffu, (covariance.w >> 16) & 0xffu, (covariance.w >> 24) & 0xffu) / 255.0;\n\
|
|
190
|
+
#if defined(HAS_SPHERICAL_HARMONICS)\n\
|
|
191
|
+
vec4 splatWC = czm_inverseView * splatViewPos;\n\
|
|
192
|
+
vec3 viewDirModel = normalize(u_inverseModelRotation * (splatWC.xyz - u_cameraPositionWC.xyz));\n\
|
|
193
|
+
\n\
|
|
194
|
+
v_splatColor.rgb += evaluateSH(texIdx, viewDirModel).rgb;\n\
|
|
195
|
+
#endif\n\
|
|
196
|
+
v_splitDirection = u_splitDirection;\n\
|
|
197
|
+
}";
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
//This file is automatically rebuilt by the Cesium build process.
|
|
2
|
+
export default "// See IntersectionUtils.glsl for the definitions of Ray, Intersections, INF_HIT,\n\
|
|
3
|
+
// NO_HIT, setShapeIntersection\n\
|
|
4
|
+
\n\
|
|
5
|
+
/* Clipping plane defines (set in Scene/VoxelRenderResources.js)\n\
|
|
6
|
+
#define CLIPPING_PLANES_UNION\n\
|
|
7
|
+
#define CLIPPING_PLANES_COUNT\n\
|
|
8
|
+
#define CLIPPING_PLANES_INTERSECTION_INDEX\n\
|
|
9
|
+
*/\n\
|
|
10
|
+
\n\
|
|
11
|
+
uniform sampler2D u_clippingPlanesTexture;\n\
|
|
12
|
+
uniform mat4 u_clippingPlanesMatrix;\n\
|
|
13
|
+
\n\
|
|
14
|
+
// Plane is in Hessian Normal Form\n\
|
|
15
|
+
vec4 intersectPlane(in Ray ray, in vec4 plane) {\n\
|
|
16
|
+
vec3 n = plane.xyz; // normal\n\
|
|
17
|
+
float w = plane.w; // -dot(pointOnPlane, normal)\n\
|
|
18
|
+
\n\
|
|
19
|
+
float a = dot(ray.pos, n);\n\
|
|
20
|
+
float b = dot(ray.dir, n);\n\
|
|
21
|
+
float t = -(w + a) / b;\n\
|
|
22
|
+
\n\
|
|
23
|
+
return vec4(n, t);\n\
|
|
24
|
+
}\n\
|
|
25
|
+
\n\
|
|
26
|
+
#ifdef CLIPPING_PLANES\n\
|
|
27
|
+
void intersectClippingPlanes(in Ray ray, inout Intersections ix) {\n\
|
|
28
|
+
vec4 backSide = vec4(-ray.dir, -INF_HIT);\n\
|
|
29
|
+
vec4 farSide = vec4(ray.dir, +INF_HIT);\n\
|
|
30
|
+
RayShapeIntersection clippingVolume;\n\
|
|
31
|
+
\n\
|
|
32
|
+
#if (CLIPPING_PLANES_COUNT == 1)\n\
|
|
33
|
+
// Union and intersection are the same when there's one clipping plane, and the code\n\
|
|
34
|
+
// is more simplified.\n\
|
|
35
|
+
vec4 planeUv = getClippingPlane(u_clippingPlanesTexture, 0);\n\
|
|
36
|
+
vec4 intersection = intersectPlane(ray, planeUv);\n\
|
|
37
|
+
bool reflects = dot(ray.dir, intersection.xyz) < 0.0;\n\
|
|
38
|
+
clippingVolume.entry = reflects ? backSide : intersection;\n\
|
|
39
|
+
clippingVolume.exit = reflects ? intersection : farSide;\n\
|
|
40
|
+
setShapeIntersection(ix, CLIPPING_PLANES_INTERSECTION_INDEX, clippingVolume);\n\
|
|
41
|
+
#elif defined(CLIPPING_PLANES_UNION)\n\
|
|
42
|
+
vec4 firstTransmission = vec4(ray.dir, +INF_HIT);\n\
|
|
43
|
+
vec4 lastReflection = vec4(-ray.dir, -INF_HIT);\n\
|
|
44
|
+
for (int i = 0; i < CLIPPING_PLANES_COUNT; i++) {\n\
|
|
45
|
+
vec4 planeUv = getClippingPlane(u_clippingPlanesTexture, i);\n\
|
|
46
|
+
vec4 intersection = intersectPlane(ray, planeUv);\n\
|
|
47
|
+
if (dot(ray.dir, planeUv.xyz) > 0.0) {\n\
|
|
48
|
+
firstTransmission = intersection.w <= firstTransmission.w ? intersection : firstTransmission;\n\
|
|
49
|
+
} else {\n\
|
|
50
|
+
lastReflection = intersection.w >= lastReflection.w ? intersection : lastReflection;\n\
|
|
51
|
+
}\n\
|
|
52
|
+
}\n\
|
|
53
|
+
clippingVolume.entry = backSide;\n\
|
|
54
|
+
clippingVolume.exit = lastReflection;\n\
|
|
55
|
+
setShapeIntersection(ix, CLIPPING_PLANES_INTERSECTION_INDEX + 0, clippingVolume);\n\
|
|
56
|
+
clippingVolume.entry = firstTransmission;\n\
|
|
57
|
+
clippingVolume.exit = farSide;\n\
|
|
58
|
+
setShapeIntersection(ix, CLIPPING_PLANES_INTERSECTION_INDEX + 1, clippingVolume);\n\
|
|
59
|
+
#else // intersection\n\
|
|
60
|
+
vec4 lastTransmission = vec4(ray.dir, -INF_HIT);\n\
|
|
61
|
+
vec4 firstReflection = vec4(-ray.dir, +INF_HIT);\n\
|
|
62
|
+
for (int i = 0; i < CLIPPING_PLANES_COUNT; i++) {\n\
|
|
63
|
+
vec4 planeUv = getClippingPlane(u_clippingPlanesTexture, i);\n\
|
|
64
|
+
vec4 intersection = intersectPlane(ray, planeUv);\n\
|
|
65
|
+
if (dot(ray.dir, planeUv.xyz) > 0.0) {\n\
|
|
66
|
+
lastTransmission = intersection.w > lastTransmission.w ? intersection : lastTransmission;\n\
|
|
67
|
+
} else {\n\
|
|
68
|
+
firstReflection = intersection.w < firstReflection.w ? intersection: firstReflection;\n\
|
|
69
|
+
}\n\
|
|
70
|
+
}\n\
|
|
71
|
+
if (lastTransmission.w < firstReflection.w) {\n\
|
|
72
|
+
clippingVolume.entry = lastTransmission;\n\
|
|
73
|
+
clippingVolume.exit = firstReflection;\n\
|
|
74
|
+
} else {\n\
|
|
75
|
+
clippingVolume.entry = vec4(-ray.dir, NO_HIT);\n\
|
|
76
|
+
clippingVolume.exit = vec4(ray.dir, NO_HIT);\n\
|
|
77
|
+
}\n\
|
|
78
|
+
setShapeIntersection(ix, CLIPPING_PLANES_INTERSECTION_INDEX, clippingVolume);\n\
|
|
79
|
+
#endif\n\
|
|
80
|
+
}\n\
|
|
81
|
+
#endif\n\
|
|
82
|
+
";
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
//This file is automatically rebuilt by the Cesium build process.
|
|
2
|
+
export default "uniform vec3 u_boxLocalToShapeUvScale;\n\
|
|
3
|
+
\n\
|
|
4
|
+
uniform ivec4 u_cameraTileCoordinates;\n\
|
|
5
|
+
uniform vec3 u_cameraTileUv;\n\
|
|
6
|
+
uniform mat3 u_boxEcToXyz;\n\
|
|
7
|
+
\n\
|
|
8
|
+
mat3 convertLocalToShapeSpaceDerivative(in vec3 positionLocal) {\n\
|
|
9
|
+
// For BOX, local space = shape space, so the Jacobian is the identity matrix.\n\
|
|
10
|
+
return mat3(1.0);\n\
|
|
11
|
+
}\n\
|
|
12
|
+
\n\
|
|
13
|
+
vec3 scaleShapeUvToShapeSpace(in vec3 shapeUv) {\n\
|
|
14
|
+
return shapeUv / u_boxLocalToShapeUvScale;\n\
|
|
15
|
+
}\n\
|
|
16
|
+
\n\
|
|
17
|
+
vec3 convertEcToDeltaTile(in vec3 positionEC) {\n\
|
|
18
|
+
vec3 dPosition = u_boxEcToXyz * positionEC;\n\
|
|
19
|
+
return u_boxLocalToShapeUvScale * dPosition * float(1 << u_cameraTileCoordinates.w);\n\
|
|
20
|
+
}\n\
|
|
21
|
+
\n\
|
|
22
|
+
TileAndUvCoordinate getTileAndUvCoordinate(in vec3 positionEC) {\n\
|
|
23
|
+
vec3 deltaTileCoordinate = convertEcToDeltaTile(positionEC);\n\
|
|
24
|
+
vec3 tileUvSum = u_cameraTileUv + deltaTileCoordinate;\n\
|
|
25
|
+
ivec3 tileCoordinate = u_cameraTileCoordinates.xyz + ivec3(floor(tileUvSum));\n\
|
|
26
|
+
tileCoordinate = min(max(ivec3(0), tileCoordinate), ivec3((1 << u_cameraTileCoordinates.w) - 1));\n\
|
|
27
|
+
ivec3 tileCoordinateChange = tileCoordinate - u_cameraTileCoordinates.xyz;\n\
|
|
28
|
+
vec3 tileUv = clamp(tileUvSum - vec3(tileCoordinateChange), 0.0, 1.0);\n\
|
|
29
|
+
return TileAndUvCoordinate(ivec4(tileCoordinate, u_cameraTileCoordinates.w), tileUv);\n\
|
|
30
|
+
}\n\
|
|
31
|
+
";
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
//This file is automatically rebuilt by the Cesium build process.
|
|
2
|
+
export default "uniform vec3 u_cylinderLocalToShapeUvScale; // x = radius scale, y = angle scale, z = height scale\n\
|
|
3
|
+
uniform float u_cylinderShapeUvAngleRangeOrigin;\n\
|
|
4
|
+
uniform mat3 u_cylinderEcToRadialTangentUp;\n\
|
|
5
|
+
uniform ivec4 u_cameraTileCoordinates;\n\
|
|
6
|
+
uniform vec3 u_cameraTileUv;\n\
|
|
7
|
+
uniform vec3 u_cameraShapePosition; // (radial distance, angle, height) of camera in shape space\n\
|
|
8
|
+
\n\
|
|
9
|
+
mat3 convertLocalToShapeSpaceDerivative(in vec3 position) {\n\
|
|
10
|
+
vec3 radial = normalize(vec3(position.xy, 0.0));\n\
|
|
11
|
+
vec3 z = vec3(0.0, 0.0, 1.0);\n\
|
|
12
|
+
vec3 east = normalize(vec3(-position.y, position.x, 0.0));\n\
|
|
13
|
+
return mat3(radial, east / length(position.xy), z);\n\
|
|
14
|
+
}\n\
|
|
15
|
+
\n\
|
|
16
|
+
vec3 scaleShapeUvToShapeSpace(in vec3 shapeUv) {\n\
|
|
17
|
+
float radius = shapeUv.x / u_cylinderLocalToShapeUvScale.x;\n\
|
|
18
|
+
float angle = shapeUv.y * czm_twoPi / u_cylinderLocalToShapeUvScale.y;\n\
|
|
19
|
+
float height = shapeUv.z / u_cylinderLocalToShapeUvScale.z;\n\
|
|
20
|
+
\n\
|
|
21
|
+
return vec3(radius, angle, height);\n\
|
|
22
|
+
}\n\
|
|
23
|
+
\n\
|
|
24
|
+
/**\n\
|
|
25
|
+
* Computes the change in polar coordinates given a change in position.\n\
|
|
26
|
+
* @param {vec2} dPosition The change in position in Cartesian coordinates.\n\
|
|
27
|
+
* @param {float} cameraRadialDistance The radial distance of the camera from the origin.\n\
|
|
28
|
+
* @return {vec2} The change in polar coordinates (radial distance, angle).\n\
|
|
29
|
+
*/\n\
|
|
30
|
+
vec2 computePolarChange(in vec2 dPosition, in float cameraRadialDistance) {\n\
|
|
31
|
+
float dAngle = atan(dPosition.y, cameraRadialDistance + dPosition.x);\n\
|
|
32
|
+
// Find the direction of the radial axis at the output angle, in Cartesian coordinates\n\
|
|
33
|
+
vec2 outputRadialAxis = vec2(cos(dAngle), sin(dAngle));\n\
|
|
34
|
+
float sinHalfAngle = sin(dAngle / 2.0);\n\
|
|
35
|
+
float versine = 2.0 * sinHalfAngle * sinHalfAngle;\n\
|
|
36
|
+
float dRadial = dot(dPosition, outputRadialAxis) - cameraRadialDistance * versine;\n\
|
|
37
|
+
return vec2(dRadial, dAngle);\n\
|
|
38
|
+
}\n\
|
|
39
|
+
\n\
|
|
40
|
+
vec3 convertEcToDeltaShape(in vec3 positionEC) {\n\
|
|
41
|
+
// 1. Rotate to radial, tangent, and up coordinates\n\
|
|
42
|
+
vec3 rtu = u_cylinderEcToRadialTangentUp * positionEC;\n\
|
|
43
|
+
// 2. Compute change in angular and radial coordinates.\n\
|
|
44
|
+
vec2 dPolar = computePolarChange(rtu.xy, u_cameraShapePosition.x);\n\
|
|
45
|
+
return vec3(dPolar.xy, rtu.z);\n\
|
|
46
|
+
}\n\
|
|
47
|
+
\n\
|
|
48
|
+
vec3 convertEcToDeltaTile(in vec3 positionEC) {\n\
|
|
49
|
+
vec3 deltaShape = convertEcToDeltaShape(positionEC);\n\
|
|
50
|
+
// Convert to tileset coordinates in [0, 1]\n\
|
|
51
|
+
float dx = u_cylinderLocalToShapeUvScale.x * deltaShape.x;\n\
|
|
52
|
+
float dy = deltaShape.y / czm_twoPi;\n\
|
|
53
|
+
#if defined(CYLINDER_HAS_SHAPE_BOUNDS_ANGLE)\n\
|
|
54
|
+
// Wrap to ensure dy is not crossing through the unoccupied angle range, where\n\
|
|
55
|
+
// angle to tile coordinate conversions would be more complicated\n\
|
|
56
|
+
float cameraUvAngle = (u_cameraShapePosition.y + czm_pi) / czm_twoPi;\n\
|
|
57
|
+
float cameraUvAngleShift = fract(cameraUvAngle - u_cylinderShapeUvAngleRangeOrigin);\n\
|
|
58
|
+
float rawOutputUvAngle = cameraUvAngleShift + dy;\n\
|
|
59
|
+
float rotation = floor(rawOutputUvAngle);\n\
|
|
60
|
+
dy -= rotation;\n\
|
|
61
|
+
#endif\n\
|
|
62
|
+
dy *= u_cylinderLocalToShapeUvScale.y;\n\
|
|
63
|
+
float dz = u_cylinderLocalToShapeUvScale.z * deltaShape.z;\n\
|
|
64
|
+
// Convert to tile coordinate changes\n\
|
|
65
|
+
return vec3(dx, dy, dz) * float(1 << u_cameraTileCoordinates.w);\n\
|
|
66
|
+
}\n\
|
|
67
|
+
\n\
|
|
68
|
+
TileAndUvCoordinate getTileAndUvCoordinate(in vec3 positionEC) {\n\
|
|
69
|
+
vec3 deltaTileCoordinate = convertEcToDeltaTile(positionEC);\n\
|
|
70
|
+
vec3 tileUvSum = u_cameraTileUv + deltaTileCoordinate;\n\
|
|
71
|
+
ivec3 tileCoordinate = u_cameraTileCoordinates.xyz + ivec3(floor(tileUvSum));\n\
|
|
72
|
+
int maxTileCoordinate = (1 << u_cameraTileCoordinates.w) - 1;\n\
|
|
73
|
+
tileCoordinate.x = min(max(0, tileCoordinate.x), maxTileCoordinate);\n\
|
|
74
|
+
tileCoordinate.z = min(max(0, tileCoordinate.z), maxTileCoordinate);\n\
|
|
75
|
+
#if (!defined(CYLINDER_HAS_SHAPE_BOUNDS_ANGLE))\n\
|
|
76
|
+
ivec3 tileCoordinateChange = tileCoordinate - u_cameraTileCoordinates.xyz;\n\
|
|
77
|
+
if (tileCoordinate.y < 0) {\n\
|
|
78
|
+
tileCoordinate.y += (maxTileCoordinate + 1);\n\
|
|
79
|
+
} else if (tileCoordinate.y > maxTileCoordinate) {\n\
|
|
80
|
+
tileCoordinate.y -= (maxTileCoordinate + 1);\n\
|
|
81
|
+
}\n\
|
|
82
|
+
#else\n\
|
|
83
|
+
tileCoordinate.y = min(max(0, tileCoordinate.y), maxTileCoordinate);\n\
|
|
84
|
+
ivec3 tileCoordinateChange = tileCoordinate - u_cameraTileCoordinates.xyz;\n\
|
|
85
|
+
#endif\n\
|
|
86
|
+
vec3 tileUv = tileUvSum - vec3(tileCoordinateChange);\n\
|
|
87
|
+
tileUv.x = clamp(tileUv.x, 0.0, 1.0);\n\
|
|
88
|
+
#if (!defined(CYLINDER_HAS_SHAPE_BOUNDS_ANGLE))\n\
|
|
89
|
+
// If there is only one tile spanning 2*PI angle, the coordinate wraps around\n\
|
|
90
|
+
tileUv.y = (u_cameraTileCoordinates.w == 0) ? fract(tileUv.y) : clamp(tileUv.y, 0.0, 1.0);\n\
|
|
91
|
+
#else\n\
|
|
92
|
+
tileUv.y = clamp(tileUv.y, 0.0, 1.0);\n\
|
|
93
|
+
#endif\n\
|
|
94
|
+
tileUv.z = clamp(tileUv.z, 0.0, 1.0);\n\
|
|
95
|
+
return TileAndUvCoordinate(ivec4(tileCoordinate, u_cameraTileCoordinates.w), tileUv);\n\
|
|
96
|
+
}\n\
|
|
97
|
+
";
|
|
@@ -0,0 +1,185 @@
|
|
|
1
|
+
//This file is automatically rebuilt by the Cesium build process.
|
|
2
|
+
export default "/* Ellipsoid defines (set in Scene/VoxelEllipsoidShape.js)\n\
|
|
3
|
+
#define ELLIPSOID_HAS_SHAPE_BOUNDS_LONGITUDE\n\
|
|
4
|
+
#define ELLIPSOID_HAS_SHAPE_BOUNDS_LATITUDE\n\
|
|
5
|
+
*/\n\
|
|
6
|
+
\n\
|
|
7
|
+
uniform vec3 u_cameraPositionCartographic; // (longitude, latitude, height) in radians and meters\n\
|
|
8
|
+
uniform vec2 u_ellipsoidCurvatureAtLatitude;\n\
|
|
9
|
+
uniform mat3 u_ellipsoidEcToEastNorthUp;\n\
|
|
10
|
+
uniform vec3 u_ellipsoidRadii;\n\
|
|
11
|
+
uniform vec2 u_evoluteScale; // (radii.x ^ 2 - radii.z ^ 2) * vec2(1.0, -1.0) / radii;\n\
|
|
12
|
+
uniform vec3 u_ellipsoidInverseRadiiSquared;\n\
|
|
13
|
+
#if defined(ELLIPSOID_HAS_SHAPE_BOUNDS_LONGITUDE)\n\
|
|
14
|
+
uniform float u_ellipsoidShapeUvLongitudeRangeOrigin;\n\
|
|
15
|
+
#endif\n\
|
|
16
|
+
uniform vec3 u_ellipsoidLocalToShapeUvScale; // x = longitude scale, y = latitude scale, z = height scale\n\
|
|
17
|
+
\n\
|
|
18
|
+
uniform ivec4 u_cameraTileCoordinates;\n\
|
|
19
|
+
uniform vec3 u_cameraTileUv;\n\
|
|
20
|
+
\n\
|
|
21
|
+
// robust iterative solution without trig functions\n\
|
|
22
|
+
// https://github.com/0xfaded/ellipse_demo/issues/1\n\
|
|
23
|
+
// https://stackoverflow.com/questions/22959698/distance-from-given-point-to-given-ellipse\n\
|
|
24
|
+
// Extended to return radius of curvature along with the point\n\
|
|
25
|
+
vec3 nearestPointAndRadiusOnEllipse(vec2 pos, vec2 radii) {\n\
|
|
26
|
+
vec2 p = abs(pos);\n\
|
|
27
|
+
vec2 inverseRadii = 1.0 / radii;\n\
|
|
28
|
+
\n\
|
|
29
|
+
// We describe the ellipse parametrically: v = radii * vec2(cos(t), sin(t))\n\
|
|
30
|
+
// but store the cos and sin of t in a vec2 for efficiency.\n\
|
|
31
|
+
// Initial guess: t = pi/4\n\
|
|
32
|
+
vec2 tTrigs = vec2(0.7071067811865476);\n\
|
|
33
|
+
// Initial guess of point on ellipsoid\n\
|
|
34
|
+
vec2 v = radii * tTrigs;\n\
|
|
35
|
+
// Center of curvature of the ellipse at v\n\
|
|
36
|
+
vec2 evolute = u_evoluteScale * tTrigs * tTrigs * tTrigs;\n\
|
|
37
|
+
\n\
|
|
38
|
+
const int iterations = 3;\n\
|
|
39
|
+
for (int i = 0; i < iterations; ++i) {\n\
|
|
40
|
+
// Find the (approximate) intersection of p - evolute with the ellipsoid.\n\
|
|
41
|
+
vec2 q = normalize(p - evolute) * length(v - evolute);\n\
|
|
42
|
+
// Update the estimate of t.\n\
|
|
43
|
+
tTrigs = (q + evolute) * inverseRadii;\n\
|
|
44
|
+
tTrigs = normalize(clamp(tTrigs, 0.0, 1.0));\n\
|
|
45
|
+
v = radii * tTrigs;\n\
|
|
46
|
+
evolute = u_evoluteScale * tTrigs * tTrigs * tTrigs;\n\
|
|
47
|
+
}\n\
|
|
48
|
+
\n\
|
|
49
|
+
return vec3(v * sign(pos), length(v - evolute));\n\
|
|
50
|
+
}\n\
|
|
51
|
+
\n\
|
|
52
|
+
mat3 convertLocalToShapeSpaceDerivative(in vec3 position) {\n\
|
|
53
|
+
vec3 east = normalize(vec3(-position.y, position.x, 0.0));\n\
|
|
54
|
+
\n\
|
|
55
|
+
// Convert the 3D position to a 2D position relative to the ellipse (radii.x, radii.z)\n\
|
|
56
|
+
// (assume radii.y == radii.x) and find the nearest point on the ellipse and its normal\n\
|
|
57
|
+
float distanceFromZAxis = length(position.xy);\n\
|
|
58
|
+
vec2 posEllipse = vec2(distanceFromZAxis, position.z);\n\
|
|
59
|
+
vec3 surfacePointAndRadius = nearestPointAndRadiusOnEllipse(posEllipse, u_ellipsoidRadii.xz);\n\
|
|
60
|
+
vec2 surfacePoint = surfacePointAndRadius.xy;\n\
|
|
61
|
+
\n\
|
|
62
|
+
vec2 normal2d = normalize(surfacePoint * u_ellipsoidInverseRadiiSquared.xz);\n\
|
|
63
|
+
vec3 north = vec3(-normal2d.y * normalize(position.xy), abs(normal2d.x));\n\
|
|
64
|
+
\n\
|
|
65
|
+
float heightSign = length(posEllipse) < length(surfacePoint) ? -1.0 : 1.0;\n\
|
|
66
|
+
float height = heightSign * length(posEllipse - surfacePoint);\n\
|
|
67
|
+
vec3 up = normalize(cross(east, north));\n\
|
|
68
|
+
\n\
|
|
69
|
+
return mat3(east / distanceFromZAxis, north / (surfacePointAndRadius.z + height), up);\n\
|
|
70
|
+
}\n\
|
|
71
|
+
\n\
|
|
72
|
+
vec3 scaleShapeUvToShapeSpace(in vec3 shapeUv) {\n\
|
|
73
|
+
// Convert from [0, 1] to radians [-pi, pi]\n\
|
|
74
|
+
float longitude = shapeUv.x * czm_twoPi;\n\
|
|
75
|
+
#if defined (ELLIPSOID_HAS_SHAPE_BOUNDS_LONGITUDE)\n\
|
|
76
|
+
longitude /= u_ellipsoidLocalToShapeUvScale.x;\n\
|
|
77
|
+
#endif\n\
|
|
78
|
+
\n\
|
|
79
|
+
// Convert from [0, 1] to radians [-pi/2, pi/2]\n\
|
|
80
|
+
float latitude = shapeUv.y * czm_pi;\n\
|
|
81
|
+
#if defined(ELLIPSOID_HAS_SHAPE_BOUNDS_LATITUDE)\n\
|
|
82
|
+
latitude /= u_ellipsoidLocalToShapeUvScale.y;\n\
|
|
83
|
+
#endif\n\
|
|
84
|
+
\n\
|
|
85
|
+
float height = shapeUv.z / u_ellipsoidLocalToShapeUvScale.z;\n\
|
|
86
|
+
\n\
|
|
87
|
+
return vec3(longitude, latitude, height);\n\
|
|
88
|
+
}\n\
|
|
89
|
+
\n\
|
|
90
|
+
vec3 convertEcToDeltaShape(in vec3 positionEC) {\n\
|
|
91
|
+
vec3 enu = u_ellipsoidEcToEastNorthUp * positionEC;\n\
|
|
92
|
+
\n\
|
|
93
|
+
// 1. Compute the change in longitude from the camera to the ENU point\n\
|
|
94
|
+
// First project the camera and ENU positions to the equatorial XY plane,\n\
|
|
95
|
+
// positioning the camera on the +x axis, so that enu.x projects along the +y axis\n\
|
|
96
|
+
float cosLatitude = cos(u_cameraPositionCartographic.y);\n\
|
|
97
|
+
float sinLatitude = sin(u_cameraPositionCartographic.y);\n\
|
|
98
|
+
float primeVerticalRadius = 1.0 / u_ellipsoidCurvatureAtLatitude.x;\n\
|
|
99
|
+
vec2 cameraXY = vec2((primeVerticalRadius + u_cameraPositionCartographic.z) * cosLatitude, 0.0);\n\
|
|
100
|
+
// Note precision loss in positionXY.x if length(enu) << length(cameraXY)\n\
|
|
101
|
+
vec2 positionXY = cameraXY + vec2(-enu.y * sinLatitude + enu.z * cosLatitude, enu.x);\n\
|
|
102
|
+
float dLongitude = atan(positionXY.y, positionXY.x);\n\
|
|
103
|
+
\n\
|
|
104
|
+
// 2. Find the longitude component of positionXY, by rotating about Z until the y component is zero.\n\
|
|
105
|
+
// Use the versine to compute the change in x directly from the change in angle:\n\
|
|
106
|
+
// versine(angle) = 2 * sin^2(angle/2)\n\
|
|
107
|
+
float sinHalfLongitude = sin(dLongitude / 2.0);\n\
|
|
108
|
+
float dx = length(positionXY) * 2.0 * sinHalfLongitude * sinHalfLongitude;\n\
|
|
109
|
+
// Rotate longitude component back to ENU North and Up, and remove from enu\n\
|
|
110
|
+
enu += vec3(-enu.x, -dx * sinLatitude, dx * cosLatitude);\n\
|
|
111
|
+
\n\
|
|
112
|
+
// 3. Compute the change in latitude from the camera to the ENU point.\n\
|
|
113
|
+
// First project the camera and ENU positions to the meridional ZX plane,\n\
|
|
114
|
+
// positioning the camera on the +Z axis, so that enu.y maps to the +X axis.\n\
|
|
115
|
+
float meridionalRadius = 1.0 / u_ellipsoidCurvatureAtLatitude.y;\n\
|
|
116
|
+
vec2 cameraZX = vec2(meridionalRadius + u_cameraPositionCartographic.z, 0.0);\n\
|
|
117
|
+
vec2 positionZX = cameraZX + vec2(enu.z, enu.y);\n\
|
|
118
|
+
float dLatitude = atan(positionZX.y, positionZX.x);\n\
|
|
119
|
+
\n\
|
|
120
|
+
// 4. Compute the change in height above the ellipsoid\n\
|
|
121
|
+
// Find the change in enu.z associated with rotating the point to the latitude of the camera\n\
|
|
122
|
+
float sinHalfLatitude = sin(dLatitude / 2.0);\n\
|
|
123
|
+
float dz = length(positionZX) * 2.0 * sinHalfLatitude * sinHalfLatitude;\n\
|
|
124
|
+
// The remaining change in enu.z is the change in height above the ellipsoid\n\
|
|
125
|
+
float dHeight = enu.z + dz;\n\
|
|
126
|
+
\n\
|
|
127
|
+
return vec3(dLongitude, dLatitude, dHeight);\n\
|
|
128
|
+
}\n\
|
|
129
|
+
\n\
|
|
130
|
+
vec3 convertEcToDeltaTile(in vec3 positionEC) {\n\
|
|
131
|
+
vec3 deltaShape = convertEcToDeltaShape(positionEC);\n\
|
|
132
|
+
// Convert to tileset coordinates in [0, 1]\n\
|
|
133
|
+
float dx = deltaShape.x / czm_twoPi;\n\
|
|
134
|
+
\n\
|
|
135
|
+
#if (defined(ELLIPSOID_HAS_SHAPE_BOUNDS_LONGITUDE))\n\
|
|
136
|
+
// Wrap to ensure dx is not crossing through the unoccupied angle range, where\n\
|
|
137
|
+
// angle to tile coordinate conversions would be more complicated\n\
|
|
138
|
+
float cameraUvLongitude = (u_cameraPositionCartographic.x + czm_pi) / czm_twoPi;\n\
|
|
139
|
+
float cameraUvLongitudeShift = fract(cameraUvLongitude - u_ellipsoidShapeUvLongitudeRangeOrigin);\n\
|
|
140
|
+
float rawOutputUvLongitude = cameraUvLongitudeShift + dx;\n\
|
|
141
|
+
float rotation = floor(rawOutputUvLongitude);\n\
|
|
142
|
+
dx -= rotation;\n\
|
|
143
|
+
dx *= u_ellipsoidLocalToShapeUvScale.x;\n\
|
|
144
|
+
#endif\n\
|
|
145
|
+
\n\
|
|
146
|
+
float dy = deltaShape.y / czm_pi;\n\
|
|
147
|
+
#if (defined(ELLIPSOID_HAS_SHAPE_BOUNDS_LATITUDE))\n\
|
|
148
|
+
dy *= u_ellipsoidLocalToShapeUvScale.y;\n\
|
|
149
|
+
#endif\n\
|
|
150
|
+
\n\
|
|
151
|
+
float dz = u_ellipsoidLocalToShapeUvScale.z * deltaShape.z;\n\
|
|
152
|
+
// Convert to tile coordinate changes\n\
|
|
153
|
+
return vec3(dx, dy, dz) * float(1 << u_cameraTileCoordinates.w);\n\
|
|
154
|
+
}\n\
|
|
155
|
+
\n\
|
|
156
|
+
TileAndUvCoordinate getTileAndUvCoordinate(in vec3 positionEC) {\n\
|
|
157
|
+
vec3 deltaTileCoordinate = convertEcToDeltaTile(positionEC);\n\
|
|
158
|
+
vec3 tileUvSum = u_cameraTileUv + deltaTileCoordinate;\n\
|
|
159
|
+
ivec3 tileCoordinate = u_cameraTileCoordinates.xyz + ivec3(floor(tileUvSum));\n\
|
|
160
|
+
int maxTileCoordinate = (1 << u_cameraTileCoordinates.w) - 1;\n\
|
|
161
|
+
tileCoordinate.y = min(max(0, tileCoordinate.y), maxTileCoordinate);\n\
|
|
162
|
+
tileCoordinate.z = min(max(0, tileCoordinate.z), maxTileCoordinate);\n\
|
|
163
|
+
#if (!defined(ELLIPSOID_HAS_SHAPE_BOUNDS_LONGITUDE))\n\
|
|
164
|
+
ivec3 tileCoordinateChange = tileCoordinate - u_cameraTileCoordinates.xyz;\n\
|
|
165
|
+
if (tileCoordinate.x < 0) {\n\
|
|
166
|
+
tileCoordinate.x += (maxTileCoordinate + 1);\n\
|
|
167
|
+
} else if (tileCoordinate.x > maxTileCoordinate) {\n\
|
|
168
|
+
tileCoordinate.x -= (maxTileCoordinate + 1);\n\
|
|
169
|
+
}\n\
|
|
170
|
+
#else\n\
|
|
171
|
+
tileCoordinate.x = min(max(0, tileCoordinate.x), maxTileCoordinate);\n\
|
|
172
|
+
ivec3 tileCoordinateChange = tileCoordinate - u_cameraTileCoordinates.xyz;\n\
|
|
173
|
+
#endif\n\
|
|
174
|
+
vec3 tileUv = tileUvSum - vec3(tileCoordinateChange);\n\
|
|
175
|
+
#if (!defined(ELLIPSOID_HAS_SHAPE_BOUNDS_LONGITUDE))\n\
|
|
176
|
+
// If there is only one tile spanning 2*PI angle, the coordinate wraps around\n\
|
|
177
|
+
tileUv.x = (u_cameraTileCoordinates.w == 0) ? fract(tileUv.x) : clamp(tileUv.x, 0.0, 1.0);\n\
|
|
178
|
+
#else\n\
|
|
179
|
+
tileUv.x = clamp(tileUv.x, 0.0, 1.0);\n\
|
|
180
|
+
#endif\n\
|
|
181
|
+
tileUv.y = clamp(tileUv.y, 0.0, 1.0);\n\
|
|
182
|
+
tileUv.z = clamp(tileUv.z, 0.0, 1.0);\n\
|
|
183
|
+
return TileAndUvCoordinate(ivec4(tileCoordinate, u_cameraTileCoordinates.w), tileUv);\n\
|
|
184
|
+
}\n\
|
|
185
|
+
";
|