Skip to content

Commit 06e62a1

Browse files
authored
Merge pull request #556 from EarthyScience/jp/country-borders-sdf
Land Masking
2 parents d031592 + f301a15 commit 06e62a1

23 files changed

Lines changed: 516 additions & 112 deletions

public/border_distance_sdf.png

2.88 MB
Loading

public/land_mask_sdf.png

2.06 MB
Loading

src/GlobalStates/PlotStore.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,10 @@ type PlotState ={
5858
coarsen: boolean, //Seperate from zarr store so dependencies don't update when changing coarsen in a menu
5959
kernel:{kernelSize:number, kernelDepth:number}
6060
is360Deg:boolean,
61+
maskTexture: THREE.Texture | undefined;
62+
borderTexture: THREE.Texture | undefined;
63+
useBorderTexture: boolean;
64+
maskValue: number;
6165

6266
setQuality: (quality: number) => void;
6367
setTimeScale: (timeScale : number) =>void;
@@ -171,6 +175,11 @@ export const usePlotStore = create<PlotState>((set, get) => ({
171175
coarsen: false,
172176
kernel:{kernelDepth:1, kernelSize:1},
173177
is360Deg:false,
178+
maskTexture:undefined,
179+
borderTexture: undefined,
180+
useBorderTexture: false,
181+
maskValue: 0,
182+
borderWidth: 0.05,
174183

175184
setVTransferRange: (vTransferRange) => set({ vTransferRange }),
176185
setVTransferScale: (vTransferScale) => set({ vTransferScale }),

src/components/plots/DataCube.tsx

Lines changed: 20 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@ import { vertexShader, fragmentShader, fragOpt, orthoVertex } from '@/components
44
import { useGlobalStore, usePlotStore } from '@/GlobalStates';
55
import { useShallow } from 'zustand/shallow';
66
import { invalidate, useFrame } from '@react-three/fiber';
7+
import { deg2rad } from '@/utils/HelperFuncs';
8+
import { useCoordBounds } from '@/hooks/useCoordBounds';
79

810
interface DataCubeProps {
911
volTexture: THREE.Data3DTexture[] | THREE.DataTexture[] | null,
@@ -18,19 +20,16 @@ export const DataCube = ({ volTexture }: DataCubeProps ) => {
1820
}))) //We have to useShallow when returning an object instead of a state. I don't fully know the logic yet
1921
const {
2022
valueRange, xRange, yRange, zRange, quality, useOrtho,
21-
animProg, cScale, cOffset, useFragOpt, transparency,
23+
animProg, cScale, cOffset, useFragOpt, transparency, maskTexture, maskValue,
2224
nanTransparency, nanColor, vTransferRange, vTransferScale, fillValue} = usePlotStore(useShallow(state => ({
23-
valueRange: state.valueRange,
24-
xRange: state.xRange,
25-
yRange: state.yRange,
26-
zRange: state.zRange,
27-
quality: state.quality,
28-
useOrtho: state.useOrtho,
29-
animProg: state.animProg,
30-
cScale: state.cScale,
31-
cOffset: state.cOffset,
32-
useFragOpt: state.useFragOpt,
25+
valueRange: state.valueRange, xRange: state.xRange,
26+
yRange: state.yRange, zRange: state.zRange,
27+
quality: state.quality, useOrtho: state.useOrtho,
28+
animProg: state.animProg, cScale: state.cScale,
29+
cOffset: state.cOffset, useFragOpt: state.useFragOpt,
3330
transparency: state.transparency,
31+
maskTexture: state.maskTexture,
32+
maskValue: state.maskValue,
3433
nanTransparency: state.nanTransparency,
3534
nanColor: state.nanColor,
3635
vTransferRange: state.vTransferRange,
@@ -40,11 +39,15 @@ export const DataCube = ({ volTexture }: DataCubeProps ) => {
4039
const meshRef = useRef<THREE.Mesh>(null!);
4140
const aspectRatio = shape.y/shape.x
4241
const timeRatio = shape.z/shape.x;
42+
const {lonBounds, latBounds} = useCoordBounds()
43+
4344
const shaderMaterial = useMemo(()=>new THREE.ShaderMaterial({
4445
glslVersion: THREE.GLSL3,
4546
uniforms: {
4647
modelViewMatrixInverse: { value: new THREE.Matrix4() }, // Used for Orthographic RayMarcher
4748
map: { value: volTexture },
49+
maskTexture: { value: maskTexture },
50+
maskValue: {value: maskValue },
4851
textureDepths: {value: new THREE.Vector3(textureArrayDepths[2], textureArrayDepths[1], textureArrayDepths[0])},
4952
cmap:{value: colormap},
5053
cOffset:{value: cOffset},
@@ -53,6 +56,8 @@ export const DataCube = ({ volTexture }: DataCubeProps ) => {
5356
scale: {value: shape},
5457
flatBounds:{value: new THREE.Vector4(-xRange[1],-xRange[0],zRange[0] * timeRatio, zRange[1] * timeRatio)},
5558
vertBounds:{value: new THREE.Vector2(yRange[0]*aspectRatio,yRange[1]*aspectRatio)},
59+
latBounds: {value: new THREE.Vector2(deg2rad(latBounds[0]), deg2rad(latBounds[1]))},
60+
lonBounds: {value: new THREE.Vector2(deg2rad(lonBounds[0]), deg2rad(lonBounds[1]))},
5661
steps: { value: quality },
5762
animateProg: {value: animProg},
5863
transparency: {value: transparency},
@@ -82,6 +87,8 @@ export const DataCube = ({ volTexture }: DataCubeProps ) => {
8287
uniforms.scale.value = shape;
8388
uniforms.flatBounds.value.set(-xRange[1], -xRange[0], zRange[0] * timeRatio, zRange[1] * timeRatio);
8489
uniforms.vertBounds.value.set(yRange[0] * aspectRatio, yRange[1] * aspectRatio);
90+
uniforms.latBounds.value = new THREE.Vector2(deg2rad(latBounds[0]), deg2rad(latBounds[1]))
91+
uniforms.lonBounds.value = new THREE.Vector2(deg2rad(lonBounds[0]), deg2rad(lonBounds[1]))
8592
uniforms.steps.value = quality;
8693
uniforms.animateProg.value = animProg;
8794
uniforms.transparency.value = transparency;
@@ -90,9 +97,10 @@ export const DataCube = ({ volTexture }: DataCubeProps ) => {
9097
uniforms.opacityMag.value = vTransferScale;
9198
uniforms.useClipScale.value = vTransferRange;
9299
uniforms.fillValue.value = fillValue;
100+
uniforms.maskValue.value = maskValue
93101
invalidate() // Needed because Won't trigger re-render if camera is stationary.
94102
}
95-
}, [volTexture, shape, colormap, cOffset, cScale, valueRange, xRange, yRange, zRange, aspectRatio, quality, animProg, transparency, nanTransparency, nanColor, fillValue, vTransferScale, vTransferRange]);
103+
}, [volTexture, shape, colormap, cOffset, cScale, valueRange, xRange, yRange, zRange, aspectRatio, latBounds, lonBounds, quality, animProg, transparency, nanTransparency, nanColor, maskValue, fillValue, vTransferScale, vTransferRange]);
96104
useFrame(({camera})=>{ // This calculates InverseModel matrix for the orthographic raymarcher
97105
if (!useOrtho || !meshRef.current || !shaderMaterial) return;
98106
meshRef.current.modelViewMatrix.multiplyMatrices(camera.matrixWorldInverse, meshRef.current.matrixWorld);

src/components/plots/FlatBlocks.tsx

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,9 @@ import { useShallow } from 'zustand/shallow'
44
import * as THREE from 'three'
55
import { sphereBlocksFrag, flatBlocksVert, flatBlocksVert3D } from '../textures/shaders'
66
import { invalidate } from '@react-three/fiber'
7+
import { deg2rad } from '@/utils/HelperFuncs'
8+
import { useCoordBounds } from '@/hooks/useCoordBounds'
9+
710
const FlatBlocks = ({textures} : {textures: THREE.Data3DTexture[] | THREE.DataTexture[] | null}) => {
811
const {colormap, isFlat, valueScales, flipY,
912
dataShape, textureArrayDepths} = useGlobalStore(useShallow(state=>({
@@ -14,11 +17,13 @@ const FlatBlocks = ({textures} : {textures: THREE.Data3DTexture[] | THREE.DataTe
1417
dataShape: state.dataShape,
1518
textureArrayDepths: state.textureArrayDepths
1619
})))
17-
const { animProg, cOffset, cScale, nanColor, nanTransparency, displacement, offsetNegatives, rotateFlat} = usePlotStore(useShallow(state=> ({
20+
const { animProg, cOffset, cScale, nanColor, nanTransparency, displacement, offsetNegatives, rotateFlat, maskTexture, maskValue,
21+
} = usePlotStore(useShallow(state=> ({
1822
animate: state.animate, animProg: state.animProg, cOffset: state.cOffset,
1923
cScale: state.cScale, nanColor: state.nanColor, nanTransparency: state.nanTransparency,
2024
displacement: state.displacement, sphereResolution: state.sphereResolution,
21-
offsetNegatives: state.offsetNegatives, rotateFlat:state.rotateFlat
25+
offsetNegatives: state.offsetNegatives, rotateFlat:state.rotateFlat,
26+
maskTexture:state.maskTexture, maskValue:state.maskValue,
2227
})))
2328
const {analysisMode, axis} = useAnalysisStore(useShallow(state => ({
2429
analysisMode: state.analysisMode, axis:state.axis
@@ -67,12 +72,17 @@ const FlatBlocks = ({textures} : {textures: THREE.Data3DTexture[] | THREE.DataTe
6772
);
6873
return geo
6974
},[width, height])
75+
const {lonBounds, latBounds} = useCoordBounds()
7076

7177
const shaderMaterial = useMemo(()=>{
7278
const shader = new THREE.ShaderMaterial({
7379
glslVersion: THREE.GLSL3,
7480
uniforms: {
7581
map: { value: textures },
82+
maskTexture: {value: maskTexture},
83+
maskValue: {value: maskValue},
84+
latBounds: {value: new THREE.Vector2(deg2rad(latBounds[0]), deg2rad(latBounds[1]))},
85+
lonBounds: {value: new THREE.Vector2(deg2rad(lonBounds[0]), deg2rad(lonBounds[1]))},
7686
aspect: {value: width/height},
7787
textureDepths: {value: new THREE.Vector3(textureArrayDepths[2], textureArrayDepths[1], textureArrayDepths[0])},
7888
cmap:{value: colormap},
@@ -103,11 +113,14 @@ const FlatBlocks = ({textures} : {textures: THREE.Data3DTexture[] | THREE.DataTe
103113
uniforms.cmap.value = colormap
104114
uniforms.cOffset.value = cOffset
105115
uniforms.cScale.value = cScale
116+
uniforms.latBounds.value = new THREE.Vector2(deg2rad(latBounds[0]), deg2rad(latBounds[1]))
117+
uniforms.lonBounds.value = new THREE.Vector2(deg2rad(lonBounds[0]), deg2rad(lonBounds[1]))
106118
uniforms.displaceZero.value = offsetNegatives ? 0 : (-valueScales.minVal/(valueScales.maxVal-valueScales.minVal))
107119
uniforms.aspect.value = width/height;
120+
uniforms.maskValue.value = maskValue
108121
}
109122
invalidate();
110-
},[animProg, valueScales, displacement, colormap, cScale, cOffset, offsetNegatives, textures, analysisMode, axis, width, height])
123+
},[animProg, valueScales, displacement, colormap, cScale, cOffset, offsetNegatives, textures, analysisMode, axis, width, height, latBounds, lonBounds, maskValue])
111124

112125
return (
113126

src/components/plots/FlatMap.tsx

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,9 @@ import { vertShader } from '@/components/computation/shaders'
77
import { flatFrag3D, fragmentFlat } from '../textures/shaders';
88
import { useShallow } from 'zustand/shallow'
99
import { ThreeEvent } from '@react-three/fiber';
10-
import { coarsenFlatArray, GetCurrentArray, GetTimeSeries, parseUVCoords } from '@/utils/HelperFuncs';
10+
import { coarsenFlatArray, GetCurrentArray, GetTimeSeries, parseUVCoords, deg2rad } from '@/utils/HelperFuncs';
1111
import { evaluate_cmap } from 'js-colormaps-es';
12+
import { useCoordBounds } from '@/hooks/useCoordBounds';
1213

1314
interface InfoSettersProps{
1415
setLoc: React.Dispatch<React.SetStateAction<number[]>>;
@@ -39,14 +40,15 @@ const FlatMap = ({textures, infoSetters} : {textures : THREE.DataTexture | THREE
3940
})))
4041

4142
const {cScale, cOffset, animProg, nanTransparency, nanColor,
42-
zSlice, ySlice, xSlice, selectTS, coarsen,
43+
zSlice, ySlice, xSlice, selectTS, coarsen, maskTexture, maskValue,
4344
getColorIdx, incrementColorIdx} = usePlotStore(useShallow(state => ({
4445
cOffset: state.cOffset, cScale: state.cScale,
4546
resetAnim: state.resetAnim, animate: state.animate,
4647
animProg: state.animProg, nanTransparency: state.nanTransparency,
4748
nanColor: state.nanColor, zSlice: state.zSlice,
4849
ySlice: state.ySlice, xSlice: state.xSlice,
4950
selectTS: state.selectTS, coarsen: state.coarsen,
51+
maskTexture:state.maskTexture, maskValue:state.maskValue,
5052
getColorIdx: state.getColorIdx,
5153
incrementColorIdx: state.incrementColorIdx
5254
})))
@@ -94,6 +96,8 @@ const FlatMap = ({textures, infoSetters} : {textures : THREE.DataTexture | THREE
9496
const sampleArray = useMemo(()=> analysisMode ? analysisArray : GetCurrentArray(),[analysisMode, analysisArray, textures])
9597
const analysisDims = useMemo(()=>dimArrays.length > 2 ? dimSlices.filter((_e,idx)=> idx != axis) : dimSlices,[dimSlices,axis])
9698

99+
const {lonBounds, latBounds} = useCoordBounds()
100+
97101
useEffect(()=>{
98102
geometry.dispose()
99103
},[geometry])
@@ -196,6 +200,10 @@ const FlatMap = ({textures, infoSetters} : {textures : THREE.DataTexture | THREE
196200
selectTS: {value: selectTS},
197201
selectBounds: {value: bounds},
198202
map : {value: textures},
203+
maskTexture: {value: maskTexture},
204+
maskValue: {value: maskValue},
205+
latBounds: {value: new THREE.Vector2(deg2rad(latBounds[0]), deg2rad(latBounds[1]))},
206+
lonBounds: {value: new THREE.Vector2(deg2rad(lonBounds[0]), deg2rad(lonBounds[1]))},
199207
textureDepths: {value: new THREE.Vector3(textureArrayDepths[2], textureArrayDepths[1], textureArrayDepths[0])},
200208
cmap : { value : colormap},
201209
animateProg: {value:animProg},
@@ -217,10 +225,13 @@ const FlatMap = ({textures, infoSetters} : {textures : THREE.DataTexture | THREE
217225
uniforms.nanColor.value = new THREE.Color(nanColor);
218226
uniforms.nanAlpha.value = 1 - nanTransparency;
219227
uniforms.cScale.value = cScale;
228+
uniforms.latBounds.value = new THREE.Vector2(deg2rad(latBounds[0]), deg2rad(latBounds[1]))
229+
uniforms.lonBounds.value = new THREE.Vector2(deg2rad(lonBounds[0]), deg2rad(lonBounds[1]))
220230
uniforms.selectBounds.value = bounds;
221-
uniforms.selectTS.value = selectTS
231+
uniforms.selectTS.value = selectTS;
232+
uniforms.maskValue.value = maskValue
222233
}
223-
},[cScale, cOffset, textures, colormap, animProg, nanColor, nanTransparency, bounds, selectTS])
234+
},[cScale, cOffset, textures, colormap, animProg, nanColor, nanTransparency, bounds, selectTS, latBounds, lonBounds, maskValue])
224235

225236
return (
226237
<>

src/components/plots/Plot.tsx

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
1-
import { OrbitControls } from '@react-three/drei';
1+
import { OrbitControls, useTexture } from '@react-three/drei';
22
import React, { useMemo, useRef, useState, useEffect } from 'react';
33
import * as THREE from 'three';
44
import { PointCloud, UVCube, DataCube, FlatMap, Sphere, CountryBorders, AxisLines, SphereBlocks, FlatBlocks, KeyFramePreviewer } from '@/components/plots';
5-
import { Canvas, invalidate, useThree } from '@react-three/fiber';
5+
import { Canvas, invalidate, useThree, useLoader } from '@react-three/fiber';
66
import { CreateTexture } from '@/components/textures';
77
import { useAnalysisStore, useGlobalStore, useImageExportStore, usePlotStore } from '@/GlobalStates';
88
import { useShallow } from 'zustand/shallow';
@@ -174,6 +174,16 @@ const Plot = () => {
174174
useEffect(()=>{ // Rotates flat back when changing away
175175
usePlotStore.setState({rotateFlat: false})
176176
},[plotType])
177+
178+
useEffect(()=>{
179+
const loader = new THREE.TextureLoader()
180+
async function SetTextures(){
181+
const maskTexture = await loader.loadAsync('/land_mask_sdf.png')
182+
const borderTexture = await loader.loadAsync('/border_distance_sdf.png')
183+
usePlotStore.setState({borderTexture, maskTexture})
184+
}
185+
SetTextures()
186+
},[])
177187

178188
const Nav = useMemo(()=>Navbar,[])
179189
return (

src/components/plots/PointCloud.tsx

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
1-
21
import * as THREE from 'three'
32
import { useEffect, useMemo, useState, useRef } from 'react'
43
import { pointFrag, pointVert } from '@/components/textures/shaders'
54
import { useAnalysisStore, useGlobalStore, usePlotStore } from '@/GlobalStates';
65
import { useShallow } from 'zustand/shallow';
7-
import { parseUVCoords, getUnitAxis, GetTimeSeries, GetCurrentArray } from '@/utils/HelperFuncs';
6+
import { parseUVCoords, getUnitAxis, GetTimeSeries, GetCurrentArray, deg2rad } from '@/utils/HelperFuncs';
87
import { evaluate_cmap } from 'js-colormaps-es';
8+
import { useCoordBounds } from '@/hooks/useCoordBounds';
99

1010
interface PCProps {
1111
texture: THREE.Data3DTexture[] | null,
@@ -146,7 +146,9 @@ export const PointCloud = ({textures} : {textures:PCProps} )=>{
146146
dataShape: state.dataShape,
147147
textureData: state.textureData
148148
})))
149-
const {scalePoints, scaleIntensity, pointSize, cScale, cOffset, valueRange, animProg, selectTS, timeScale, xRange, yRange, zRange, fillValue} = usePlotStore(useShallow(state => ({
149+
const {scalePoints, scaleIntensity, pointSize, cScale, cOffset, valueRange, animProg,
150+
selectTS, timeScale, xRange, yRange, zRange, fillValue,
151+
maskTexture, maskValue } = usePlotStore(useShallow(state => ({
150152
scalePoints: state.scalePoints,
151153
scaleIntensity: state.scaleIntensity,
152154
pointSize: state.pointSize,
@@ -159,7 +161,9 @@ export const PointCloud = ({textures} : {textures:PCProps} )=>{
159161
xRange: state.xRange,
160162
yRange: state.yRange,
161163
zRange: state.zRange,
162-
fillValue:state.fillValue
164+
fillValue:state.fillValue,
165+
maskTexture: state.maskTexture,
166+
maskValue: state.maskValue,
163167
})))
164168

165169
const [pointsObj, setPointsObj] = useState<Record<string, number>>({})
@@ -199,10 +203,15 @@ export const PointCloud = ({textures} : {textures:PCProps} )=>{
199203
geom.setDrawRange(0, arrayLength); // This is used to tell it how many data points are needed since we aren't giving it positions.
200204
return geom;
201205
}, [data]);
206+
const {lonBounds, latBounds} = useCoordBounds()
202207

203208
const shaderMaterial = useMemo(()=> (new THREE.ShaderMaterial({
204209
glslVersion: THREE.GLSL3,
205210
uniforms: {
211+
maskTexture: {value: maskTexture},
212+
maskValue: {value: maskValue},
213+
latBounds: {value: new THREE.Vector2(deg2rad(latBounds[0]), deg2rad(latBounds[1]))},
214+
lonBounds: {value: new THREE.Vector2(deg2rad(lonBounds[0]), deg2rad(lonBounds[1]))},
206215
pointSize: {value: pointSize},
207216
cmap: {value: colormap},
208217
cOffset: {value: cOffset},
@@ -243,6 +252,8 @@ export const PointCloud = ({textures} : {textures:PCProps} )=>{
243252
uniforms.scaleIntensity.value = scaleIntensity;
244253
uniforms.startIDs.value = pointIDs;
245254
uniforms.stride.value = stride;
255+
uniforms.latBounds.value = new THREE.Vector2(deg2rad(latBounds[0]), deg2rad(latBounds[1]))
256+
uniforms.lonBounds.value = new THREE.Vector2(deg2rad(lonBounds[0]), deg2rad(lonBounds[1]))
246257
uniforms.showTransect.value = selectTS;
247258
uniforms.dimWidth.value = dimWidth;
248259
uniforms.timeScale.value = timeScale;
@@ -255,8 +266,9 @@ export const PointCloud = ({textures} : {textures:PCProps} )=>{
255266
yRange[0], yRange[1]
256267
);
257268
uniforms.fillValue.value = fillValue
269+
uniforms.maskValue.value = maskValue
258270
}
259-
}, [pointSize, colormap, cOffset, cScale, valueRange, scalePoints, scaleIntensity, pointIDs, stride, selectTS, animProg, timeScale, xRange, yRange, fillValue, zRange]);
271+
}, [pointSize, colormap, cOffset, cScale, valueRange, scalePoints, scaleIntensity, pointIDs, stride, selectTS, animProg, timeScale, xRange, yRange, fillValue, zRange, maskValue, lonBounds, latBounds]);
260272

261273
return (
262274
<>

0 commit comments

Comments
 (0)