仅使用变量变量的一部分

时间:2017-04-29 16:41:56

标签: opengl glsl

假设我在声明为vec4的任何两个GLSL着色器阶段(例如顶点和片段阶段)之间有变化的变量:

in/out/varying vec4 texCoord;

如果我只在两个着色器中使用该变量的一部分(例如,通过混合)会发生什么,即我只在顶点着色器中写入其中的一部分并且仅从中读取片段着色器中的相同部分

// vertex shader
texCoord.st = ...

// fragment shader
... = texture2D(..., texCoord.st);

是否保证(即按规范)始终产生合理的结果? 似乎合理,但是我不是对GLSL语言律师的复杂性过于精通,并且不知道编译器/链接器是否将某个变量变量解释为“不完整”,因为它不是完全写入前一阶段。我确定texCoord.pq的值无论如何都不会被定义,但是会影响texCoord.st的有效性,还是整个变化的系统在纯组件级别上运行?

乍看之下我没有在GLSL规范中找到任何相关的内容,我希望根据实际规范或任何其他“官方”保证得到答案,而不是 的陈述>在合理的硬件上工作(当然除非这种情况只是 未指定或实现定义)。我也会对整个GLSL历史中的任何可能的变化感兴趣,包括在旧的GLSL 1.10中将所有返回其设备的内容变为已变化的变量变量,如gl_TexCoord[]

2 个答案:

答案 0 :(得分:4)

我试图争辩说你的代码会很好,按照规范。但是,我不确定你是否会发现我的推理100%令人信服,因为我认为这个规范似乎有点不精确。我将引用OpenGL 4.5 Core Profile SpecificationOpenGL Shading language 4.50 specification.

关于输入和输出变量,GLSL规范在4.3.4节中建立了以下内容

  

使用存储限定符in声明着色器输入变量。它们之间形成输入接口   OpenGL管道的前几个阶段和声明着色器。 [...] 上一个管道阶段的值被复制到开头的输入变量中   着色器执行。

和4.3.6分别:

  

使用存储限定符out使用存储限定符声明着色器输出变量。它们形成   声明着色器与OpenGL管道的后续阶段之间的输出接口。 [...]   在着色器执行期间,它们将正常运行   不合格的全局变量。 它们的值将复制到着色器出口上的后续管道阶段。   只需要写入后续管道阶段读取的输出变量; 允许它   有多余的输出变量声明。

第5.8节“作业”确定了

  

在写入(或初始化)之前读取变量是合法的,但是值是未定义的。

由于.st向量的赋值将写入子向量,我们可以确定此变量将在着色器调用结束时包含两个初始化和两个未初始化的组件,以及整个向量将被复制到输出。

GL规范第11.1.2.1节规定:

  

如果输出变量直接传递给顶点处理   导致光栅化的阶段,所有输出的值   期望在被渲染的图元上进行插值,   除非flatshaded。否则,将收集所有输出的   通过原始组装阶段并传递给后续   管道阶段一旦收集了一个原语的足够数据。

“所有输出的值”由着色器确定,虽然某些组件具有未定义的值,但它们仍具有值,并且此处没有未定义或实现定义的行为。线和多边形基元的插值公式(第14.5.1和14.6.1节)也从不在组件之间混合,因此任何定义的组件值都将在插值数据中产生一个定义的值。

第11.1.2.1节还包含关于顶点着色器输出的声明:

  

当程序链接时,由a写的任何输出的所有组件   顶点着色器将计入此限制。一个程序的顶点   着色器写入的内容超过MAX_VERTEX_OUTPUT_COMPONENTS的值   除非依赖于设备,否则组件的输出组件可能无法链接   优化能够使程序适合可用   硬件资源。

请注意,这种语言意味着只要写入一个组件,vec4的完整4个组件就会被计入限制。

答案 1 :(得分:2)

关于输出变量,规范说:

  

将它们的值复制到着色器出口处的后续管道阶段。

所以问题归结为两件事:

  1. 这样的输出变量的值是什么?

    这很容易回答。关于调配的部分清楚地表明,写入一个混合模板不会修改不属于混合模板的组件。由于您没有写入这些组件,因此它们的值未定义。因此,未定义的值将被复制到后续的管道阶段。

  2. 未定义值的插值是否会影响定义值的插值?

    没有。插值是一种分量操作。一个组件插值的结果不会影响另一个组件。

  3. 所以这很好。