@deck.gl-community/layers 9.2.8 → 9.3.0-beta.2
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/dist/index.cjs +384 -49
- package/dist/index.cjs.map +4 -4
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/dist/path-outline-layer/outline.d.ts +1 -1
- package/dist/path-outline-layer/outline.d.ts.map +1 -1
- package/dist/path-outline-layer/outline.js +2 -4
- package/dist/path-outline-layer/outline.js.map +1 -1
- package/dist/path-outline-layer/path-outline-layer.d.ts +2 -6
- package/dist/path-outline-layer/path-outline-layer.d.ts.map +1 -1
- package/dist/path-outline-layer/path-outline-layer.js +77 -51
- package/dist/path-outline-layer/path-outline-layer.js.map +1 -1
- package/dist/skybox-layer/cubemap-utils.d.ts +15 -0
- package/dist/skybox-layer/cubemap-utils.d.ts.map +1 -0
- package/dist/skybox-layer/cubemap-utils.js +64 -0
- package/dist/skybox-layer/cubemap-utils.js.map +1 -0
- package/dist/skybox-layer/skybox-layer.d.ts +58 -0
- package/dist/skybox-layer/skybox-layer.d.ts.map +1 -0
- package/dist/skybox-layer/skybox-layer.js +248 -0
- package/dist/skybox-layer/skybox-layer.js.map +1 -0
- package/package.json +13 -11
- package/src/index.ts +3 -0
- package/src/path-outline-layer/outline.ts +2 -4
- package/src/path-outline-layer/path-outline-layer.ts +91 -58
- package/src/skybox-layer/cubemap-utils.ts +105 -0
- package/src/skybox-layer/skybox-layer.ts +344 -0
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
// deck.gl-community
|
|
2
|
+
// SPDX-License-Identifier: MIT
|
|
3
|
+
// Copyright (c) vis.gl contributors
|
|
4
|
+
|
|
5
|
+
import type {TextureCubeManifest, TextureCubeLoaderOptions} from '@loaders.gl/textures';
|
|
6
|
+
import type {TextureCubeData, TextureCubeFace} from '@luma.gl/engine';
|
|
7
|
+
|
|
8
|
+
const CUBE_FACES: TextureCubeFace[] = ['+X', '-X', '+Y', '-Y', '+Z', '-Z'];
|
|
9
|
+
|
|
10
|
+
type LoadedTextureLevel = {
|
|
11
|
+
/** Browser-native bitmap representation for a mip level. */
|
|
12
|
+
imageBitmap?: ImageBitmap;
|
|
13
|
+
/** Explicit WebGPU texture format name. */
|
|
14
|
+
textureFormat?: string;
|
|
15
|
+
/** Legacy format field returned by some loaders.gl code paths. */
|
|
16
|
+
format?: string;
|
|
17
|
+
/** Raw pixel data for CPU-side texture uploads. */
|
|
18
|
+
data?: Uint8Array;
|
|
19
|
+
/** Width in pixels for raw pixel data uploads. */
|
|
20
|
+
width?: number;
|
|
21
|
+
/** Height in pixels for raw pixel data uploads. */
|
|
22
|
+
height?: number;
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
type LoadedCubemapTexture = {
|
|
26
|
+
type: 'cube';
|
|
27
|
+
data: unknown[];
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Normalizes loaders.gl cubemap load options so in-memory manifests can still
|
|
32
|
+
* resolve relative face URLs through `core.baseUrl`.
|
|
33
|
+
*/
|
|
34
|
+
export function createCubemapLoadOptions(
|
|
35
|
+
cubemap: string | TextureCubeManifest,
|
|
36
|
+
loadOptions?: TextureCubeLoaderOptions | null
|
|
37
|
+
): TextureCubeLoaderOptions | undefined {
|
|
38
|
+
if (!loadOptions) {
|
|
39
|
+
return undefined;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
if (typeof cubemap === 'string' || loadOptions.core?.baseUrl || !loadOptions.baseUrl) {
|
|
43
|
+
return loadOptions;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
return {
|
|
47
|
+
...loadOptions,
|
|
48
|
+
core: {
|
|
49
|
+
...loadOptions.core,
|
|
50
|
+
baseUrl: loadOptions.baseUrl
|
|
51
|
+
}
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/** Converts a loaders.gl cubemap result into luma.gl `TextureCubeData`. */
|
|
56
|
+
export function convertLoadedCubemapToTextureData(texture: LoadedCubemapTexture): TextureCubeData {
|
|
57
|
+
if (texture.type !== 'cube' || !Array.isArray(texture.data) || texture.data.length !== 6) {
|
|
58
|
+
throw new Error('SkyboxLayer expected a cubemap texture with six faces.');
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
return Object.fromEntries(
|
|
62
|
+
CUBE_FACES.map((face, index) => [face, normalizeTextureSlice(texture.data[index], face)])
|
|
63
|
+
) as TextureCubeData;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/** Normalizes a cubemap face that may contain one or more mip levels. */
|
|
67
|
+
function normalizeTextureSlice(faceData: unknown, face: TextureCubeFace): any {
|
|
68
|
+
if (Array.isArray(faceData)) {
|
|
69
|
+
if (faceData.length === 0) {
|
|
70
|
+
throw new Error(`SkyboxLayer received an empty mip chain for face ${face}.`);
|
|
71
|
+
}
|
|
72
|
+
return faceData.map((level, mipLevel) => normalizeTextureLevel(level, face, mipLevel));
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
return normalizeTextureLevel(faceData, face, 0);
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/** Normalizes a single cubemap face mip level into luma.gl upload data. */
|
|
79
|
+
function normalizeTextureLevel(faceData: unknown, face: TextureCubeFace, mipLevel: number) {
|
|
80
|
+
if (typeof ImageBitmap !== 'undefined' && faceData instanceof ImageBitmap) {
|
|
81
|
+
return faceData;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
const level = faceData as LoadedTextureLevel | null | undefined;
|
|
85
|
+
|
|
86
|
+
if (level?.imageBitmap) {
|
|
87
|
+
return level.imageBitmap;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
if (level && ArrayBuffer.isView(level.data) && level.width && level.height) {
|
|
91
|
+
return {
|
|
92
|
+
data: level.data,
|
|
93
|
+
width: level.width,
|
|
94
|
+
height: level.height,
|
|
95
|
+
format:
|
|
96
|
+
typeof level.textureFormat === 'string'
|
|
97
|
+
? level.textureFormat
|
|
98
|
+
: typeof level.format === 'string'
|
|
99
|
+
? level.format
|
|
100
|
+
: 'rgba8unorm'
|
|
101
|
+
};
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
throw new Error(`SkyboxLayer could not normalize cubemap face ${face} mip ${mipLevel}.`);
|
|
105
|
+
}
|
|
@@ -0,0 +1,344 @@
|
|
|
1
|
+
// deck.gl-community
|
|
2
|
+
// SPDX-License-Identifier: MIT
|
|
3
|
+
// Copyright (c) vis.gl contributors
|
|
4
|
+
|
|
5
|
+
import {load} from '@loaders.gl/core';
|
|
6
|
+
import {
|
|
7
|
+
TextureCubeLoader,
|
|
8
|
+
type TextureCubeLoaderOptions,
|
|
9
|
+
type TextureCubeManifest
|
|
10
|
+
} from '@loaders.gl/textures';
|
|
11
|
+
import {Layer} from '@deck.gl/core';
|
|
12
|
+
import type {DefaultProps, LayerProps, UpdateParameters, Viewport} from '@deck.gl/core';
|
|
13
|
+
import {Matrix4} from '@math.gl/core';
|
|
14
|
+
import type {Device, RenderPipelineParameters} from '@luma.gl/core';
|
|
15
|
+
import {CubeGeometry, DynamicTexture, Model, ShaderInputs} from '@luma.gl/engine';
|
|
16
|
+
import type {TextureCubeData} from '@luma.gl/engine';
|
|
17
|
+
import type {ShaderModule} from '@luma.gl/shadertools';
|
|
18
|
+
import {convertLoadedCubemapToTextureData, createCubemapLoadOptions} from './cubemap-utils';
|
|
19
|
+
|
|
20
|
+
type AppUniforms = {
|
|
21
|
+
/** World transform for the unit cube used to draw the skybox. */
|
|
22
|
+
modelMatrix: any;
|
|
23
|
+
/** View transform with translation removed so the skybox stays camera-centered. */
|
|
24
|
+
viewMatrix: any;
|
|
25
|
+
/** Projection transform for the active viewport. */
|
|
26
|
+
projectionMatrix: any;
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
const app: ShaderModule<AppUniforms, AppUniforms> = {
|
|
30
|
+
name: 'app',
|
|
31
|
+
uniformTypes: {
|
|
32
|
+
modelMatrix: 'mat4x4<f32>',
|
|
33
|
+
viewMatrix: 'mat4x4<f32>',
|
|
34
|
+
projectionMatrix: 'mat4x4<f32>'
|
|
35
|
+
}
|
|
36
|
+
} as any;
|
|
37
|
+
|
|
38
|
+
const SKYBOX_PARAMETERS: RenderPipelineParameters = {
|
|
39
|
+
cullMode: 'front',
|
|
40
|
+
depthWriteEnabled: false,
|
|
41
|
+
depthCompare: 'less-equal'
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
const SKYBOX_SCALE = new Matrix4().scale([2, 2, 2]);
|
|
45
|
+
|
|
46
|
+
const defaultProps: DefaultProps<SkyboxLayerProps> = {
|
|
47
|
+
cubemap: null,
|
|
48
|
+
loadOptions: null,
|
|
49
|
+
orientation: 'default'
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
type _SkyboxLayerProps = {
|
|
53
|
+
/** Cubemap manifest URL or manifest object to load and render. */
|
|
54
|
+
cubemap: string | TextureCubeManifest | null;
|
|
55
|
+
/** Optional loaders.gl texture-cube load options. */
|
|
56
|
+
loadOptions?: TextureCubeLoaderOptions | null;
|
|
57
|
+
/**
|
|
58
|
+
* Declares how the cubemap faces are oriented relative to deck.gl's Z-up
|
|
59
|
+
* world. Use `y-up` for cubemaps authored for Y-up scenes, such as the
|
|
60
|
+
* Tycho star map faces from the luma.gl globe showcase.
|
|
61
|
+
*/
|
|
62
|
+
orientation?: 'default' | 'y-up';
|
|
63
|
+
};
|
|
64
|
+
|
|
65
|
+
export type SkyboxLayerProps = _SkyboxLayerProps & LayerProps;
|
|
66
|
+
|
|
67
|
+
type LoadedCubemapTexture = {
|
|
68
|
+
type: 'cube';
|
|
69
|
+
data: unknown[];
|
|
70
|
+
};
|
|
71
|
+
|
|
72
|
+
type SkyboxLayerState = {
|
|
73
|
+
/** Active GPU cubemap texture, if one has been loaded successfully. */
|
|
74
|
+
cubemapTexture: DynamicTexture | null;
|
|
75
|
+
/** Monotonic load token used to discard stale async cubemap loads. */
|
|
76
|
+
loadCount: number;
|
|
77
|
+
/** Backing model that renders the cube geometry. */
|
|
78
|
+
model?: Model;
|
|
79
|
+
/** Shader input manager for the skybox uniforms. */
|
|
80
|
+
shaderInputs?: ShaderInputs<any>;
|
|
81
|
+
};
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* Renders a camera-centered cubemap background for `MapView`, `GlobeView`,
|
|
85
|
+
* `FirstPersonView`, and other 3D-capable deck.gl views.
|
|
86
|
+
*/
|
|
87
|
+
export class SkyboxLayer<
|
|
88
|
+
ExtraProps extends Record<string, unknown> = Record<string, unknown>
|
|
89
|
+
> extends Layer<Required<_SkyboxLayerProps> & ExtraProps> {
|
|
90
|
+
static defaultProps = defaultProps;
|
|
91
|
+
static layerName = 'SkyboxLayer';
|
|
92
|
+
|
|
93
|
+
state: SkyboxLayerState = undefined!;
|
|
94
|
+
|
|
95
|
+
/** Initializes the cube model and starts loading the cubemap texture. */
|
|
96
|
+
initializeState(): void {
|
|
97
|
+
const attributeManager = this.getAttributeManager();
|
|
98
|
+
attributeManager?.remove(['instancePickingColors']);
|
|
99
|
+
|
|
100
|
+
const shaderInputs = new ShaderInputs(
|
|
101
|
+
createShaderInputModules(this.context.defaultShaderModules),
|
|
102
|
+
{
|
|
103
|
+
disableWarnings: true
|
|
104
|
+
}
|
|
105
|
+
);
|
|
106
|
+
const model = this._getModel(shaderInputs);
|
|
107
|
+
|
|
108
|
+
this.setState({
|
|
109
|
+
cubemapTexture: null,
|
|
110
|
+
loadCount: 0,
|
|
111
|
+
model,
|
|
112
|
+
shaderInputs
|
|
113
|
+
});
|
|
114
|
+
|
|
115
|
+
this._loadCubemap().catch(() => {});
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
/** Reloads the cubemap when its source manifest or load options change. */
|
|
119
|
+
updateState({props, oldProps}: UpdateParameters<this>): void {
|
|
120
|
+
if (props.cubemap !== oldProps.cubemap || props.loadOptions !== oldProps.loadOptions) {
|
|
121
|
+
this._loadCubemap().catch(() => {});
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
/** Releases GPU resources owned by the layer. */
|
|
126
|
+
finalizeState(): void {
|
|
127
|
+
this.state.cubemapTexture?.destroy();
|
|
128
|
+
this.state.model?.destroy();
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
/** Draws the skybox cube for the current viewport. */
|
|
132
|
+
draw(): void {
|
|
133
|
+
const {model, cubemapTexture, shaderInputs} = this.state;
|
|
134
|
+
if (!model || !cubemapTexture || !shaderInputs) {
|
|
135
|
+
return;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
const viewport = this.context.viewport;
|
|
139
|
+
shaderInputs.setProps({
|
|
140
|
+
app: {
|
|
141
|
+
modelMatrix: getSkyboxModelMatrix(this.props.orientation),
|
|
142
|
+
viewMatrix: getSkyboxViewMatrix(viewport),
|
|
143
|
+
projectionMatrix: viewport.projectionMatrix
|
|
144
|
+
}
|
|
145
|
+
});
|
|
146
|
+
|
|
147
|
+
model.draw(this.context.renderPass);
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
/** Creates the luma.gl model used to render the skybox cube. */
|
|
151
|
+
protected _getModel(shaderInputs: ShaderInputs<any>): Model {
|
|
152
|
+
return new Model(this.context.device, {
|
|
153
|
+
...this.getShaders(),
|
|
154
|
+
id: this.props.id,
|
|
155
|
+
bufferLayout: this.getAttributeManager()?.getBufferLayouts() || [],
|
|
156
|
+
geometry: new CubeGeometry({indices: true}),
|
|
157
|
+
shaderInputs,
|
|
158
|
+
isInstanced: false,
|
|
159
|
+
parameters: SKYBOX_PARAMETERS
|
|
160
|
+
});
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
/** Returns the WGSL/GLSL shader pair used by the layer. */
|
|
164
|
+
getShaders() {
|
|
165
|
+
return {
|
|
166
|
+
source: SKYBOX_WGSL,
|
|
167
|
+
vs: SKYBOX_VS,
|
|
168
|
+
fs: SKYBOX_FS
|
|
169
|
+
};
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
/** Starts an asynchronous cubemap load for the current props. */
|
|
173
|
+
private async _loadCubemap(): Promise<void> {
|
|
174
|
+
const {cubemap, loadOptions} = this.props;
|
|
175
|
+
const nextLoadCount = this.state.loadCount + 1;
|
|
176
|
+
this.setState({loadCount: nextLoadCount});
|
|
177
|
+
|
|
178
|
+
if (!cubemap) {
|
|
179
|
+
this._setCubemapTexture(null);
|
|
180
|
+
return;
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
try {
|
|
184
|
+
const loadedTexture = await loadCubemapSource(cubemap, loadOptions);
|
|
185
|
+
if (this.state.loadCount !== nextLoadCount || !this.state.model) {
|
|
186
|
+
return;
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
const cubemapData = convertLoadedCubemapToTextureData(loadedTexture);
|
|
190
|
+
this._setCubemapTexture(createCubemapTexture(this.context.device, cubemapData));
|
|
191
|
+
} catch (error) {
|
|
192
|
+
if (this.state.loadCount === nextLoadCount) {
|
|
193
|
+
this.raiseError(error as Error, 'SkyboxLayer failed to load cubemap');
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
/** Swaps the active GPU cubemap texture and updates model bindings. */
|
|
199
|
+
private _setCubemapTexture(texture: DynamicTexture | null): void {
|
|
200
|
+
const {cubemapTexture, model} = this.state;
|
|
201
|
+
if (cubemapTexture === texture) {
|
|
202
|
+
return;
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
cubemapTexture?.destroy();
|
|
206
|
+
this.setState({cubemapTexture: texture});
|
|
207
|
+
|
|
208
|
+
if (texture && model) {
|
|
209
|
+
model.setBindings({cubeTexture: texture});
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
this.setNeedsRedraw();
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
/** Loads a cubemap manifest or manifest URL through loaders.gl. */
|
|
217
|
+
async function loadCubemapSource(
|
|
218
|
+
cubemap: string | TextureCubeManifest,
|
|
219
|
+
loadOptions?: TextureCubeLoaderOptions | null
|
|
220
|
+
): Promise<LoadedCubemapTexture> {
|
|
221
|
+
const normalizedLoadOptions = createCubemapLoadOptions(cubemap, loadOptions);
|
|
222
|
+
|
|
223
|
+
if (typeof cubemap === 'string') {
|
|
224
|
+
return (await load(cubemap, TextureCubeLoader, normalizedLoadOptions)) as LoadedCubemapTexture;
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
return (await TextureCubeLoader.parseText(
|
|
228
|
+
JSON.stringify(cubemap),
|
|
229
|
+
normalizedLoadOptions
|
|
230
|
+
)) as LoadedCubemapTexture;
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
/** Creates the runtime `DynamicTexture` instance used by the skybox model. */
|
|
234
|
+
function createCubemapTexture(device: Device, data: TextureCubeData): DynamicTexture {
|
|
235
|
+
return new DynamicTexture(device, {
|
|
236
|
+
dimension: 'cube',
|
|
237
|
+
data,
|
|
238
|
+
mipmaps: true,
|
|
239
|
+
sampler: {
|
|
240
|
+
addressModeU: 'clamp-to-edge',
|
|
241
|
+
addressModeV: 'clamp-to-edge',
|
|
242
|
+
addressModeW: 'clamp-to-edge',
|
|
243
|
+
magFilter: 'linear',
|
|
244
|
+
minFilter: 'linear',
|
|
245
|
+
mipmapFilter: 'linear'
|
|
246
|
+
}
|
|
247
|
+
});
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
/** Removes camera translation from the active view matrix for skybox rendering. */
|
|
251
|
+
function getSkyboxViewMatrix(viewport: Viewport): Matrix4 {
|
|
252
|
+
const viewMatrix = new Matrix4(viewport.viewMatrixUncentered || viewport.viewMatrix);
|
|
253
|
+
viewMatrix[12] = 0;
|
|
254
|
+
viewMatrix[13] = 0;
|
|
255
|
+
viewMatrix[14] = 0;
|
|
256
|
+
return viewMatrix;
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
/** Returns the skybox cube transform for the requested cubemap orientation. */
|
|
260
|
+
function getSkyboxModelMatrix(orientation: 'default' | 'y-up' = 'default'): Matrix4 {
|
|
261
|
+
if (orientation === 'y-up') {
|
|
262
|
+
return new Matrix4().rotateX(Math.PI / 2).scale([2, 2, 2]);
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
return new Matrix4(SKYBOX_SCALE);
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
/** Converts the current shader module list into a name-indexed dictionary. */
|
|
269
|
+
function createShaderInputModules(defaultShaderModules: ShaderModule[]): {
|
|
270
|
+
[moduleName: string]: ShaderModule;
|
|
271
|
+
} {
|
|
272
|
+
return Object.fromEntries([app, ...defaultShaderModules].map((module) => [module.name, module]));
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
const SKYBOX_WGSL = /* wgsl */ `
|
|
276
|
+
struct appUniforms {
|
|
277
|
+
modelMatrix: mat4x4<f32>,
|
|
278
|
+
viewMatrix: mat4x4<f32>,
|
|
279
|
+
projectionMatrix: mat4x4<f32>,
|
|
280
|
+
};
|
|
281
|
+
|
|
282
|
+
@group(0) @binding(auto) var<uniform> app : appUniforms;
|
|
283
|
+
@group(0) @binding(auto) var cubeTexture : texture_cube<f32>;
|
|
284
|
+
@group(0) @binding(auto) var cubeTextureSampler : sampler;
|
|
285
|
+
|
|
286
|
+
struct VertexInputs {
|
|
287
|
+
@location(0) positions : vec3<f32>,
|
|
288
|
+
};
|
|
289
|
+
|
|
290
|
+
struct VertexOutputs {
|
|
291
|
+
@builtin(position) position : vec4<f32>,
|
|
292
|
+
@location(0) direction : vec3<f32>,
|
|
293
|
+
};
|
|
294
|
+
|
|
295
|
+
@vertex
|
|
296
|
+
fn vertexMain(inputs: VertexInputs) -> VertexOutputs {
|
|
297
|
+
var outputs : VertexOutputs;
|
|
298
|
+
let clipPosition =
|
|
299
|
+
app.projectionMatrix *
|
|
300
|
+
app.viewMatrix *
|
|
301
|
+
app.modelMatrix *
|
|
302
|
+
vec4<f32>(inputs.positions, 1.0);
|
|
303
|
+
outputs.position = vec4<f32>(clipPosition.x, clipPosition.y, clipPosition.w, clipPosition.w);
|
|
304
|
+
outputs.direction = inputs.positions;
|
|
305
|
+
return outputs;
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
@fragment
|
|
309
|
+
fn fragmentMain(inputs: VertexOutputs) -> @location(0) vec4<f32> {
|
|
310
|
+
return textureSample(cubeTexture, cubeTextureSampler, normalize(inputs.direction));
|
|
311
|
+
}
|
|
312
|
+
`;
|
|
313
|
+
|
|
314
|
+
const SKYBOX_VS = /* glsl */ `#version 300 es
|
|
315
|
+
in vec3 positions;
|
|
316
|
+
|
|
317
|
+
uniform appUniforms {
|
|
318
|
+
mat4 modelMatrix;
|
|
319
|
+
mat4 viewMatrix;
|
|
320
|
+
mat4 projectionMatrix;
|
|
321
|
+
} app;
|
|
322
|
+
|
|
323
|
+
out vec3 vDirection;
|
|
324
|
+
|
|
325
|
+
void main(void) {
|
|
326
|
+
vec4 clipPosition =
|
|
327
|
+
app.projectionMatrix * app.viewMatrix * app.modelMatrix * vec4(positions, 1.0);
|
|
328
|
+
gl_Position = clipPosition.xyww;
|
|
329
|
+
vDirection = positions;
|
|
330
|
+
}
|
|
331
|
+
`;
|
|
332
|
+
|
|
333
|
+
const SKYBOX_FS = /* glsl */ `#version 300 es
|
|
334
|
+
precision highp float;
|
|
335
|
+
|
|
336
|
+
uniform samplerCube cubeTexture;
|
|
337
|
+
|
|
338
|
+
in vec3 vDirection;
|
|
339
|
+
out vec4 fragColor;
|
|
340
|
+
|
|
341
|
+
void main(void) {
|
|
342
|
+
fragColor = texture(cubeTexture, normalize(vDirection));
|
|
343
|
+
}
|
|
344
|
+
`;
|