react-native-cesium 1.2.7 → 1.2.9
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/android/CMakeLists.txt +24 -9
- package/android/src/main/cpp/CesiumBridgeAndroid.cpp +16 -3
- package/android/src/main/cpp/CesiumBridgeAndroid.h +2 -1
- package/android/src/main/cpp/vulkan/VulkanBackend.cpp +166 -67
- package/android/src/main/cpp/vulkan/VulkanBackend.h +60 -19
- package/android/src/main/cpp/vulkan/shaders/terrain.frag +36 -8
- package/android/src/main/java/com/margelo/nitro/reactnativecesium/CesiumBridgeJNI.kt +4 -3
- package/android/src/main/java/com/margelo/nitro/reactnativecesium/HybridCesiumView.kt +26 -7
- package/cpp/engine/CesiumEngine.cpp +487 -34
- package/cpp/engine/CesiumEngine.hpp +73 -4
- package/cpp/engine/GlobeCamera.cpp +0 -1
- package/cpp/renderer/RenderTypes.hpp +13 -0
- package/ios/CesiumBridge.h +14 -3
- package/ios/CesiumBridge.mm +72 -5
- package/ios/HybridCesiumView.swift +30 -13
- package/ios/metal/MetalBackend.h +22 -2
- package/ios/metal/MetalBackend.mm +248 -93
- package/lib/typescript/src/specs/cesium-view.nitro.d.ts +11 -3
- package/lib/typescript/src/specs/cesium-view.nitro.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/specs/cesium-view.nitro.ts +17 -3
|
@@ -62,7 +62,7 @@ struct OverlayParamsCPP {
|
|
|
62
62
|
float wmTransX; // offset 48
|
|
63
63
|
float wmTransY; // offset 52
|
|
64
64
|
float wmScale; // offset 56
|
|
65
|
-
float
|
|
65
|
+
float lodFade; // offset 60 — LOD dither threshold
|
|
66
66
|
// RTC centre in absolute ECEF (float3). Fragment shader reconstructs world
|
|
67
67
|
// position as: wp = in.localPos + rtcCentre (see shader).
|
|
68
68
|
float rtcCenterX; // offset 64
|
|
@@ -125,7 +125,7 @@ struct OverlayParams {
|
|
|
125
125
|
float wmWest, wmSouth, wmEast, wmNorth;
|
|
126
126
|
float wmTransX, wmTransY;
|
|
127
127
|
float wmScale;
|
|
128
|
-
float _pad1
|
|
128
|
+
float lodFade; // LOD dither threshold (was _pad1)
|
|
129
129
|
// RTC centre in ECEF (float). wp = in.localPos + rtcCentre gives a world
|
|
130
130
|
// position with ~0.75 m ULP (vs ~4 m for eyeRelPos + cameraEcef at altitude).
|
|
131
131
|
float rtcCenterX, rtcCenterY, rtcCenterZ;
|
|
@@ -157,6 +157,20 @@ fragment float4 terrainFragment(
|
|
|
157
157
|
texture2d<float> overlayTex [[texture(0)]],
|
|
158
158
|
texture2d<float> waterMaskTex [[texture(1)]])
|
|
159
159
|
{
|
|
160
|
+
#ifdef TERRAIN_DITHER
|
|
161
|
+
// ── LOD transition dither (IGN / Jorge Jimenez) ──────────────────────────
|
|
162
|
+
// Compiled only into the dither pipeline so the solid pipeline keeps Apple
|
|
163
|
+
// TBDR Hidden Surface Removal enabled at full speed. Interleaved Gradient
|
|
164
|
+
// Noise produces a fine-grained per-pixel threshold approximating blue noise
|
|
165
|
+
// without a texture lookup; the pattern is far less perceptible than Bayer.
|
|
166
|
+
// lodFade=1 → all pass; lodFade=0 → all discard.
|
|
167
|
+
{
|
|
168
|
+
float ign = fract(52.9829189f *
|
|
169
|
+
fract(0.06711056f * in.position.x + 0.00583715f * in.position.y));
|
|
170
|
+
if (ov.lodFade <= ign) { discard_fragment(); }
|
|
171
|
+
}
|
|
172
|
+
#endif
|
|
173
|
+
|
|
160
174
|
constexpr sampler s(filter::linear, address::clamp_to_edge);
|
|
161
175
|
|
|
162
176
|
// ── World position (RTC reconstruction) ──────────────────────────────────
|
|
@@ -190,14 +204,19 @@ fragment float4 terrainFragment(
|
|
|
190
204
|
? 1.0f
|
|
191
205
|
: waterMaskTex.sample(s, wmUV).r;
|
|
192
206
|
|
|
193
|
-
float3 lit;
|
|
194
|
-
|
|
195
207
|
if (ov.hasOverlay != 0u) {
|
|
196
208
|
float2 texUV = in.uv * float2(ov.scale[0], ov.scale[1])
|
|
197
209
|
+ float2(ov.translation[0], ov.translation[1]);
|
|
198
210
|
texUV.y = 1.0f - texUV.y;
|
|
199
|
-
|
|
200
|
-
|
|
211
|
+
// Return the overlay RGBA directly — preserves any transparency at tile
|
|
212
|
+
// edges and avoids incorrectly stamping the coastline outline on top of
|
|
213
|
+
// satellite imagery. The dither discard above fires before this return,
|
|
214
|
+
// so LOD fading still works correctly on overlay tiles.
|
|
215
|
+
return overlayTex.sample(s, texUV);
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
float3 lit;
|
|
219
|
+
{
|
|
201
220
|
// ── Lighting ──────────────────────────────────────────────────────────
|
|
202
221
|
// Normals from screen-space derivatives of tile-local position.
|
|
203
222
|
// (Using localPos rather than eyeRelPos makes no difference for the
|
|
@@ -237,21 +256,28 @@ fragment float4 terrainFragment(
|
|
|
237
256
|
|
|
238
257
|
// 1 km lat/lon grid — fades when sub-pixel to suppress Moiré.
|
|
239
258
|
float gridLat = 1000.f / 6371000.f;
|
|
240
|
-
|
|
259
|
+
// cosLat from pxy (already computed above for the Bowring iteration) —
|
|
260
|
+
// avoids a second cos() transcendental. pxy/a_e is the geocentric cosine;
|
|
261
|
+
// the ~0.2 % geodetic difference is imperceptible at grid-line scale.
|
|
262
|
+
float cosLat = max(pxy / 6378137.f, 0.001f);
|
|
241
263
|
float gridLon = gridLat / cosLat;
|
|
242
264
|
float wLat = fwidth(lat) * 1.5f, wLon = fwidth(lon) * 1.5f;
|
|
243
265
|
float gridVis = clamp(min(gridLat / max(wLat, 1e-9f),
|
|
244
266
|
gridLon / max(wLon, 1e-9f)), 0.f, 1.f);
|
|
267
|
+
// MSL fmod() uses truncation (not floor), which returns negative values for
|
|
268
|
+
// negative latitudes (southern hemisphere) — use the floor formula.
|
|
245
269
|
float latCell = lat - gridLat * floor(lat / gridLat);
|
|
246
270
|
float lonCell = lon - gridLon * floor(lon / gridLon);
|
|
247
271
|
float dLat = min(latCell, gridLat - latCell);
|
|
248
272
|
float dLon = min(lonCell, gridLon - lonCell);
|
|
249
|
-
|
|
250
|
-
|
|
273
|
+
// Linear ramp instead of smoothstep cubic — visually identical for a
|
|
274
|
+
// 1.5 px anti-aliased line, saves two multiplies per component.
|
|
275
|
+
float gridA = max(clamp(1.f - dLat / max(wLat, 1e-9f), 0.f, 1.f),
|
|
276
|
+
clamp(1.f - dLon / max(wLon, 1e-9f), 0.f, 1.f)) * gridVis;
|
|
251
277
|
lit = mix(lit, float3(0.15f, 0.15f, 0.15f), gridA * 0.6f);
|
|
252
278
|
}
|
|
253
279
|
|
|
254
|
-
// Coastline outline from water mask
|
|
280
|
+
// Coastline outline from water mask.
|
|
255
281
|
if (ov.isEllipsoidFallback == 0u) {
|
|
256
282
|
float dWater = fwidth(waterVal);
|
|
257
283
|
float coastPx = abs(waterVal - 0.5f) / max(dWater * 0.5f, 0.01f);
|
|
@@ -373,7 +399,8 @@ namespace reactnativecesium {
|
|
|
373
399
|
|
|
374
400
|
MetalBackend::MetalBackend()
|
|
375
401
|
: device_(nullptr), commandQueue_(nullptr), metalLayer_(nullptr),
|
|
376
|
-
|
|
402
|
+
terrainSolidPipeline_(nullptr), terrainDitherPipeline_(nullptr),
|
|
403
|
+
skyPipeline_(nullptr),
|
|
377
404
|
terrainDepthState_(nullptr), skyDepthState_(nullptr),
|
|
378
405
|
depthTexture_(nullptr), fallbackTexture_(nullptr),
|
|
379
406
|
fallbackWaterMaskTexture_(nullptr),
|
|
@@ -383,6 +410,8 @@ MetalBackend::MetalBackend()
|
|
|
383
410
|
for (int i = 0; i < kMaxFramesInFlight; ++i) {
|
|
384
411
|
vtxBufs_[i] = idxBufs_[i] = uvBufs_[i] = altBufs_[i] = nullptr;
|
|
385
412
|
vtxCaps_[i] = idxCaps_[i] = uvCaps_[i] = altCaps_[i] = 0;
|
|
413
|
+
uniformsBufs_[i] = nullptr;
|
|
414
|
+
uniformsCaps_[i] = 0;
|
|
386
415
|
}
|
|
387
416
|
}
|
|
388
417
|
|
|
@@ -418,40 +447,68 @@ void MetalBackend::buildRenderPipelines() {
|
|
|
418
447
|
CAMetalLayer* layer = (__bridge CAMetalLayer*)metalLayer_;
|
|
419
448
|
const MTLPixelFormat colorFmt = layer.pixelFormat;
|
|
420
449
|
|
|
421
|
-
if (
|
|
422
|
-
CFRelease(
|
|
423
|
-
|
|
450
|
+
if (terrainSolidPipeline_) {
|
|
451
|
+
CFRelease(terrainSolidPipeline_);
|
|
452
|
+
terrainSolidPipeline_ = nullptr;
|
|
453
|
+
}
|
|
454
|
+
if (terrainDitherPipeline_) {
|
|
455
|
+
CFRelease(terrainDitherPipeline_);
|
|
456
|
+
terrainDitherPipeline_ = nullptr;
|
|
424
457
|
}
|
|
425
458
|
if (skyPipeline_) {
|
|
426
459
|
CFRelease(skyPipeline_);
|
|
427
460
|
skyPipeline_ = nullptr;
|
|
428
461
|
}
|
|
429
462
|
|
|
430
|
-
//
|
|
431
|
-
//
|
|
432
|
-
//
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
463
|
+
// Build two terrain pipelines from a single MSL source:
|
|
464
|
+
// • Solid: compiled without TERRAIN_DITHER → no discard_fragment() in the
|
|
465
|
+
// shader, so Apple TBDR Hidden Surface Removal stays enabled.
|
|
466
|
+
// Used for every tile whose LOD-fade percentage is 1.0 (i.e. the
|
|
467
|
+
// overwhelming majority outside an active LOD transition).
|
|
468
|
+
// • Dither: compiled with TERRAIN_DITHER=1 → includes the IGN-based dither
|
|
469
|
+
// discard. Only used for tiles where DrawPrimitive::lodFade<1.
|
|
470
|
+
//
|
|
471
|
+
// Engineering trade-off documented in CesiumEngine::updateFrame: the draws
|
|
472
|
+
// are stable_partition-ed so all solid tiles come first; a single pipeline
|
|
473
|
+
// switch per frame is then enough to render the fading tail.
|
|
474
|
+
auto buildTerrainPipeline =
|
|
475
|
+
^id<MTLRenderPipelineState>(NSDictionary<NSString*, NSObject*>* macros,
|
|
476
|
+
NSString* label) {
|
|
477
|
+
MTLCompileOptions* opts = [MTLCompileOptions new];
|
|
478
|
+
if (macros) opts.preprocessorMacros = macros;
|
|
479
|
+
NSError* libErr = nil;
|
|
480
|
+
id<MTLLibrary> lib = [dev newLibraryWithSource:kTerrainShaderSrc
|
|
481
|
+
options:opts error:&libErr];
|
|
482
|
+
if (!lib) {
|
|
483
|
+
NSLog(@"[MetalBackend] terrain %@ shader compilation FAILED: %@",
|
|
484
|
+
label, libErr);
|
|
485
|
+
return nil;
|
|
486
|
+
}
|
|
487
|
+
MTLRenderPipelineDescriptor* desc = [MTLRenderPipelineDescriptor new];
|
|
488
|
+
desc.label = [@"terrain-" stringByAppendingString:label];
|
|
489
|
+
desc.vertexFunction = [lib newFunctionWithName:@"terrainVertex"];
|
|
490
|
+
desc.fragmentFunction = [lib newFunctionWithName:@"terrainFragment"];
|
|
491
|
+
desc.colorAttachments[0].pixelFormat = colorFmt;
|
|
492
|
+
desc.depthAttachmentPixelFormat = MTLPixelFormatDepth32Float;
|
|
493
|
+
desc.rasterSampleCount = (NSUInteger)std::max(1, sampleCount_);
|
|
494
|
+
NSError* pipeErr = nil;
|
|
495
|
+
id<MTLRenderPipelineState> pipe =
|
|
496
|
+
[dev newRenderPipelineStateWithDescriptor:desc error:&pipeErr];
|
|
497
|
+
if (!pipe) {
|
|
498
|
+
NSLog(@"[MetalBackend] terrain %@ pipeline build FAILED: %@",
|
|
499
|
+
label, pipeErr);
|
|
500
|
+
}
|
|
501
|
+
return pipe;
|
|
502
|
+
};
|
|
440
503
|
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
[dev newRenderPipelineStateWithDescriptor:tDesc error:&terrainPipelineErr];
|
|
450
|
-
if (!terrainPipeline) {
|
|
451
|
-
NSLog(@"[MetalBackend] terrain pipeline build FAILED: %@", terrainPipelineErr);
|
|
452
|
-
return;
|
|
453
|
-
}
|
|
454
|
-
terrainPipeline_ = (__bridge_retained void*)terrainPipeline;
|
|
504
|
+
id<MTLRenderPipelineState> solidPipeline = buildTerrainPipeline(nil, @"solid");
|
|
505
|
+
if (!solidPipeline) return;
|
|
506
|
+
terrainSolidPipeline_ = (__bridge_retained void*)solidPipeline;
|
|
507
|
+
|
|
508
|
+
id<MTLRenderPipelineState> ditherPipeline = buildTerrainPipeline(
|
|
509
|
+
@{ @"TERRAIN_DITHER": @"1" }, @"dither");
|
|
510
|
+
if (!ditherPipeline) return;
|
|
511
|
+
terrainDitherPipeline_ = (__bridge_retained void*)ditherPipeline;
|
|
455
512
|
|
|
456
513
|
NSError* skyLibErr = nil;
|
|
457
514
|
id<MTLLibrary> sLib = [dev newLibraryWithSource:kSkyShaderSrc
|
|
@@ -562,12 +619,15 @@ void MetalBackend::shutdown() {
|
|
|
562
619
|
if (idxBufs_[i]) { CFRelease(idxBufs_[i]); idxBufs_[i] = nullptr; }
|
|
563
620
|
if (uvBufs_[i]) { CFRelease(uvBufs_[i]); uvBufs_[i] = nullptr; }
|
|
564
621
|
if (altBufs_[i]) { CFRelease(altBufs_[i]); altBufs_[i] = nullptr; }
|
|
622
|
+
if (uniformsBufs_[i]) { CFRelease(uniformsBufs_[i]); uniformsBufs_[i] = nullptr; }
|
|
623
|
+
uniformsCaps_[i] = 0;
|
|
565
624
|
vtxCaps_[i] = idxCaps_[i] = uvCaps_[i] = altCaps_[i] = 0;
|
|
566
625
|
}
|
|
567
626
|
|
|
568
627
|
if (device_) { CFRelease(device_); device_ = nullptr; }
|
|
569
628
|
if (commandQueue_) { CFRelease(commandQueue_); commandQueue_ = nullptr; }
|
|
570
|
-
if (
|
|
629
|
+
if (terrainSolidPipeline_) { CFRelease(terrainSolidPipeline_); terrainSolidPipeline_ = nullptr; }
|
|
630
|
+
if (terrainDitherPipeline_) { CFRelease(terrainDitherPipeline_); terrainDitherPipeline_ = nullptr; }
|
|
571
631
|
if (skyPipeline_) { CFRelease(skyPipeline_); skyPipeline_ = nullptr; }
|
|
572
632
|
if (terrainDepthState_) { CFRelease(terrainDepthState_); terrainDepthState_ = nullptr; }
|
|
573
633
|
if (skyDepthState_) { CFRelease(skyDepthState_); skyDepthState_ = nullptr; }
|
|
@@ -763,38 +823,75 @@ void MetalBackend::drawScene(const FrameResult& frame) {
|
|
|
763
823
|
}
|
|
764
824
|
|
|
765
825
|
// ── Terrain pass ──────────────────────────────────────────────────────────
|
|
766
|
-
if (frame.draws.empty() ||
|
|
767
|
-
!
|
|
826
|
+
if (frame.draws.empty() ||
|
|
827
|
+
!terrainSolidPipeline_ || !terrainDitherPipeline_ || !terrainDepthState_) {
|
|
768
828
|
return;
|
|
769
829
|
}
|
|
770
830
|
|
|
771
831
|
const int fi = frameIndex_;
|
|
772
832
|
|
|
773
|
-
//
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
const
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
id<MTLBuffer>
|
|
786
|
-
|
|
833
|
+
// check the per-slot geometry signature. When it matches the engine
|
|
834
|
+
// has intentionally skipped repopulating the merged CPU arrays — the
|
|
835
|
+
// persistent vtx/idx/uv/alt buffers from a previous frame already hold the
|
|
836
|
+
// right bytes for this signature.
|
|
837
|
+
const uint64_t sig = frame.geometrySignature;
|
|
838
|
+
const bool slotMatches = (sig != 0ULL) && (sig == geomSlotSig_[fi]);
|
|
839
|
+
|
|
840
|
+
if (!slotMatches && (frame.localPositions.empty() || frame.indices.empty())) {
|
|
841
|
+
return;
|
|
842
|
+
}
|
|
843
|
+
|
|
844
|
+
id<MTLBuffer> vtxBuf = nil;
|
|
845
|
+
id<MTLBuffer> idxBuf = nil;
|
|
846
|
+
id<MTLBuffer> uvBuf = nil;
|
|
847
|
+
id<MTLBuffer> altBuf = nil;
|
|
848
|
+
|
|
849
|
+
if (slotMatches) {
|
|
850
|
+
vtxBuf = (__bridge id<MTLBuffer>)vtxBufs_[fi];
|
|
851
|
+
idxBuf = (__bridge id<MTLBuffer>)idxBufs_[fi];
|
|
852
|
+
uvBuf = (__bridge id<MTLBuffer>)uvBufs_[fi];
|
|
853
|
+
altBuf = (__bridge id<MTLBuffer>)altBufs_[fi];
|
|
854
|
+
} else {
|
|
855
|
+
const size_t vtxBytes = frame.localPositions.size() * sizeof(float);
|
|
856
|
+
const size_t idxBytes = frame.indices.size() * sizeof(uint32_t);
|
|
857
|
+
const size_t uvBytes = frame.uvs.size() * sizeof(float);
|
|
858
|
+
const size_t altBytes = frame.altitudes.size() * sizeof(float);
|
|
859
|
+
|
|
860
|
+
vtxBuf = ensureBuffer(&vtxBufs_[fi], &vtxCaps_[fi],
|
|
861
|
+
vtxBytes, frame.localPositions.data(), dev);
|
|
862
|
+
idxBuf = ensureBuffer(&idxBufs_[fi], &idxCaps_[fi],
|
|
863
|
+
idxBytes, frame.indices.data(), dev);
|
|
864
|
+
uvBuf = ensureBuffer(&uvBufs_[fi], &uvCaps_[fi],
|
|
865
|
+
uvBytes, frame.uvs.data(), dev);
|
|
866
|
+
altBuf = ensureBuffer(&altBufs_[fi], &altCaps_[fi],
|
|
867
|
+
altBytes, frame.altitudes.data(), dev);
|
|
868
|
+
|
|
869
|
+
// Record what this slot now holds — set only after all four buffers
|
|
870
|
+
// have been refreshed (avoids the partial-update bug we hit on the
|
|
871
|
+
// previous attempt where the signature was bumped after the first
|
|
872
|
+
// buffer copy and the rest were skipped).
|
|
873
|
+
geomSlotSig_[fi] = sig;
|
|
874
|
+
}
|
|
787
875
|
|
|
788
876
|
if (!vtxBuf || !idxBuf || !altBuf) return;
|
|
789
877
|
|
|
790
|
-
|
|
878
|
+
id<MTLRenderPipelineState> solidPS =
|
|
879
|
+
(__bridge id<MTLRenderPipelineState>)terrainSolidPipeline_;
|
|
880
|
+
id<MTLRenderPipelineState> ditherPS =
|
|
881
|
+
(__bridge id<MTLRenderPipelineState>)terrainDitherPipeline_;
|
|
882
|
+
// Start with the solid pipeline. CesiumEngine has stable_partition-ed draws so
|
|
883
|
+
// every lodFade==1 draw is first; we only switch to the dither pipeline once,
|
|
884
|
+
// when the first fading draw is reached.
|
|
885
|
+
id<MTLRenderPipelineState> currentPS = solidPS;
|
|
886
|
+
[enc setRenderPipelineState:currentPS];
|
|
791
887
|
[enc setDepthStencilState:(__bridge id<MTLDepthStencilState>)terrainDepthState_];
|
|
792
888
|
[enc setFrontFacingWinding:MTLWindingCounterClockwise];
|
|
793
889
|
[enc setCullMode:MTLCullModeBack];
|
|
794
890
|
|
|
795
891
|
// Set vertex buffers that are shared across all draws.
|
|
796
892
|
// buffer(0): tile-local positions, buffer(1): altitudes, buffer(3): UVs.
|
|
797
|
-
// buffer(2) is the per-draw
|
|
893
|
+
// buffer(2) is the per-draw VS uniforms (offset is updated per draw via the
|
|
894
|
+
// uniforms ring, fragment slot 0 likewise).
|
|
798
895
|
[enc setVertexBuffer:vtxBuf offset:0 atIndex:0];
|
|
799
896
|
[enc setVertexBuffer:altBuf offset:0 atIndex:1];
|
|
800
897
|
if (uvBuf) [enc setVertexBuffer:uvBuf offset:0 atIndex:3];
|
|
@@ -802,55 +899,113 @@ void MetalBackend::drawScene(const FrameResult& frame) {
|
|
|
802
899
|
id<MTLTexture> fallbackTex = (__bridge id<MTLTexture>)fallbackTexture_;
|
|
803
900
|
id<MTLTexture> fallbackWMTex = (__bridge id<MTLTexture>)fallbackWaterMaskTexture_;
|
|
804
901
|
|
|
902
|
+
// ── build the per-draw uniforms ring ───────────────────────────────
|
|
903
|
+
// Layout: [draw0 VS][draw0 FS][draw1 VS][draw1 FS]…, each padded to
|
|
904
|
+
// kUniformAlign (256 B). One contiguous MTLBuffer per frame slot. We
|
|
905
|
+
// memcpy all per-draw structs in one pass on the CPU, then in the draw
|
|
906
|
+
// loop only update setVertexBufferOffset / setFragmentBufferOffset.
|
|
907
|
+
const size_t pad = kUniformAlign;
|
|
908
|
+
const size_t vsStride = ((sizeof(PerDrawVertexUniformsCPP) + pad - 1) / pad) * pad;
|
|
909
|
+
const size_t fsStride = ((sizeof(OverlayParamsCPP) + pad - 1) / pad) * pad;
|
|
910
|
+
const size_t perDraw = vsStride + fsStride;
|
|
911
|
+
const size_t needed = perDraw * frame.draws.size();
|
|
912
|
+
|
|
913
|
+
id<MTLBuffer> uniBuf = nil;
|
|
914
|
+
if (needed > 0) {
|
|
915
|
+
if (needed > uniformsCaps_[fi]) {
|
|
916
|
+
size_t newCap = std::max(needed, uniformsCaps_[fi] > 0 ? uniformsCaps_[fi] * 2 : needed);
|
|
917
|
+
newCap = (newCap + 4095UL) & ~4095UL;
|
|
918
|
+
if (uniformsBufs_[fi]) CFRelease(uniformsBufs_[fi]);
|
|
919
|
+
id<MTLBuffer> b = [dev newBufferWithLength:newCap
|
|
920
|
+
options:MTLResourceStorageModeShared];
|
|
921
|
+
uniformsBufs_[fi] = (__bridge_retained void*)b;
|
|
922
|
+
uniformsCaps_[fi] = newCap;
|
|
923
|
+
}
|
|
924
|
+
uniBuf = (__bridge id<MTLBuffer>)uniformsBufs_[fi];
|
|
925
|
+
|
|
926
|
+
uint8_t* base = static_cast<uint8_t*>(uniBuf.contents);
|
|
927
|
+
size_t off = 0;
|
|
928
|
+
for (const auto& draw : frame.draws) {
|
|
929
|
+
auto* vdu = reinterpret_cast<PerDrawVertexUniformsCPP*>(base + off);
|
|
930
|
+
const float* mp = glm::value_ptr(draw.mvpMatrix);
|
|
931
|
+
for (int i = 0; i < 16; ++i) vdu->mvpMatrix[i] = mp[i];
|
|
932
|
+
|
|
933
|
+
auto* ov = reinterpret_cast<OverlayParamsCPP*>(base + off + vsStride);
|
|
934
|
+
*ov = OverlayParamsCPP{};
|
|
935
|
+
ov->hasOverlay = (draw.overlayTexture && draw.hasUVs) ? 1u : 0u;
|
|
936
|
+
ov->isEllipsoidFallback = draw.isEllipsoidFallback ? 1u : 0u;
|
|
937
|
+
ov->isOnlyWater = draw.isOnlyWater ? 1u : 0u;
|
|
938
|
+
ov->hasWaterMask = draw.waterMaskTexture ? 1u : 0u;
|
|
939
|
+
ov->translation[0] = draw.overlayTranslation.x;
|
|
940
|
+
ov->translation[1] = draw.overlayTranslation.y;
|
|
941
|
+
ov->scale[0] = draw.overlayScale.x;
|
|
942
|
+
ov->scale[1] = draw.overlayScale.y;
|
|
943
|
+
ov->wmWest = draw.wmTileBounds.x;
|
|
944
|
+
ov->wmSouth = draw.wmTileBounds.y;
|
|
945
|
+
ov->wmEast = draw.wmTileBounds.z;
|
|
946
|
+
ov->wmNorth = draw.wmTileBounds.w;
|
|
947
|
+
ov->wmTransX = draw.wmTranslation.x;
|
|
948
|
+
ov->wmTransY = draw.wmTranslation.y;
|
|
949
|
+
ov->wmScale = draw.wmScale;
|
|
950
|
+
ov->lodFade = draw.lodFade;
|
|
951
|
+
ov->rtcCenterX = draw.rtcCenterEcef.x;
|
|
952
|
+
ov->rtcCenterY = draw.rtcCenterEcef.y;
|
|
953
|
+
ov->rtcCenterZ = draw.rtcCenterEcef.z;
|
|
954
|
+
ov->cameraTilespaceX = frame.cameraEcef.x - draw.rtcCenterEcef.x;
|
|
955
|
+
ov->cameraTilespaceY = frame.cameraEcef.y - draw.rtcCenterEcef.y;
|
|
956
|
+
ov->cameraTilespaceZ = frame.cameraEcef.z - draw.rtcCenterEcef.z;
|
|
957
|
+
|
|
958
|
+
off += perDraw;
|
|
959
|
+
}
|
|
960
|
+
|
|
961
|
+
// Bind once; per-draw we only rebind the offset (cheap encoder call).
|
|
962
|
+
[enc setVertexBuffer:uniBuf offset:0 atIndex:2];
|
|
963
|
+
[enc setFragmentBuffer:uniBuf offset:0 atIndex:0];
|
|
964
|
+
}
|
|
965
|
+
|
|
805
966
|
if (fallbackWMTex) [enc setFragmentTexture:fallbackWMTex atIndex:1];
|
|
806
967
|
|
|
968
|
+
// track last-bound textures to dedupe redundant setFragmentTexture
|
|
969
|
+
// calls. The Vulkan path already dedupes its descriptor-set 1/2 binds via
|
|
970
|
+
// VkDescriptorSet identity; this matches that on Metal.
|
|
971
|
+
id<MTLTexture> lastTex0 = nil;
|
|
972
|
+
id<MTLTexture> lastTex1 = fallbackWMTex; // bound above
|
|
973
|
+
|
|
974
|
+
size_t drawOff = 0;
|
|
807
975
|
for (const auto& draw : frame.draws) {
|
|
976
|
+
const size_t thisOff = drawOff;
|
|
977
|
+
drawOff += perDraw;
|
|
978
|
+
|
|
808
979
|
if (draw.indexCount == 0) continue;
|
|
809
980
|
|
|
810
|
-
// ──
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
ov.translation[0] = draw.overlayTranslation.x;
|
|
823
|
-
ov.translation[1] = draw.overlayTranslation.y;
|
|
824
|
-
ov.scale[0] = draw.overlayScale.x;
|
|
825
|
-
ov.scale[1] = draw.overlayScale.y;
|
|
826
|
-
ov.wmWest = draw.wmTileBounds.x;
|
|
827
|
-
ov.wmSouth = draw.wmTileBounds.y;
|
|
828
|
-
ov.wmEast = draw.wmTileBounds.z;
|
|
829
|
-
ov.wmNorth = draw.wmTileBounds.w;
|
|
830
|
-
ov.wmTransX = draw.wmTranslation.x;
|
|
831
|
-
ov.wmTransY = draw.wmTranslation.y;
|
|
832
|
-
ov.wmScale = draw.wmScale;
|
|
833
|
-
// RTC: tile centre and camera-in-tile-space for fragment world-position
|
|
834
|
-
// reconstruction and view-direction lighting.
|
|
835
|
-
ov.rtcCenterX = draw.rtcCenterEcef.x;
|
|
836
|
-
ov.rtcCenterY = draw.rtcCenterEcef.y;
|
|
837
|
-
ov.rtcCenterZ = draw.rtcCenterEcef.z;
|
|
838
|
-
// cameraTilespace = cameraEcef − rtcCentre. Calculated here to keep the
|
|
839
|
-
// fragment shader free of subtraction of two large float3 values.
|
|
840
|
-
ov.cameraTilespaceX = frame.cameraEcef.x - draw.rtcCenterEcef.x;
|
|
841
|
-
ov.cameraTilespaceY = frame.cameraEcef.y - draw.rtcCenterEcef.y;
|
|
842
|
-
ov.cameraTilespaceZ = frame.cameraEcef.z - draw.rtcCenterEcef.z;
|
|
843
|
-
[enc setFragmentBytes:&ov length:sizeof(ov) atIndex:0];
|
|
981
|
+
// ── Pipeline switch for LOD-fade dither ─────────────────────────────────
|
|
982
|
+
// Solid pipeline (no discard) for fully-visible tiles preserves Apple TBDR
|
|
983
|
+
// Hidden Surface Removal; dither pipeline only used for actively-fading
|
|
984
|
+
// tiles. Draws are partitioned so this switch fires at most once per frame.
|
|
985
|
+
id<MTLRenderPipelineState> wantedPS = (draw.lodFade < 1.0f) ? ditherPS : solidPS;
|
|
986
|
+
if (wantedPS != currentPS) {
|
|
987
|
+
currentPS = wantedPS;
|
|
988
|
+
[enc setRenderPipelineState:currentPS];
|
|
989
|
+
}
|
|
990
|
+
|
|
991
|
+
[enc setVertexBufferOffset:thisOff atIndex:2];
|
|
992
|
+
[enc setFragmentBufferOffset:thisOff + vsStride atIndex:0];
|
|
844
993
|
|
|
845
994
|
id<MTLTexture> tex = (draw.overlayTexture && draw.hasUVs)
|
|
846
995
|
? (__bridge id<MTLTexture>)draw.overlayTexture
|
|
847
996
|
: fallbackTex;
|
|
848
|
-
if (tex
|
|
997
|
+
if (tex && tex != lastTex0) {
|
|
998
|
+
[enc setFragmentTexture:tex atIndex:0];
|
|
999
|
+
lastTex0 = tex;
|
|
1000
|
+
}
|
|
849
1001
|
|
|
850
1002
|
id<MTLTexture> wmTex = draw.waterMaskTexture
|
|
851
1003
|
? (__bridge id<MTLTexture>)draw.waterMaskTexture
|
|
852
1004
|
: fallbackWMTex;
|
|
853
|
-
if (wmTex
|
|
1005
|
+
if (wmTex && wmTex != lastTex1) {
|
|
1006
|
+
[enc setFragmentTexture:wmTex atIndex:1];
|
|
1007
|
+
lastTex1 = wmTex;
|
|
1008
|
+
}
|
|
854
1009
|
|
|
855
1010
|
[enc drawIndexedPrimitives:MTLPrimitiveTypeTriangle
|
|
856
1011
|
indexCount:draw.indexCount
|
|
@@ -57,7 +57,7 @@ export interface CesiumViewProps extends HybridViewProps {
|
|
|
57
57
|
preloadAncestors?: boolean;
|
|
58
58
|
/** Pre-load sibling tiles around the visible set. Default true. */
|
|
59
59
|
preloadSiblings?: boolean;
|
|
60
|
-
/** Refuse to render holes in the terrain. Default
|
|
60
|
+
/** Refuse to render holes in the terrain. Default false (matching Cesium Native). Relax for fast pans. */
|
|
61
61
|
forbidHoles?: boolean;
|
|
62
62
|
/** Decode water-mask textures (coastline shading). Default true. */
|
|
63
63
|
enableWaterMask?: boolean;
|
|
@@ -71,9 +71,17 @@ export interface CesiumViewProps extends HybridViewProps {
|
|
|
71
71
|
enableLodTransitionPeriod?: boolean;
|
|
72
72
|
/** Length (s) of the LOD cross-fade. Default 1. */
|
|
73
73
|
lodTransitionLength?: number;
|
|
74
|
-
/**
|
|
74
|
+
/**
|
|
75
|
+
* Sqlite asset cache row budget. Default 4096.
|
|
76
|
+
* Must be set on initial mount — changes after the first render are ignored
|
|
77
|
+
* because the cache is opened once at engine construction time.
|
|
78
|
+
*/
|
|
75
79
|
sqliteCacheMaxRows?: number;
|
|
76
|
-
/**
|
|
80
|
+
/**
|
|
81
|
+
* Worker thread count. 0 = auto (hardware_concurrency-1, clamped 2..16).
|
|
82
|
+
* Must be set on initial mount — the thread pool is sized once at engine
|
|
83
|
+
* construction time and cannot be resized at runtime.
|
|
84
|
+
*/
|
|
77
85
|
taskProcessorThreads?: number;
|
|
78
86
|
/**
|
|
79
87
|
* Minimum altitude above the loaded terrain surface, in metres MSL.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cesium-view.nitro.d.ts","sourceRoot":"","sources":["../../../../src/specs/cesium-view.nitro.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,UAAU,EACV,eAAe,EACf,iBAAiB,EAClB,MAAM,4BAA4B,CAAA;AAEnC;;;GAGG;AACH,MAAM,WAAW,WAAW;IAC1B,QAAQ,EAAE,MAAM,CAAA;IAChB,SAAS,EAAE,MAAM,CAAA;IACjB,QAAQ,EAAE,MAAM,CAAA;IAChB,OAAO,EAAE,MAAM,CAAA;IACf,KAAK,EAAE,MAAM,CAAA;IACb,IAAI,EAAE,MAAM,CAAA;IACZ,cAAc,EAAE,MAAM,CAAA;CACvB;AAED;;;;GAIG;AACH,MAAM,WAAW,UAAU;IACzB,CAAC,EAAE,MAAM,CAAA;IACT,CAAC,EAAE,MAAM,CAAA;IACT,CAAC,EAAE,MAAM,CAAA;IACT,CAAC,EAAE,MAAM,CAAA;CACV;AAED,iEAAiE;AACjE,MAAM,WAAW,aAAa;IAC5B,GAAG,EAAE,MAAM,CAAA;IACX,aAAa,EAAE,MAAM,CAAA;IACrB,YAAY,EAAE,MAAM,CAAA;IACpB,YAAY,EAAE,MAAM,CAAA;IACpB,kBAAkB,EAAE,OAAO,CAAA;IAC3B,+DAA+D;IAC/D,aAAa,EAAE,OAAO,CAAA;IACtB,YAAY,EAAE,OAAO,CAAA;IACrB,gBAAgB,EAAE,MAAM,CAAA;CACzB;AAED,MAAM,WAAW,eAAgB,SAAQ,eAAe;IACtD,cAAc,EAAE,MAAM,CAAA;IACtB,UAAU,EAAE,MAAM,CAAA;IAClB;;;;OAIG;IACH,aAAa,EAAE,WAAW,CAAA;IAC1B,cAAc,EAAE,OAAO,CAAA;IACvB,uBAAuB,EAAE,MAAM,CAAA;IAC/B,4BAA4B,EAAE,MAAM,CAAA;IACpC,sBAAsB,EAAE,MAAM,CAAA;IAC9B,6CAA6C;IAC7C,eAAe,EAAE,MAAM,CAAA;IACvB,iBAAiB,EAAE,MAAM,CAAA;
|
|
1
|
+
{"version":3,"file":"cesium-view.nitro.d.ts","sourceRoot":"","sources":["../../../../src/specs/cesium-view.nitro.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -61,13 +61,17 @@ export interface CesiumViewProps extends HybridViewProps {
|
|
|
61
61
|
ionImageryAssetId: number
|
|
62
62
|
|
|
63
63
|
// ── Optional perf / quality knobs ────────────────────────────────────────
|
|
64
|
+
// Note: all optional props below use "set once" semantics. Once a value has
|
|
65
|
+
// been applied to the native engine, removing the prop (returning it to
|
|
66
|
+
// `undefined`) does NOT revert the engine to its built-in default — the last
|
|
67
|
+
// explicitly set value is retained. To reset, pass the desired default value.
|
|
64
68
|
/** RAM budget for live tileset, in mebibytes. Default 256. */
|
|
65
69
|
maximumCachedMiB?: number
|
|
66
70
|
/** Pre-load ancestor tiles around the visible set (smoother panning, more loads). Default true. */
|
|
67
71
|
preloadAncestors?: boolean
|
|
68
72
|
/** Pre-load sibling tiles around the visible set. Default true. */
|
|
69
73
|
preloadSiblings?: boolean
|
|
70
|
-
/** Refuse to render holes in the terrain. Default
|
|
74
|
+
/** Refuse to render holes in the terrain. Default false (matching Cesium Native). Relax for fast pans. */
|
|
71
75
|
forbidHoles?: boolean
|
|
72
76
|
/** Decode water-mask textures (coastline shading). Default true. */
|
|
73
77
|
enableWaterMask?: boolean
|
|
@@ -81,9 +85,17 @@ export interface CesiumViewProps extends HybridViewProps {
|
|
|
81
85
|
enableLodTransitionPeriod?: boolean
|
|
82
86
|
/** Length (s) of the LOD cross-fade. Default 1. */
|
|
83
87
|
lodTransitionLength?: number
|
|
84
|
-
/**
|
|
88
|
+
/**
|
|
89
|
+
* Sqlite asset cache row budget. Default 4096.
|
|
90
|
+
* Must be set on initial mount — changes after the first render are ignored
|
|
91
|
+
* because the cache is opened once at engine construction time.
|
|
92
|
+
*/
|
|
85
93
|
sqliteCacheMaxRows?: number
|
|
86
|
-
/**
|
|
94
|
+
/**
|
|
95
|
+
* Worker thread count. 0 = auto (hardware_concurrency-1, clamped 2..16).
|
|
96
|
+
* Must be set on initial mount — the thread pool is sized once at engine
|
|
97
|
+
* construction time and cannot be resized at runtime.
|
|
98
|
+
*/
|
|
87
99
|
taskProcessorThreads?: number
|
|
88
100
|
/**
|
|
89
101
|
* Minimum altitude above the loaded terrain surface, in metres MSL.
|
|
@@ -98,6 +110,8 @@ export interface CesiumViewProps extends HybridViewProps {
|
|
|
98
110
|
// angular / linear speed on the integrator's per-DoF velocity. Useful when
|
|
99
111
|
// your sensor feed is noisy and you would rather drop the change than
|
|
100
112
|
// visually whip the camera.
|
|
113
|
+
// Note: same "set once" semantics as the knobs above — removing the prop
|
|
114
|
+
// keeps the last value rather than reverting to 0 (uncapped).
|
|
101
115
|
/** Maximum yaw rate (degrees per second). 0 = uncapped. */
|
|
102
116
|
maxYawRateDegSec?: number
|
|
103
117
|
/** Maximum pitch rate (degrees per second). 0 = uncapped. */
|