@takram/three-clouds 0.1.0
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/CHANGELOG.md +5 -0
- package/README.md +1130 -0
- package/assets/local_weather.png +0 -0
- package/assets/shape.bin +1 -0
- package/assets/shape_detail.bin +1 -0
- package/assets/turbulence.png +0 -0
- package/build/index.cjs +583 -0
- package/build/index.cjs.map +1 -0
- package/build/index.js +728 -0
- package/build/index.js.map +1 -0
- package/build/r3f.cjs +2 -0
- package/build/r3f.cjs.map +1 -0
- package/build/r3f.js +205 -0
- package/build/r3f.js.map +1 -0
- package/build/shared.cjs +2189 -0
- package/build/shared.cjs.map +1 -0
- package/build/shared.js +3825 -0
- package/build/shared.js.map +1 -0
- package/package.json +77 -0
- package/src/CascadedShadowMaps.ts +288 -0
- package/src/CloudLayer.ts +85 -0
- package/src/CloudLayers.test.ts +61 -0
- package/src/CloudLayers.ts +181 -0
- package/src/CloudShape.ts +22 -0
- package/src/CloudShapeDetail.ts +22 -0
- package/src/CloudsEffect.ts +810 -0
- package/src/CloudsMaterial.ts +467 -0
- package/src/CloudsPass.ts +285 -0
- package/src/CloudsResolveMaterial.ts +108 -0
- package/src/DensityProfile.ts +38 -0
- package/src/LocalWeather.ts +21 -0
- package/src/PassBase.ts +28 -0
- package/src/Procedural3DTexture.ts +94 -0
- package/src/ProceduralTexture.ts +94 -0
- package/src/ShaderArrayPass.ts +32 -0
- package/src/ShadowMaterial.ts +141 -0
- package/src/ShadowPass.ts +185 -0
- package/src/ShadowResolveMaterial.ts +72 -0
- package/src/Turbulence.ts +21 -0
- package/src/bayer.ts +23 -0
- package/src/constants.ts +8 -0
- package/src/helpers/FrustumCorners.ts +138 -0
- package/src/helpers/setArrayRenderTargetLayers.ts +32 -0
- package/src/helpers/splitFrustum.ts +59 -0
- package/src/index.ts +14 -0
- package/src/qualityPresets.ts +117 -0
- package/src/r3f/CloudLayer.tsx +95 -0
- package/src/r3f/CloudLayers.tsx +54 -0
- package/src/r3f/Clouds.tsx +278 -0
- package/src/r3f/index.ts +2 -0
- package/src/shaders/catmullRomSampling.glsl +113 -0
- package/src/shaders/cloudShape.frag +78 -0
- package/src/shaders/cloudShapeDetail.frag +56 -0
- package/src/shaders/clouds.frag +996 -0
- package/src/shaders/clouds.glsl +190 -0
- package/src/shaders/clouds.vert +69 -0
- package/src/shaders/cloudsEffect.frag +11 -0
- package/src/shaders/cloudsResolve.frag +202 -0
- package/src/shaders/cloudsResolve.vert +10 -0
- package/src/shaders/localWeather.frag +83 -0
- package/src/shaders/parameters.glsl +64 -0
- package/src/shaders/perlin.glsl +211 -0
- package/src/shaders/shadow.frag +197 -0
- package/src/shaders/shadow.vert +16 -0
- package/src/shaders/shadowResolve.frag +76 -0
- package/src/shaders/shadowResolve.vert +10 -0
- package/src/shaders/structuredSampling.glsl +101 -0
- package/src/shaders/tileableNoise.glsl +88 -0
- package/src/shaders/turbulence.frag +51 -0
- package/src/shaders/types.glsl +18 -0
- package/src/shaders/varianceClipping.glsl +114 -0
- package/src/uniforms.ts +218 -0
- package/types/CascadedShadowMaps.d.ts +52 -0
- package/types/CloudLayer.d.ts +26 -0
- package/types/CloudLayers.d.ts +21 -0
- package/types/CloudShape.d.ts +5 -0
- package/types/CloudShapeDetail.d.ts +5 -0
- package/types/CloudsEffect.d.ts +170 -0
- package/types/CloudsMaterial.d.ts +86 -0
- package/types/CloudsPass.d.ts +44 -0
- package/types/CloudsResolveMaterial.d.ts +30 -0
- package/types/DensityProfile.d.ts +12 -0
- package/types/LocalWeather.d.ts +5 -0
- package/types/PassBase.d.ts +14 -0
- package/types/Procedural3DTexture.d.ts +20 -0
- package/types/ProceduralTexture.d.ts +24 -0
- package/types/ShaderArrayPass.d.ts +7 -0
- package/types/ShadowMaterial.d.ts +34 -0
- package/types/ShadowPass.d.ts +34 -0
- package/types/ShadowResolveMaterial.d.ts +20 -0
- package/types/Turbulence.d.ts +5 -0
- package/types/bayer.d.ts +4 -0
- package/types/constants.d.ts +6 -0
- package/types/helpers/FrustumCorners.d.ts +18 -0
- package/types/helpers/setArrayRenderTargetLayers.d.ts +3 -0
- package/types/helpers/splitFrustum.d.ts +9 -0
- package/types/index.d.ts +13 -0
- package/types/qualityPresets.d.ts +46 -0
- package/types/r3f/CloudLayer.d.ts +7 -0
- package/types/r3f/CloudLayers.d.ts +15 -0
- package/types/r3f/Clouds.d.ts +16 -0
- package/types/r3f/index.d.ts +2 -0
- package/types/uniforms.d.ts +66 -0
@@ -0,0 +1,285 @@
|
|
1
|
+
import { ShaderPass } from 'postprocessing'
|
2
|
+
import {
|
3
|
+
HalfFloatType,
|
4
|
+
LinearFilter,
|
5
|
+
RedFormat,
|
6
|
+
WebGLRenderTarget,
|
7
|
+
type Camera,
|
8
|
+
type DataArrayTexture,
|
9
|
+
type DepthPackingStrategies,
|
10
|
+
type Texture,
|
11
|
+
type TextureDataType,
|
12
|
+
type WebGLRenderer
|
13
|
+
} from 'three'
|
14
|
+
|
15
|
+
import { type AtmosphereParameters } from '@takram/three-atmosphere'
|
16
|
+
|
17
|
+
import { CloudsMaterial } from './CloudsMaterial'
|
18
|
+
import { CloudsResolveMaterial } from './CloudsResolveMaterial'
|
19
|
+
import { PassBase, type PassBaseOptions } from './PassBase'
|
20
|
+
import { defaults } from './qualityPresets'
|
21
|
+
import {
|
22
|
+
type AtmosphereUniforms,
|
23
|
+
type CloudLayerUniforms,
|
24
|
+
type CloudParameterUniforms
|
25
|
+
} from './uniforms'
|
26
|
+
|
27
|
+
type RenderTarget = WebGLRenderTarget & {
|
28
|
+
depthVelocity: Texture | null
|
29
|
+
shadowLength: Texture | null
|
30
|
+
}
|
31
|
+
|
32
|
+
interface RenderTargetOptions {
|
33
|
+
depthVelocity: boolean
|
34
|
+
shadowLength: boolean
|
35
|
+
}
|
36
|
+
|
37
|
+
function createRenderTarget(
|
38
|
+
name: string,
|
39
|
+
{ depthVelocity, shadowLength }: RenderTargetOptions
|
40
|
+
): RenderTarget {
|
41
|
+
const renderTarget: WebGLRenderTarget & {
|
42
|
+
depthVelocity?: Texture
|
43
|
+
shadowLength?: Texture
|
44
|
+
} = new WebGLRenderTarget(1, 1, {
|
45
|
+
depthBuffer: false,
|
46
|
+
stencilBuffer: false,
|
47
|
+
type: HalfFloatType
|
48
|
+
})
|
49
|
+
renderTarget.texture.minFilter = LinearFilter
|
50
|
+
renderTarget.texture.magFilter = LinearFilter
|
51
|
+
renderTarget.texture.name = name
|
52
|
+
|
53
|
+
let depthVelocityBuffer
|
54
|
+
if (depthVelocity) {
|
55
|
+
depthVelocityBuffer = renderTarget.texture.clone()
|
56
|
+
depthVelocityBuffer.isRenderTargetTexture = true
|
57
|
+
renderTarget.depthVelocity = depthVelocityBuffer
|
58
|
+
renderTarget.textures.push(depthVelocityBuffer)
|
59
|
+
}
|
60
|
+
let shadowLengthBuffer
|
61
|
+
if (shadowLength) {
|
62
|
+
shadowLengthBuffer = renderTarget.texture.clone()
|
63
|
+
shadowLengthBuffer.isRenderTargetTexture = true
|
64
|
+
shadowLengthBuffer.format = RedFormat
|
65
|
+
renderTarget.shadowLength = shadowLengthBuffer
|
66
|
+
renderTarget.textures.push(shadowLengthBuffer)
|
67
|
+
}
|
68
|
+
|
69
|
+
return Object.assign(renderTarget, {
|
70
|
+
depthVelocity: depthVelocityBuffer ?? null,
|
71
|
+
shadowLength: shadowLengthBuffer ?? null
|
72
|
+
})
|
73
|
+
}
|
74
|
+
|
75
|
+
export interface CloudsPassOptions extends PassBaseOptions {
|
76
|
+
parameterUniforms: CloudParameterUniforms
|
77
|
+
layerUniforms: CloudLayerUniforms
|
78
|
+
atmosphereUniforms: AtmosphereUniforms
|
79
|
+
}
|
80
|
+
|
81
|
+
export class CloudsPass extends PassBase {
|
82
|
+
private currentRenderTarget!: RenderTarget
|
83
|
+
readonly currentMaterial: CloudsMaterial
|
84
|
+
readonly currentPass: ShaderPass
|
85
|
+
private resolveRenderTarget!: RenderTarget
|
86
|
+
readonly resolveMaterial: CloudsResolveMaterial
|
87
|
+
readonly resolvePass: ShaderPass
|
88
|
+
private historyRenderTarget!: RenderTarget
|
89
|
+
|
90
|
+
private width = 0
|
91
|
+
private height = 0
|
92
|
+
|
93
|
+
constructor(
|
94
|
+
{
|
95
|
+
parameterUniforms,
|
96
|
+
layerUniforms,
|
97
|
+
atmosphereUniforms,
|
98
|
+
...options
|
99
|
+
}: CloudsPassOptions,
|
100
|
+
private readonly atmosphere: AtmosphereParameters
|
101
|
+
) {
|
102
|
+
super('CloudsPass', options)
|
103
|
+
|
104
|
+
this.currentMaterial = new CloudsMaterial(
|
105
|
+
{
|
106
|
+
parameterUniforms,
|
107
|
+
layerUniforms,
|
108
|
+
atmosphereUniforms
|
109
|
+
},
|
110
|
+
atmosphere
|
111
|
+
)
|
112
|
+
this.currentPass = new ShaderPass(this.currentMaterial)
|
113
|
+
this.resolveMaterial = new CloudsResolveMaterial()
|
114
|
+
this.resolvePass = new ShaderPass(this.resolveMaterial)
|
115
|
+
|
116
|
+
this.initRenderTargets({
|
117
|
+
depthVelocity: true,
|
118
|
+
shadowLength: defaults.lightShafts
|
119
|
+
})
|
120
|
+
}
|
121
|
+
|
122
|
+
copyCameraSettings(camera: Camera): void {
|
123
|
+
this.currentMaterial.copyCameraSettings(camera)
|
124
|
+
}
|
125
|
+
|
126
|
+
override initialize(
|
127
|
+
renderer: WebGLRenderer,
|
128
|
+
alpha: boolean,
|
129
|
+
frameBufferType: TextureDataType
|
130
|
+
): void {
|
131
|
+
this.currentPass.initialize(renderer, alpha, frameBufferType)
|
132
|
+
this.resolvePass.initialize(renderer, alpha, frameBufferType)
|
133
|
+
}
|
134
|
+
|
135
|
+
private initRenderTargets(options: RenderTargetOptions): void {
|
136
|
+
this.currentRenderTarget?.dispose()
|
137
|
+
this.resolveRenderTarget?.dispose()
|
138
|
+
this.historyRenderTarget?.dispose()
|
139
|
+
const current = createRenderTarget('Clouds', options)
|
140
|
+
const resolve = createRenderTarget('Clouds.A', {
|
141
|
+
...options,
|
142
|
+
depthVelocity: false
|
143
|
+
})
|
144
|
+
const history = createRenderTarget('Clouds.B', {
|
145
|
+
...options,
|
146
|
+
depthVelocity: false
|
147
|
+
})
|
148
|
+
this.currentRenderTarget = current
|
149
|
+
this.resolveRenderTarget = resolve
|
150
|
+
this.historyRenderTarget = history
|
151
|
+
|
152
|
+
const resolveUniforms = this.resolveMaterial.uniforms
|
153
|
+
resolveUniforms.colorBuffer.value = current.texture
|
154
|
+
resolveUniforms.depthVelocityBuffer.value = current.depthVelocity
|
155
|
+
resolveUniforms.shadowLengthBuffer.value = current.shadowLength
|
156
|
+
resolveUniforms.colorHistoryBuffer.value = history.texture
|
157
|
+
resolveUniforms.shadowLengthHistoryBuffer.value = history.shadowLength
|
158
|
+
}
|
159
|
+
|
160
|
+
private copyShadow(): void {
|
161
|
+
const shadow = this.shadow
|
162
|
+
const currentUniforms = this.currentMaterial.uniforms
|
163
|
+
for (let i = 0; i < shadow.cascadeCount; ++i) {
|
164
|
+
const cascade = shadow.cascades[i]
|
165
|
+
currentUniforms.shadowIntervals.value[i].copy(cascade.interval)
|
166
|
+
currentUniforms.shadowMatrices.value[i].copy(cascade.matrix)
|
167
|
+
}
|
168
|
+
currentUniforms.shadowFar.value = shadow.far
|
169
|
+
}
|
170
|
+
|
171
|
+
private copyReprojection(): void {
|
172
|
+
this.currentMaterial.copyReprojectionMatrix(this.mainCamera)
|
173
|
+
}
|
174
|
+
|
175
|
+
private swapBuffers(): void {
|
176
|
+
const nextResolve = this.historyRenderTarget
|
177
|
+
const nextHistory = this.resolveRenderTarget
|
178
|
+
this.resolveRenderTarget = nextResolve
|
179
|
+
this.historyRenderTarget = nextHistory
|
180
|
+
|
181
|
+
const resolveUniforms = this.resolveMaterial.uniforms
|
182
|
+
resolveUniforms.colorHistoryBuffer.value = nextHistory.texture
|
183
|
+
resolveUniforms.shadowLengthHistoryBuffer.value = nextHistory.shadowLength
|
184
|
+
}
|
185
|
+
|
186
|
+
update(renderer: WebGLRenderer, frame: number, deltaTime: number): void {
|
187
|
+
// Update frame uniforms before copyCameraSettings.
|
188
|
+
this.currentMaterial.uniforms.frame.value = frame
|
189
|
+
this.resolveMaterial.uniforms.frame.value = frame
|
190
|
+
|
191
|
+
this.copyCameraSettings(this.mainCamera)
|
192
|
+
this.copyShadow()
|
193
|
+
|
194
|
+
this.currentPass.render(renderer, null, this.currentRenderTarget)
|
195
|
+
this.resolvePass.render(renderer, null, this.resolveRenderTarget)
|
196
|
+
|
197
|
+
// Store the current view and projection matrices for the next reprojection.
|
198
|
+
this.copyReprojection()
|
199
|
+
|
200
|
+
// Swap resolve and history render targets for the next render.
|
201
|
+
this.swapBuffers()
|
202
|
+
}
|
203
|
+
|
204
|
+
override setSize(width: number, height: number): void {
|
205
|
+
this.width = width
|
206
|
+
this.height = height
|
207
|
+
|
208
|
+
if (this.temporalUpscale) {
|
209
|
+
const lowResWidth = Math.ceil(width / 4)
|
210
|
+
const lowResHeight = Math.ceil(height / 4)
|
211
|
+
this.currentRenderTarget.setSize(lowResWidth, lowResHeight)
|
212
|
+
this.currentMaterial.setSize(
|
213
|
+
lowResWidth * 4,
|
214
|
+
lowResHeight * 4,
|
215
|
+
width,
|
216
|
+
height
|
217
|
+
)
|
218
|
+
} else {
|
219
|
+
this.currentRenderTarget.setSize(width, height)
|
220
|
+
this.currentMaterial.setSize(width, height)
|
221
|
+
}
|
222
|
+
this.resolveRenderTarget.setSize(width, height)
|
223
|
+
this.resolveMaterial.setSize(width, height)
|
224
|
+
this.historyRenderTarget.setSize(width, height)
|
225
|
+
}
|
226
|
+
|
227
|
+
setShadowSize(width: number, height: number, depth: number): void {
|
228
|
+
this.currentMaterial.shadowCascadeCount = depth
|
229
|
+
this.currentMaterial.setShadowSize(width, height)
|
230
|
+
}
|
231
|
+
|
232
|
+
override setDepthTexture(
|
233
|
+
depthTexture: Texture,
|
234
|
+
depthPacking?: DepthPackingStrategies
|
235
|
+
): void {
|
236
|
+
this.currentMaterial.depthBuffer = depthTexture
|
237
|
+
this.currentMaterial.depthPacking = depthPacking ?? 0
|
238
|
+
}
|
239
|
+
|
240
|
+
get outputBuffer(): Texture {
|
241
|
+
// Resolve and history render targets are already swapped.
|
242
|
+
return this.historyRenderTarget.texture
|
243
|
+
}
|
244
|
+
|
245
|
+
get shadowBuffer(): DataArrayTexture | null {
|
246
|
+
return this.currentMaterial.uniforms.shadowBuffer.value
|
247
|
+
}
|
248
|
+
|
249
|
+
set shadowBuffer(value: DataArrayTexture | null) {
|
250
|
+
this.currentMaterial.uniforms.shadowBuffer.value = value
|
251
|
+
}
|
252
|
+
|
253
|
+
get shadowLengthBuffer(): Texture | null {
|
254
|
+
// Resolve and history render targets are already swapped.
|
255
|
+
return this.historyRenderTarget.shadowLength
|
256
|
+
}
|
257
|
+
|
258
|
+
get temporalUpscale(): boolean {
|
259
|
+
return this.currentMaterial.temporalUpscale
|
260
|
+
}
|
261
|
+
|
262
|
+
set temporalUpscale(value: boolean) {
|
263
|
+
if (value !== this.temporalUpscale) {
|
264
|
+
this.currentMaterial.temporalUpscale = value
|
265
|
+
this.resolveMaterial.temporalUpscale = value
|
266
|
+
this.setSize(this.width, this.height)
|
267
|
+
}
|
268
|
+
}
|
269
|
+
|
270
|
+
get lightShafts(): boolean {
|
271
|
+
return this.currentMaterial.shadowLength
|
272
|
+
}
|
273
|
+
|
274
|
+
set lightShafts(value: boolean) {
|
275
|
+
if (value !== this.lightShafts) {
|
276
|
+
this.currentMaterial.shadowLength = value
|
277
|
+
this.resolveMaterial.shadowLength = value
|
278
|
+
this.initRenderTargets({
|
279
|
+
depthVelocity: true,
|
280
|
+
shadowLength: value
|
281
|
+
})
|
282
|
+
this.setSize(this.width, this.height)
|
283
|
+
}
|
284
|
+
}
|
285
|
+
}
|
@@ -0,0 +1,108 @@
|
|
1
|
+
import {
|
2
|
+
GLSL3,
|
3
|
+
RawShaderMaterial,
|
4
|
+
Uniform,
|
5
|
+
Vector2,
|
6
|
+
type BufferGeometry,
|
7
|
+
type Camera,
|
8
|
+
type Group,
|
9
|
+
type Object3D,
|
10
|
+
type Scene,
|
11
|
+
type Texture,
|
12
|
+
type WebGLRenderer
|
13
|
+
} from 'three'
|
14
|
+
|
15
|
+
import { define, resolveIncludes, unrollLoops } from '@takram/three-geospatial'
|
16
|
+
import { turbo } from '@takram/three-geospatial/shaders'
|
17
|
+
|
18
|
+
import { bayerOffsets } from './bayer'
|
19
|
+
|
20
|
+
import catmullRomSampling from './shaders/catmullRomSampling.glsl?raw'
|
21
|
+
import fragmentShader from './shaders/cloudsResolve.frag?raw'
|
22
|
+
import vertexShader from './shaders/cloudsResolve.vert?raw'
|
23
|
+
import varianceClipping from './shaders/varianceClipping.glsl?raw'
|
24
|
+
|
25
|
+
export interface CloudsResolveMaterialParameters {
|
26
|
+
colorBuffer?: Texture | null
|
27
|
+
depthVelocityBuffer?: Texture | null
|
28
|
+
shadowLengthBuffer?: Texture | null
|
29
|
+
colorHistoryBuffer?: Texture | null
|
30
|
+
shadowLengthHistoryBuffer?: Texture | null
|
31
|
+
}
|
32
|
+
|
33
|
+
export interface CloudsResolveMaterialUniforms {
|
34
|
+
[key: string]: Uniform<unknown>
|
35
|
+
colorBuffer: Uniform<Texture | null>
|
36
|
+
depthVelocityBuffer: Uniform<Texture | null>
|
37
|
+
shadowLengthBuffer: Uniform<Texture | null>
|
38
|
+
colorHistoryBuffer: Uniform<Texture | null>
|
39
|
+
shadowLengthHistoryBuffer: Uniform<Texture | null>
|
40
|
+
texelSize: Uniform<Vector2>
|
41
|
+
frame: Uniform<number>
|
42
|
+
jitterOffset: Uniform<Vector2>
|
43
|
+
varianceGamma: Uniform<number>
|
44
|
+
temporalAlpha: Uniform<number>
|
45
|
+
}
|
46
|
+
|
47
|
+
export class CloudsResolveMaterial extends RawShaderMaterial {
|
48
|
+
declare uniforms: CloudsResolveMaterialUniforms
|
49
|
+
|
50
|
+
constructor({
|
51
|
+
colorBuffer = null,
|
52
|
+
depthVelocityBuffer = null,
|
53
|
+
shadowLengthBuffer = null,
|
54
|
+
colorHistoryBuffer = null,
|
55
|
+
shadowLengthHistoryBuffer = null
|
56
|
+
}: CloudsResolveMaterialParameters = {}) {
|
57
|
+
super({
|
58
|
+
name: 'CloudsResolveMaterial',
|
59
|
+
glslVersion: GLSL3,
|
60
|
+
vertexShader,
|
61
|
+
fragmentShader: unrollLoops(
|
62
|
+
resolveIncludes(fragmentShader, {
|
63
|
+
core: { turbo },
|
64
|
+
catmullRomSampling,
|
65
|
+
varianceClipping
|
66
|
+
})
|
67
|
+
),
|
68
|
+
uniforms: {
|
69
|
+
colorBuffer: new Uniform(colorBuffer),
|
70
|
+
depthVelocityBuffer: new Uniform(depthVelocityBuffer),
|
71
|
+
shadowLengthBuffer: new Uniform(shadowLengthBuffer),
|
72
|
+
colorHistoryBuffer: new Uniform(colorHistoryBuffer),
|
73
|
+
shadowLengthHistoryBuffer: new Uniform(shadowLengthHistoryBuffer),
|
74
|
+
texelSize: new Uniform(new Vector2()),
|
75
|
+
frame: new Uniform(0),
|
76
|
+
jitterOffset: new Uniform(new Vector2()),
|
77
|
+
varianceGamma: new Uniform(2),
|
78
|
+
temporalAlpha: new Uniform(0.1)
|
79
|
+
} satisfies CloudsResolveMaterialUniforms
|
80
|
+
})
|
81
|
+
}
|
82
|
+
|
83
|
+
setSize(width: number, height: number): void {
|
84
|
+
this.uniforms.texelSize.value.set(1 / width, 1 / height)
|
85
|
+
}
|
86
|
+
|
87
|
+
onBeforeRender(
|
88
|
+
renderer: WebGLRenderer,
|
89
|
+
scene: Scene,
|
90
|
+
camera: Camera,
|
91
|
+
geometry: BufferGeometry,
|
92
|
+
object: Object3D,
|
93
|
+
group: Group
|
94
|
+
): void {
|
95
|
+
const uniforms = this.uniforms
|
96
|
+
const frame = uniforms.frame.value % 16
|
97
|
+
const offset = bayerOffsets[frame]
|
98
|
+
const dx = (offset.x - 0.5) * 4
|
99
|
+
const dy = (offset.y - 0.5) * 4
|
100
|
+
this.uniforms.jitterOffset.value.set(dx, dy)
|
101
|
+
}
|
102
|
+
|
103
|
+
@define('TEMPORAL_UPSCALE')
|
104
|
+
temporalUpscale = true
|
105
|
+
|
106
|
+
@define('SHADOW_LENGTH')
|
107
|
+
shadowLength = true
|
108
|
+
}
|
@@ -0,0 +1,38 @@
|
|
1
|
+
export interface DensityProfileLike
|
2
|
+
extends Partial<
|
3
|
+
Pick<DensityProfile, 'expTerm' | 'exponent' | 'linearTerm' | 'constantTerm'>
|
4
|
+
> {}
|
5
|
+
|
6
|
+
export class DensityProfile {
|
7
|
+
constructor(
|
8
|
+
public expTerm = 0,
|
9
|
+
public exponent = 0,
|
10
|
+
public linearTerm = 0,
|
11
|
+
public constantTerm = 0
|
12
|
+
) {}
|
13
|
+
|
14
|
+
set(expTerm = 0, exponent = 0, linearTerm = 0, constantTerm = 0): this {
|
15
|
+
this.expTerm = expTerm
|
16
|
+
this.exponent = exponent
|
17
|
+
this.linearTerm = linearTerm
|
18
|
+
this.constantTerm = constantTerm
|
19
|
+
return this
|
20
|
+
}
|
21
|
+
|
22
|
+
clone(): DensityProfile {
|
23
|
+
return new DensityProfile(
|
24
|
+
this.expTerm,
|
25
|
+
this.exponent,
|
26
|
+
this.linearTerm,
|
27
|
+
this.constantTerm
|
28
|
+
)
|
29
|
+
}
|
30
|
+
|
31
|
+
copy(other: DensityProfile): this {
|
32
|
+
this.expTerm = other.expTerm
|
33
|
+
this.exponent = other.exponent
|
34
|
+
this.linearTerm = other.linearTerm
|
35
|
+
this.constantTerm = other.constantTerm
|
36
|
+
return this
|
37
|
+
}
|
38
|
+
}
|
@@ -0,0 +1,21 @@
|
|
1
|
+
import { resolveIncludes } from '@takram/three-geospatial'
|
2
|
+
import { math } from '@takram/three-geospatial/shaders'
|
3
|
+
|
4
|
+
import { ProceduralTextureBase } from './ProceduralTexture'
|
5
|
+
|
6
|
+
import fragmentShader from './shaders/localWeather.frag?raw'
|
7
|
+
import perlin from './shaders/perlin.glsl?raw'
|
8
|
+
import tileableNoise from './shaders/tileableNoise.glsl?raw'
|
9
|
+
|
10
|
+
export class LocalWeather extends ProceduralTextureBase {
|
11
|
+
constructor() {
|
12
|
+
super({
|
13
|
+
size: 512,
|
14
|
+
fragmentShader: resolveIncludes(fragmentShader, {
|
15
|
+
core: { math },
|
16
|
+
perlin,
|
17
|
+
tileableNoise
|
18
|
+
})
|
19
|
+
})
|
20
|
+
}
|
21
|
+
}
|
package/src/PassBase.ts
ADDED
@@ -0,0 +1,28 @@
|
|
1
|
+
import { Pass } from 'postprocessing'
|
2
|
+
import { Camera } from 'three'
|
3
|
+
|
4
|
+
import { type CascadedShadowMaps } from './CascadedShadowMaps'
|
5
|
+
|
6
|
+
export interface PassBaseOptions {
|
7
|
+
shadow: CascadedShadowMaps
|
8
|
+
}
|
9
|
+
|
10
|
+
export abstract class PassBase extends Pass {
|
11
|
+
shadow: CascadedShadowMaps
|
12
|
+
|
13
|
+
private _mainCamera = new Camera()
|
14
|
+
|
15
|
+
constructor(name: string, options: PassBaseOptions) {
|
16
|
+
super(name)
|
17
|
+
const { shadow } = options
|
18
|
+
this.shadow = shadow
|
19
|
+
}
|
20
|
+
|
21
|
+
get mainCamera(): Camera {
|
22
|
+
return this._mainCamera
|
23
|
+
}
|
24
|
+
|
25
|
+
set mainCamera(value: Camera) {
|
26
|
+
this._mainCamera = value
|
27
|
+
}
|
28
|
+
}
|
@@ -0,0 +1,94 @@
|
|
1
|
+
import {
|
2
|
+
Camera,
|
3
|
+
GLSL3,
|
4
|
+
LinearFilter,
|
5
|
+
Mesh,
|
6
|
+
NoColorSpace,
|
7
|
+
PlaneGeometry,
|
8
|
+
RawShaderMaterial,
|
9
|
+
RedFormat,
|
10
|
+
RepeatWrapping,
|
11
|
+
Uniform,
|
12
|
+
WebGL3DRenderTarget,
|
13
|
+
type Data3DTexture,
|
14
|
+
type WebGLRenderer
|
15
|
+
} from 'three'
|
16
|
+
|
17
|
+
import { type ProceduralTexture } from './ProceduralTexture'
|
18
|
+
|
19
|
+
export type Procedural3DTexture = ProceduralTexture<Data3DTexture>
|
20
|
+
|
21
|
+
export interface Procedural3DTextureBaseParameters {
|
22
|
+
size: number
|
23
|
+
fragmentShader: string
|
24
|
+
}
|
25
|
+
|
26
|
+
export class Procedural3DTextureBase implements Procedural3DTexture {
|
27
|
+
readonly size: number
|
28
|
+
needsRender = true
|
29
|
+
|
30
|
+
private readonly material: RawShaderMaterial
|
31
|
+
private readonly mesh: Mesh
|
32
|
+
private readonly renderTarget: WebGL3DRenderTarget
|
33
|
+
private readonly camera = new Camera()
|
34
|
+
|
35
|
+
constructor({ size, fragmentShader }: Procedural3DTextureBaseParameters) {
|
36
|
+
this.size = size
|
37
|
+
this.material = new RawShaderMaterial({
|
38
|
+
glslVersion: GLSL3,
|
39
|
+
vertexShader: /* glsl */ `
|
40
|
+
in vec3 position;
|
41
|
+
out vec2 vUv;
|
42
|
+
void main() {
|
43
|
+
vUv = position.xy * 0.5 + 0.5;
|
44
|
+
gl_Position = vec4(position.xy, 0.0, 1.0);
|
45
|
+
}
|
46
|
+
`,
|
47
|
+
fragmentShader,
|
48
|
+
uniforms: {
|
49
|
+
layer: new Uniform(0)
|
50
|
+
}
|
51
|
+
})
|
52
|
+
this.mesh = new Mesh(new PlaneGeometry(2, 2), this.material)
|
53
|
+
|
54
|
+
this.renderTarget = new WebGL3DRenderTarget(size, size, size, {
|
55
|
+
depthBuffer: false,
|
56
|
+
stencilBuffer: false,
|
57
|
+
format: RedFormat
|
58
|
+
})
|
59
|
+
const texture = this.renderTarget.texture
|
60
|
+
texture.minFilter = LinearFilter
|
61
|
+
texture.magFilter = LinearFilter
|
62
|
+
texture.wrapS = RepeatWrapping
|
63
|
+
texture.wrapT = RepeatWrapping
|
64
|
+
texture.wrapR = RepeatWrapping
|
65
|
+
texture.colorSpace = NoColorSpace
|
66
|
+
texture.needsUpdate = true
|
67
|
+
}
|
68
|
+
|
69
|
+
dispose(): void {
|
70
|
+
this.renderTarget.dispose()
|
71
|
+
this.material.dispose()
|
72
|
+
}
|
73
|
+
|
74
|
+
render(renderer: WebGLRenderer, deltaTime?: number): void {
|
75
|
+
if (!this.needsRender) {
|
76
|
+
return
|
77
|
+
}
|
78
|
+
this.needsRender = false
|
79
|
+
|
80
|
+
// Unfortunately, rendering into 3D target requires as many draw calls as
|
81
|
+
// the value of "size".
|
82
|
+
const renderTarget = renderer.getRenderTarget()
|
83
|
+
for (let layer = 0; layer < this.size; ++layer) {
|
84
|
+
this.material.uniforms.layer.value = layer / this.size
|
85
|
+
renderer.setRenderTarget(this.renderTarget, layer)
|
86
|
+
renderer.render(this.mesh, this.camera)
|
87
|
+
}
|
88
|
+
renderer.setRenderTarget(renderTarget)
|
89
|
+
}
|
90
|
+
|
91
|
+
get texture(): Data3DTexture {
|
92
|
+
return this.renderTarget.texture
|
93
|
+
}
|
94
|
+
}
|
@@ -0,0 +1,94 @@
|
|
1
|
+
import {
|
2
|
+
Camera,
|
3
|
+
GLSL3,
|
4
|
+
LinearFilter,
|
5
|
+
LinearMipMapLinearFilter,
|
6
|
+
Mesh,
|
7
|
+
NoColorSpace,
|
8
|
+
PlaneGeometry,
|
9
|
+
RawShaderMaterial,
|
10
|
+
RepeatWrapping,
|
11
|
+
RGBAFormat,
|
12
|
+
Uniform,
|
13
|
+
WebGLRenderTarget,
|
14
|
+
type Texture,
|
15
|
+
type WebGLRenderer
|
16
|
+
} from 'three'
|
17
|
+
|
18
|
+
export interface ProceduralTexture<T extends Texture = Texture> {
|
19
|
+
readonly size: number
|
20
|
+
readonly texture: T
|
21
|
+
|
22
|
+
dispose: () => void
|
23
|
+
render: (renderer: WebGLRenderer, deltaTime?: number) => void
|
24
|
+
}
|
25
|
+
|
26
|
+
export interface ProceduralTextureBaseParameters {
|
27
|
+
size: number
|
28
|
+
fragmentShader: string
|
29
|
+
}
|
30
|
+
|
31
|
+
export class ProceduralTextureBase implements ProceduralTexture {
|
32
|
+
readonly size: number
|
33
|
+
needsRender = true
|
34
|
+
|
35
|
+
private readonly material: RawShaderMaterial
|
36
|
+
private readonly mesh: Mesh
|
37
|
+
private readonly renderTarget: WebGLRenderTarget
|
38
|
+
private readonly camera = new Camera()
|
39
|
+
|
40
|
+
constructor({ size, fragmentShader }: ProceduralTextureBaseParameters) {
|
41
|
+
this.size = size
|
42
|
+
this.material = new RawShaderMaterial({
|
43
|
+
glslVersion: GLSL3,
|
44
|
+
vertexShader: /* glsl */ `
|
45
|
+
in vec3 position;
|
46
|
+
out vec2 vUv;
|
47
|
+
void main() {
|
48
|
+
vUv = position.xy * 0.5 + 0.5;
|
49
|
+
gl_Position = vec4(position.xy, 0.0, 1.0);
|
50
|
+
}
|
51
|
+
`,
|
52
|
+
fragmentShader,
|
53
|
+
uniforms: {
|
54
|
+
layer: new Uniform(0)
|
55
|
+
}
|
56
|
+
})
|
57
|
+
this.mesh = new Mesh(new PlaneGeometry(2, 2), this.material)
|
58
|
+
|
59
|
+
this.renderTarget = new WebGLRenderTarget(size, size, {
|
60
|
+
depthBuffer: false,
|
61
|
+
stencilBuffer: false,
|
62
|
+
format: RGBAFormat
|
63
|
+
})
|
64
|
+
const texture = this.renderTarget.texture
|
65
|
+
texture.generateMipmaps = true
|
66
|
+
texture.minFilter = LinearMipMapLinearFilter
|
67
|
+
texture.magFilter = LinearFilter
|
68
|
+
texture.wrapS = RepeatWrapping
|
69
|
+
texture.wrapT = RepeatWrapping
|
70
|
+
texture.colorSpace = NoColorSpace
|
71
|
+
texture.needsUpdate = true
|
72
|
+
}
|
73
|
+
|
74
|
+
dispose(): void {
|
75
|
+
this.renderTarget.dispose()
|
76
|
+
this.material.dispose()
|
77
|
+
}
|
78
|
+
|
79
|
+
render(renderer: WebGLRenderer, deltaTime?: number): void {
|
80
|
+
if (!this.needsRender) {
|
81
|
+
return
|
82
|
+
}
|
83
|
+
this.needsRender = false
|
84
|
+
|
85
|
+
const renderTarget = renderer.getRenderTarget()
|
86
|
+
renderer.setRenderTarget(this.renderTarget)
|
87
|
+
renderer.render(this.mesh, this.camera)
|
88
|
+
renderer.setRenderTarget(renderTarget)
|
89
|
+
}
|
90
|
+
|
91
|
+
get texture(): Texture {
|
92
|
+
return this.renderTarget.texture
|
93
|
+
}
|
94
|
+
}
|
@@ -0,0 +1,32 @@
|
|
1
|
+
import { ShaderPass, type CopyMaterial } from 'postprocessing'
|
2
|
+
import {
|
3
|
+
type Uniform,
|
4
|
+
type WebGLArrayRenderTarget,
|
5
|
+
type WebGLRenderer,
|
6
|
+
type WebGLRenderTarget
|
7
|
+
} from 'three'
|
8
|
+
|
9
|
+
import { setArrayRenderTargetLayers } from './helpers/setArrayRenderTargetLayers'
|
10
|
+
|
11
|
+
export class ShaderArrayPass extends ShaderPass {
|
12
|
+
declare input: string
|
13
|
+
|
14
|
+
override render(
|
15
|
+
renderer: WebGLRenderer,
|
16
|
+
inputBuffer: WebGLRenderTarget | null,
|
17
|
+
outputBuffer: WebGLArrayRenderTarget,
|
18
|
+
deltaTime?: number,
|
19
|
+
stencilTest?: boolean
|
20
|
+
): void {
|
21
|
+
const uniforms = (
|
22
|
+
this.fullscreenMaterial as CopyMaterial & {
|
23
|
+
uniforms?: Record<string, Uniform>
|
24
|
+
}
|
25
|
+
).uniforms
|
26
|
+
if (inputBuffer !== null && uniforms?.[this.input] != null) {
|
27
|
+
uniforms[this.input].value = inputBuffer.texture
|
28
|
+
}
|
29
|
+
setArrayRenderTargetLayers(renderer, outputBuffer)
|
30
|
+
renderer.render(this.scene, this.camera)
|
31
|
+
}
|
32
|
+
}
|