HLSL着色器实际上如何最终影响渲染输出?


11

我了解HLSL的语法,例如,让我们假设我将其作为HLSL:

struct VOut
{
    float4 position : SV_POSITION;
    float4 color : COLOR;
};

VOut VShader(float4 position : POSITION, float4 color : COLOR)
{
    VOut output;

    output.position = position;
    output.position.xy *= 0.7f;    // "shrink" the vertex on the x and y axes
    output.color = color;

    return output;
}


float4 PShader(float4 position : SV_POSITION, float4 color : COLOR) : SV_TARGET
{
    return color;
}

我这样编译它:

D3DX11CompileFromFile(L"shaders.hlsl", 0, 0, "VShader", "vs_5_0", 0, 0, 0, &VS, 0, 0);
D3DX11CompileFromFile(L"shaders.hlsl", 0, 0, "PShader", "ps_5_0", 0, 0, 0, &PS, 0, 0);

感觉如何...知道要更改...我对HLSL和屏幕上实际像素/顶点之间的流水线到底是什么感到困惑。

这实际上是“应用”它们的方法吗?

dev->CreateVertexShader(VS->GetBufferPointer(), VS->GetBufferSize(), NULL, &pVS);
dev->CreatePixelShader(PS->GetBufferPointer(), PS->GetBufferSize(), NULL, &pPS);

// set the shader objects
devcon->VSSetShader(pVS, 0, 0);
devcon->PSSetShader(pPS, 0, 0);

请记住,我像这个东西的初学者。有人可以也许解释什么它做什么?我假设顶点HLSL函数遍历每个顶点,然后将它们更改为我在函数中拥有的任何东西,并且输出是已更改的内容……对于像素着色器来说,类似吗?

另一个困惑,我知道什么是像素,我知道什么是顶点……但是像素着色器到底是做什么的?


可以,没有人可以
-bobobobo

Answers:


10

感觉如何……知道要更改...。我对HLSL和屏幕上实际的像素/顶点之间的流水线感到困惑。

它的工作原理大致如下:当您发出绘制调用时(D3D中的DrawPrimitives,DrawIndexedPrimitives,10 +中的Draw等),将处理已绑定到管道(顶点缓冲区)的几何数据。对于每个顶点,执行顶点着色器以在剪辑空间中生成输出顶点。

然后,GPU在该裁剪空间顶点上执行一些固定功能,例如裁剪/剔除并将顶点引入屏幕空间,在此屏幕上开始对三角形进行栅格化。在对每个三角形进行栅格化期间,GPU会在该三角形的表面上插值顶点属性,并将每个插值的属性馈送到像素着色器,以为该像素生成半最终颜色(在像素着色器执行后应用混合,因此“半最后”)。

这实际上是“应用”它们的原因:

您首先发布的代码将编译着色器,然后将它们绑定到管道,在此管道中,着色器将保持活动状态,以进行后续的绘画调用,直到更改为止。它实际上并不会导致它们被执行。

有人可以解释一下它在做什么吗,我假设顶点HLSL函数遍历每个顶点(作为输入Position:POSITION和color:COLOR),然后将其更改为我在函数中拥有的任何东西,而输出就是已更改的内容。 ...(像素着色器也一样)。

另一个困惑,我知道像素是什么,我知道顶点是.....但是像素着色器到底是做什么的......

顶点着色器负责将顶点从模型空间转换为剪贴空间。

像素着色器负责根据内插的顶点属性计算像素的倒数第二个颜色/深度。


9

我将尝试在不使用大量术语的情况下解释事物的工作方式。

如果只考虑简单性而不是交互速度,那么计算机中的3D表面将是空间中巨大的点云,足够密集,因此我们可以单独渲染每个点,而不会出现间隙。

您只想在内存中存储一​​次模型,但是需要以各种大小和不同角度显示模型,因此,在渲染3D模型时,需要从内存中读取所有点进行“转换”。例如,要将模型放大50%,您需要将点的位置缩放一半:

out.position = in.position * 0.5;
out.color = in.color;

这几乎是人们可以想到的最简单的“顶点着色器”:从内存进入顶点位置,而出一个新的顶点位置,变大一半。一半大的顶点不会存储回内存中,而是立即用于渲染然后丢弃。

尽管完全简化了一些关键概念但从本质上讲,它描述了电影如何制作图形的各个方面。

交互式图形(游戏)不能这么简单,因为它们需要比电影更快地渲染图形几个数量级。

在游戏中,我们无法为屏幕上的每个像素渲染一个点,也无法弥补空白。因此,作为一种折衷方案,将附近三个点之间的间隙渲染为三角形,由于各种技术原因,该间隙最好在屏幕上至少有10个像素大。

可以将3D三角形投影到2D屏幕上,然后分成一堆1D线,每条线可以分成一堆0D像素。因此,我们可以将渲染3D三角形的问题分解并解决为更简单的孤立地渲染大量0D像素的问题。计算机可以在更短的时间内解决更简单的问题。

像素着色器是一个小程序,我们在每个像素上运行,因此是通过分解三角形生成的。

out.color = in.color;

这几乎是可以想到的最简单的“像素着色器”:进入三个三角形顶点的颜色的混合,然后进入相同的颜色。输入来自“顶点着色器”的输出,并将输出写入内存中的屏幕。

因此,“顶点着色器”是在GPU芯片内部运行的程序。它的输入是GPU内存中的“顶点缓冲区”,其输出直接馈入“像素着色器”。“像素着色器”也是在GPU芯片内部运行的程序。它的输入是来自顶点着色器的三个顶点的混合,其输出是屏幕上的一个像素。



-2

现在不用担心像素着色器。如果您是初学者,那么您应该是仅包含顶点着色器和片段着色器的GLSL / HLSL的世界。一旦熟悉了,就开始了解变量运动等,然后扩大视野。

我强烈推荐一本教科书,以使您了解API的工作原理。OpenGL的书籍也做说明事情如何做好改变多年来从固定管道的动态可编程管线。

去冠军!


1
片段着色器实现与像素着色器相同的功能。

1
我认为我们不能从这个问题中看出OP是否是所有游戏编程的初学者-他只是说他是编写着色器代码的初学者。学写着色器是在游戏开发商的棚一个非常重要的工具,我不会仅仅除非你在是唯一的粉饰他们非常学习游戏开发的开始阶段。
Olhovsky
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.