-
Notifications
You must be signed in to change notification settings - Fork 99
/
GLSL_NV_fragment_shader_barycentric.txt
520 lines (379 loc) · 20.8 KB
/
GLSL_NV_fragment_shader_barycentric.txt
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
Name
NV_fragment_shader_barycentric
Name Strings
GL_NV_fragment_shader_barycentric
Contact
Pat Brown, NVIDIA (pbrown 'at' nvidia.com)
Contributors
Ashwin Lele, NVIDIA
Jeff Bolz, NVIDIA
Michael Chock, NVIDIA
Status
Shipping
Version
Last Modified: April 8, 2019
Revision: 3
Dependencies
This extension can be applied to OpenGL GLSL versions 4.50
(#version 450) and higher.
This extension can be applied to OpenGL ES ESSL versions 3.20
(#version 320) and higher.
This extension is written against the OpenGL Shading Language
Specification, version 4.60, dated July 23, 2017.
Additional changes are written against the OpenGL ES Shading
Language Specification, Version 3.20.5, dated December 12, 2018.
Overview
This extension provides two new OpenGL Shading Language (GLSL) fragment
shader built-in inputs (gl_BaryCoordNV and gl_BaryCoordNoPerspNV) that are
three-component vectors specifying the relative weights for each vertex in
the original primitive. Fragments located in the corners of a triangle
primitive will have weights of (1,0,0), (0,1,0), and (0,0,1), while a
fragment in the exact middle of a triangle will have weights of (1/3, 1/3,
1/3). The weights in the vector gl_BaryCoordNV are perspective-corrected
and reflect the location of the fragment as projected onto the original
primitive. The weights in the vector gl_BaryCoordNoPerspNV are not
perspective-corrected and reflect the location of the fragment relative to
the on-screen projection of the original primitive. For both vectors, the
values of the three components should add to approximately 1.0.
This extension also allows fragment shaders to read the raw per-vertex
values of shader outputs from the last shader executed before
rasterization. This mechanism uses the same syntax used to read
per-vertex inputs in for tessellation and geometry shaders. The qualifier
"pervertexNV" can be applied to fragment shader input blocks and
variables to specify that those inputs do not read interpolated
per-fragment values, but instead read raw per-vertex values from the
vertices of the original primitive. Like tessellation and geometry shader
inputs, such variables or blocks must be declared as arrays and indexed
with a vertex number (0, 1, or 2). For example, if a shader declares the
following input block:
pervertexNV in Inputs {
float f;
float g;
} inputs[];
the expression "inputs[0].f" reads the value of <f> for the first vertex
of the original primitive, while "inputs[2].g" reads the value of <g> for
the third vertex.
While barycentric weights can be used to interpolate values by reading the
outputs of previous shaders (using "pervertexNV" attributes), it can
also be used to interpolate values based in input values fetched directly
from memory, with no shader outputs involved. For example, in code like
the following:
pervertexNV in int vertexIDs[];
buffer VertexData {
struct VertexAttributes {
vec3 normal;
} attrs[];
};
shaders can fetch the values of <normal> for the three vertices of a
primitive using:
vec3 normal0 = attrs[vertexIDs[0]];
vec3 normal1 = attrs[vertexIDs[1]];
vec3 normal2 = attrs[vertexIDs[2]];
without reading or emitting any normal vectors in a vertex shader.
Mapping to SPIR-V
-----------------
For informational purposes (non-normative), the following is an
expected way for an implementation to map GLSL constructs to SPIR-V
constructs:
pervertexNV interpolation qualifier -> PerVertexNV Decoration
gl_BaryCoordNV -> BaryCoordNV decorated OpVariable
gl_BaryCoordNoPerspNV -> BaryCoordNoPerspNV decorated OpVariable
Input variables decorated with "PerVertexNV" are accessed with an extra
array dimension identifying a vertex number.
Modifications to the OpenGL Shading Language Specification, Version 4.60
Including the following line in a shader can be used to control the
language features described in this extension:
#extension GL_NV_fragment_shader_barycentric : <behavior>
where <behavior> is as specified in section 3.3.
New preprocessor #defines are added to the OpenGL Shading Language:
#define GL_NV_fragment_shader_barycentric 1
Modify Section 3.6, Keywords (p. 15)
(add to list of keywords, on the line with "centroid", "flat", "smooth",
and "noperspective")
pervertexNV
Modify Section 4.3.4, Input Variables (p. 45)
(modify third paragraph, p. 46, to document that fragment shader inputs
declared with "pervertexNV" are treated similarly to tessellation and
geometry shader inputs and document that "pervertexNV" has no effect in
non-fragment shaders)
Tessellation control input variables, tessellation evaluation input
variables, geometry shader input variables, and fragment shader input
variables qualified with "pervertexNV" get the per-vertex values written
out by output variables of the same names in the previous active shader
stage. For these inputs, centroid, pervertexNV and interpolation
qualifiers are allowed, but have no effect. Since all of these inputs
have separate values for each vertex in the input primitive, each such
input variable (or input block, see interface blocks below) needs to be
declared as an array. For example,
in float foo[]; // geometry shader input for vertex "out float foo"
(modify fourth paragraph, p. 46, to document how the array size for
"arrayed" inputs is obtained for tessellation shaders and per-vertex
fragment shader inputs)
... For geometry shaders, ... section 4.4.1 "Input Layout Qualifiers".
For tessellation control and evaluation shaders, the array size will be
set by (or if provided, must be consistent with) the maximum patch size
gl_MaxPatchVertices. For fragment shader inputs qualified with
"pervertexNV", the array size will be set to (or if provided, must be
equal to) three.
(modify fifth paragraph, p. 46, to treat "pervertexNV" inputs as
"arrayed" interfaces)
Some inputs and outputs are arrayed ... Geometry shader inputs,
tessellation control shader inputs and outputs, tessellation evaluation
inputs, and fragment shader inputs qualified with "pervertexNV" all have
an additional level of arrayness relative to other shader inputs and
outputs. Component limits...
(modify second paragraph, p. 47, adding alternate language about the
handling of fragment shader inputs using "pervertexNV")
Fragment shader inputs not declared with "pervertexNV" get
per-fragment values, typically interpolated from a previous stage's
outputs. ... as well as the interpolation qualifiers flat, noperspective,
and smooth. Fragment shader inputs declared with "pervertexNV" are
not interpolated. Such inputs are arrayed and may be used to directly
access the previous stage's outputs for one of the vertices of the
primitives producing the fragment, using a vertex number of 0, 1, or 2 as
an index. ...
(modify third paragraph, p. 47, allowing integer and double-precision
fragment shader inputs if qualified with "pervertexNV")
Fragment shader inputs that are, or contain, signed or unsigned integers,
integer vectors, or any double-precision floating-point type must be
qualified with the qualifier "flat" or "pervertexNV".
(modify the fourth paragraph, p. 48, adding an example)
Fragment inputs are declared as in the following examples:
...
pervertexNV in vec4 perVertexAttr[];
Modify Section 4.3.9, Interface Blocks, p. 51
(update the fake grammar, p. 52, to clarify that you can use the
interpolation qualifier "pervertexNV" on input blocks)
interface-qualifier:
...
pervertexNV in
...
Modify Section 4.5, Interpolation Qualifiers, p. 83
(add to the table in first paragraph of the section)
Qualifier Meaning
---------------- --------------------------------------------
pervertexNV no interpolation, values accessed per vertex
(add before the next-to-last paragraph, p. 83)
A variable or interface block qualified with "pervertexNV" must be
declared as an array, where each array element corresponds to one of the
vertices of the primitive that produced the fragment. This array can have
no more than three elements, and will have a size of three if declared as
unsized. The order of the three vertices of the input primitive is
defined in the OpenGL or Vulkan API Specifications. No interpolated
per-fragment values are available for inputs qualified with
"pervertexNV". For variables qualified with "pervertexNV", it is a
compile-time error to also qualify the variable with either "centroid" or
"sample".
Modify Section 4.5.1, Redeclaring Built-In Interpolation Variables in the
Compatibility Profile, p. 84
(modify the first paragraph of the section to prohibit the use of
"pervertexNV" on built-ins)
The following predeclared variables can be redeclared with an
interpolation qualifier other than "pervertexNV" when using the
compatibility profile:
...
Modify Section 7.1, Built-In Language Variables, p. 122
(modify the list of fragment built-ins, p. 124)
In the fragment, language, built-in variables are intrinsically declared
as:
...
in vec3 gl_BaryCoordNV;
in vec3 gl_BaryCoordNoPerspNV;
(add description of the new built-ins to the list of descriptions, before
gl_PerVertex, p. 131)
The built-in fragment shader input variables gl_BaryCoordNV and
gl_BaryCoordNoPerspNV are three-component vectors providing barycentric
coordinates for the fragment. The values for these built-ins are derived
as described in the OpenGL or Vulkan API Specifications.
Modifications to the OpenGL ES Shading Language Specification, Version 3.20.5
Incorporate all applicable modifications to the OpenGL Shading Language
Specification, Version 4.60 above.
Modify Section 4.3.4, Input Variables, P. 44
(modify the fragment shader input restrictions, p. 46)
It is a compile-time error to declare a fragment shader input with, or that
contains, any of the following types:
* A boolean type
* An opaque type
* An array of arrays (unless the input has a "pervertexNV" qualifier)
* An array of structures (unless the input has a "pervertexNV" qualifier)
* A structure containing an array
* A structure containing a structure
A fragment shader input declared with a pervertexNV qualifier must be an
array. The contained type of the array must not be any of the types listed
above.
Fragment shader inputs that are, or contain, integral types must be
qualified with the interpolation qualifier "flat", or with the
interpolation qualifier "pervertexNV".
Modify Section 9.2.1, Linked Shaders, p. 160
(modify the "Interpolation" row in the table, p. 160)
Qualifier Qualifier in/out Default uniform Block buffer Block
Class Uniforms
------------- ----------- ------ -------- ------------- ------------
Interpolation smooth Yes N/A N/A N/A
flat
----------- ------ -------- ------------- ------------
pervertexNV No N/A N/A N/A
Modify Section 9.2.2, Separable Programs, p. 161
(modify the "Interpolation" row in the table, p. 161)
Qualifier Class Qualifier in/out
--------------- ----------- ------
Interpolation smooth Yes
flat
----------- ------
pervertexNV No
Issues
(1) The AMD_shader_explicit_vertex_parameter extension provides similar
functionality. Why write a new extension, and how is this extension
different?
RESOLVED: We chose to implement a separate extension for several
reasons:
- The NVIDIA hardware supporting this extension is capable of providing
a three-component barycentric weight vector, while the AMD extension
provides only two components. In some cases, it may be more efficient
to explicitly interpolate an attribute via:
float value = (gl_BaryCoordNV.x * v[0].attrib +
gl_BaryCoordNV.y * v[1].attrib +
gl_BaryCoordNV.z * v[2].attrib);
instead of
float value = (gl_BaryCoordNV.x * (v[0].attrib - v[2].attrib) +
gl_BaryCoordNV.y * (v[1].attrib - v[2].attrib) +
v[2].attrib);
- The built-in gl_BaryCoordPullModelAMD does not appear to map to
anything supported NVIDIA hardware, so we would likely be unable to
support the AMD extension as written.
This extension has several other functional differences from the AMD
extension:
- This extension does not provide extra "Centroid" and "Sample" variants
of the gl_BaryCoord* built-in inputs. Equivalent values can be
obtained using built-in interpolation functions like:
vec3 bcCentroid = interpolateAtCentroid(gl_BaryCoordNV);
vec3 bcNoPerspSample = interpolateAtSample(gl_BaryCoordNoPerspNV);
- Attributes that can be explicitly fetched per-vertex instead of
interpolated are identified with the qualifier "pervertexNV". The
AMD extension uses "__explicitInterpAMD". In both extensions,
attributes that can be fetched this way do not have interpolated
per-fragment values.
- Attributes that can be explicitly fetched per-vertex instead of
interpolated are declared as "arrayed" inputs or interface blocks, and
are accessed using the vertex number as the first index. This syntax
is identical to that used to access per-vertex attributes in the
multi-vertex input primitives used for tessellation control,
tessellation evaluation, and geometry shaders. In the AMD extension,
per-vertex attributes are fetched using the built-in
interpolateAtVertexAMD().
- The vertex number used to fetch attributes is not required to be
constant, but fetches using a constant vertex numbers are preferred
when possible.
(2) Should we support "pervertexNV" on compatibility profile built-in
inputs like gl_FrontColor?
RESOLVED: No, "pervertexNV" will be allowed only on user-defined
inputs.
(3) Will the three barycentric weights always sum to exactly 1.0?
RESOLVED: No, there may be some small mathematical error in computing
the weights. The mathematical error should have roughly the same
relative magnitude as occurs when interpolating normal attributes.
(4) Can barycentric weights ever be outside the range [0.0, 1.0]?
RESOLVED: Yes, if the barycentric weights are sourced at a fragment
location not contained within the original primitive, barycentric
weights can be out of bounds. Additionally, minor rounding error from
interpolating barycentric weights can lead to out-of-bounds values.
(5) Will barycentric interpolation using gl_BaryCoordNV and per-vertex
fragment shader inputs produce results identical to conventional
fixed-function interpolation?
RESOLVED: While the inputs used for conventional interpolation and
barycentric interpolation in the fragment shader may be the same, the
order of the operations performed may be different. This can lead to
small differences due to rounding error.
(6) What functionality does this extension enable besides fragment shader
code that explicitly interpolates between values written as outputs in
a vertex, tessellation, or geometry shader?
RESOLVED: This programming model allows applications to explicitly
interpolate per-vertex values stored in a SSBO (shader storage block) or
other globally accessible memory without requiring that the values be
fetched from a vertex array and passed through a vertex shader or other
shader stage. In this model, the fragment shader interpolation logic
only needs access to the vertex IDs for the vertices of the primitives
being processed.
Additionally, this model allows fragment shaders to reconstruct
per-fragment attributes by processes other than linear interpolation.
For example, a fragment shader could look at the barycentric weights to
determine if a fragment is near the edge of a primitive and use a
different interpolation algorithm depending on the fragment's location.
(7) Could barycentric functionality be implemented in GLSL without this
extension?
RESOLVED: Yes, this functionality could be emulated with a geometry
shader. However, this approach would have a significant cost in terms
of both shader execution time (running a geometry shader that would
otherwise not be needed) and attribute bandwidth. For example, an
application could insert a geometry shader like this:
layout(triangles) in;
layout(triangle_strip, max_vertices=3) out;
in Block {
vec2 attr1;
float attr2;
float attr3;
} v[];
out vec3 barycoord;
noperspective out vec3 barynopersp;
flat out vec2 outattr1[3]; // sourced per-vertex in FS
flat out float outattr2[3]; // sourced per-vertex in FS
out float attr3; // interpolated
void main()
{
for (int i = 0; i < 3; i++) {
// Pass through position and any other interpolated attributes.
gl_Position = gl_in[i].gl_Position;
attr3 = v[i].attr3;
// Write out barycentric values that could be interpolated over
// the primitive to emulate gl_BaryCoord*NV.
barycoord = barynopersp =
vec3((i == 0) ? 1.0 : 0.0, (i == 1) ? 1.0 : 0.0,
(i == 2) ? 1.0 : 0.0);
// For each attribute to be fetched using raw per-vertex values,
// we need to pass through three separate per-vertex flat
// attributes so the fragment shader can fetch from any of the
// three vertices. This effectively triples the number of
// per-vertex outputs for each attribute we want to source this
// way.
for (int j = 0; j < 3; j++) {
outattr1[j] = v[j].attr1;
outattr2[j] = v[j].attr2;
}
// Finally, emit the vertex.
emitVertex();
}
}
The fragment shader could then use <barycoord> and <barynopersp> for
barycentric weights, and could fetch per-vertex values from the arrays
<outattr1> and <outattr2>.
(8) How should we qualify fragment shader input variables to indicate that
they can be read as per-vertex values?
RESOLVED: We will add a new interpolation qualifier named
"pervertexNV".
The initial draft of this extension was written using the name
"nointerpolateNV". This was intended to indicate that inputs would not
be interpolated, but instead sourced per-vertex. This seemed like a
good name for an interpolation qualifier, and was also consistent with
the existing "noperspective" qualifier. However, HLSL for Direct3D
already has a qualfier "nointerpolation" which is equivalent to the GLSL
"flat" qualifier. To avoid possible confusion, we chose not to use a
qualifier whose name is similar to the HLSL qualifier but whose meaning
is completely different.
We considered using a layout qualifier "layout(pervertexNV)" instead of
a raw interpolation qualifier, but chose to use regular qualifiers to be
consistent with other existing interpolation qualifiers.
Unlike the AMD extension, the final version of this extension does not
use a double underscore prefix on the qualifier keyword. The use of
underscores was presumably to avoid the (unlikely) possibility of
breaking existing shaders using identifiers like "pervertexNV". Because
GLSL reserves identifiers beginning with underscores, it's not legal to
have a (colliding) variable name starting with "__". However, this set
of identifiers is "reserved for use by underlying software layers"
(i.e., shader middleware) and not shading language extensions.
Revision History
Revision 3, 2019/04/08 (mchock)
- Add modifications specific to ESSL.
Revision 2, 2018/09/11 (pbrown)
- Prepare the extension spec for publication.
Revision 1
- Internal revisions.