我已经阅读了一些关于Cg的教程,但有一点我不太清楚.顶点和片段着色器之间究竟有什么区别?什么情况比另一种更适合?
在learnwebgl tutorial1中,我在片段着色器中发现了一条有趣的行.
precision mediump float;
Run Code Online (Sandbox Code Playgroud)
我在这里发现了一篇关于它的文章,但我仍然无法理解这是什么意思?
如果我删除这一行,没有任何变化.一切都是一样的.那precision mediump float意味着什么?
我试图在GLSL中围绕着色器,我已经找到了一些有用的资源和教程,但是我一直在为一些应该是根本和微不足道的东西碰壁:我的片段着色器如何检索颜色目前的片段?
你可以通过说明来设置最终颜色gl_FragColor = whatever,但显然这是一个仅输出值.如何获得输入的原始颜色,以便对其进行计算?这必须在某个地方变量,但如果有人知道它的名字,他们似乎没有在我到目前为止遇到的任何教程或文档中记录它,它正在推动我的问题.
我有一些参数从CPU传递到GPU,这些参数对于所有片段都是常量但在每一帧都有变化(我使用的是GLSL ES 1.1).我应该为这些价值观使用制服或属性吗?属性可以在顶点到顶点之间变化,因此我的直觉是使用在整个帧中保持不变的值的属性将是低效的.然而,我已经读过,制服是针对"相对不频繁"变化的价值,这表明在每一帧上更换制服可能效率低下.
在硬件方面,我最感兴趣的是优化iPhone 4S.
我只是想创建一个非常简单的片段着色器,它为网格绘制指定的纹理.我查看了一些自定义片段着色器,它们完成了相同的操作并构建了自己的着色器并支持它周围的JS代码.但是,它只是不起作用.这是我正在尝试运行的代码的工作抽象:
顶点着色器
<script id="vertexShader" type="x-shader/x-vertex">
varying vec2 vUv;
void main() {
vUv = uv;
gl_Position = projectionMatrix *
modelViewMatrix *
vec4(position,1.0);
}
</script>
Run Code Online (Sandbox Code Playgroud)
片段着色器
<script id="fragmentShader" type="x-shader/x-fragment">
uniform sampler2D texture1;
varying vec2 vUv;
void main() {
gl_FragColor = texture2D(texture1, vUv); // Displays Nothing
//gl_FragColor = vec4(0.5, 0.2, 1.0, 1.0); // Works; Displays Flat Color
}
</script>
Run Code Online (Sandbox Code Playgroud)
场景代码
<script>
// Initialize WebGL Renderer
var renderer = new THREE.WebGLRenderer();
renderer.setSize(window.innerWidth, window.innerHeight);
var canvas = document.getElementById('canvas').appendChild(renderer.domElement);
// Initialize Scenes
var scene = new …Run Code Online (Sandbox Code Playgroud) 如" 金属着色语言指南"中所述:
片段函数不允许写入缓冲区或纹理.
我明白这是事实,但我很好奇为什么.能够从片段着色器中写入缓冲区是非常有用的 ; 我知道在硬件端可能更复杂的是不提前知道特定线程的内存写入的结束位置,这对于原始缓冲区写入并不总是知道,但这是在Metal计算中公开的一种能力着色器,为什么不在片段着色器中呢?
我应该澄清为什么我认为来自片段函数的缓冲区写入是有用的.在光栅化管道的最常见用例中,三角形被栅格化和着色(根据片段着色器)并写入预定义的存储器位置,在每个片段着色器调用之前已知,并由来自规范化设备坐标和帧的预定义映射确定缓冲.这适用于大多数使用情况,因为大多数情况下您只想将三角形直接渲染到缓冲区或屏幕.
在其他情况下,您可能希望在片段着色器中进行延迟写入,其末端位置基于片段属性而不是片段的确切位置; 有效地,光栅化与副作用.例如,大多数基于GPU的体素化通过从一些期望的角度渲染具有正交投影的场景,然后写入3D纹理,将片段的XY坐标及其相关联的深度值映射到3D纹理中的位置来工作.这在这里描述.
其他用途包括某些形式的与订单无关的透明度(透明度,其中绘制顺序不重要,允许重叠透明对象).一种解决方案是使用多层帧缓冲区,然后在单独的传递中基于它们的深度值对片段进行排序和混合.由于没有硬件支持这样做(在大多数GPU上,我相信英特尔有硬件加速),你必须维护每个像素的原子计数器和手动纹理/缓冲区写入,以协调写入分层帧缓冲区.
另一个例子可能是通过光栅化提取GI的虚拟点光源(即在光栅化时为相关片段写出点光源).在所有这些用例中,都需要来自片段着色器的缓冲区写入,因为ROP仅为每个像素存储一个结果片段.在没有这个特征的情况下获得相同结果的唯一方法是通过某种深度剥离方式,这对于高深度复杂度的场景来说非常慢.
现在我意识到我给出的例子并不是特别关于缓冲区写入,而是更广泛地关于从片段着色器进行动态内存写入的想法,理想情况下是对原子性的支持.缓冲区写入似乎只是一个简单的问题,它们的包含将大大改善这种情况.
由于我在这里没有得到任何答案,我最终在Apple的开发者论坛上发布了这个问题.我在那里得到了更多的反馈,但仍然没有真正的答案.除非我遗漏了某些内容,否则几乎所有官方支持Metal的OS X设备都支持此功能.据我所知,这个功能最初在2009年左右开始出现在GPU中.这是当前DirectX和OpenGL(甚至不考虑DX12或Vulkan)的常见功能,因此Metal将是唯一缺乏它的"尖端"API .
我意识到PowerVR硬件可能不支持此功能,但Apple没有通过功能集区分金属着色语言的问题.例如,iOS上的Metal允许片段着色器内的"自由"帧缓冲器提取,这由高速缓存的PowerVR架构直接支持在硬件中.此功能直接在Metal Shading Language中显示,因为它允许您使用[[color(m)]]iOS着色器的属性限定符声明片段函数输入.可以说,允许使用device存储空间限定符声明缓冲区,或者使用纹理access::write作为片段着色器的输入,对语言的语义更改不会比Apple为优化iOS所做的更多.因此,就我而言,PowerVR缺乏支持并不能解释我在OS X上缺少的功能.
我想根据它们在世界上的xyz位置来调整颜色.
我在片段着色器中试过这个:
varying vec4 verpos;
void main(){
vec4 c;
c.x = verpos.x;
c.y = verpos.y;
c.z = verpos.z;
c.w = 1.0;
gl_FragColor = c;
}
Run Code Online (Sandbox Code Playgroud)
但似乎颜色根据我的相机角度/位置而变化,我如何使坐标独立于我的相机位置/角度?
继承人我的顶点着色器:
varying vec4 verpos;
void main(){
gl_Position = ftransform();
verpos = gl_ModelViewMatrix*gl_Vertex;
}
Run Code Online (Sandbox Code Playgroud)
Edit2:改变标题,所以我想要世界坐标,而不是屏幕坐标!
Edit3:添加了我的完整代码
我有一些简单的多边形(少于20个顶点)在一个简单的xy平面上渲染平面,使用GL_TRIANGLES和一个平面颜色,一个2d模拟.
我想为这些多边形添加可变厚度和不同颜色的边框.我有一些使用相同顶点和glLineWidth/GL_LINE_LOOP实现的东西,它起作用,但是是另一个渲染过程并重复所有顶点变换.
我想我应该能够使用gl_FragCoord和顶点数据和/或纹理坐标在片段着色器中完成此操作,但我不确定,我的天真尝试显然是不正确的.
我想象下面的东西.
uniform vec2 scale; // viewport h/w
uniform float line_width;
uniform vec4 fill_color;
uniform vec4 border_color;
varying vec4 vertex; // in world coords
void main()
{
if (distance_from_edge(gl_FragCoord, vertex, scale) < line_width)
{
// we're close to the edge the polygon, so we're the border.
gl_FragColor = border_color;
}
else
{
gl_FragColor = fill_color;
}
}
Run Code Online (Sandbox Code Playgroud)
我想弄清楚的部分是distance_from_edge函数 - 如何计算?使用gl_FragCoord是错误的方法 - 我应该使用某种纹理映射吗?
作为一个实验,我尝试用缩放将顶点转换为像素空间,然后以像素为单位计算它与gl_FragCoord之间的距离,但这会产生我并不真正理解的奇怪结果.另外我需要到边缘的距离,而不是顶点,但我不知道如何得到它.
有任何想法吗?
编辑:根据尼科尔的回应,我的问题变成:
假设我有一个三角形,其中3个角顶点标记为边缘顶点,并且中间的一个顶点标记为非边缘(因此总共渲染了3个三角形),那么如何在片段着色器中插值以绘制给定边框厚度?我假设我将边缘标志传递给片段着色器,以及所需的线条粗细,并进行一些插值计算以计算边缘与非边缘顶点之间的距离,并将颜色阈值设置为适当的边界/填充?
我想有两个像素着色器; 第一个做一件事,然后下一个做别的事情.这是可能的,还是我必须将所有内容打包到一个着色器中?
我试图通过片段着色器调整纹理颜色.我的片段着色器非常简单:
uniform sampler2D sampler;
void main() {
vec4 tex = texture2D ( sampler, uvVarying );
gl_FragColor = vec4(tex.r, tex.g, tex.b, tex.a);
}
Run Code Online (Sandbox Code Playgroud)
这按照预期绘制了我的狗纹理:

如果我然后将着色器更改为
gl_FragColor = vec4(tex.r, tex.g, tex.b, 1.0);
Run Code Online (Sandbox Code Playgroud)
结果是我的预期,透明度信息丢失:

但如果我把它设置为:
gl_FragColor = vec4(tex.r, tex.g, tex.b, 0.0);
Run Code Online (Sandbox Code Playgroud)
我期待它完全消失,但我得到:

到底是怎么回事??
对于我原来的问题:我想在我的纹理中添加一点红色:
gl_FragColor = vec4(tex.r + 0.5, tex.g, tex.b, tex.a);
Run Code Online (Sandbox Code Playgroud)
现在,我希望它与原始纹理具有相同的透明度信息,但我得到了这个:

我在这里想念的是什么 纹理使用引擎的默认混合src = GL_ONE, dst = GL_ONE_MINUS_SRC_ALPHA.
fragment-shader ×10
glsl ×6
opengl ×5
opengl-es ×3
shader ×3
buffer ×1
cg ×1
javascript ×1
metal ×1
pixel ×1
terminology ×1
textures ×1
three.js ×1
webgl ×1