@@ -43,25 +43,17 @@ export function latToMercatorNorm(lat: number): number {
4343 ) ;
4444}
4545
46- /**
47- * Compute the reprojection props from latitude bounds and data orientation.
48- */
49- export function computeReproject4326Props (
50- latMin : number ,
51- latMax : number ,
52- latIsAscending : boolean ,
53- ) : Reproject4326Props {
54- // Compute Mercator Y bounds from latitude
55- // mercatorYBounds[0] = north (smaller Y value), mercatorYBounds[1] = south (larger Y value)
56- const mercYNorth = latToMercatorNorm ( latMax ) ;
57- const mercYSouth = latToMercatorNorm ( latMin ) ;
46+ /** Module name - must match uniform block name */
47+ const MODULE_NAME = "reproject4326" ;
5848
59- return {
60- latBounds : [ latMin , latMax ] ,
61- mercatorYBounds : [ mercYNorth , mercYSouth ] ,
62- latIsAscending,
63- } ;
64- }
49+ /** Uniform block for luma.gl v9 pattern */
50+ const uniformBlock = /* glsl */ `\
51+ uniform ${ MODULE_NAME } Uniforms {
52+ vec2 latBounds;
53+ vec2 mercatorYBounds;
54+ int latIsAscending;
55+ } ${ MODULE_NAME } ;
56+ ` ;
6557
6658/**
6759 * Reprojection shader module for EPSG:4326 source data.
@@ -73,16 +65,12 @@ export function computeReproject4326Props(
7365 * texture sampling module (e.g., CreateTexture).
7466 */
7567export const Reproject4326 = {
76- name : "reproject-4326" ,
68+ name : MODULE_NAME ,
69+ fs : uniformBlock ,
7770 inject : {
7871 "fs:#decl" : /* glsl */ `
7972 const float PI_REPROJECT_4326 = 3.14159265358979323846;
8073
81- // Uniforms for EPSG:4326 reprojection
82- uniform vec2 reproject4326_latBounds; // [latMin, latMax] in degrees
83- uniform vec2 reproject4326_mercatorYBounds; // [mercY_north, mercY_south] in [0,1]
84- uniform int reproject4326_latIsAscending; // 1 = row 0 is south, 0 = row 0 is north
85-
8674 // Invert Mercator Y to latitude in degrees
8775 float mercatorYToLat(float mercY) {
8876 // mercY is normalized [0,1] where 0=north, 1=south
@@ -97,15 +85,15 @@ export const Reproject4326 = {
9785 float lat = mercatorYToLat(mercY);
9886
9987 // Map latitude to texture V coordinate based on data orientation
100- float latRange = reproject4326_latBounds. y - reproject4326_latBounds .x;
88+ float latRange = reproject4326.latBounds. y - reproject4326.latBounds .x;
10189 float texV;
10290
103- if (reproject4326_latIsAscending == 1) {
91+ if (reproject4326.latIsAscending == 1) {
10492 // Row 0 = south (latMin), row N = north (latMax)
105- texV = (lat - reproject4326_latBounds .x) / latRange;
93+ texV = (lat - reproject4326.latBounds .x) / latRange;
10694 } else {
10795 // Row 0 = north (latMax), row N = south (latMin)
108- texV = (reproject4326_latBounds .y - lat) / latRange;
96+ texV = (reproject4326.latBounds .y - lat) / latRange;
10997 }
11098
11199 return texV;
@@ -114,36 +102,50 @@ export const Reproject4326 = {
114102 // Inject BEFORE DECKGL_FILTER_COLOR to modify geometry.uv before texture sampling
115103 // Using the fs:#main-start hook which runs at the beginning of main()
116104 "fs:#main-start" : /* glsl */ `
117- // Only apply reprojection if mercatorYBounds are set (non-zero range)
118- float mercRange = reproject4326_mercatorYBounds.y - reproject4326_mercatorYBounds.x;
119- if (abs(mercRange) > 0.0001) {
120- // Compute current Mercator Y from UV
121- // vTexCoord.y maps linearly across the mesh, which is positioned in Mercator space
122- // We need to interpolate between the north and south Mercator Y bounds
123- float currentMercY = mix(
124- reproject4326_mercatorYBounds.x,
125- reproject4326_mercatorYBounds.y,
105+ // Discard when bounds not set (prevents flash during loading)
106+ float latRange = reproject4326.latBounds.y - reproject4326.latBounds.x;
107+ if (abs(latRange) < 0.0001) {
108+ discard;
109+ }
110+
111+ // Compute current Mercator Y from UV
112+ // vTexCoord.y maps linearly across the mesh, which is positioned in Mercator space
113+ // We need to interpolate between the north and south Mercator Y bounds
114+ float currentMercY;
115+ if (reproject4326.latIsAscending == 1) {
116+ // UV.y: 0 at south, 1 at north
117+ currentMercY = mix(
118+ reproject4326.mercatorYBounds.y, // south (at y=0)
119+ reproject4326.mercatorYBounds.x, // north (at y=1)
126120 vTexCoord.y
127121 );
122+ } else {
123+ // UV.y: 0 at north, 1 at south
124+ currentMercY = mix(
125+ reproject4326.mercatorYBounds.x, // north (at y=0)
126+ reproject4326.mercatorYBounds.y, // south (at y=1)
127+ vTexCoord.y
128+ );
129+ }
128130
129- // Compute reprojected texture V
130- float reprojectTexV = computeReprojectTexV(currentMercY);
131+ // Compute reprojected texture V
132+ float reprojectTexV = computeReprojectTexV(currentMercY);
131133
132- // Store original UV for later restoration if needed
133- // Override geometry.uv with reprojected coordinates
134- geometry.uv = vec2(vTexCoord.x, reprojectTexV);
135- }
134+ // Override geometry.uv with reprojected coordinates
135+ geometry.uv = vec2(vTexCoord.x, reprojectTexV);
136136 ` ,
137137 } ,
138+ // Uniform types for luma.gl v9 (must match uniform block order)
139+ uniformTypes : {
140+ latBounds : "vec2<f32>" ,
141+ mercatorYBounds : "vec2<f32>" ,
142+ latIsAscending : "i32" ,
143+ } ,
138144 getUniforms : ( props : Partial < Reproject4326Props > = { } ) => {
139- const latBounds = props . latBounds ?? [ 0 , 0 ] ;
140- const mercatorYBounds = props . mercatorYBounds ?? [ 0 , 0 ] ;
141- const latIsAscending = props . latIsAscending ?? false ;
142-
143145 return {
144- reproject4326_latBounds : latBounds ,
145- reproject4326_mercatorYBounds : mercatorYBounds ,
146- reproject4326_latIsAscending : latIsAscending ? 1 : 0 ,
146+ latBounds : props . latBounds ?? [ 0 , 0 ] ,
147+ mercatorYBounds : props . mercatorYBounds ?? [ 0 , 0 ] ,
148+ latIsAscending : props . latIsAscending ? 1 : 0 ,
147149 } ;
148150 } ,
149151} as const ;
0 commit comments