phoria2 1.0.0 → 1.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/README.md +6 -6
- package/dist/bloom.js +4 -4
- package/dist/bloom.js.map +1 -1
- package/dist/charts.js +377 -377
- package/dist/charts.js.map +1 -1
- package/dist/core.js +1052 -558
- package/dist/core.js.map +1 -1
- package/dist/edit.js +48 -48
- package/dist/edit.js.map +1 -1
- package/dist/explain.js +1 -1
- package/dist/gltf.js +207 -162
- package/dist/gltf.js.map +1 -1
- package/dist/motion.js +27 -27
- package/dist/motion.js.map +1 -1
- package/dist/particles.js +50 -50
- package/dist/particles.js.map +1 -1
- package/dist/passes.js +199 -97
- package/dist/passes.js.map +1 -1
- package/dist/phoria2.js +1 -1
- package/dist/picking.js +16 -21
- package/dist/picking.js.map +1 -1
- package/dist/snapshot.js +1 -1
- package/dist/tooltip.js +3 -3
- package/dist/tooltip.js.map +1 -1
- package/dist/types/View.d.ts +5 -0
- package/dist/types/geometry/Geometry.d.ts +6 -0
- package/dist/types/material/Material.d.ts +125 -0
- package/dist/types/material/Texture.d.ts +37 -5
- package/dist/types/webgl/WebGLRenderer.d.ts +6 -0
- package/dist/types/webgl/passes.d.ts +37 -13
- package/dist/types/webgl/resources.d.ts +24 -2
- package/dist/types/webgl/shaders.d.ts +4 -2
- package/llms-full.txt +96 -7
- package/package.json +1 -1
- package/schema/scene.schema.json +127 -0
- package/src/View.js +4 -2
- package/src/geometry/Geometry.js +8 -1
- package/src/gltf/load.js +50 -6
- package/src/material/Material.js +104 -19
- package/src/material/Texture.js +116 -11
- package/src/watch.js +19 -0
- package/src/webgl/WebGLRenderer.js +51 -12
- package/src/webgl/passes.js +190 -32
- package/src/webgl/picking.js +0 -1
- package/src/webgl/resources.js +89 -8
- package/src/webgl/shaders.js +350 -48
package/dist/tooltip.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tooltip.js","names":["
|
|
1
|
+
{"version":3,"file":"tooltip.js","names":["fail","describe","STYLE","GAP","Tooltip","content","style","className","hit","render","x","y","w","h","left","top","box","title","rows","entries","name","value","n","v"],"sources":["../src/tooltip.js"],"sourcesContent":["// The hover tooltip: one element that follows the pointer and shows what the app says about the\n// thing under it. Its default look is in a :where() rule, which has no specificity, so any CSS for\n// .phoria-tooltip overrides it.\nimport { describe, fail } from './validate.js'\n\n/** @import { Hit } from './Raycaster.js' */\n\n/**\n * What a tooltip function returns: text (new lines kept), an element, or a title with rows of\n * name/value pairs. null (or '') shows nothing.\n * @typedef {string | number | Node | { title?: string, rows?: Record<string, unknown> | Array<[string, unknown]> } | null | undefined | false} TooltipContent\n */\n\nconst STYLE = `\n:where(.phoria-tooltip) { position: fixed; left: 0; top: 0; z-index: 1000; pointer-events: none; max-width: 320px;\n padding: 6px 10px; border-radius: 6px; background: rgba(20, 20, 24, 0.92); color: #fff;\n font: 12px/1.45 system-ui, sans-serif; box-shadow: 0 4px 16px rgba(0, 0, 0, 0.3); white-space: pre-line; }\n:where(.phoria-tooltip-title) { font-weight: 600; }\n:where(.phoria-tooltip-rows) { display: grid; grid-template-columns: auto auto; column-gap: 12px; }\n:where(.phoria-tooltip-rows > :nth-child(odd)) { opacity: 0.7; }\n:where(.phoria-tooltip-rows > :nth-child(even)) { text-align: right; font-variant-numeric: tabular-nums; }\n`\n// space between the pointer and the tooltip, in CSS pixels\nconst GAP = 14\n\nexport class Tooltip {\n /** @type {HTMLDivElement} */ el\n /** @type {(hit: Hit) => TooltipContent} */ content\n\n /** @param {(hit: Hit) => TooltipContent} content @param {string} [className] */\n constructor(content, className = '') {\n if (typeof content !== 'function') fail('View', `tooltip() takes a function (hit) => text, got ${describe(content)}`)\n this.content = content\n if (!document.getElementById('phoria-tooltip-style')) {\n const style = document.createElement('style')\n style.id = 'phoria-tooltip-style'\n style.textContent = STYLE\n document.head.prepend(style)\n }\n this.el = document.createElement('div')\n this.el.className = `phoria-tooltip${className ? ` ${className}` : ''}`\n this.el.setAttribute('role', 'tooltip')\n this.el.hidden = true\n document.body.append(this.el)\n }\n\n /** Show what the content function says about a hit, near the pointer. @param {Hit} hit @param {number} x @param {number} y */\n show(hit, x, y) {\n const content = this.content(hit)\n if (content === null || content === undefined || content === false || content === '') return this.hide()\n this.el.replaceChildren(render(content))\n this.el.hidden = false\n this.move(x, y)\n }\n\n /** Follow the pointer, staying inside the window. @param {number} x @param {number} y client pixels */\n move(x, y) {\n if (this.el.hidden) return\n const w = this.el.offsetWidth, h = this.el.offsetHeight\n const left = x + GAP + w > window.innerWidth ? x - GAP - w : x + GAP\n const top = y + GAP + h > window.innerHeight ? y - GAP - h : y + GAP\n this.el.style.transform = `translate(${Math.round(Math.max(0, left))}px, ${Math.round(Math.max(0, top))}px)`\n }\n\n hide() {\n this.el.hidden = true\n }\n\n dispose() {\n this.el.remove()\n }\n}\n\n/** @param {TooltipContent} content @returns {Node} */\nfunction render(content) {\n if (typeof content === 'string' || typeof content === 'number') return document.createTextNode(String(content))\n if (content instanceof Node) return content\n if (typeof content === 'object' && content && ('title' in content || 'rows' in content)) {\n const box = document.createDocumentFragment()\n if (content.title !== undefined) {\n const title = document.createElement('div')\n title.className = 'phoria-tooltip-title'\n title.textContent = String(content.title)\n box.append(title)\n }\n if (content.rows) {\n const rows = document.createElement('div')\n rows.className = 'phoria-tooltip-rows'\n const entries = Array.isArray(content.rows) ? content.rows : Object.entries(content.rows)\n for (const [name, value] of entries) {\n const n = document.createElement('span'), v = document.createElement('span')\n n.textContent = String(name)\n v.textContent = typeof value === 'number' ? value.toLocaleString() : String(value)\n rows.append(n, v)\n }\n box.append(rows)\n }\n return box\n }\n return fail('View', `a tooltip function returns text, an element or { title, rows }, got ${describe(content)}`)\n}\n"],"mappings":";;AAaA,IAAME,IAAQ,2oBAURC,IAAM,IAECC,IAAb,MAAqB;CACW;CACc;CAG5C,YAAY,GAAS,IAAY,IAAI;EAGnC,IAFI,OAAOC,KAAY,cAAYL,EAAK,QAAQ,iDAAiDC,EAASI,CAAO,GAAG,GACpH,KAAK,UAAUA,GACX,CAAC,SAAS,eAAe,sBAAsB,GAAG;GACpD,IAAMC,IAAQ,SAAS,cAAc,OAAO;GAG5C,AAFA,EAAM,KAAK,wBACX,EAAM,cAAcJ,GACpB,SAAS,KAAK,QAAQI,CAAK;EAC7B;EAKA,AAJA,KAAK,KAAK,SAAS,cAAc,KAAK,GACtC,KAAK,GAAG,YAAY,iBAAiBC,IAAY,IAAIA,MAAc,MACnE,KAAK,GAAG,aAAa,QAAQ,SAAS,GACtC,KAAK,GAAG,SAAS,IACjB,SAAS,KAAK,OAAO,KAAK,EAAE;CAC9B;CAGA,KAAK,GAAK,GAAG,GAAG;EACd,IAAMF,IAAU,KAAK,QAAQG,CAAG;EAChC,IAAIH,KAAY,QAAiCA,MAAY,MAASA,MAAY,IAAI,OAAO,KAAK,KAAK;EAGvG,AAFA,KAAK,GAAG,gBAAgBI,EAAOJ,CAAO,CAAC,GACvC,KAAK,GAAG,SAAS,IACjB,KAAK,KAAKK,GAAGC,CAAC;CAChB;CAGA,KAAK,GAAG,GAAG;EACT,IAAI,KAAK,GAAG,QAAQ;EACpB,IAAMC,IAAI,KAAK,GAAG,aAAaC,IAAI,KAAK,GAAG,cACrCC,IAAOJ,IAAIP,IAAMS,IAAI,OAAO,aAAaF,IAAIP,IAAMS,IAAIF,IAAIP,GAC3DY,IAAMJ,IAAIR,IAAMU,IAAI,OAAO,cAAcF,IAAIR,IAAMU,IAAIF,IAAIR;EACjE,KAAK,GAAG,MAAM,YAAY,aAAa,KAAK,MAAM,KAAK,IAAI,GAAGW,CAAI,CAAC,EAAE,MAAM,KAAK,MAAM,KAAK,IAAI,GAAGC,CAAG,CAAC,EAAE;CAC1G;CAEA,OAAO;EACL,KAAK,GAAG,SAAS;CACnB;CAEA,UAAU;EACR,KAAK,GAAG,OAAO;CACjB;AACF;AAGA,SAASN,EAAO,GAAS;CACvB,IAAI,OAAOJ,KAAY,YAAY,OAAOA,KAAY,UAAU,OAAO,SAAS,eAAe,OAAOA,CAAO,CAAC;CAC9G,IAAIA,aAAmB,MAAM,OAAOA;CACpC,IAAI,OAAOA,KAAY,YAAYA,MAAY,WAAWA,KAAW,UAAUA,IAAU;EACvF,IAAMW,IAAM,SAAS,uBAAuB;EAC5C,IAAIX,EAAQ,UAAU,KAAA,GAAW;GAC/B,IAAMY,IAAQ,SAAS,cAAc,KAAK;GAG1C,AAFA,EAAM,YAAY,wBAClB,EAAM,cAAc,OAAOZ,EAAQ,KAAK,GACxCW,EAAI,OAAOC,CAAK;EAClB;EACA,IAAIZ,EAAQ,MAAM;GAChB,IAAMa,IAAO,SAAS,cAAc,KAAK;GACzC,EAAK,YAAY;GACjB,IAAMC,IAAU,MAAM,QAAQd,EAAQ,IAAI,IAAIA,EAAQ,OAAO,OAAO,QAAQA,EAAQ,IAAI;GACxF,KAAK,IAAM,CAACe,GAAMC,MAAUF,GAAS;IACnC,IAAMG,IAAI,SAAS,cAAc,MAAM,GAAGC,IAAI,SAAS,cAAc,MAAM;IAG3E,AAFA,EAAE,cAAc,OAAOH,CAAI,GAC3B,EAAE,cAAc,OAAOC,KAAU,WAAWA,EAAM,eAAe,IAAI,OAAOA,CAAK,GACjFH,EAAK,OAAOI,GAAGC,CAAC;GAClB;GACA,EAAI,OAAOL,CAAI;EACjB;EACA,OAAOF;CACT;CACA,OAAOhB,EAAK,QAAQ,uEAAuEC,EAASI,CAAO,GAAG;AAChH"}
|
package/dist/types/View.d.ts
CHANGED
|
@@ -73,6 +73,11 @@ export type ViewOptions = {
|
|
|
73
73
|
* (default true)
|
|
74
74
|
*/
|
|
75
75
|
antialias?: boolean;
|
|
76
|
+
/**
|
|
77
|
+
* soft-edged outlines with round corners (default: as antialias); change it
|
|
78
|
+
* any time with view.renderer.outlineAntialias
|
|
79
|
+
*/
|
|
80
|
+
outlineAntialias?: boolean;
|
|
76
81
|
/**
|
|
77
82
|
* which WebGL context draws it: 'own' gives the canvas one of
|
|
78
83
|
* its own; 'shared' draws with the page's one shared context and copies the picture over, so a page can hold
|
|
@@ -12,6 +12,11 @@ export type GeometryOptions = {
|
|
|
12
12
|
* uv per vertex - glTF convention, (0, 0) is the image's top left
|
|
13
13
|
*/
|
|
14
14
|
uvs?: ArrayLike<number>;
|
|
15
|
+
/**
|
|
16
|
+
* a second uv per vertex, for maps that need every surface on its own
|
|
17
|
+
* patch of texture - baked occlusion and light maps (a texture's uvSet: 1 reads it)
|
|
18
|
+
*/
|
|
19
|
+
uvs2?: ArrayLike<number>;
|
|
15
20
|
/**
|
|
16
21
|
* rgb per vertex, sRGB 0-1 like every colour input
|
|
17
22
|
*/
|
|
@@ -31,6 +36,7 @@ export declare class Geometry {
|
|
|
31
36
|
static OPTIONS: string[];
|
|
32
37
|
/** @type {Float32Array} */ positions: Float32Array;
|
|
33
38
|
/** @type {Float32Array | null} */ uvs: Float32Array | null;
|
|
39
|
+
/** A second UV set, for baked occlusion and light maps. @type {Float32Array | null} */ uvs2: Float32Array | null;
|
|
34
40
|
/** @type {Float32Array | null} */ colors: Float32Array | null;
|
|
35
41
|
/** @type {Uint16Array | Uint32Array | null} */ indices: Uint16Array | Uint32Array | null;
|
|
36
42
|
/**
|
|
@@ -76,6 +76,20 @@ export type MaterialOptions = {
|
|
|
76
76
|
* multiplies the emissive colour
|
|
77
77
|
*/
|
|
78
78
|
emissiveMap?: MapInput | null;
|
|
79
|
+
/**
|
|
80
|
+
* light baked into a texture, added as light from all round - usually on
|
|
81
|
+
* the second UV set (uvSet: 1)
|
|
82
|
+
*/
|
|
83
|
+
lightMap?: MapInput | null;
|
|
84
|
+
/**
|
|
85
|
+
* (default 1)
|
|
86
|
+
*/
|
|
87
|
+
lightMapIntensity?: number;
|
|
88
|
+
/**
|
|
89
|
+
* this material's share of the environment's light and reflections:
|
|
90
|
+
* lower for a matte floor in a shiny showroom, higher to make one thing catch the light (default 1)
|
|
91
|
+
*/
|
|
92
|
+
environmentIntensity?: number;
|
|
79
93
|
/**
|
|
80
94
|
* glow colour (default black)
|
|
81
95
|
*/
|
|
@@ -84,6 +98,74 @@ export type MaterialOptions = {
|
|
|
84
98
|
* (default 1)
|
|
85
99
|
*/
|
|
86
100
|
emissiveIntensity?: number;
|
|
101
|
+
/**
|
|
102
|
+
* 0-1: how much light passes through, as through glass (default 0). Unlike
|
|
103
|
+
* opacity, which fades the whole surface, glass keeps its reflections, and shows less of what is behind it
|
|
104
|
+
* towards its edges. Its colour shows in proportion to 1 - transmission
|
|
105
|
+
*/
|
|
106
|
+
transmission?: number;
|
|
107
|
+
/**
|
|
108
|
+
* 0-1: a clear glossy layer over the surface - car paint, lacquer, varnish (default 0)
|
|
109
|
+
*/
|
|
110
|
+
clearcoat?: number;
|
|
111
|
+
/**
|
|
112
|
+
* 0-1: how glossy the coat is, 0 a mirror (default 0)
|
|
113
|
+
*/
|
|
114
|
+
clearcoatRoughness?: number;
|
|
115
|
+
/**
|
|
116
|
+
* 0-1: the soft bright rim of cloth at grazing angles - velvet, felt, upholstery (default 0)
|
|
117
|
+
*/
|
|
118
|
+
sheen?: number;
|
|
119
|
+
/**
|
|
120
|
+
* the sheen's colour (default white)
|
|
121
|
+
*/
|
|
122
|
+
sheenColor?: ColorInput;
|
|
123
|
+
/**
|
|
124
|
+
* 0-1: a thin bright rim at 0, a broad soft glow at 1 (default 0.5)
|
|
125
|
+
*/
|
|
126
|
+
sheenRoughness?: number;
|
|
127
|
+
/**
|
|
128
|
+
* index of refraction, 1 or more: how strongly a non-metal reflects - water 1.33, glass and
|
|
129
|
+
* plastic 1.5 (the default), diamond 2.4
|
|
130
|
+
*/
|
|
131
|
+
ior?: number;
|
|
132
|
+
/**
|
|
133
|
+
* 0-1: scales a non-metal's reflections, 0 for none - chalk, clay (default 1)
|
|
134
|
+
*/
|
|
135
|
+
specularIntensity?: number;
|
|
136
|
+
/**
|
|
137
|
+
* tints a non-metal's reflections face on (default white)
|
|
138
|
+
*/
|
|
139
|
+
specularColor?: ColorInput;
|
|
140
|
+
/**
|
|
141
|
+
* 0-1: brushed metal - highlights drawn out along the brushing, which runs along
|
|
142
|
+
* the UVs' u (around the mesh where it has no UVs) (default 0)
|
|
143
|
+
*/
|
|
144
|
+
anisotropy?: number;
|
|
145
|
+
/**
|
|
146
|
+
* turns the brushing from the UVs' u, in radians (default 0)
|
|
147
|
+
*/
|
|
148
|
+
anisotropyRotation?: number;
|
|
149
|
+
/**
|
|
150
|
+
* 0-1: light through thin surfaces, lighting them from behind - leaves, paper,
|
|
151
|
+
* lampshades, curtains (default 0)
|
|
152
|
+
*/
|
|
153
|
+
translucency?: number;
|
|
154
|
+
/**
|
|
155
|
+
* tints the light that comes through (default white)
|
|
156
|
+
*/
|
|
157
|
+
translucencyColor?: ColorInput;
|
|
158
|
+
/**
|
|
159
|
+
* a picture of a lit sphere that gives the whole look - clay, wax, chrome,
|
|
160
|
+
* a painted ball - picked by which way the surface faces the camera. Lights, shadows and the environment are
|
|
161
|
+
* ignored; the colour and colour map multiply it
|
|
162
|
+
*/
|
|
163
|
+
matcap?: MapInput | null;
|
|
164
|
+
/**
|
|
165
|
+
* cartoon shading in this many flat tones (2 or more) with a hard-edged highlight;
|
|
166
|
+
* 0 (the default) is smooth
|
|
167
|
+
*/
|
|
168
|
+
toon?: number;
|
|
87
169
|
/**
|
|
88
170
|
* flat colour that ignores lights (default false)
|
|
89
171
|
*/
|
|
@@ -144,7 +226,17 @@ export declare class Material {
|
|
|
144
226
|
side: string;
|
|
145
227
|
wireframe: string;
|
|
146
228
|
shininess: string;
|
|
229
|
+
envMapIntensity: string;
|
|
230
|
+
reflectivityScale: string;
|
|
231
|
+
matcapMap: string;
|
|
232
|
+
gradientMap: string;
|
|
233
|
+
cel: string;
|
|
234
|
+
celShading: string;
|
|
147
235
|
specular: string;
|
|
236
|
+
reflectivity: string;
|
|
237
|
+
anisotropyStrength: string;
|
|
238
|
+
diffuseTransmission: string;
|
|
239
|
+
subsurface: string;
|
|
148
240
|
colour: string;
|
|
149
241
|
emissiveColor: string;
|
|
150
242
|
alpha: string;
|
|
@@ -159,6 +251,19 @@ export declare class Material {
|
|
|
159
251
|
/** @type {number} */ roughness: number;
|
|
160
252
|
/** @type {number} */ metalness: number;
|
|
161
253
|
/** @type {number} */ emissiveIntensity: number;
|
|
254
|
+
/** How much light passes through, as through glass: 0-1. @type {number} */ transmission: number;
|
|
255
|
+
/** A clear glossy layer over the surface: 0-1. @type {number} */ clearcoat: number;
|
|
256
|
+
/** How glossy the coat is, 0 a mirror. @type {number} */ clearcoatRoughness: number;
|
|
257
|
+
/** The soft bright rim of cloth: 0-1. @type {number} */ sheen: number;
|
|
258
|
+
/** A thin bright rim at 0, a broad soft glow at 1. @type {number} */ sheenRoughness: number;
|
|
259
|
+
/** Index of refraction: how strongly a non-metal reflects (1.5). @type {number} */ ior: number;
|
|
260
|
+
/** Scales a non-metal's reflections, 0-1. @type {number} */ specularIntensity: number;
|
|
261
|
+
/** Brushed metal: 0-1. @type {number} */ anisotropy: number;
|
|
262
|
+
/** Turns the brushing from the UVs' u, in radians. @type {number} */ anisotropyRotation: number;
|
|
263
|
+
/** Light through thin surfaces: 0-1. @type {number} */ translucency: number;
|
|
264
|
+
/** Cartoon shading in this many flat tones; 0 is smooth. @type {number} */ toon: number;
|
|
265
|
+
/** @type {number} */ lightMapIntensity: number;
|
|
266
|
+
/** This material's share of the environment's light and reflections. @type {number} */ environmentIntensity: number;
|
|
162
267
|
/** @type {boolean} */ unlit: boolean;
|
|
163
268
|
/** @type {boolean} */ flatShading: boolean;
|
|
164
269
|
/** @type {boolean} */ doubleSided: boolean;
|
|
@@ -180,6 +285,18 @@ export declare class Material {
|
|
|
180
285
|
get emissive(): Color;
|
|
181
286
|
/** @param {ColorInput} v */
|
|
182
287
|
set emissive(v: ColorInput);
|
|
288
|
+
/** The sheen's colour; assign any colour input. @returns {Color} */
|
|
289
|
+
get sheenColor(): Color;
|
|
290
|
+
/** @param {ColorInput} v */
|
|
291
|
+
set sheenColor(v: ColorInput);
|
|
292
|
+
/** Tints a non-metal's reflections face on; assign any colour input. @returns {Color} */
|
|
293
|
+
get specularColor(): Color;
|
|
294
|
+
/** @param {ColorInput} v */
|
|
295
|
+
set specularColor(v: ColorInput);
|
|
296
|
+
/** Tints the light that comes through a translucent surface; assign any colour input. @returns {Color} */
|
|
297
|
+
get translucencyColor(): Color;
|
|
298
|
+
/** @param {ColorInput} v */
|
|
299
|
+
set translucencyColor(v: ColorInput);
|
|
183
300
|
/** @returns {Texture | null} */
|
|
184
301
|
get map(): Texture | null;
|
|
185
302
|
/** @param {MapInput | null} v */
|
|
@@ -208,6 +325,14 @@ export declare class Material {
|
|
|
208
325
|
get emissiveMap(): Texture | null;
|
|
209
326
|
/** @param {MapInput | null} v */
|
|
210
327
|
set emissiveMap(v: MapInput | null);
|
|
328
|
+
/** Light baked into a texture. @returns {Texture | null} */
|
|
329
|
+
get lightMap(): Texture | null;
|
|
330
|
+
/** @param {MapInput | null} v */
|
|
331
|
+
set lightMap(v: MapInput | null);
|
|
332
|
+
/** A picture of a lit sphere that gives the whole look. @returns {Texture | null} */
|
|
333
|
+
get matcap(): Texture | null;
|
|
334
|
+
/** @param {MapInput | null} v */
|
|
335
|
+
set matcap(v: MapInput | null);
|
|
211
336
|
/** The maps that are set, by slot. @returns {[string, Texture][]} */
|
|
212
337
|
get textures(): [string, Texture][];
|
|
213
338
|
/** Rendered in the transparent pass: an opacity below 1, additive or multiply blending, or set for maps with soft alpha. @returns {boolean} */
|
|
@@ -11,7 +11,8 @@ export type TextureOptions = {
|
|
|
11
11
|
image?: TextureImage;
|
|
12
12
|
/**
|
|
13
13
|
* image to load (starts loading immediately in a browser); a .hdr file loads as
|
|
14
|
-
* linear HDR radiance, for scene.environment
|
|
14
|
+
* linear HDR radiance, for scene.environment; a video (.mp4, .webm, .ogv, .mov, .m4v) plays muted and on a
|
|
15
|
+
* loop, and texture.image is its <video> to pause, seek or unmute
|
|
15
16
|
*/
|
|
16
17
|
url?: string;
|
|
17
18
|
/**
|
|
@@ -31,12 +32,26 @@ export type TextureOptions = {
|
|
|
31
32
|
* [u, v] (default [0, 0])
|
|
32
33
|
*/
|
|
33
34
|
offset?: number[];
|
|
35
|
+
/**
|
|
36
|
+
* turns the image on the surface, in radians, about `center` (default 0)
|
|
37
|
+
*/
|
|
38
|
+
rotation?: number;
|
|
39
|
+
/**
|
|
40
|
+
* [u, v] the point rotation turns about, in repeated UVs (default [0, 0], the
|
|
41
|
+
* corner, as glTF has it; [0.5, 0.5] for the middle of an unrepeated image)
|
|
42
|
+
*/
|
|
43
|
+
center?: number[];
|
|
44
|
+
/**
|
|
45
|
+
* which UV set to read: 0 the first, 1 the second (Geometry uvs2) - baked occlusion
|
|
46
|
+
* and light maps usually come on the second (default 0)
|
|
47
|
+
*/
|
|
48
|
+
uvSet?: 0 | 1;
|
|
34
49
|
/**
|
|
35
50
|
* (default 'linear')
|
|
36
51
|
*/
|
|
37
52
|
filter?: 'linear' | 'nearest';
|
|
38
53
|
/**
|
|
39
|
-
* (default true)
|
|
54
|
+
* (default true; false for a video, which would make them every frame)
|
|
40
55
|
*/
|
|
41
56
|
mipmaps?: boolean;
|
|
42
57
|
/**
|
|
@@ -49,7 +64,10 @@ export type TextureOptions = {
|
|
|
49
64
|
*/
|
|
50
65
|
flipY?: boolean;
|
|
51
66
|
};
|
|
52
|
-
/**
|
|
67
|
+
/**
|
|
68
|
+
* An image for a material map. A video's frames upload by themselves as it plays; after drawing on
|
|
69
|
+
* a canvas, call `needsUpdate()`.
|
|
70
|
+
*/
|
|
53
71
|
export declare class Texture {
|
|
54
72
|
#private;
|
|
55
73
|
/** The options it takes, and hints for names people reach for instead. */
|
|
@@ -59,15 +77,22 @@ export declare class Texture {
|
|
|
59
77
|
encoding: string;
|
|
60
78
|
wrapS: string;
|
|
61
79
|
maxAnisotropy: string;
|
|
80
|
+
channel: string;
|
|
81
|
+
texCoord: string;
|
|
82
|
+
scale: string;
|
|
62
83
|
};
|
|
63
|
-
/** @type {TextureImage | null} null until loaded */
|
|
64
|
-
image: TextureImage | null;
|
|
65
84
|
/** @type {string | null} */
|
|
66
85
|
url: string | null;
|
|
67
86
|
/** @type {'repeat' | 'clamp' | 'mirror'} */
|
|
68
87
|
wrap: 'repeat' | 'clamp' | 'mirror';
|
|
69
88
|
repeat: number[];
|
|
70
89
|
offset: number[];
|
|
90
|
+
/** Turns the image on the surface, in radians, about `center`. */
|
|
91
|
+
rotation: number;
|
|
92
|
+
/** [u, v] the point rotation turns about, in repeated UVs. */
|
|
93
|
+
center: number[];
|
|
94
|
+
/** Which UV set it reads: 0 the first, 1 the second (Geometry uvs2). @type {0 | 1} */
|
|
95
|
+
uvSet: 0 | 1;
|
|
71
96
|
/** @type {'linear' | 'nearest'} */
|
|
72
97
|
filter: 'linear' | 'nearest';
|
|
73
98
|
mipmaps: boolean;
|
|
@@ -79,6 +104,13 @@ export declare class Texture {
|
|
|
79
104
|
/** @param {TextureOptions | string} [options] options, or just a url */
|
|
80
105
|
constructor(options?: TextureOptions | string);
|
|
81
106
|
/** Call after redrawing a canvas or advancing a video. @returns {this} */
|
|
107
|
+
/**
|
|
108
|
+
* The pixels: null until loaded. A <video>'s frames upload by themselves while it plays.
|
|
109
|
+
* @returns {TextureImage | null}
|
|
110
|
+
*/
|
|
111
|
+
get image(): TextureImage | null;
|
|
112
|
+
/** @param {TextureImage | null} v */
|
|
113
|
+
set image(v: TextureImage | null);
|
|
82
114
|
/** 'srgb' for colour (decoded to linear by the GPU), 'linear' for data such as normals and roughness. Call needsUpdate() after changing it. @returns {'srgb' | 'linear'} */
|
|
83
115
|
get colorSpace(): 'srgb' | 'linear';
|
|
84
116
|
set colorSpace(v: 'srgb' | 'linear');
|
|
@@ -29,6 +29,10 @@ export type WebGLRendererOptions = {
|
|
|
29
29
|
* multisampling (default true; a shared context always has it)
|
|
30
30
|
*/
|
|
31
31
|
antialias?: boolean;
|
|
32
|
+
/**
|
|
33
|
+
* soft-edged outlines with round corners (default: as antialias)
|
|
34
|
+
*/
|
|
35
|
+
outlineAntialias?: boolean;
|
|
32
36
|
/**
|
|
33
37
|
* how lit colours are mapped to the screen: 'neutral' keeps colours
|
|
34
38
|
* true (Khronos PBR Neutral, the default), 'aces' is filmic, 'none' clips
|
|
@@ -80,6 +84,8 @@ export declare class WebGLRenderer {
|
|
|
80
84
|
/** @type {ToneMapping} */ toneMapping: ToneMapping;
|
|
81
85
|
exposure: number;
|
|
82
86
|
pixelRatio: number;
|
|
87
|
+
/** Outlines with soft edges and round corners, or hard pixel steps; takes effect on the next frame. */
|
|
88
|
+
outlineAntialias: boolean;
|
|
83
89
|
/** Counts from the last frame and the GPU caches. */
|
|
84
90
|
info: {
|
|
85
91
|
drawCalls: number;
|
|
@@ -24,6 +24,30 @@ export type ShadowMap = {
|
|
|
24
24
|
sampler: string;
|
|
25
25
|
texture: WebGLTexture;
|
|
26
26
|
};
|
|
27
|
+
export type Target = {
|
|
28
|
+
texture: WebGLTexture;
|
|
29
|
+
framebuffer: WebGLFramebuffer;
|
|
30
|
+
};
|
|
31
|
+
export type OutlineTargets = {
|
|
32
|
+
width: number;
|
|
33
|
+
height: number;
|
|
34
|
+
smooth: boolean;
|
|
35
|
+
mask: Target;
|
|
36
|
+
wide: Target;
|
|
37
|
+
coverage: Target | null;
|
|
38
|
+
msaa: {
|
|
39
|
+
framebuffer: WebGLFramebuffer;
|
|
40
|
+
renderbuffers: WebGLRenderbuffer[];
|
|
41
|
+
} | null;
|
|
42
|
+
};
|
|
43
|
+
export type OutlineMask = {
|
|
44
|
+
mask: WebGLTexture;
|
|
45
|
+
wide: WebGLTexture;
|
|
46
|
+
coverage: WebGLTexture | null;
|
|
47
|
+
radius: number;
|
|
48
|
+
width: number;
|
|
49
|
+
height: number;
|
|
50
|
+
};
|
|
27
51
|
/**
|
|
28
52
|
* @typedef {object} Environment
|
|
29
53
|
* @property {WebGLTexture} source the HDR image, mipmapped
|
|
@@ -38,6 +62,12 @@ export type ShadowMap = {
|
|
|
38
62
|
* a pass that returns one of these.
|
|
39
63
|
* @typedef {{ define: string, uniforms: Record<string, unknown>, sampler: string, texture: WebGLTexture }} ShadowMap
|
|
40
64
|
*/
|
|
65
|
+
/**
|
|
66
|
+
* @typedef {{ texture: WebGLTexture, framebuffer: WebGLFramebuffer }} Target
|
|
67
|
+
* @typedef {{ width: number, height: number, smooth: boolean, mask: Target, wide: Target, coverage: Target | null,
|
|
68
|
+
* msaa: { framebuffer: WebGLFramebuffer, renderbuffers: WebGLRenderbuffer[] } | null }} OutlineTargets
|
|
69
|
+
* @typedef {{ mask: WebGLTexture, wide: WebGLTexture, coverage: WebGLTexture | null, radius: number, width: number, height: number }} OutlineMask
|
|
70
|
+
*/
|
|
41
71
|
export declare class Passes {
|
|
42
72
|
#private;
|
|
43
73
|
gl: WebGL2RenderingContext;
|
|
@@ -88,25 +118,19 @@ export declare class Passes {
|
|
|
88
118
|
* The first half of drawing outlines, before the scene: a mask of the outlined subtrees - each
|
|
89
119
|
* pixel they cover in their colour, with the line's width in alpha - then that mask widened
|
|
90
120
|
* sideways. outlineComposite() widens it up and down and draws the ring left round each mask.
|
|
121
|
+
* Smooth outlines draw the mask multisampled, with how much of each pixel it covers, and measure
|
|
122
|
+
* the ring from the shape's edge; otherwise each pixel is in or out.
|
|
91
123
|
* @param {FrameOutline[]} outlines @param {FrameDescription} frame
|
|
92
124
|
* @param {number} width @param {number} height drawing buffer pixels
|
|
93
125
|
* @param {number} pixelRatio
|
|
94
|
-
* @
|
|
126
|
+
* @param {boolean} smooth antialiased: soft edges and round corners
|
|
127
|
+
* @returns {OutlineMask}
|
|
95
128
|
*/
|
|
96
|
-
outlineMask(outlines: FrameOutline[], frame: FrameDescription, width: number, height: number, pixelRatio: number):
|
|
97
|
-
mask: WebGLTexture;
|
|
98
|
-
wide: WebGLTexture;
|
|
99
|
-
radius: number;
|
|
100
|
-
};
|
|
129
|
+
outlineMask(outlines: FrameOutline[], frame: FrameDescription, width: number, height: number, pixelRatio: number, smooth: boolean): OutlineMask;
|
|
101
130
|
/**
|
|
102
131
|
* Draw the outlines over the finished scene, into whatever is bound: the sideways-widened mask
|
|
103
132
|
* widened up and down too, less the mask itself, so a ring is left round each subtree.
|
|
104
|
-
* @param {
|
|
105
|
-
* @param {number} height drawing buffer pixels
|
|
133
|
+
* @param {OutlineMask} outline
|
|
106
134
|
*/
|
|
107
|
-
outlineComposite(outline:
|
|
108
|
-
mask: WebGLTexture;
|
|
109
|
-
wide: WebGLTexture;
|
|
110
|
-
radius: number;
|
|
111
|
-
}, height: number): void;
|
|
135
|
+
outlineComposite(outline: OutlineMask): void;
|
|
112
136
|
}
|
|
@@ -41,6 +41,26 @@ export type MeshBuffers = {
|
|
|
41
41
|
*/
|
|
42
42
|
layout?: string;
|
|
43
43
|
};
|
|
44
|
+
/**
|
|
45
|
+
* Per-vertex tangents along the UVs' u, with the way v runs in w (Lengyel's method): smooth where
|
|
46
|
+
* the normals are. Without UVs, around the mesh's up axis.
|
|
47
|
+
* @param {Geometry} g
|
|
48
|
+
* @returns {Float32Array}
|
|
49
|
+
*/
|
|
50
|
+
export declare function tangentsOf(g: Geometry): Float32Array;
|
|
51
|
+
/**
|
|
52
|
+
* A map's UV transform as a 3x3 (column-major): repeat, then rotation about its centre, then offset -
|
|
53
|
+
* glTF's KHR_texture_transform order, turning the way three.js and glTF viewers do. Written into one
|
|
54
|
+
* shared array, so set it as a uniform straight away.
|
|
55
|
+
* @param {{ repeat: number[], offset: number[], rotation: number, center: number[] }} t
|
|
56
|
+
* @returns {Float32Array}
|
|
57
|
+
*/
|
|
58
|
+
export declare function uvMatrix(t: {
|
|
59
|
+
repeat: number[];
|
|
60
|
+
offset: number[];
|
|
61
|
+
rotation: number;
|
|
62
|
+
center: number[];
|
|
63
|
+
}): Float32Array;
|
|
44
64
|
export declare class Resources {
|
|
45
65
|
#private;
|
|
46
66
|
/** @type {WebGL2RenderingContext} */ gl: WebGL2RenderingContext;
|
|
@@ -59,17 +79,19 @@ export declare class Resources {
|
|
|
59
79
|
* @param {Geometry} geometry
|
|
60
80
|
* @param {{ instanceMatrices: Float32Array, instanceColors: Float32Array | null, version: number } | null} instances
|
|
61
81
|
* @param {boolean} withNormals
|
|
82
|
+
* @param {boolean} [withTangents] add tangents, for brushed metal - kept once added
|
|
62
83
|
* @returns {MeshBuffers}
|
|
63
84
|
*/
|
|
64
85
|
mesh(geometry: Geometry, instances: {
|
|
65
86
|
instanceMatrices: Float32Array;
|
|
66
87
|
instanceColors: Float32Array | null;
|
|
67
88
|
version: number;
|
|
68
|
-
} | null, withNormals: boolean): MeshBuffers;
|
|
89
|
+
} | null, withNormals: boolean, withTangents?: boolean): MeshBuffers;
|
|
69
90
|
/**
|
|
70
91
|
* Draw a mesh's triangles - instanced or not, indexed or not - with the program in use, as far as
|
|
71
92
|
* its drawn count goes. Every pass that draws meshes draws them this way.
|
|
72
93
|
* @param {Geometry} geometry @param {{ instanceMatrices: Float32Array, instanceColors: Float32Array | null, version: number, count: number } | null} instances
|
|
94
|
+
* @param {boolean} [withTangents] for brushed metal
|
|
73
95
|
* @returns {number} triangles drawn
|
|
74
96
|
*/
|
|
75
97
|
drawTriangles(geometry: Geometry, instances: {
|
|
@@ -77,7 +99,7 @@ export declare class Resources {
|
|
|
77
99
|
instanceColors: Float32Array | null;
|
|
78
100
|
version: number;
|
|
79
101
|
count: number;
|
|
80
|
-
} | null): number;
|
|
102
|
+
} | null, withTangents?: boolean): number;
|
|
81
103
|
/**
|
|
82
104
|
* Vertex array for Lines: one instance per segment with its two endpoints (and colours),
|
|
83
105
|
* expanded to a screen-space quad in the vertex shader.
|
|
@@ -6,6 +6,8 @@ export declare const ATTRIBUTES: {
|
|
|
6
6
|
color: number;
|
|
7
7
|
instanceMatrix: number;
|
|
8
8
|
instanceColor: number;
|
|
9
|
+
tangent: number;
|
|
10
|
+
uv2: number;
|
|
9
11
|
segmentStart: number;
|
|
10
12
|
segmentEnd: number;
|
|
11
13
|
segmentColorStart: number;
|
|
@@ -14,12 +16,12 @@ export declare const ATTRIBUTES: {
|
|
|
14
16
|
};
|
|
15
17
|
export declare const CLIP = "\n#ifdef CLIP\nuniform vec4 uClipPlane; // world space, unit normal: cut away where dot(n, p) + d > 0\nvoid clipAway(vec3 p) {\n if (dot(uClipPlane.xyz, p) + uClipPlane.w > 0.0) discard;\n}\n#else\nvoid clipAway(vec3 p) {}\n#endif\n";
|
|
16
18
|
export declare const FOG = "\n#ifdef FOG\nuniform vec3 uFogColor; // linear\nuniform vec2 uFogRange; // linear fog: near, far\nuniform float uFogDensity; // exponential fog\nin float vFogDepth;\nvec3 fogged(vec3 c) {\n#ifdef FOG_LINEAR\n float f = clamp((vFogDepth - uFogRange.x) / max(uFogRange.y - uFogRange.x, 1e-4), 0.0, 1.0);\n#else\n float d = uFogDensity * vFogDepth;\n float f = 1.0 - exp(-d * d);\n#endif\n#ifdef FOG_ADD\n return c * (1.0 - f);\n#elif defined(FOG_MULTIPLY)\n // a filter in the fog fades to white, which leaves what is behind it as it was\n return mix(c, vec3(1.0), f);\n#else\n return mix(c, uFogColor, f);\n#endif\n}\n#else\nvec3 fogged(vec3 c) { return c; }\n#endif\n";
|
|
17
|
-
export declare const CLIP_ONLY_FRAGMENT
|
|
19
|
+
export declare const CLIP_ONLY_FRAGMENT: string;
|
|
18
20
|
export declare const COMMON = "\nvec3 srgbToLinear(vec3 c) {\n return mix(c / 12.92, pow((c + 0.055) / 1.055, vec3(2.4)), step(0.04045, c));\n}\nvec3 linearToSrgb(vec3 c) {\n c = clamp(c, 0.0, 1.0);\n return mix(c * 12.92, 1.055 * pow(c, vec3(1.0 / 2.4)) - 0.055, step(0.0031308, c));\n}\n";
|
|
19
21
|
export declare const EQUIRECT = "\nvec2 equirectUv(vec3 d) {\n return vec2(atan(d.z, d.x) * 0.15915494 + 0.5, acos(clamp(d.y, -1.0, 1.0)) * 0.31830989);\n}\nvec3 equirectDirection(vec2 uv) {\n float phi = (uv.x - 0.5) * 6.28318531, theta = uv.y * 3.14159265;\n return vec3(cos(phi) * sin(theta), cos(theta), sin(phi) * sin(theta));\n}\n";
|
|
20
22
|
export declare const FULLSCREEN_VERTEX = "\nout vec2 vUv;\nvoid main() {\n vec2 p = vec2(float((gl_VertexID << 1) & 2), float(gl_VertexID & 2));\n vUv = p;\n gl_Position = vec4(p * 2.0 - 1.0, 0.0, 1.0);\n}\n";
|
|
21
23
|
export declare const TONE_MAP = "\nuniform float uExposure;\nuniform int uToneMapping; // 0 none, 1 aces, 2 neutral\n\nvec3 toneMap(vec3 c) {\n c *= uExposure;\n if (uToneMapping == 1) {\n // ACES filmic, Narkowicz's fit\n c = clamp((c * (2.51 * c + 0.03)) / (c * (2.43 * c + 0.59) + 0.14), 0.0, 1.0);\n } else if (uToneMapping == 2) {\n // Khronos PBR Neutral\n float x = min(c.r, min(c.g, c.b));\n float offset = x < 0.08 ? x - 6.25 * x * x : 0.04;\n c -= offset;\n float peak = max(c.r, max(c.g, c.b));\n if (peak > 0.8) {\n float d = 0.2;\n float newPeak = 1.0 - d * d / (peak + d - 0.8);\n c *= newPeak / peak;\n float g = 1.0 - 1.0 / (0.15 * (peak - newPeak) + 1.0);\n c = mix(c, vec3(newPeak), g);\n }\n }\n return c;\n}\n";
|
|
22
|
-
export declare const MESH_VERTEX = "\nlayout(location = 0) in vec3 position;\nlayout(location = 1) in vec3 normal;\nlayout(location = 2) in vec2 uv;\nlayout(location = 3) in vec3 color;\n#ifdef INSTANCED\nlayout(location = 4) in mat4 instanceMatrix;\nlayout(location = 8) in vec3 instanceColor;\n#endif\n\nuniform mat4 uModel;\nuniform mat3 uNormalMatrix;\nuniform mat4 uViewProjection;\nuniform
|
|
24
|
+
export declare const MESH_VERTEX = "\nlayout(location = 0) in vec3 position;\nlayout(location = 1) in vec3 normal;\nlayout(location = 2) in vec2 uv;\nlayout(location = 3) in vec3 color;\n#ifdef INSTANCED\nlayout(location = 4) in mat4 instanceMatrix;\nlayout(location = 8) in vec3 instanceColor;\n#endif\n#ifdef ANISOTROPY\nlayout(location = 9) in vec4 tangent;\nout vec4 vTangent;\n#endif\n#ifdef UV2\nlayout(location = 10) in vec2 uv2;\nout vec2 vUv2;\n#endif\n\nuniform mat4 uModel;\nuniform mat3 uNormalMatrix;\nuniform mat4 uViewProjection;\nuniform int uHighlightIndex; // -2 none, -1 the whole node, otherwise the instance\n#ifdef FOG\nuniform mat4 uView;\nout float vFogDepth;\n#endif\n\nout vec3 vWorldPosition;\nout vec3 vNormal;\nout vec2 vUv;\nout vec3 vColor;\nflat out float vHighlight;\n#ifdef TRIPLANAR\n// the mesh's own space, so projected maps stay on it as it moves; and how its normals turn into the world\nout vec3 vObjectPosition;\nout vec3 vObjectNormal;\nout mat3 vObjectToWorld;\n#endif\n#ifdef PICK\nflat out uint vPickElement; // which instance, point or segment, for GPU picking\n#endif\n\n\nvec3 srgbToLinear(vec3 c) {\n return mix(c / 12.92, pow((c + 0.055) / 1.055, vec3(2.4)), step(0.04045, c));\n}\nvec3 linearToSrgb(vec3 c) {\n c = clamp(c, 0.0, 1.0);\n return mix(c * 12.92, 1.055 * pow(c, vec3(1.0 / 2.4)) - 0.055, step(0.0031308, c));\n}\n\n\n// Matrices times vectors only - a matrix times a matrix per vertex is four times the work, and\n// with 100,000 instances the vertex stage is most of the frame.\nvoid main() {\n vColor = vec3(1.0);\n vHighlight = uHighlightIndex == -1 ? 1.0 : 0.0;\n#ifdef INSTANCED\n vec4 local = instanceMatrix * vec4(position, 1.0);\n // the instance's normal matrix as its cofactor: the inverse transpose up to scale, from three\n // cross products, flipped back for mirroring transforms\n mat3 m = mat3(instanceMatrix);\n mat3 instanceNormal = mat3(cross(m[1], m[2]), cross(m[2], m[0]), cross(m[0], m[1])) * sign(dot(m[0], cross(m[1], m[2])));\n vec3 n = instanceNormal * normal;\n vColor *= instanceColor;\n if (gl_InstanceID == uHighlightIndex) vHighlight = 1.0;\n#else\n vec4 local = vec4(position, 1.0);\n vec3 n = normal;\n#endif\n#ifdef VERTEX_COLORS\n vColor *= srgbToLinear(color);\n#endif\n vec4 world = uModel * local;\n vWorldPosition = world.xyz;\n vNormal = uNormalMatrix * n;\n vUv = uv;\n#ifdef UV2\n vUv2 = uv2;\n#endif\n#ifdef ANISOTROPY\n // a direction along the surface, so it turns as the model does\n#ifdef INSTANCED\n vTangent = vec4(mat3(uModel) * (m * tangent.xyz), tangent.w);\n#else\n vTangent = vec4(mat3(uModel) * tangent.xyz, tangent.w);\n#endif\n#endif\n#ifdef TRIPLANAR\n vObjectPosition = position;\n vObjectNormal = normal;\n#ifdef INSTANCED\n vObjectToWorld = uNormalMatrix * instanceNormal;\n#else\n vObjectToWorld = uNormalMatrix;\n#endif\n#endif\n gl_Position = uViewProjection * world;\n#ifdef FOG\n vFogDepth = -(uView * world).z;\n#endif\n#ifdef PICK\n vPickElement = uint(gl_InstanceID);\n#endif\n}\n";
|
|
23
25
|
export declare const POINTS_VERTEX = "\nlayout(location = 0) in vec3 position;\nlayout(location = 3) in vec3 color;\n\nuniform mat4 uModel;\nuniform mat4 uView;\nuniform mat4 uProjection;\nuniform float uSize; // pixels (with the pixel ratio applied), or world units when attenuated\nuniform float uScale; // projection focal term x half the buffer height: world size -> pixels at depth 1\nuniform int uHighlightIndex; // -2 none, -1 every point, otherwise the point\n\nout vec3 vColor;\nflat out float vHighlight;\n#ifdef PICK\nflat out uint vPickElement; // which instance, point or segment, for GPU picking\n#endif\n#ifdef FOG\nout float vFogDepth;\n#endif\n\n\nvec3 srgbToLinear(vec3 c) {\n return mix(c / 12.92, pow((c + 0.055) / 1.055, vec3(2.4)), step(0.04045, c));\n}\nvec3 linearToSrgb(vec3 c) {\n c = clamp(c, 0.0, 1.0);\n return mix(c * 12.92, 1.055 * pow(c, vec3(1.0 / 2.4)) - 0.055, step(0.0031308, c));\n}\n\n\nvoid main() {\n vec4 viewPosition = uView * (uModel * vec4(position, 1.0));\n gl_Position = uProjection * viewPosition;\n#ifdef FOG\n vFogDepth = -viewPosition.z;\n#endif\n#ifdef SIZE_ATTENUATION\n // perspective shrinks with distance; an orthographic projection (w row 0, 0, 0, 1) doesn't\n float depth = uProjection[3][3] == 1.0 ? 1.0 : max(-viewPosition.z, 1e-4);\n gl_PointSize = uSize * uScale / depth;\n#else\n gl_PointSize = uSize;\n#endif\n vColor = vec3(1.0);\n#ifdef VERTEX_COLORS\n vColor = srgbToLinear(color);\n#endif\n vHighlight = uHighlightIndex == -1 || gl_VertexID == uHighlightIndex ? 1.0 : 0.0;\n#ifdef PICK\n vPickElement = uint(gl_VertexID);\n#endif\n}\n";
|
|
24
26
|
export declare const LINES_VERTEX = "\nlayout(location = 0) in vec3 segmentStart;\nlayout(location = 1) in vec3 segmentEnd;\nlayout(location = 2) in vec3 segmentColorStart;\nlayout(location = 3) in vec3 segmentColorEnd;\nlayout(location = 4) in vec2 corner; // x: 0 at start, 1 at end; y: -1 or 1 across\n\nuniform mat4 uModel;\nuniform mat4 uView;\nuniform mat4 uProjection;\nuniform vec2 uResolution; // drawing buffer size in pixels\nuniform float uWidth; // pixels, already scaled by the pixel ratio\nuniform float uNear;\n\nout vec3 vColor;\n#ifdef PICK\nflat out uint vPickElement; // which instance, point or segment, for GPU picking\n#endif\n#ifdef FOG\nout float vFogDepth;\n#endif\n\n\nvec3 srgbToLinear(vec3 c) {\n return mix(c / 12.92, pow((c + 0.055) / 1.055, vec3(2.4)), step(0.04045, c));\n}\nvec3 linearToSrgb(vec3 c) {\n c = clamp(c, 0.0, 1.0);\n return mix(c * 12.92, 1.055 * pow(c, vec3(1.0 / 2.4)) - 0.055, step(0.0031308, c));\n}\n\n\nvoid main() {\n vec4 a = uView * (uModel * vec4(segmentStart, 1.0));\n vec4 b = uView * (uModel * vec4(segmentEnd, 1.0));\n // clip the segment to the near plane so lines passing behind the camera stay correct\n float clipZ = -uNear;\n if (a.z > clipZ && b.z > clipZ) {\n gl_Position = vec4(2.0, 2.0, 2.0, 1.0); // wholly behind: off screen\n return;\n }\n if (a.z > clipZ) a = mix(a, b, (clipZ - a.z) / (b.z - a.z));\n if (b.z > clipZ) b = mix(b, a, (clipZ - b.z) / (a.z - b.z));\n\n vec4 ca = uProjection * a;\n vec4 cb = uProjection * b;\n vec2 sa = ca.xy / ca.w * uResolution * 0.5;\n vec2 sb = cb.xy / cb.w * uResolution * 0.5;\n vec2 dir = sb - sa;\n float len = length(dir);\n dir = len > 0.0 ? dir / len : vec2(1.0, 0.0);\n vec2 normal = vec2(-dir.y, dir.x);\n\n vec4 clip = mix(ca, cb, corner.x);\n#ifdef FOG\n vFogDepth = -mix(a.z, b.z, corner.x);\n#endif\n // extend past each end by half the width so joins look continuous\n vec2 offset = normal * corner.y * uWidth * 0.5 + dir * (corner.x * 2.0 - 1.0) * uWidth * 0.5;\n clip.xy += offset / (uResolution * 0.5) * clip.w;\n gl_Position = clip;\n#ifdef PICK\n vPickElement = uint(gl_InstanceID);\n#endif\n\n vColor = vec3(1.0);\n#ifdef VERTEX_COLORS\n vColor = srgbToLinear(mix(segmentColorStart, segmentColorEnd, corner.x));\n#endif\n}\n";
|
|
25
27
|
export type ShaderKind = 'mesh' | 'points' | 'lines';
|