@kitware/vtk.js 25.1.3 → 25.2.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/Rendering/Core/Light.d.ts +36 -2
- package/Rendering/Core/Light.js +10 -4
- package/Rendering/Core/Property.d.ts +120 -0
- package/Rendering/Core/Property.js +17 -1
- package/Rendering/Core/Texture.js +31 -0
- package/Rendering/WebGPU/CellArrayMapper.js +205 -52
- package/Rendering/WebGPU/Glyph3DMapper.js +2 -1
- package/Rendering/WebGPU/Renderer.js +109 -4
- package/Rendering/WebGPU/SphereMapper.js +2 -2
- package/Rendering/WebGPU/StickMapper.js +2 -2
- package/Rendering/WebGPU/Texture.js +6 -2
- package/package.json +1 -1
|
@@ -5,7 +5,7 @@ import { RGBColor, Vector3 } from './../../types';
|
|
|
5
5
|
export enum LIGHT_TYPES {
|
|
6
6
|
'HeadLight',
|
|
7
7
|
'CameraLight',
|
|
8
|
-
'SceneLight'
|
|
8
|
+
'SceneLight',
|
|
9
9
|
}
|
|
10
10
|
|
|
11
11
|
export interface ILightInitialValues {
|
|
@@ -17,6 +17,7 @@ export interface ILightInitialValues {
|
|
|
17
17
|
positional?: boolean;
|
|
18
18
|
exponent?: number;
|
|
19
19
|
coneAngle?: number;
|
|
20
|
+
coneFalloff?: number;
|
|
20
21
|
attenuationValues?: number[];
|
|
21
22
|
lightType?: LIGHT_TYPES;
|
|
22
23
|
shadowAttenuation?: number;
|
|
@@ -54,6 +55,15 @@ export interface vtkLight extends vtkObject {
|
|
|
54
55
|
*/
|
|
55
56
|
getConeAngle(): number;
|
|
56
57
|
|
|
58
|
+
/**
|
|
59
|
+
* Get the lighting falloff angle of a positional light in degrees.
|
|
60
|
+
* This is the angle that sets how much the cone will be extended to
|
|
61
|
+
* smooth the border. A value of 0 indicates that the spot light will
|
|
62
|
+
* have a completely sharp edge (this does not mean completely sharp
|
|
63
|
+
* lighting, just that the border will be sharp).
|
|
64
|
+
*/
|
|
65
|
+
getConeFalloff(): number;
|
|
66
|
+
|
|
57
67
|
/**
|
|
58
68
|
* Set the position and focal point of a light based on elevation and azimuth.
|
|
59
69
|
* The light is moved so it is shining from the given angle. Angles are
|
|
@@ -174,6 +184,16 @@ export interface vtkLight extends vtkObject {
|
|
|
174
184
|
*/
|
|
175
185
|
setConeAngle(coneAngle: number): boolean;
|
|
176
186
|
|
|
187
|
+
/**
|
|
188
|
+
* Set the lighting falloff angle of a positional light in degrees.
|
|
189
|
+
* This is the angle that sets how much the cone will be extended to
|
|
190
|
+
* smooth the border. A value of 0 indicates that the spot light will
|
|
191
|
+
* have a completely sharp edge (this does not mean completely sharp
|
|
192
|
+
* lighting, just that the border will be sharp).
|
|
193
|
+
* @param {Number} coneFalloff The cone falloff angle.
|
|
194
|
+
*/
|
|
195
|
+
setConeFalloff(coneFalloff: number): boolean;
|
|
196
|
+
|
|
177
197
|
/**
|
|
178
198
|
* Set the position and focal point of a light based on elevation and
|
|
179
199
|
* azimuth. The light is moved so it is shining from the given angle. Angles
|
|
@@ -184,6 +204,20 @@ export interface vtkLight extends vtkObject {
|
|
|
184
204
|
*/
|
|
185
205
|
setDirectionAngle(elevation: number, azimuth: number): boolean;
|
|
186
206
|
|
|
207
|
+
/**
|
|
208
|
+
* Set the direction vector of the light from X, Y, and Z values
|
|
209
|
+
* @param {Number} x The x coordinate.
|
|
210
|
+
* @param {Number} y The y coordinate.
|
|
211
|
+
* @param {Number} z The z coordinate.
|
|
212
|
+
*/
|
|
213
|
+
setDirection(x: number, y: number, z: number): boolean;
|
|
214
|
+
|
|
215
|
+
/**
|
|
216
|
+
* Set the direction vector of the light from X, Y, and Z values
|
|
217
|
+
* @param {Vector3} direction
|
|
218
|
+
*/
|
|
219
|
+
setDirection(direction: Vector3): boolean;
|
|
220
|
+
|
|
187
221
|
/**
|
|
188
222
|
* Set the exponent of the cosine used in positional lighting.
|
|
189
223
|
* @param {Number} exponent The exponent of the cosine.
|
|
@@ -299,7 +333,7 @@ export function extend(publicAPI: object, model: object, initialValues?: ILightI
|
|
|
299
333
|
/**
|
|
300
334
|
* Method use to create a new instance of vtkLight with the focal point at the origin and its position
|
|
301
335
|
* set to [0, 0, 1]. The light is a SceneLight, its color is white, intensity=1, the light is turned on,
|
|
302
|
-
* positional lighting is off, coneAngle=30, AttenuationValues=[1, 0, 0], exponent=1 and the transformMatrix is null.
|
|
336
|
+
* positional lighting is off, coneAngle=30, coneFalloff=5, AttenuationValues=[1, 0, 0], exponent=1 and the transformMatrix is null.
|
|
303
337
|
* @param {ILightInitialValues} [initialValues] for pre-setting some of its content
|
|
304
338
|
*/
|
|
305
339
|
export function newInstance(initialValues?: ILightInitialValues): vtkLight;
|
package/Rendering/Core/Light.js
CHANGED
|
@@ -33,14 +33,19 @@ function vtkLight(publicAPI, model) {
|
|
|
33
33
|
|
|
34
34
|
publicAPI.getDirection = function () {
|
|
35
35
|
if (model.directionMTime < model.mtime) {
|
|
36
|
-
model.direction
|
|
37
|
-
model.direction[1] = model.focalPoint[1] - model.position[1];
|
|
38
|
-
model.direction[2] = model.focalPoint[2] - model.position[2];
|
|
36
|
+
vec3.sub(model.direction, model.focalPoint, model.position);
|
|
39
37
|
normalize(model.direction);
|
|
40
38
|
model.directionMTime = model.mtime;
|
|
41
39
|
}
|
|
42
40
|
|
|
43
41
|
return model.direction;
|
|
42
|
+
}; // Sets the direction from a vec3 instead of a focal point
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
publicAPI.setDirection = function (directionVector) {
|
|
46
|
+
var newFocalPoint = new Float64Array(3);
|
|
47
|
+
vec3.sub(newFocalPoint, model.position, directionVector);
|
|
48
|
+
model.focalPoint = newFocalPoint;
|
|
44
49
|
};
|
|
45
50
|
|
|
46
51
|
publicAPI.setDirectionAngle = function (elevation, azimuth) {
|
|
@@ -89,6 +94,7 @@ var DEFAULT_VALUES = {
|
|
|
89
94
|
positional: false,
|
|
90
95
|
exponent: 1,
|
|
91
96
|
coneAngle: 30,
|
|
97
|
+
coneFalloff: 5,
|
|
92
98
|
attenuationValues: [1, 0, 0],
|
|
93
99
|
transformMatrix: null,
|
|
94
100
|
lightType: 'SceneLight',
|
|
@@ -102,7 +108,7 @@ function extend(publicAPI, model) {
|
|
|
102
108
|
Object.assign(model, DEFAULT_VALUES, initialValues); // Build VTK API
|
|
103
109
|
|
|
104
110
|
macro.obj(publicAPI, model);
|
|
105
|
-
macro.setGet(publicAPI, model, ['intensity', 'switch', 'positional', 'exponent', 'coneAngle', 'transformMatrix', 'lightType', 'shadowAttenuation', 'attenuationValues']);
|
|
111
|
+
macro.setGet(publicAPI, model, ['intensity', 'switch', 'positional', 'exponent', 'coneAngle', 'coneFalloff', 'transformMatrix', 'lightType', 'shadowAttenuation', 'attenuationValues']);
|
|
106
112
|
macro.setGetArray(publicAPI, model, ['color', 'position', 'focalPoint', 'attenuationValues'], 3); // Object methods
|
|
107
113
|
|
|
108
114
|
vtkLight(publicAPI, model);
|
|
@@ -1,15 +1,27 @@
|
|
|
1
1
|
import { vtkObject } from './../../interfaces';
|
|
2
2
|
import { RGBColor } from './../../types';
|
|
3
3
|
import { Interpolation, Representation, Shading } from './Property/Constants';
|
|
4
|
+
import { vtkTexture } from './Texture';
|
|
4
5
|
|
|
5
6
|
export interface IPropertyInitialValues {
|
|
6
7
|
color?: RGBColor;
|
|
7
8
|
ambientColor?: RGBColor;
|
|
8
9
|
diffuseColor?: RGBColor;
|
|
9
10
|
specularColor?: RGBColor;
|
|
11
|
+
diffuseTexture?: vtkTexture;
|
|
12
|
+
metallicTexture?: vtkTexture;
|
|
13
|
+
roughnessTexture?: vtkTexture;
|
|
14
|
+
normalTexture?: vtkTexture;
|
|
15
|
+
ambientOcclusionTexture?: vtkTexture;
|
|
16
|
+
emissionTexture?: vtkTexture;
|
|
10
17
|
edgeColor?: RGBColor;
|
|
11
18
|
ambient?: number;
|
|
12
19
|
diffuse?: number;
|
|
20
|
+
metallic?: number;
|
|
21
|
+
roughness?: number;
|
|
22
|
+
normalStrength?: number;
|
|
23
|
+
emission?: number;
|
|
24
|
+
baseIOR?: number;
|
|
13
25
|
specular?: number;
|
|
14
26
|
specularPower?: number;
|
|
15
27
|
opacity?: number;
|
|
@@ -161,6 +173,36 @@ export interface vtkProperty extends vtkObject {
|
|
|
161
173
|
*/
|
|
162
174
|
getSpecular(): number;
|
|
163
175
|
|
|
176
|
+
/**
|
|
177
|
+
* Get the roughness coefficient.
|
|
178
|
+
* @default 1
|
|
179
|
+
*/
|
|
180
|
+
getRoughness(): number;
|
|
181
|
+
|
|
182
|
+
/**
|
|
183
|
+
* Get the metallic coefficient.
|
|
184
|
+
* @default 0
|
|
185
|
+
*/
|
|
186
|
+
getMetallic(): number;
|
|
187
|
+
|
|
188
|
+
/**
|
|
189
|
+
* Get the index of refraction.
|
|
190
|
+
* @default 0
|
|
191
|
+
*/
|
|
192
|
+
getBaseIOR(): number;
|
|
193
|
+
|
|
194
|
+
/**
|
|
195
|
+
* Get the strength of the normal map.
|
|
196
|
+
* @default 1
|
|
197
|
+
*/
|
|
198
|
+
getNormalStrength(): number;
|
|
199
|
+
|
|
200
|
+
/**
|
|
201
|
+
* Get the emission coefficient.
|
|
202
|
+
* @default 0
|
|
203
|
+
*/
|
|
204
|
+
getEmission(): number;
|
|
205
|
+
|
|
164
206
|
/**
|
|
165
207
|
* Get the specular surface color.
|
|
166
208
|
* @return {RGBColor} Array of RGB color.
|
|
@@ -178,6 +220,36 @@ export interface vtkProperty extends vtkObject {
|
|
|
178
220
|
*/
|
|
179
221
|
getSpecularPower(): number;
|
|
180
222
|
|
|
223
|
+
/**
|
|
224
|
+
* Get the diffuse texture.
|
|
225
|
+
*/
|
|
226
|
+
getDiffuseTexture(): vtkTexture;
|
|
227
|
+
|
|
228
|
+
/**
|
|
229
|
+
* Get the metallic texture.
|
|
230
|
+
*/
|
|
231
|
+
getMetallicTexture(): vtkTexture;
|
|
232
|
+
|
|
233
|
+
/**
|
|
234
|
+
* Get the roughness texture.
|
|
235
|
+
*/
|
|
236
|
+
getRoughnessTexture(): vtkTexture;
|
|
237
|
+
|
|
238
|
+
/**
|
|
239
|
+
* Get the normal texture.
|
|
240
|
+
*/
|
|
241
|
+
getNormalTexture(): vtkTexture;
|
|
242
|
+
|
|
243
|
+
/**
|
|
244
|
+
* Get the ambient occlusion texture.
|
|
245
|
+
*/
|
|
246
|
+
getAmbientOcclusionTexture(): vtkTexture;
|
|
247
|
+
|
|
248
|
+
/**
|
|
249
|
+
* Get the emission texture.
|
|
250
|
+
*/
|
|
251
|
+
getEmissionTexture(): vtkTexture;
|
|
252
|
+
|
|
181
253
|
/**
|
|
182
254
|
* Set the ambient lighting coefficient.
|
|
183
255
|
* @param {Number} ambient The ambient lighting coefficient.
|
|
@@ -385,6 +457,18 @@ export interface vtkProperty extends vtkObject {
|
|
|
385
457
|
*/
|
|
386
458
|
setSpecular(specular: number): boolean;
|
|
387
459
|
|
|
460
|
+
/**
|
|
461
|
+
* Set the normal map strength.
|
|
462
|
+
* @param {Boolean} normal
|
|
463
|
+
*/
|
|
464
|
+
setNormalStrength(normalStrength: number): boolean;
|
|
465
|
+
|
|
466
|
+
/**
|
|
467
|
+
* Set the ambient occlusion map strength.
|
|
468
|
+
* @param {Boolean} emission
|
|
469
|
+
*/
|
|
470
|
+
setEmission(emission: number): boolean;
|
|
471
|
+
|
|
388
472
|
/**
|
|
389
473
|
* Set the specular surface color.
|
|
390
474
|
* @param {Number} r Defines the red component (between 0 and 1)
|
|
@@ -410,6 +494,42 @@ export interface vtkProperty extends vtkObject {
|
|
|
410
494
|
* @param {Number} specularPower
|
|
411
495
|
*/
|
|
412
496
|
setSpecularPower(specularPower: number): boolean;
|
|
497
|
+
|
|
498
|
+
/**
|
|
499
|
+
* Set the diffuse texture.
|
|
500
|
+
* @param {vtkTexture} diffuseTexture
|
|
501
|
+
*/
|
|
502
|
+
setDiffuseTexture(diffuseTexture: vtkTexture): boolean;
|
|
503
|
+
|
|
504
|
+
/**
|
|
505
|
+
* Set the metallic texture.
|
|
506
|
+
* @param {vtkTexture} metallicTexture
|
|
507
|
+
*/
|
|
508
|
+
setMetallicTexture(metallicTexture: vtkTexture): boolean;
|
|
509
|
+
|
|
510
|
+
/**
|
|
511
|
+
* Set the roughness texture.
|
|
512
|
+
* @param {vtkTexture} roughnessTexture
|
|
513
|
+
*/
|
|
514
|
+
setRoughnessTexture(roughnessTexture: vtkTexture): boolean;
|
|
515
|
+
|
|
516
|
+
/**
|
|
517
|
+
* Set the normal texture.
|
|
518
|
+
* @param {vtkTexture} normalTexture
|
|
519
|
+
*/
|
|
520
|
+
setNormalTexture(normalTexture: vtkTexture): boolean;
|
|
521
|
+
|
|
522
|
+
/**
|
|
523
|
+
* Set the ambient occlusion texture.
|
|
524
|
+
* @param {vtkTexture} ambientOcclusionTexture
|
|
525
|
+
*/
|
|
526
|
+
setAmbientOcclusionTexture(ambientOcclusionTexture: vtkTexture): boolean;
|
|
527
|
+
|
|
528
|
+
/**
|
|
529
|
+
* Set the emission texture.
|
|
530
|
+
* @param {vtkTexture} emissionTexture
|
|
531
|
+
*/
|
|
532
|
+
setEmissionTexture(emissionTexture: vtkTexture): boolean;
|
|
413
533
|
}
|
|
414
534
|
|
|
415
535
|
/**
|
|
@@ -58,6 +58,17 @@ function vtkProperty(publicAPI, model) {
|
|
|
58
58
|
return [].concat(model.color);
|
|
59
59
|
};
|
|
60
60
|
|
|
61
|
+
publicAPI.setSpecularPower = function (specularPower) {
|
|
62
|
+
var roughness = 1 / Math.max(1.0, specularPower);
|
|
63
|
+
|
|
64
|
+
if (model.roughness !== roughness || model.specularPower !== specularPower) {
|
|
65
|
+
model.specularPower = specularPower; // Specular power still needs to be set as long as webgl is using it (otherwise testShaderReplacementsClear fails)
|
|
66
|
+
|
|
67
|
+
model.roughness = roughness;
|
|
68
|
+
publicAPI.modified();
|
|
69
|
+
}
|
|
70
|
+
};
|
|
71
|
+
|
|
61
72
|
publicAPI.addShaderVariable = notImplemented('AddShaderVariable');
|
|
62
73
|
|
|
63
74
|
publicAPI.setInterpolationToFlat = function () {
|
|
@@ -104,6 +115,11 @@ var DEFAULT_VALUES = {
|
|
|
104
115
|
edgeColor: [0, 0, 0],
|
|
105
116
|
ambient: 0,
|
|
106
117
|
diffuse: 1,
|
|
118
|
+
metallic: 0,
|
|
119
|
+
roughness: 0.6,
|
|
120
|
+
normalStrength: 1,
|
|
121
|
+
emission: 1,
|
|
122
|
+
baseIOR: 1.45,
|
|
107
123
|
specular: 0,
|
|
108
124
|
specularPower: 1,
|
|
109
125
|
opacity: 1,
|
|
@@ -124,7 +140,7 @@ function extend(publicAPI, model) {
|
|
|
124
140
|
Object.assign(model, DEFAULT_VALUES, initialValues); // Build VTK API
|
|
125
141
|
|
|
126
142
|
macro.obj(publicAPI, model);
|
|
127
|
-
macro.setGet(publicAPI, model, ['lighting', 'interpolation', 'ambient', 'diffuse', 'specular', 'specularPower', 'opacity', 'edgeVisibility', 'lineWidth', 'pointSize', 'backfaceCulling', 'frontfaceCulling', 'representation']);
|
|
143
|
+
macro.setGet(publicAPI, model, ['lighting', 'interpolation', 'ambient', 'diffuse', 'metallic', 'roughness', 'normalStrength', 'emission', 'baseIOR', 'specular', 'specularPower', 'opacity', 'edgeVisibility', 'lineWidth', 'pointSize', 'backfaceCulling', 'frontfaceCulling', 'representation', 'diffuseTexture', 'metallicTexture', 'roughnessTexture', 'normalTexture', 'ambientOcclusionTexture', 'emissionTexture']);
|
|
128
144
|
macro.setGetArray(publicAPI, model, ['ambientColor', 'specularColor', 'diffuseColor', 'edgeColor'], 3); // Object methods
|
|
129
145
|
|
|
130
146
|
vtkProperty(publicAPI, model);
|
|
@@ -72,6 +72,37 @@ function vtkTexture(publicAPI, model) {
|
|
|
72
72
|
|
|
73
73
|
publicAPI.modified();
|
|
74
74
|
};
|
|
75
|
+
|
|
76
|
+
publicAPI.getDimensionality = function () {
|
|
77
|
+
var width = 0;
|
|
78
|
+
var height = 0;
|
|
79
|
+
var depth = 1;
|
|
80
|
+
|
|
81
|
+
if (publicAPI.getInputData()) {
|
|
82
|
+
var data = publicAPI.getInputData();
|
|
83
|
+
width = data.getDimensions()[0];
|
|
84
|
+
height = data.getDimensions()[1];
|
|
85
|
+
depth = data.getDimensions()[2];
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
if (model.jsImageData) {
|
|
89
|
+
width = model.jsImageData.width;
|
|
90
|
+
height = model.jsImageData.height;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
if (model.canvas) {
|
|
94
|
+
width = model.canvas.width;
|
|
95
|
+
height = model.canvas.height;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
if (model.image) {
|
|
99
|
+
width = model.image.width;
|
|
100
|
+
height = model.image.height;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
var dimensionality = (width > 1) + (height > 1) + (depth > 1);
|
|
104
|
+
return dimensionality;
|
|
105
|
+
};
|
|
75
106
|
} // ----------------------------------------------------------------------------
|
|
76
107
|
// Object factory
|
|
77
108
|
// ----------------------------------------------------------------------------
|
|
@@ -18,7 +18,7 @@ var ScalarMode = vtkMapper.ScalarMode;
|
|
|
18
18
|
var CoordinateSystem = vtkProp.CoordinateSystem;
|
|
19
19
|
var DisplayLocation = vtkProperty2D.DisplayLocation;
|
|
20
20
|
var vtkWebGPUPolyDataVS = "\n//VTK::Renderer::Dec\n\n//VTK::Color::Dec\n\n//VTK::Normal::Dec\n\n//VTK::TCoord::Dec\n\n//VTK::Select::Dec\n\n//VTK::Mapper::Dec\n\n//VTK::IOStructs::Dec\n\n@vertex\nfn main(\n//VTK::IOStructs::Input\n)\n//VTK::IOStructs::Output\n{\n var output : vertexOutput;\n\n var vertex: vec4<f32> = vertexBC;\n\n //VTK::Color::Impl\n\n //VTK::Normal::Impl\n\n //VTK::TCoord::Impl\n\n //VTK::Select::Impl\n\n //VTK::Position::Impl\n\n return output;\n}\n";
|
|
21
|
-
var vtkWebGPUPolyDataFS = "\n//VTK::Renderer::Dec\n\n//VTK::Color::Dec\n\n// optional surface normal declaration\n//VTK::Normal::Dec\n\n//VTK::
|
|
21
|
+
var vtkWebGPUPolyDataFS = "\nstruct PBRData {\n diffuse: vec3<f32>,\n specular: vec3<f32>,\n}\n\n// Dot product with the max already in it\nfn mdot(a: vec3<f32>, b: vec3<f32>) -> f32 {\n return max(0.0, dot(a, b));\n}\n\n// Lambertian diffuse model\nfn lambertDiffuse(base: vec3<f32>, N: vec3<f32>, L: vec3<f32>) -> vec3<f32> {\n var pi: f32 = 3.14159265359; \n var NdotL: f32 = mdot(N, L);\n NdotL = pow(NdotL, 1.5);\n return (base/pi)*NdotL;\n}\n\n// Yasuhiro Fujii improvement on the Oren-Nayar model\n// https://mimosa-pudica.net/improved-oren-nayar.html\n// p is surface color, o is roughness\nfn fujiiOrenNayar(p: vec3<f32>, o: f32, N: vec3<f32>, L: vec3<f32>, V: vec3<f32>) -> vec3<f32> {\n var invpi: f32 = 0.31830988618; // 1/pi\n\n var o2 = o*o;\n var NdotL: f32 = mdot(N, L);\n NdotL = pow(NdotL, 1.5); // Less physically accurate, but hides the \"seams\" between lights better\n\n var NdotV: f32 = mdot(N, V);\n var LdotV: f32 = mdot(L, V);\n\n var s: f32 = LdotV - NdotL*NdotV;\n var t: f32 = mix(1, max(NdotL, NdotV), step(0, s)); // Mix with step is the equivalent of an if statement\n var A: vec3<f32> = 0.5*(o2 / (o2 + 0.33)) + 0.17*p*(o2 / (o2 + 0.13));\n A = invpi*(1 - A);\n var B: f32 = 0.45*(o2 / (o2 + 0.09));\n B = invpi*B;\n\n return p*NdotL*(A + B*(s/t));\n}\n\n// Fresnel portion of BRDF (IOR only, simplified)\nfn schlickFresnelIOR(V: vec3<f32>, N: vec3<f32>, ior: f32, k: f32) -> f32 {\n var NdotV: f32 = mdot(V, N);\n // var R0: f32 = pow((ior - 1.0) / (ior + 1.0), 2); // 1.0 is about the ior of air, and it is assumed that light will be traveling through air\n var F0: f32 = (pow((ior - 1.0), 2) + k*k) / (pow((ior + 1.0), 2) + k*k); // This takes into account the roughness, whic the other one does not\n return F0 + (1 - F0) * pow((1-NdotV), 5); \n}\n\n// Fresnel portion of BRDF (Color ior, better)\nfn schlickFresnelRGB(V: vec3<f32>, N: vec3<f32>, F0: vec3<f32>) -> vec3<f32> {\n var NdotV: f32 = mdot(V, N);\n return F0 + (1 - F0) * pow((1-NdotV), 5); \n}\n\n// Normal portion of BRDF\n// https://learnopengl.com/PBR/Theory\n// Trowbridge-Reitz GGX functions: normal, halfway, roughness^2\nfn trGGX(N: vec3<f32>, H: vec3<f32>, a: f32) -> f32 {\n var pi: f32 = 3.14159265359; \n\n var a2: f32 = a*a;\n var NdotH = mdot(N, H);\n var NdotH2 = NdotH*NdotH;\n \n var denom: f32 = NdotH2 * (a2 - 1.0) + 1.0;\n\n return a2 / max((pi*denom*denom), 0.000001);\n}\n\n// A VERY bad approximation of anisotropy. Real anisotropic calculations require tangent and bitangent\nfn anisotrophicTrGGX(N: vec3<f32>, H: vec3<f32>, O: vec3<f32>, s: f32, a: f32) -> f32 {\n var Op: vec3<f32> = (rendererUBO.WCVCNormals * vec4<f32>(normalize(O) * s, 0.)).xyz;\n\n var ggx1: f32 = trGGX(N + Op*s, H, a);\n var ggx2: f32 = trGGX(N - Op*s, H, a);\n return (0.5 * ggx1 + 0.5 * ggx2);\n}\n\n// Geometry portion of BRDF\nfn schlickGGX(N: vec3<f32>, X: vec3<f32>, k: f32) -> f32 {\n var NdotX = mdot(N, X);\n return NdotX / max(0.000001, (NdotX*(1-k) + k));\n}\n\nfn smithSurfaceRoughness(N: vec3<f32>, V: vec3<f32>, L: vec3<f32>, k: f32) -> f32 {\n var ggx1: f32 = max(0.01, schlickGGX(N, V, k)); // Prevents void zones at the cost of some accuracy\n var ggx2: f32 = schlickGGX(N, L, k);\n return ggx1*ggx2;\n}\n\n// BRDF Combination\nfn cookTorrance(D: f32, F: f32, G: f32, N: vec3<f32>, V: vec3<f32>, L: vec3<f32>) -> f32 {\n var num: f32 = D*F*G;\n var denom: f32 = 4*mdot(V, N)*mdot(L, N);\n\n return num / max(denom, 0.000001);\n}\n\n// Different lighting calculations for different light sources\nfn calcDirectionalLight(N: vec3<f32>, V: vec3<f32>, ior: f32, roughness: f32, metallic: f32, direction: vec3<f32>, color: vec3<f32>, base: vec3<f32>) -> PBRData { \n var L: vec3<f32> = normalize(direction); // Light Vector\n var H: vec3<f32> = normalize(L + V); // Halfway Vector\n\n var alpha = roughness*roughness;\n var k: f32 = alpha*alpha / 2;\n\n var D: f32 = trGGX(N, H, alpha); // Distribution\n // var F: f32 = schlickFresnelIOR(V, N, ior, k); // Fresnel\n var G: f32 = smithSurfaceRoughness(N, V, L, k); // Geometry\n\n var brdf: f32 = cookTorrance(D, 1, G, N, V, L); // Fresnel term is replaced with 1 because it is added later\n var incoming: vec3<f32> = color;\n var angle: f32 = mdot(L, N);\n angle = pow(angle, 1.5);\n\n var specular: vec3<f32> = brdf*incoming*angle;\n // Oren-Nayar gives a clay-like effect when fully rough which some people may not want, so it might be better to give a separate\n // control property for the diffuse vs specular roughness\n var diffuse: vec3<f32> = incoming*fujiiOrenNayar(base, roughness, N, L, V); \n // Stores the specular and diffuse separately to allow for finer post processing\n // Could also be done (propably more properly) with a struct\n var out = PBRData(diffuse, specular);\n \n return out; // Returns angle along with color of light so the final color can be multiplied by angle as well (creates black areas)\n}\n\n// TODO: find some way to reduce the number of arguments going in here\nfn calcPointLight(N: vec3<f32>, V: vec3<f32>, fragPos: vec3<f32>, ior: f32, roughness: f32, metallic: f32, position: vec3<f32>, color: vec3<f32>, base: vec3<f32>) -> PBRData {\n var L: vec3<f32> = normalize(position - fragPos); // Light Vector\n var H: vec3<f32> = normalize(L + V); // Halfway Vector\n var dist = distance(position, fragPos);\n\n var alpha = roughness*roughness;\n var k: f32 = alpha*alpha / 2; // could also be pow(alpha + 1.0, 2) / 8\n\n var D: f32 = trGGX(N, H, alpha); // Distribution\n // var F: f32 = schlickFresnelIOR(V, N, ior, k); // Fresnel\n var G: f32 = smithSurfaceRoughness(N, V, L, k); // Geometry\n\n var brdf: f32 = cookTorrance(D, 1, G, N, V, L); \n var incoming: vec3<f32> = color * (1. / (dist*dist));\n var angle: f32 = mdot(L, N);\n angle = pow(angle, 1.5); // Smoothing factor makes it less accurate, but reduces ugly \"seams\" bewteen light sources\n\n var specular: vec3<f32> = brdf*incoming*angle;\n var diffuse: vec3<f32> = incoming*fujiiOrenNayar(base, roughness, N, L, V);\n\n // Stores the specular and diffuse separately to allow for finer post processing\n // Could also be done (propably more properly) with a struct\n var out = PBRData(diffuse, specular);\n \n return out; // Returns angle along with color of light so the final color can be multiplied by angle as well (creates black areas)\n}\n\n// For a reason unknown to me, spheres dont seem to behave propperly with head-on spot lights\nfn calcSpotLight(N: vec3<f32>, V: vec3<f32>, fragPos: vec3<f32>, ior: f32, roughness: f32, metallic: f32, position: vec3<f32>, direction: vec3<f32>, cones: vec2<f32>, color: vec3<f32>, base: vec3<f32>) -> PBRData {\n var L: vec3<f32> = normalize(position - fragPos);\n var H: vec3<f32> = normalize(L + V); // Halfway Vector\n var dist = distance(position, fragPos);\n\n var alpha = roughness*roughness;\n var k: f32 = alpha*alpha / 2; // could also be pow(alpha + 1.0, 2) / 8\n\n var D: f32 = trGGX(N, H, alpha); // Distribution\n // var F: f32 = schlickFresnelIOR(V, N, ior, k); // Fresnel\n var G: f32 = smithSurfaceRoughness(N, V, L, k); // Geometry\n\n var brdf: f32 = cookTorrance(D, 1, G, N, V, L); \n \n // Cones.x is the inner phi and cones.y is the outer phi\n var theta: f32 = mdot(normalize(direction), L);\n var epsilon: f32 = cones.x - cones.y;\n var intensity: f32 = (theta - cones.y) / epsilon;\n intensity = clamp(intensity, 0.0, 1.0);\n intensity /= dist*dist;\n\n var incoming: vec3<f32> = color * intensity;\n\n var angle: f32 = mdot(L, N);\n angle = pow(angle, 1.5); // Smoothing factor makes it less accurate, but reduces ugly \"seams\" bewteen light sources\n\n var specular: vec3<f32> = brdf*incoming*angle;\n var diffuse: vec3<f32> = incoming*fujiiOrenNayar(base, roughness, N, L, V);\n\n // Stores the specular and diffuse separately to allow for finer post processing\n // Could also be done (propably more properly) with a struct\n var out = PBRData(diffuse, specular);\n \n return out; // Returns angle along with color of light so the final color can be multiplied by angle as well (creates black areas)\n}\n\n// Environment mapping stuff\n// Takes in a vector and converts it to an equivalent coordinate in a rectilinear texture. Should be replaced with cubemaps at some point\nfn vecToRectCoord(dir: vec3<f32>) -> vec2<f32> {\n var tau: f32 = 6.28318530718;\n var out: vec2<f32> = vec2<f32>(0.);\n\n out.x = atan2(dir.z, dir.x) / tau;\n out.x += 0.5;\n\n out.y = (dir.y * .5) + .5;\n\n return out;\n}\n\n//VTK::Renderer::Dec\n\n//VTK::Color::Dec\n\n//VTK::TCoord::Dec\n\n// optional surface normal declaration\n//VTK::Normal::Dec\n\n//VTK::Select::Dec\n\n//VTK::RenderEncoder::Dec\n\n//VTK::Mapper::Dec\n\n//VTK::IOStructs::Dec\n\n@fragment\nfn main(\n//VTK::IOStructs::Input\n)\n//VTK::IOStructs::Output\n{\n var output : fragmentOutput;\n\n // Temporary ambient, diffuse, and opacity\n var ambientColor: vec4<f32> = mapperUBO.AmbientColor;\n var diffuseColor: vec4<f32> = mapperUBO.DiffuseColor;\n var opacity: f32 = mapperUBO.Opacity;\n\n // This should be declared somewhere else\n var _diffuseMap: vec4<f32> = vec4<f32>(1);\n var _roughnessMap: vec4<f32> = vec4<f32>(1);\n var _metallicMap: vec4<f32> = vec4<f32>(1);\n var _normalMap: vec4<f32> = vec4<f32>(0, 0, 1, 0); // normal map was setting off the normal vector detection in fragment\n var _ambientOcclusionMap: vec4<f32> = vec4<f32>(0);\n var _emissionMap: vec4<f32> = vec4<f32>(0);\n\n //VTK::Color::Impl\n\n //VTK::TCoord::Impl\n\n //VTK::Normal::Impl\n\n var computedColor: vec4<f32> = vec4<f32>(diffuseColor.rgb, 1.);\n\n //VTK::Light::Impl\n\n //VTK::Select::Impl\n\n if (computedColor.a == 0.0) { discard; };\n\n //VTK::Position::Impl\n\n //VTK::RenderEncoder::Impl\n\n return output;\n}\n";
|
|
22
22
|
|
|
23
23
|
function isEdges(hash) {
|
|
24
24
|
// edge pipelines have "edge" in them
|
|
@@ -72,6 +72,9 @@ function vtkWebGPUCellArrayMapper(publicAPI, model) {
|
|
|
72
72
|
var utime = model.UBO.getSendTime();
|
|
73
73
|
|
|
74
74
|
if (publicAPI.getMTime() > utime || ppty.getMTime() > utime || model.renderable.getMTime() > utime) {
|
|
75
|
+
var _ppty$getEdgeColorByR;
|
|
76
|
+
|
|
77
|
+
// Matricies
|
|
75
78
|
var keyMats = model.WebGPUActor.getKeyMatrices(model.WebGPURenderer);
|
|
76
79
|
model.UBO.setArray('BCWCMatrix', keyMats.bcwc);
|
|
77
80
|
model.UBO.setArray('BCSCMatrix', keyMats.bcsc);
|
|
@@ -79,25 +82,42 @@ function vtkWebGPUCellArrayMapper(publicAPI, model) {
|
|
|
79
82
|
|
|
80
83
|
if (model.is2D) {
|
|
81
84
|
model.UBO.setValue('ZValue', model.WebGPUActor.getRenderable().getProperty().getDisplayLocation() === DisplayLocation.FOREGROUND ? 1.0 : 0.0);
|
|
82
|
-
|
|
85
|
+
|
|
86
|
+
var _aColor = ppty.getColorByReference();
|
|
87
|
+
|
|
83
88
|
model.UBO.setValue('AmbientIntensity', 1.0);
|
|
84
|
-
model.UBO.setArray('
|
|
89
|
+
model.UBO.setArray('DiffuseColor', [_aColor[0], _aColor[1], _aColor[2], 1.0]);
|
|
85
90
|
model.UBO.setValue('DiffuseIntensity', 0.0);
|
|
86
91
|
model.UBO.setValue('SpecularIntensity', 0.0);
|
|
87
92
|
} else {
|
|
88
|
-
|
|
93
|
+
// Base Colors
|
|
94
|
+
var _aColor2 = ppty.getAmbientColorByReference();
|
|
89
95
|
|
|
90
96
|
model.UBO.setValue('AmbientIntensity', ppty.getAmbient());
|
|
91
|
-
model.UBO.setArray('AmbientColor', [
|
|
97
|
+
model.UBO.setArray('AmbientColor', [_aColor2[0], _aColor2[1], _aColor2[2], 1.0]);
|
|
92
98
|
model.UBO.setValue('DiffuseIntensity', ppty.getDiffuse());
|
|
93
|
-
|
|
94
|
-
model.UBO.setArray('DiffuseColor', [
|
|
99
|
+
_aColor2 = ppty.getDiffuseColorByReference();
|
|
100
|
+
model.UBO.setArray('DiffuseColor', [_aColor2[0], _aColor2[1], _aColor2[2], 1.0]); // Roughness
|
|
101
|
+
|
|
102
|
+
model.UBO.setValue('Roughness', ppty.getRoughness());
|
|
103
|
+
model.UBO.setValue('BaseIOR', ppty.getBaseIOR()); // Metallic
|
|
104
|
+
|
|
105
|
+
model.UBO.setValue('Metallic', ppty.getMetallic()); // Normal
|
|
106
|
+
|
|
107
|
+
model.UBO.setValue('NormalStrength', ppty.getNormalStrength()); // Emission
|
|
108
|
+
|
|
109
|
+
model.UBO.setValue('Emission', ppty.getEmission()); // Specular
|
|
110
|
+
|
|
95
111
|
model.UBO.setValue('SpecularIntensity', ppty.getSpecular());
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
112
|
+
_aColor2 = ppty.getSpecularColorByReference();
|
|
113
|
+
model.UBO.setArray('SpecularColor', [_aColor2[0], _aColor2[1], _aColor2[2], 1.0]);
|
|
114
|
+
} // Edge and line rendering
|
|
115
|
+
|
|
116
|
+
|
|
117
|
+
var aColor = (_ppty$getEdgeColorByR = ppty.getEdgeColorByReference) === null || _ppty$getEdgeColorByR === void 0 ? void 0 : _ppty$getEdgeColorByR.call(ppty);
|
|
118
|
+
|
|
119
|
+
if (aColor) {
|
|
120
|
+
model.UBO.setArray('EdgeColor', [aColor[0], aColor[1], aColor[2], 1.0]);
|
|
101
121
|
}
|
|
102
122
|
|
|
103
123
|
model.UBO.setValue('LineWidth', ppty.getLineWidth());
|
|
@@ -130,10 +150,11 @@ function vtkWebGPUCellArrayMapper(publicAPI, model) {
|
|
|
130
150
|
publicAPI.replaceShaderPosition = function (hash, pipeline, vertexInput) {
|
|
131
151
|
var vDesc = pipeline.getShaderDescription('vertex');
|
|
132
152
|
vDesc.addBuiltinOutput('vec4<f32>', '@builtin(position) Position');
|
|
153
|
+
if (!vDesc.hasOutput('vertexVC')) vDesc.addOutput('vec4<f32>', 'vertexVC');
|
|
133
154
|
var code = vDesc.getCode();
|
|
134
155
|
|
|
135
156
|
if (model.useRendererMatrix) {
|
|
136
|
-
code = vtkWebGPUShaderCache.substitute(code, '//VTK::Position::Impl', [' var pCoord: vec4<f32> = rendererUBO.SCPCMatrix*mapperUBO.BCSCMatrix*vertexBC;', '//VTK::Position::Impl']).result;
|
|
157
|
+
code = vtkWebGPUShaderCache.substitute(code, '//VTK::Position::Impl', [' var pCoord: vec4<f32> = rendererUBO.SCPCMatrix*mapperUBO.BCSCMatrix*vertexBC;', ' output.vertexVC = rendererUBO.SCVCMatrix * mapperUBO.BCSCMatrix * vec4<f32>(vertexBC.xyz, 1.0);', '//VTK::Position::Impl']).result;
|
|
137
158
|
|
|
138
159
|
if (model.forceZValue) {
|
|
139
160
|
code = vtkWebGPUShaderCache.substitute(code, '//VTK::Position::Impl', ['pCoord = vec4<f32>(pCoord.xyz/pCoord.w, 1.0);', 'pCoord.z = mapperUBO.ZValue;', '//VTK::Position::Impl']).result;
|
|
@@ -161,16 +182,38 @@ function vtkWebGPUCellArrayMapper(publicAPI, model) {
|
|
|
161
182
|
|
|
162
183
|
publicAPI.replaceShaderNormal = function (hash, pipeline, vertexInput) {
|
|
163
184
|
var normalBuffer = vertexInput.getBuffer('normalMC');
|
|
185
|
+
var actor = model.WebGPUActor.getRenderable();
|
|
164
186
|
|
|
165
187
|
if (normalBuffer) {
|
|
166
188
|
var vDesc = pipeline.getShaderDescription('vertex');
|
|
167
|
-
|
|
189
|
+
|
|
190
|
+
if (!vDesc.hasOutput('normalVC')) {
|
|
191
|
+
vDesc.addOutput('vec3<f32>', 'normalVC', normalBuffer.getArrayInformation()[0].interpolation);
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
if (!vDesc.hasOutput('tangentVC')) {
|
|
195
|
+
vDesc.addOutput('vec3<f32>', 'tangentVC', normalBuffer.getArrayInformation()[0].interpolation);
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
if (!vDesc.hasOutput('bitangentVC')) {
|
|
199
|
+
vDesc.addOutput('vec3<f32>', 'bitangentVC', normalBuffer.getArrayInformation()[0].interpolation);
|
|
200
|
+
}
|
|
201
|
+
|
|
168
202
|
var code = vDesc.getCode();
|
|
169
|
-
code = vtkWebGPUShaderCache.substitute(code, '//VTK::Normal::Impl', [' output.normalVC = normalize((rendererUBO.WCVCNormals * mapperUBO.MCWCNormals * normalMC).xyz);'
|
|
203
|
+
code = vtkWebGPUShaderCache.substitute(code, '//VTK::Normal::Impl', [' output.normalVC = normalize((rendererUBO.WCVCNormals * mapperUBO.MCWCNormals * normalMC).xyz);', // This is just an approximation, but it happens to work extremely well
|
|
204
|
+
// It only works well for normals that are head on and not super angled though
|
|
205
|
+
// Definitely needs to be replaced
|
|
206
|
+
' var c1: vec3<f32> = cross(output.normalVC, vec3<f32>(0, 0, 1));', ' var c2: vec3<f32> = cross(output.normalVC, vec3<f32>(0, 1, 0));', ' var tangent: vec3<f32> = mix(c1, c2, distance(c1, c2));', ' output.tangentVC = normalize(tangent);', ' output.bitangentVC = normalize(cross(output.normalVC, tangent));']).result;
|
|
170
207
|
vDesc.setCode(code);
|
|
171
208
|
var fDesc = pipeline.getShaderDescription('fragment');
|
|
172
209
|
code = fDesc.getCode();
|
|
173
|
-
|
|
210
|
+
|
|
211
|
+
if (actor.getProperty().getNormalTexture()) {
|
|
212
|
+
code = vtkWebGPUShaderCache.substitute(code, '//VTK::Normal::Impl', [' var normal: vec3<f32> = input.normalVC;', ' if (!input.frontFacing) { normal = -normal; }', ' var tangent: vec3<f32> = input.tangentVC;', ' var bitangent: vec3<f32> = input.bitangentVC;', ' var TCVCMatrix: mat3x3<f32> = mat3x3<f32>(', ' tangent.x, bitangent.x, normal.x,', ' tangent.y, bitangent.y, normal.y,', ' tangent.z, bitangent.z, normal.z,', ' );', ' normal = TCVCMatrix * (_normalMap.xyz * 2 - 1);', ' normal = mix(input.normalVC, normal, mapperUBO.NormalStrength);', ' normal = normalize(normal);']).result;
|
|
213
|
+
} else {
|
|
214
|
+
code = vtkWebGPUShaderCache.substitute(code, '//VTK::Normal::Impl', [' var normal: vec3<f32> = input.normalVC;', ' if (!input.frontFacing) { normal = -normal; }', ' normal = normalize(normal);']).result;
|
|
215
|
+
}
|
|
216
|
+
|
|
174
217
|
fDesc.setCode(code);
|
|
175
218
|
}
|
|
176
219
|
};
|
|
@@ -179,14 +222,24 @@ function vtkWebGPUCellArrayMapper(publicAPI, model) {
|
|
|
179
222
|
// fragment shader code. That is the lighting trigger.
|
|
180
223
|
|
|
181
224
|
publicAPI.replaceShaderLight = function (hash, pipeline, vertexInput) {
|
|
225
|
+
if (hash.includes('sel')) return;
|
|
226
|
+
var vDesc = pipeline.getShaderDescription('vertex');
|
|
227
|
+
if (!vDesc.hasOutput('vertexVC')) vDesc.addOutput('vec4<f32>', 'vertexVC');
|
|
182
228
|
var fDesc = pipeline.getShaderDescription('fragment');
|
|
183
|
-
var code = fDesc.getCode();
|
|
184
|
-
|
|
185
|
-
if (code.includes('var normal')) {
|
|
186
|
-
code = vtkWebGPUShaderCache.substitute(code, '//VTK::Light::Impl', [
|
|
187
|
-
|
|
229
|
+
var code = fDesc.getCode(); // Code that runs if the fragment shader includes normals
|
|
230
|
+
|
|
231
|
+
if (code.includes('var normal:') && model.useRendererMatrix && !isEdges(hash) && !model.is2D && !hash.includes('sel')) {
|
|
232
|
+
code = vtkWebGPUShaderCache.substitute(code, '//VTK::Light::Impl', [// Constants
|
|
233
|
+
' var pi: f32 = 3.14159265359;', // Vectors needed for light calculations
|
|
234
|
+
' var fragPos: vec3<f32> = vec3<f32>(input.vertexVC.xyz);', ' var V: vec3<f32> = mix(normalize(-fragPos), vec3<f32>(0, 0, 1), f32(rendererUBO.cameraParallel)); // View Vector', // Values needed for light calculations
|
|
235
|
+
' var baseColor: vec3<f32> = _diffuseMap.rgb * diffuseColor.rgb;', ' var roughness: f32 = max(0.000001, mapperUBO.Roughness * _roughnessMap.r);', // Need to have a different way of sampling greyscale values aside from .r
|
|
236
|
+
' var metallic: f32 = mapperUBO.Metallic * _metallicMap.r;', ' var alpha: f32 = roughness*roughness;', ' var ior: f32 = mapperUBO.BaseIOR;', ' var k: f32 = alpha*alpha / 2;', // Split diffuse and specular components
|
|
237
|
+
' var diffuse: vec3<f32> = vec3<f32>(0.);', ' var specular: vec3<f32> = vec3<f32>(0.);', ' var emission: vec3<f32> = _emissionMap.rgb * mapperUBO.Emission;', // Summing diffuse and specular components of directional lights
|
|
238
|
+
' {', ' var i: i32 = 0;', ' loop {', ' if !(i < rendererUBO.LightCount) { break; }', ' switch (i32(rendererLightSSBO.values[i].LightData.x)) {', ' // Point Light', ' case 0 {', ' var color: vec3<f32> = rendererLightSSBO.values[i].LightColor.rgb * rendererLightSSBO.values[i].LightColor.w;', ' var pos: vec3<f32> = (rendererLightSSBO.values[i].LightPos).xyz;', ' var calculated: PBRData = calcPointLight(normal, V, fragPos, ior, roughness, metallic, pos, color, baseColor);', ' diffuse += max(vec3<f32>(0), calculated.diffuse);', ' specular += max(vec3<f32>(0), calculated.specular);', ' }', ' // Directional light', ' case 1 {', ' var dir: vec3<f32> = (rendererUBO.WCVCNormals * vec4<f32>(normalize(rendererLightSSBO.values[i].LightDir.xyz), 0.)).xyz;', ' dir = normalize(dir);', ' var color: vec3<f32> = rendererLightSSBO.values[i].LightColor.rgb * rendererLightSSBO.values[i].LightColor.w;', ' var calculated: PBRData = calcDirectionalLight(normal, V, ior, roughness, metallic, dir, color, baseColor); // diffuseColor.rgb needs to be fixed with a more dynamic diffuse color', ' diffuse += max(vec3<f32>(0), calculated.diffuse);', ' specular += max(vec3<f32>(0), calculated.specular);', ' }', ' // Spot Light', ' case 2 {', ' var color: vec3<f32> = rendererLightSSBO.values[i].LightColor.rgb * rendererLightSSBO.values[i].LightColor.w;', ' var pos: vec3<f32> = (rendererLightSSBO.values[i].LightPos).xyz;', ' var dir: vec3<f32> = (rendererUBO.WCVCNormals * vec4<f32>(normalize(rendererLightSSBO.values[i].LightDir.xyz), 0.)).xyz;', ' dir = normalize(dir);', ' var cones: vec2<f32> = vec2<f32>(rendererLightSSBO.values[i].LightData.y, rendererLightSSBO.values[i].LightData.z);', ' var calculated: PBRData = calcSpotLight(normal, V, fragPos, ior, roughness, metallic, pos, dir, cones, color, baseColor);', ' diffuse += max(vec3<f32>(0), calculated.diffuse);', ' specular += max(vec3<f32>(0), calculated.specular);', ' }', ' default { continue; }', ' }', ' continuing { i++; }', ' }', ' }', // Final variables for combining specular and diffuse
|
|
239
|
+
' var fresnel: f32 = schlickFresnelIOR(V, normal, ior, k); // Fresnel', ' fresnel = min(1, fresnel);', ' // This could be controlled with its own variable (that isnt base color) for better artistic control', ' var fresnelMetallic: vec3<f32> = schlickFresnelRGB(V, normal, baseColor); // Fresnel for metal, takes color into account', ' var kS: vec3<f32> = mix(vec3<f32>(fresnel), fresnelMetallic, metallic);', ' kS = min(vec3<f32>(1), kS);', ' var kD: vec3<f32> = (1.0 - kS) * (1.0 - metallic);', ' var PBR: vec3<f32> = mapperUBO.DiffuseIntensity*kD*diffuse + kS*specular;', ' PBR += emission;', ' computedColor = vec4<f32>(PBR, mapperUBO.Opacity);']).result;
|
|
240
|
+
fDesc.setCode(code); // If theres no normals, just set the specular color to be flat
|
|
188
241
|
} else {
|
|
189
|
-
code = vtkWebGPUShaderCache.substitute(code, '//VTK::Light::Impl', [' var diffuse: vec3<f32> = diffuseColor.rgb;', ' var specular: vec3<f32> = mapperUBO.SpecularColor.rgb * mapperUBO.SpecularColor.a;']).result;
|
|
242
|
+
code = vtkWebGPUShaderCache.substitute(code, '//VTK::Light::Impl', [' var diffuse: vec3<f32> = diffuseColor.rgb;', ' var specular: vec3<f32> = mapperUBO.SpecularColor.rgb * mapperUBO.SpecularColor.a;', ' computedColor = vec4<f32>(diffuse, mapperUBO.Opacity);']).result;
|
|
190
243
|
fDesc.setCode(code);
|
|
191
244
|
}
|
|
192
245
|
};
|
|
@@ -194,6 +247,7 @@ function vtkWebGPUCellArrayMapper(publicAPI, model) {
|
|
|
194
247
|
model.shaderReplacements.set('replaceShaderLight', publicAPI.replaceShaderLight);
|
|
195
248
|
|
|
196
249
|
publicAPI.replaceShaderColor = function (hash, pipeline, vertexInput) {
|
|
250
|
+
// By default, set the colors to be flat
|
|
197
251
|
if (isEdges(hash)) {
|
|
198
252
|
var _fDesc = pipeline.getShaderDescription('fragment');
|
|
199
253
|
|
|
@@ -204,15 +258,18 @@ function vtkWebGPUCellArrayMapper(publicAPI, model) {
|
|
|
204
258
|
_fDesc.setCode(_code);
|
|
205
259
|
|
|
206
260
|
return;
|
|
207
|
-
}
|
|
261
|
+
} // If there's no vertex color buffer return the shader as is
|
|
262
|
+
|
|
208
263
|
|
|
209
264
|
var colorBuffer = vertexInput.getBuffer('colorVI');
|
|
210
|
-
if (!colorBuffer) return;
|
|
265
|
+
if (!colorBuffer) return; // Modifies the vertex shader to include the vertex colors and interpolation in the outputs
|
|
266
|
+
|
|
211
267
|
var vDesc = pipeline.getShaderDescription('vertex');
|
|
212
268
|
vDesc.addOutput('vec4<f32>', 'color', colorBuffer.getArrayInformation()[0].interpolation);
|
|
213
269
|
var code = vDesc.getCode();
|
|
214
270
|
code = vtkWebGPUShaderCache.substitute(code, '//VTK::Color::Impl', [' output.color = colorVI;']).result;
|
|
215
|
-
vDesc.setCode(code);
|
|
271
|
+
vDesc.setCode(code); // Sets the fragment shader to accept the color inputs from the vertex shader
|
|
272
|
+
|
|
216
273
|
var fDesc = pipeline.getShaderDescription('fragment');
|
|
217
274
|
code = fDesc.getCode();
|
|
218
275
|
code = vtkWebGPUShaderCache.substitute(code, '//VTK::Color::Impl', ['ambientColor = input.color;', 'diffuseColor = input.color;', 'opacity = mapperUBO.Opacity * input.color.a;']).result;
|
|
@@ -222,27 +279,70 @@ function vtkWebGPUCellArrayMapper(publicAPI, model) {
|
|
|
222
279
|
model.shaderReplacements.set('replaceShaderColor', publicAPI.replaceShaderColor);
|
|
223
280
|
|
|
224
281
|
publicAPI.replaceShaderTCoord = function (hash, pipeline, vertexInput) {
|
|
282
|
+
var _actor$getProperty$ge, _actor$getProperty, _actor$getProperty$ge2, _actor$getProperty$ge4, _actor$getProperty3, _actor$getProperty$ge5, _actor$getProperty$ge6, _actor$getProperty4, _actor$getProperty$ge7, _actor$getProperty$ge8, _actor$getProperty5, _actor$getProperty$ge9, _actor$getProperty$ge10, _actor$getProperty6, _actor$getProperty$ge11, _actor$getProperty$ge12, _actor$getProperty7, _actor$getProperty$ge13;
|
|
283
|
+
|
|
225
284
|
if (!vertexInput.hasAttribute('tcoord')) return;
|
|
226
285
|
var vDesc = pipeline.getShaderDescription('vertex');
|
|
227
286
|
var tcoords = vertexInput.getBuffer('tcoord');
|
|
228
287
|
var numComp = vtkWebGPUTypes.getNumberOfComponentsFromBufferFormat(tcoords.getArrayInformation()[0].format);
|
|
229
288
|
var code = vDesc.getCode();
|
|
230
289
|
vDesc.addOutput("vec".concat(numComp, "<f32>"), 'tcoordVS');
|
|
231
|
-
code = vtkWebGPUShaderCache.substitute(code, '//VTK::TCoord::Impl', [' output.tcoordVS = tcoord;'
|
|
290
|
+
code = vtkWebGPUShaderCache.substitute(code, '//VTK::TCoord::Impl', [' output.tcoordVS = tcoord;' // Ensure that UV coordinates are always between 0-1
|
|
291
|
+
]).result;
|
|
232
292
|
vDesc.setCode(code);
|
|
293
|
+
if (model.is2D) return;
|
|
233
294
|
var fDesc = pipeline.getShaderDescription('fragment');
|
|
234
|
-
code = fDesc.getCode();
|
|
295
|
+
code = fDesc.getCode();
|
|
296
|
+
var actor = model.WebGPUActor.getRenderable();
|
|
235
297
|
|
|
236
|
-
|
|
237
|
-
|
|
298
|
+
var checkDims = function checkDims(texture) {
|
|
299
|
+
if (!texture) return false;
|
|
300
|
+
var dims = texture.getDimensionality();
|
|
301
|
+
return dims === numComp;
|
|
302
|
+
};
|
|
238
303
|
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
304
|
+
var usedTextures = [];
|
|
305
|
+
|
|
306
|
+
if ((_actor$getProperty$ge = (_actor$getProperty = actor.getProperty()).getDiffuseTexture) !== null && _actor$getProperty$ge !== void 0 && (_actor$getProperty$ge2 = _actor$getProperty$ge.call(_actor$getProperty)) !== null && _actor$getProperty$ge2 !== void 0 && _actor$getProperty$ge2.getImageLoaded() || actor.getTextures()[0] || model.colorTexture) {
|
|
307
|
+
var _actor$getProperty$ge3, _actor$getProperty2;
|
|
308
|
+
|
|
309
|
+
if ( // Chained or statements here are questionable
|
|
310
|
+
checkDims((_actor$getProperty$ge3 = (_actor$getProperty2 = actor.getProperty()).getDiffuseTexture) === null || _actor$getProperty$ge3 === void 0 ? void 0 : _actor$getProperty$ge3.call(_actor$getProperty2)) || checkDims(actor.getTextures()[0]) || checkDims(model.colorTexture)) {
|
|
311
|
+
usedTextures.push('_diffuseMap = textureSample(DiffuseTexture, DiffuseTextureSampler, input.tcoordVS);');
|
|
312
|
+
}
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
if ((_actor$getProperty$ge4 = (_actor$getProperty3 = actor.getProperty()).getRoughnessTexture) !== null && _actor$getProperty$ge4 !== void 0 && (_actor$getProperty$ge5 = _actor$getProperty$ge4.call(_actor$getProperty3)) !== null && _actor$getProperty$ge5 !== void 0 && _actor$getProperty$ge5.getImageLoaded()) {
|
|
316
|
+
if (checkDims(actor.getProperty().getRoughnessTexture())) {
|
|
317
|
+
usedTextures.push('_roughnessMap = textureSample(RoughnessTexture, RoughnessTextureSampler, input.tcoordVS);');
|
|
318
|
+
}
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
if ((_actor$getProperty$ge6 = (_actor$getProperty4 = actor.getProperty()).getMetallicTexture) !== null && _actor$getProperty$ge6 !== void 0 && (_actor$getProperty$ge7 = _actor$getProperty$ge6.call(_actor$getProperty4)) !== null && _actor$getProperty$ge7 !== void 0 && _actor$getProperty$ge7.getImageLoaded()) {
|
|
322
|
+
if (checkDims(actor.getProperty().getMetallicTexture())) {
|
|
323
|
+
usedTextures.push('_metallicMap = textureSample(MetallicTexture, MetallicTextureSampler, input.tcoordVS);');
|
|
324
|
+
}
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
if ((_actor$getProperty$ge8 = (_actor$getProperty5 = actor.getProperty()).getNormalTexture) !== null && _actor$getProperty$ge8 !== void 0 && (_actor$getProperty$ge9 = _actor$getProperty$ge8.call(_actor$getProperty5)) !== null && _actor$getProperty$ge9 !== void 0 && _actor$getProperty$ge9.getImageLoaded()) {
|
|
328
|
+
if (checkDims(actor.getProperty().getNormalTexture())) {
|
|
329
|
+
usedTextures.push('_normalMap = textureSample(NormalTexture, NormalTextureSampler, input.tcoordVS);');
|
|
243
330
|
}
|
|
244
331
|
}
|
|
245
332
|
|
|
333
|
+
if ((_actor$getProperty$ge10 = (_actor$getProperty6 = actor.getProperty()).getAmbientOcclusionTexture) !== null && _actor$getProperty$ge10 !== void 0 && (_actor$getProperty$ge11 = _actor$getProperty$ge10.call(_actor$getProperty6)) !== null && _actor$getProperty$ge11 !== void 0 && _actor$getProperty$ge11.getImageLoaded()) {
|
|
334
|
+
if (checkDims(actor.getProperty().getAmbientOcclusionTexture())) {
|
|
335
|
+
usedTextures.push('_ambientOcclusionMap = textureSample(AmbientOcclusionTexture, AmbientOcclusionTextureSampler, input.tcoordVS);');
|
|
336
|
+
}
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
if ((_actor$getProperty$ge12 = (_actor$getProperty7 = actor.getProperty()).getEmissionTexture) !== null && _actor$getProperty$ge12 !== void 0 && (_actor$getProperty$ge13 = _actor$getProperty$ge12.call(_actor$getProperty7)) !== null && _actor$getProperty$ge13 !== void 0 && _actor$getProperty$ge13.getImageLoaded()) {
|
|
340
|
+
if (checkDims(actor.getProperty().getEmissionTexture())) {
|
|
341
|
+
usedTextures.push('_emissionMap = textureSample(EmissionTexture, EmissionTextureSampler, input.tcoordVS);');
|
|
342
|
+
}
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
code = vtkWebGPUShaderCache.substitute(code, '//VTK::TCoord::Impl', usedTextures).result;
|
|
246
346
|
fDesc.setCode(code);
|
|
247
347
|
};
|
|
248
348
|
|
|
@@ -309,7 +409,8 @@ function vtkWebGPUCellArrayMapper(publicAPI, model) {
|
|
|
309
409
|
default:
|
|
310
410
|
return 'line-list';
|
|
311
411
|
}
|
|
312
|
-
};
|
|
412
|
+
}; // TODO: calculate tangents
|
|
413
|
+
|
|
313
414
|
|
|
314
415
|
publicAPI.buildVertexInput = function () {
|
|
315
416
|
var _model$renderable$get, _model$renderable;
|
|
@@ -379,7 +480,9 @@ function vtkWebGPUCellArrayMapper(publicAPI, model) {
|
|
|
379
480
|
|
|
380
481
|
if (!model.is2D && ( // no lighting on Property2D
|
|
381
482
|
usage === BufferUsage.Triangles || usage === BufferUsage.Strips)) {
|
|
382
|
-
var normals = pd.getPointData().getNormals();
|
|
483
|
+
var normals = pd.getPointData().getNormals(); // https://vtk.org/doc/nightly/html/classvtkPolyDataTangents.html
|
|
484
|
+
// Need to find some way of using precomputed tangents (or computing new ones)
|
|
485
|
+
|
|
383
486
|
var _buffRequest2 = {
|
|
384
487
|
format: 'snorm8x4',
|
|
385
488
|
indexBuffer: indexBuffer,
|
|
@@ -466,7 +569,7 @@ function vtkWebGPUCellArrayMapper(publicAPI, model) {
|
|
|
466
569
|
};
|
|
467
570
|
|
|
468
571
|
publicAPI.updateTextures = function () {
|
|
469
|
-
var _model$renderable$get2, _model$renderable2;
|
|
572
|
+
var _model$renderable$get2, _model$renderable2, _actor$getProperty$ge14, _actor$getProperty8, _actor$getProperty$ge15, _actor$getProperty9, _actor$getProperty$ge16, _actor$getProperty10, _actor$getProperty$ge17, _actor$getProperty11, _actor$getProperty$ge18, _actor$getProperty12, _actor$getProperty$ge19, _actor$getProperty13, _renderer$getBackgrou;
|
|
470
573
|
|
|
471
574
|
// we keep track of new and used textures so
|
|
472
575
|
// that we can clean up any unused textures so we don't hold onto them
|
|
@@ -483,28 +586,69 @@ function vtkWebGPUCellArrayMapper(publicAPI, model) {
|
|
|
483
586
|
}
|
|
484
587
|
|
|
485
588
|
model.colorTexture.setInputData(idata);
|
|
486
|
-
newTextures.push(model.colorTexture);
|
|
589
|
+
newTextures.push(['Diffuse', model.colorTexture]);
|
|
487
590
|
} // actor textures?
|
|
488
591
|
|
|
489
592
|
|
|
490
593
|
var actor = model.WebGPUActor.getRenderable();
|
|
491
|
-
var
|
|
594
|
+
var renderer = model.WebGPURenderer.getRenderable(); // Reusing the old code for new and old textures, just loading in from properties instead of actor.getTextures()
|
|
595
|
+
|
|
596
|
+
var textures = []; // Feels like there should be a better way than individually adding all
|
|
597
|
+
|
|
598
|
+
if ((_actor$getProperty$ge14 = (_actor$getProperty8 = actor.getProperty()).getDiffuseTexture) !== null && _actor$getProperty$ge14 !== void 0 && _actor$getProperty$ge14.call(_actor$getProperty8)) {
|
|
599
|
+
var pair = ['Diffuse', actor.getProperty().getDiffuseTexture()];
|
|
600
|
+
textures.push(pair);
|
|
601
|
+
}
|
|
602
|
+
|
|
603
|
+
if (actor.getTextures()[0]) {
|
|
604
|
+
var _pair = ['Diffuse', actor.getTextures()[0]];
|
|
605
|
+
textures.push(_pair);
|
|
606
|
+
}
|
|
607
|
+
|
|
608
|
+
if ((_actor$getProperty$ge15 = (_actor$getProperty9 = actor.getProperty()).getRoughnessTexture) !== null && _actor$getProperty$ge15 !== void 0 && _actor$getProperty$ge15.call(_actor$getProperty9)) {
|
|
609
|
+
var _pair2 = ['Roughness', actor.getProperty().getRoughnessTexture()];
|
|
610
|
+
textures.push(_pair2);
|
|
611
|
+
}
|
|
612
|
+
|
|
613
|
+
if ((_actor$getProperty$ge16 = (_actor$getProperty10 = actor.getProperty()).getMetallicTexture) !== null && _actor$getProperty$ge16 !== void 0 && _actor$getProperty$ge16.call(_actor$getProperty10)) {
|
|
614
|
+
var _pair3 = ['Metallic', actor.getProperty().getMetallicTexture()];
|
|
615
|
+
textures.push(_pair3);
|
|
616
|
+
}
|
|
617
|
+
|
|
618
|
+
if ((_actor$getProperty$ge17 = (_actor$getProperty11 = actor.getProperty()).getNormalTexture) !== null && _actor$getProperty$ge17 !== void 0 && _actor$getProperty$ge17.call(_actor$getProperty11)) {
|
|
619
|
+
var _pair4 = ['Normal', actor.getProperty().getNormalTexture()];
|
|
620
|
+
textures.push(_pair4);
|
|
621
|
+
}
|
|
622
|
+
|
|
623
|
+
if ((_actor$getProperty$ge18 = (_actor$getProperty12 = actor.getProperty()).getAmbientOcclusionTexture) !== null && _actor$getProperty$ge18 !== void 0 && _actor$getProperty$ge18.call(_actor$getProperty12)) {
|
|
624
|
+
var _pair5 = ['AmbientOcclusion', actor.getProperty().getAmbientOcclusionTexture()];
|
|
625
|
+
textures.push(_pair5);
|
|
626
|
+
}
|
|
627
|
+
|
|
628
|
+
if ((_actor$getProperty$ge19 = (_actor$getProperty13 = actor.getProperty()).getEmissionTexture) !== null && _actor$getProperty$ge19 !== void 0 && _actor$getProperty$ge19.call(_actor$getProperty13)) {
|
|
629
|
+
var _pair6 = ['Emission', actor.getProperty().getEmissionTexture()];
|
|
630
|
+
textures.push(_pair6);
|
|
631
|
+
}
|
|
632
|
+
|
|
633
|
+
if ((_renderer$getBackgrou = renderer.getBackgroundTexture) !== null && _renderer$getBackgrou !== void 0 && _renderer$getBackgrou.call(renderer)) {
|
|
634
|
+
var _pair7 = ['Background', renderer.getBackgroundTexture()];
|
|
635
|
+
textures.push(_pair7);
|
|
636
|
+
}
|
|
492
637
|
|
|
493
638
|
for (var i = 0; i < textures.length; i++) {
|
|
494
|
-
if (textures[i].getInputData() || textures[i].getJsImageData() || textures[i].getCanvas()) {
|
|
639
|
+
if (textures[i][1].getInputData() || textures[i][1].getJsImageData() || textures[i][1].getCanvas()) {
|
|
495
640
|
newTextures.push(textures[i]);
|
|
496
641
|
}
|
|
497
642
|
|
|
498
|
-
if (textures[i].getImage() && textures[i].getImageLoaded()) {
|
|
643
|
+
if (textures[i][1].getImage() && textures[i][1].getImageLoaded()) {
|
|
499
644
|
newTextures.push(textures[i]);
|
|
500
645
|
}
|
|
501
646
|
}
|
|
502
647
|
|
|
503
|
-
var usedCount = 0;
|
|
504
|
-
|
|
505
648
|
for (var _i = 0; _i < newTextures.length; _i++) {
|
|
506
|
-
var srcTexture = newTextures[_i];
|
|
507
|
-
var
|
|
649
|
+
var srcTexture = newTextures[_i][1];
|
|
650
|
+
var textureName = newTextures[_i][0];
|
|
651
|
+
var newTex = model.device.getTextureManager().getTextureForVTKTexture(srcTexture); // Generates hash
|
|
508
652
|
|
|
509
653
|
if (newTex.getReady()) {
|
|
510
654
|
// is this a new texture
|
|
@@ -512,7 +656,6 @@ function vtkWebGPUCellArrayMapper(publicAPI, model) {
|
|
|
512
656
|
|
|
513
657
|
for (var t = 0; t < model.textures.length; t++) {
|
|
514
658
|
if (model.textures[t] === newTex) {
|
|
515
|
-
usedCount++;
|
|
516
659
|
found = true;
|
|
517
660
|
usedTextures[t] = true;
|
|
518
661
|
}
|
|
@@ -520,7 +663,7 @@ function vtkWebGPUCellArrayMapper(publicAPI, model) {
|
|
|
520
663
|
|
|
521
664
|
if (!found) {
|
|
522
665
|
usedTextures[model.textures.length] = true;
|
|
523
|
-
var tview = newTex.createView("
|
|
666
|
+
var tview = newTex.createView("".concat(textureName, "Texture"));
|
|
524
667
|
model.textures.push(newTex);
|
|
525
668
|
model.textureViews.push(tview);
|
|
526
669
|
var interpolate = srcTexture.getInterpolate() ? 'linear' : 'nearest';
|
|
@@ -623,14 +766,15 @@ var DEFAULT_VALUES = {
|
|
|
623
766
|
}; // ----------------------------------------------------------------------------
|
|
624
767
|
|
|
625
768
|
function extend(publicAPI, model) {
|
|
626
|
-
var
|
|
627
|
-
Object.assign(model, DEFAULT_VALUES,
|
|
769
|
+
var initiaLalues = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};
|
|
770
|
+
Object.assign(model, DEFAULT_VALUES, initiaLalues); // Inheritance
|
|
628
771
|
|
|
629
|
-
vtkWebGPUSimpleMapper.extend(publicAPI, model,
|
|
772
|
+
vtkWebGPUSimpleMapper.extend(publicAPI, model, initiaLalues);
|
|
630
773
|
model.fragmentShaderTemplate = vtkWebGPUPolyDataFS;
|
|
631
774
|
model.vertexShaderTemplate = vtkWebGPUPolyDataVS;
|
|
632
775
|
model._tmpMat3 = mat3.identity(new Float64Array(9));
|
|
633
|
-
model._tmpMat4 = mat4.identity(new Float64Array(16));
|
|
776
|
+
model._tmpMat4 = mat4.identity(new Float64Array(16)); // UBO
|
|
777
|
+
|
|
634
778
|
model.UBO = vtkWebGPUUniformBuffer.newInstance({
|
|
635
779
|
label: 'mapperUBO'
|
|
636
780
|
});
|
|
@@ -643,12 +787,21 @@ function extend(publicAPI, model) {
|
|
|
643
787
|
model.UBO.addEntry('SpecularColor', 'vec4<f32>');
|
|
644
788
|
model.UBO.addEntry('AmbientIntensity', 'f32');
|
|
645
789
|
model.UBO.addEntry('DiffuseIntensity', 'f32');
|
|
790
|
+
model.UBO.addEntry('Roughness', 'f32');
|
|
791
|
+
model.UBO.addEntry('Metallic', 'f32');
|
|
792
|
+
model.UBO.addEntry('Ambient', 'f32');
|
|
793
|
+
model.UBO.addEntry('Normal', 'f32');
|
|
794
|
+
model.UBO.addEntry('Emission', 'f32');
|
|
795
|
+
model.UBO.addEntry('NormalStrength', 'f32');
|
|
796
|
+
model.UBO.addEntry('BaseIOR', 'f32');
|
|
646
797
|
model.UBO.addEntry('SpecularIntensity', 'f32');
|
|
647
798
|
model.UBO.addEntry('LineWidth', 'f32');
|
|
648
799
|
model.UBO.addEntry('Opacity', 'f32');
|
|
649
|
-
model.UBO.addEntry('SpecularPower', 'f32');
|
|
650
800
|
model.UBO.addEntry('ZValue', 'f32');
|
|
651
|
-
model.UBO.addEntry('PropID', 'u32');
|
|
801
|
+
model.UBO.addEntry('PropID', 'u32');
|
|
802
|
+
model.UBO.addEntry('ClipNear', 'f32');
|
|
803
|
+
model.UBO.addEntry('ClipFar', 'f32');
|
|
804
|
+
model.UBO.addEntry('Time', 'u32'); // Build VTK API
|
|
652
805
|
|
|
653
806
|
setGet(publicAPI, model, ['cellArray', 'currentInput', 'cellOffset', 'is2D', 'primitiveType', 'renderEncoder']);
|
|
654
807
|
model.textures = []; // Object methods
|
|
@@ -29,8 +29,9 @@ function vtkWebGPUGlyph3DCellArrayMapper(publicAPI, model) {
|
|
|
29
29
|
var vDesc = pipeline.getShaderDescription('vertex');
|
|
30
30
|
vDesc.addBuiltinInput('u32', '@builtin(instance_index) instanceIndex');
|
|
31
31
|
vDesc.addBuiltinOutput('vec4<f32>', '@builtin(position) Position');
|
|
32
|
+
if (!vDesc.hasOutput('vertexVC')) vDesc.addOutput('vec3<f32>', 'vertexVC');
|
|
32
33
|
var code = vDesc.getCode();
|
|
33
|
-
code = vtkWebGPUShaderCache.substitute(code, '//VTK::Position::Impl', ['
|
|
34
|
+
code = vtkWebGPUShaderCache.substitute(code, '//VTK::Position::Impl', [' var vertexSC: vec4<f32> = mapperUBO.BCSCMatrix*glyphSSBO.values[input.instanceIndex].matrix*vertexBC;', ' output.vertexVC = (rendererUBO.SCVCMatrix*vertexSC).xyz;', ' output.Position = rendererUBO.SCPCMatrix*vertexSC;']).result;
|
|
34
35
|
vDesc.setCode(code);
|
|
35
36
|
};
|
|
36
37
|
|
|
@@ -1,18 +1,41 @@
|
|
|
1
1
|
import { mat4, vec3 } from 'gl-matrix';
|
|
2
2
|
import { newInstance as newInstance$1, obj, get, getArray, setGet, vtkDebugMacro as vtkDebugMacro$1 } from '../../macros.js';
|
|
3
|
+
import { r as radiansFromDegrees } from '../../Common/Core/Math/index.js';
|
|
3
4
|
import vtkViewNode from '../SceneGraph/ViewNode.js';
|
|
4
5
|
import vtkWebGPUBindGroup from './BindGroup.js';
|
|
5
6
|
import vtkWebGPUFullScreenQuad from './FullScreenQuad.js';
|
|
7
|
+
import vtkWebGPUStorageBuffer from './StorageBuffer.js';
|
|
6
8
|
import vtkWebGPUUniformBuffer from './UniformBuffer.js';
|
|
7
9
|
import { registerOverride } from './ViewNodeFactory.js';
|
|
8
10
|
|
|
9
11
|
var vtkDebugMacro = vtkDebugMacro$1;
|
|
10
|
-
var clearFragTemplate = "\n//VTK::Renderer::Dec\n\n//VTK::Mapper::Dec\n\n//VTK::TCoord::Dec\n\n//VTK::RenderEncoder::Dec\n\n//VTK::IOStructs::Dec\n\n@fragment\nfn main(\n//VTK::IOStructs::Input\n)\n//VTK::IOStructs::Output\n{\n var output: fragmentOutput;\n\n var computedColor: vec4<f32> = mapperUBO.BackgroundColor;\n\n //VTK::RenderEncoder::Impl\n return output;\n}\n"; //
|
|
12
|
+
var clearFragTemplate = "\n//VTK::Renderer::Dec\n\n//VTK::Mapper::Dec\n\n//VTK::TCoord::Dec\n\n//VTK::RenderEncoder::Dec\n\n//VTK::IOStructs::Dec\n\n@fragment\nfn main(\n//VTK::IOStructs::Input\n)\n//VTK::IOStructs::Output\n{\n var output: fragmentOutput;\n\n var computedColor: vec4<f32> = mapperUBO.BackgroundColor;\n\n //VTK::RenderEncoder::Impl\n return output;\n}\n"; // Light type index gives either 0, 1, or 2 which indicates what type of light there is.
|
|
13
|
+
// While technically, there are only spot and directional lights, within the CellArrayMapper
|
|
14
|
+
// there is a third, positional light. It is technically just a variant of a spot light with
|
|
15
|
+
// a cone angle of 90 or above, however certain calculations can be skipped if it is treated
|
|
16
|
+
// separately.
|
|
17
|
+
// The mappings are shown below:
|
|
18
|
+
// 0 -> positional light
|
|
19
|
+
// 1 -> directional light
|
|
20
|
+
// 2 -> spot light
|
|
21
|
+
|
|
22
|
+
function getLightTypeIndex(light) {
|
|
23
|
+
if (light.getPositional()) {
|
|
24
|
+
if (light.getConeAngle() >= 90) {
|
|
25
|
+
return 0;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
return 2;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
return 1;
|
|
32
|
+
} // ----------------------------------------------------------------------------
|
|
11
33
|
// vtkWebGPURenderer methods
|
|
12
34
|
// ----------------------------------------------------------------------------
|
|
13
35
|
|
|
14
36
|
/* eslint-disable no-bitwise */
|
|
15
37
|
|
|
38
|
+
|
|
16
39
|
function vtkWebGPURenderer(publicAPI, model) {
|
|
17
40
|
// Set our className
|
|
18
41
|
model.classHierarchy.push('vtkWebGPURenderer'); // Builds myself.
|
|
@@ -108,6 +131,7 @@ function vtkWebGPURenderer(publicAPI, model) {
|
|
|
108
131
|
model.UBO.setArray('SCVCMatrix', keyMats.scvc);
|
|
109
132
|
model.UBO.setArray('VCPCMatrix', keyMats.vcpc);
|
|
110
133
|
model.UBO.setArray('WCVCNormals', keyMats.normalMatrix);
|
|
134
|
+
model.UBO.setValue('LightCount', model.renderable.getLights().length);
|
|
111
135
|
var tsize = publicAPI.getYInvertedTiledSizeAndOrigin();
|
|
112
136
|
model.UBO.setArray('viewportSize', [tsize.usize, tsize.vsize]);
|
|
113
137
|
model.UBO.setValue('cameraParallel', model.camera.getParallelProjection());
|
|
@@ -118,6 +142,79 @@ function vtkWebGPURenderer(publicAPI, model) {
|
|
|
118
142
|
}
|
|
119
143
|
};
|
|
120
144
|
|
|
145
|
+
publicAPI.updateSSBO = function () {
|
|
146
|
+
var lights = model.renderable.getLights();
|
|
147
|
+
var keyMats = model.webgpuCamera.getKeyMatrices(publicAPI);
|
|
148
|
+
var lightTimeString = "".concat(model.renderable.getMTime());
|
|
149
|
+
|
|
150
|
+
for (var i = 0; i < lights.length; i++) {
|
|
151
|
+
lightTimeString += lights[i].getMTime();
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
if (lightTimeString !== model.lightTimeString) {
|
|
155
|
+
var lightPosArray = new Float32Array(lights.length * 4);
|
|
156
|
+
var lightDirArray = new Float32Array(lights.length * 4);
|
|
157
|
+
var lightColorArray = new Float32Array(lights.length * 4);
|
|
158
|
+
var lightTypeArray = new Float32Array(lights.length * 4);
|
|
159
|
+
|
|
160
|
+
for (var _i = 0; _i < lights.length; _i++) {
|
|
161
|
+
var offset = _i * 4; // Position
|
|
162
|
+
|
|
163
|
+
var viewCoordinatePosition = lights[_i].getPosition();
|
|
164
|
+
|
|
165
|
+
vec3.transformMat4(viewCoordinatePosition, viewCoordinatePosition, keyMats.wcvc); // console.log(viewCoordinatePosition);
|
|
166
|
+
// viewCoordinatePosition
|
|
167
|
+
|
|
168
|
+
lightPosArray[offset] = viewCoordinatePosition[0];
|
|
169
|
+
lightPosArray[offset + 1] = viewCoordinatePosition[1];
|
|
170
|
+
lightPosArray[offset + 2] = viewCoordinatePosition[2];
|
|
171
|
+
lightPosArray[offset + 3] = 0; // Rotation (All are negative to correct for -Z being forward)
|
|
172
|
+
|
|
173
|
+
lightDirArray[offset] = -lights[_i].getDirection()[0];
|
|
174
|
+
lightDirArray[offset + 1] = -lights[_i].getDirection()[1];
|
|
175
|
+
lightDirArray[offset + 2] = -lights[_i].getDirection()[2];
|
|
176
|
+
lightDirArray[offset + 3] = 0; // Color
|
|
177
|
+
|
|
178
|
+
lightColorArray[offset] = lights[_i].getColor()[0];
|
|
179
|
+
lightColorArray[offset + 1] = lights[_i].getColor()[1];
|
|
180
|
+
lightColorArray[offset + 2] = lights[_i].getColor()[2];
|
|
181
|
+
lightColorArray[offset + 3] = lights[_i].getIntensity() * 5; // arbitrary multiplication to fix the dullness of low value PBR lights
|
|
182
|
+
// Type
|
|
183
|
+
|
|
184
|
+
lightTypeArray[offset] = getLightTypeIndex(lights[_i]); // Type
|
|
185
|
+
|
|
186
|
+
lightTypeArray[offset + 1] = Math.cos(radiansFromDegrees(lights[_i].getConeAngle())); // Inner Phi, should probably do some check on these to make sure they dont excede limits
|
|
187
|
+
|
|
188
|
+
lightTypeArray[offset + 2] = Math.cos(radiansFromDegrees(lights[_i].getConeAngle() + lights[_i].getConeFalloff())); // Outer Phi
|
|
189
|
+
|
|
190
|
+
lightTypeArray[offset + 3] = 0;
|
|
191
|
+
} // Im not sure how correct this is, but this is what the example does
|
|
192
|
+
// https://kitware.github.io/vtk-js/api/Rendering_WebGPU_VolumePassFSQ.html
|
|
193
|
+
|
|
194
|
+
|
|
195
|
+
model.SSBO.clearData();
|
|
196
|
+
model.SSBO.setNumberOfInstances(lights.length);
|
|
197
|
+
model.SSBO.addEntry('LightPos', 'vec4<f32>'); // Position
|
|
198
|
+
|
|
199
|
+
model.SSBO.addEntry('LightDir', 'vec4<f32>'); // Direction
|
|
200
|
+
|
|
201
|
+
model.SSBO.addEntry('LightColor', 'vec4<f32>'); // Color (r, g, b, intensity)
|
|
202
|
+
|
|
203
|
+
model.SSBO.addEntry('LightData', 'vec4<f32>'); // Other data (type, etc, etc, etc)
|
|
204
|
+
|
|
205
|
+
model.SSBO.setAllInstancesFromArray('LightPos', lightPosArray);
|
|
206
|
+
model.SSBO.setAllInstancesFromArray('LightDir', lightDirArray);
|
|
207
|
+
model.SSBO.setAllInstancesFromArray('LightColor', lightColorArray);
|
|
208
|
+
model.SSBO.setAllInstancesFromArray('LightData', lightTypeArray);
|
|
209
|
+
|
|
210
|
+
var device = model._parent.getDevice();
|
|
211
|
+
|
|
212
|
+
model.SSBO.send(device);
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
model.lightTimeString = lightTimeString;
|
|
216
|
+
};
|
|
217
|
+
|
|
121
218
|
publicAPI.scissorAndViewport = function (encoder) {
|
|
122
219
|
var tsize = publicAPI.getYInvertedTiledSizeAndOrigin();
|
|
123
220
|
encoder.getHandle().setViewport(tsize.lowerLeftU, tsize.lowerLeftV, tsize.usize, tsize.vsize, 0.0, 1.0); // set scissor
|
|
@@ -134,6 +231,7 @@ function vtkWebGPURenderer(publicAPI, model) {
|
|
|
134
231
|
if (prepass) {
|
|
135
232
|
model.renderEncoder.begin(model._parent.getCommandEncoder());
|
|
136
233
|
publicAPI.updateUBO();
|
|
234
|
+
publicAPI.updateSSBO();
|
|
137
235
|
} else {
|
|
138
236
|
publicAPI.scissorAndViewport(model.renderEncoder);
|
|
139
237
|
publicAPI.clear();
|
|
@@ -284,7 +382,8 @@ function extend(publicAPI, model) {
|
|
|
284
382
|
var initialValues = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};
|
|
285
383
|
Object.assign(model, DEFAULT_VALUES, initialValues); // Inheritance
|
|
286
384
|
|
|
287
|
-
vtkViewNode.extend(publicAPI, model, initialValues);
|
|
385
|
+
vtkViewNode.extend(publicAPI, model, initialValues); // UBO
|
|
386
|
+
|
|
288
387
|
model.UBO = vtkWebGPUUniformBuffer.newInstance({
|
|
289
388
|
label: 'rendererUBO'
|
|
290
389
|
});
|
|
@@ -295,11 +394,17 @@ function extend(publicAPI, model) {
|
|
|
295
394
|
model.UBO.addEntry('VCPCMatrix', 'mat4x4<f32>');
|
|
296
395
|
model.UBO.addEntry('WCVCNormals', 'mat4x4<f32>');
|
|
297
396
|
model.UBO.addEntry('viewportSize', 'vec2<f32>');
|
|
298
|
-
model.UBO.addEntry('
|
|
397
|
+
model.UBO.addEntry('LightCount', 'i32');
|
|
398
|
+
model.UBO.addEntry('cameraParallel', 'u32'); // SSBO (Light data)
|
|
399
|
+
|
|
400
|
+
model.SSBO = vtkWebGPUStorageBuffer.newInstance({
|
|
401
|
+
label: 'rendererLightSSBO'
|
|
402
|
+
});
|
|
403
|
+
model.lightTimeString = '';
|
|
299
404
|
model.bindGroup = vtkWebGPUBindGroup.newInstance({
|
|
300
405
|
label: 'rendererBG'
|
|
301
406
|
});
|
|
302
|
-
model.bindGroup.setBindables([model.UBO]);
|
|
407
|
+
model.bindGroup.setBindables([model.UBO, model.SSBO]);
|
|
303
408
|
model.tmpMat4 = mat4.identity(new Float64Array(16));
|
|
304
409
|
model.stabilizedTime = {};
|
|
305
410
|
obj(model.stabilizedTime, {
|
|
@@ -7,7 +7,7 @@ import { registerOverride } from './ViewNodeFactory.js';
|
|
|
7
7
|
|
|
8
8
|
var BufferUsage = vtkWebGPUBufferManager.BufferUsage;
|
|
9
9
|
var vtkErrorMacro = vtkErrorMacro$1;
|
|
10
|
-
var vtkWebGPUSphereMapperVS = "\n//VTK::Renderer::Dec\n\n//VTK::Mapper::Dec\n\n//VTK::Color::Dec\n\n//VTK::IOStructs::Dec\n\n@vertex\nfn main(\n//VTK::IOStructs::Input\n)\n//VTK::IOStructs::Output\n{\n var output : vertexOutput;\n\n var vertexVC: vec4<f32> = rendererUBO.SCVCMatrix * mapperUBO.BCSCMatrix * vec4<f32>(vertexBC.
|
|
10
|
+
var vtkWebGPUSphereMapperVS = "\n//VTK::Renderer::Dec\n\n//VTK::Mapper::Dec\n\n//VTK::Color::Dec\n\n//VTK::IOStructs::Dec\n\n@vertex\nfn main(\n//VTK::IOStructs::Input\n)\n//VTK::IOStructs::Output\n{\n var output : vertexOutput;\n\n var vertexVC: vec4<f32> = rendererUBO.SCVCMatrix * mapperUBO.BCSCMatrix * vec4<f32>(vertexBC.xyz, 1.0);\n\n //VTK::Color::Impl\n\n // compute the projected vertex position\n output.centerVC = vertexVC.xyz;\n output.radiusVC = length(offsetMC)*0.5;\n\n // make the triangle face the camera\n if (rendererUBO.cameraParallel == 0u)\n {\n var dir: vec3<f32> = normalize(-vertexVC.xyz);\n var base2: vec3<f32> = normalize(cross(dir,vec3<f32>(1.0,0.0,0.0)));\n var base1: vec3<f32> = cross(base2,dir);\n dir = vertexVC.xyz + offsetMC.x*base1 + offsetMC.y*base2;\n vertexVC = vec4<f32>(dir, 1.0);\n }\n else\n {\n // add in the offset\n var tmp2: vec2<f32> = vertexVC.xy + offsetMC;\n vertexVC = vec4<f32>(tmp2, vertexVC.zw);\n }\n\n output.vertexVC = vec4<f32>(vertexVC.xyz, 0.0);\n\n //VTK::Position::Impl\n\n return output;\n}\n"; // ----------------------------------------------------------------------------
|
|
11
11
|
// vtkWebGPUSphereMapper methods
|
|
12
12
|
// ----------------------------------------------------------------------------
|
|
13
13
|
|
|
@@ -32,7 +32,7 @@ function vtkWebGPUSphereMapper(publicAPI, model) {
|
|
|
32
32
|
|
|
33
33
|
publicAPI.replaceShaderNormal = function (hash, pipeline, vertexInput) {
|
|
34
34
|
var vDesc = pipeline.getShaderDescription('vertex');
|
|
35
|
-
vDesc.addOutput('
|
|
35
|
+
if (!vDesc.hasOutput('vertexVC')) vDesc.addOutput('vec4<f32>', 'vertexVC');
|
|
36
36
|
vDesc.addOutput('vec3<f32>', 'centerVC');
|
|
37
37
|
vDesc.addOutput('f32', 'radiusVC');
|
|
38
38
|
var fDesc = pipeline.getShaderDescription('fragment');
|
|
@@ -26,7 +26,7 @@ var vtkErrorMacro = vtkErrorMacro$1; // Vertices
|
|
|
26
26
|
// 4: 011
|
|
27
27
|
// 5: 111
|
|
28
28
|
|
|
29
|
-
var vtkWebGPUStickMapperVS = "\n//VTK::Renderer::Dec\n\n//VTK::Mapper::Dec\n\n//VTK::Color::Dec\n\n//VTK::IOStructs::Dec\n\n@vertex\nfn main(\n//VTK::IOStructs::Input\n)\n//VTK::IOStructs::Output\n{\n var offsetsArray: array<vec3<f32>, 12> = array<vec3<f32>, 12>(\n vec3<f32>(-1.0, -1.0, -1.0),\n vec3<f32>(1.0, -1.0, -1.0),\n vec3<f32>(1.0, -1.0, 1.0),\n\n vec3<f32>(-1.0, -1.0, -1.0),\n vec3<f32>(1.0, -1.0, 1.0),\n vec3<f32>(-1.0, -1.0, 1.0),\n\n vec3<f32>(-1.0, -1.0, 1.0),\n vec3<f32>(1.0, -1.0, 1.0),\n vec3<f32>(1.0, 1.0, 1.0),\n\n vec3<f32>(-1.0, -1.0, 1.0),\n vec3<f32>(1.0, 1.0, 1.0),\n vec3<f32>(-1.0, 1.0, 1.0)\n );\n\n var output : vertexOutput;\n\n var vertexVC: vec4<f32> = rendererUBO.SCVCMatrix * mapperUBO.BCSCMatrix * vec4<f32>(vertexBC.
|
|
29
|
+
var vtkWebGPUStickMapperVS = "\n//VTK::Renderer::Dec\n\n//VTK::Mapper::Dec\n\n//VTK::Color::Dec\n\n//VTK::IOStructs::Dec\n\n@vertex\nfn main(\n//VTK::IOStructs::Input\n)\n//VTK::IOStructs::Output\n{\n var offsetsArray: array<vec3<f32>, 12> = array<vec3<f32>, 12>(\n vec3<f32>(-1.0, -1.0, -1.0),\n vec3<f32>(1.0, -1.0, -1.0),\n vec3<f32>(1.0, -1.0, 1.0),\n\n vec3<f32>(-1.0, -1.0, -1.0),\n vec3<f32>(1.0, -1.0, 1.0),\n vec3<f32>(-1.0, -1.0, 1.0),\n\n vec3<f32>(-1.0, -1.0, 1.0),\n vec3<f32>(1.0, -1.0, 1.0),\n vec3<f32>(1.0, 1.0, 1.0),\n\n vec3<f32>(-1.0, -1.0, 1.0),\n vec3<f32>(1.0, 1.0, 1.0),\n vec3<f32>(-1.0, 1.0, 1.0)\n );\n\n var output : vertexOutput;\n\n var vertexVC: vec4<f32> = rendererUBO.SCVCMatrix * mapperUBO.BCSCMatrix * vec4<f32>(vertexBC.xyz, 1.0);\n\n //VTK::Color::Impl\n\n // compute the projected vertex position\n output.centerVC = vertexVC.xyz;\n output.radiusVC = radiusMC;\n output.lengthVC = length(orientMC);\n output.orientVC = (rendererUBO.WCVCNormals * vec4<f32>(normalize(orientMC), 0.0)).xyz;\n\n // make sure it is pointing out of the screen\n if (output.orientVC.z < 0.0)\n {\n output.orientVC = -output.orientVC;\n }\n\n // make the basis\n var xbase: vec3<f32>;\n var ybase: vec3<f32>;\n var dir: vec3<f32> = vec3<f32>(0.0,0.0,1.0);\n if (rendererUBO.cameraParallel == 0u)\n {\n dir = normalize(-vertexVC.xyz);\n }\n if (abs(dot(dir,output.orientVC)) == 1.0)\n {\n xbase = normalize(cross(vec3<f32>(0.0,1.0,0.0),output.orientVC));\n ybase = cross(xbase,output.orientVC);\n }\n else\n {\n xbase = normalize(cross(output.orientVC,dir));\n ybase = cross(output.orientVC,xbase);\n }\n\n\n var vertIdx: u32 = input.vertexIndex % 12u;\n var offsets: vec3<f32> = offsetsArray[vertIdx];\n\n vertexVC = vec4<f32>(vertexVC.xyz +\n output.radiusVC * offsets.x * xbase +\n output.radiusVC * offsets.y * ybase +\n 0.5 * output.lengthVC * offsets.z * output.orientVC, 1.0);\n\n output.vertexVC = vertexVC;\n\n //VTK::Position::Impl\n\n return output;\n}\n"; // ----------------------------------------------------------------------------
|
|
30
30
|
// vtkWebGPUStickMapper methods
|
|
31
31
|
// ----------------------------------------------------------------------------
|
|
32
32
|
|
|
@@ -51,7 +51,7 @@ function vtkWebGPUStickMapper(publicAPI, model) {
|
|
|
51
51
|
|
|
52
52
|
publicAPI.replaceShaderNormal = function (hash, pipeline, vertexInput) {
|
|
53
53
|
var vDesc = pipeline.getShaderDescription('vertex');
|
|
54
|
-
vDesc.addOutput('vec4<f32>', 'vertexVC');
|
|
54
|
+
if (!vDesc.hasOutput('vertexVC')) vDesc.addOutput('vec4<f32>', 'vertexVC');
|
|
55
55
|
vDesc.addOutput('vec3<f32>', 'centerVC');
|
|
56
56
|
vDesc.addOutput('vec3<f32>', 'orientVC');
|
|
57
57
|
vDesc.addOutput('f32', 'radiusVC');
|
|
@@ -184,8 +184,12 @@ function vtkWebGPUTexture(publicAPI, model) {
|
|
|
184
184
|
return tDetails.numComponents;
|
|
185
185
|
};
|
|
186
186
|
|
|
187
|
-
publicAPI.
|
|
188
|
-
|
|
187
|
+
publicAPI.getDimensionality = function () {
|
|
188
|
+
var dims = 0;
|
|
189
|
+
if (model.width > 1) dims++;
|
|
190
|
+
if (model.height > 1) dims++;
|
|
191
|
+
if (model.depth > 1) dims++;
|
|
192
|
+
return dims;
|
|
189
193
|
};
|
|
190
194
|
|
|
191
195
|
publicAPI.resizeToMatch = function (tex) {
|