着色器shader
+ -

像素着色器PixelShader

2024-05-14 35 0

什么是像素着色器?

像素着色器是针对逐个像素进行的。在光栅化阶段,一个三角形在其所覆盖的每个像素处使用插值来计算相应顶点的各个属性,然后把插值后的顶点传递给像素着色器。

  • 像素着色器也是一组指令,这组指令在顶点中像素被渲染时执行。在每个执行时间,都会有很多像素被渲染。(像素的数目依靠屏幕的分辨率决定)
  • 像素着色器的指令和顶点着色器的指令非常接近。像素着色器不能像顶点着色器那样,单独存在。他们在运行的时候,必须有一个顶点着色器被激活。

为什么大家要使用像素着色器?

  • 像素着色器过去是一种高级图形技术,专门用来提高渲染速度。
  • 和顶点着色器一样,使用像素着色器,程序员能自定义渲染每个像素。

像素着色器如何运作?

一个像素着色器操作顶点上单独的像素。和顶点着色器一样,像素着色器源代码也是通过一些API加载到硬件的。

如何创建一个像素着色器?

也和顶点着色器一样,你只需要一个文本编辑器和支持着色器编程的显卡即可。同样,API(Direct3D OpenGL)加载像素着色器代码指令到硬件中。

像素着色器示例

PixelShader.hlsl
174507297692

Texture2D txY : register(t0);
Texture2D txU : register(t1);
Texture2D txV : register(t2);
SamplerState samLinear : register(s0);

struct PS_INPUT
{
    float4 Pos : SV_POSITION;
    float2 Tex : TEXCOORD;//纹理坐标
};


float3 yuv_to_rgb(float3 YUV)
{

    /*Y'= 0.299*R' + 0.587*G' + 0.114*B'

        U'= -0.147*R' - 0.289*G' + 0.436*B' = 0.492*(B'- Y')

        V'= 0.615*R' - 0.515*G' - 0.100*B' = 0.877*(R'- Y')

        R' = Y' + 1.140*V'

        G' = Y' - 0.394*U' - 0.581*V'

        B' = Y' + 2.032*U'*/


    float u = YUV.y;
    float v = YUV.z;
    float r = YUV.x + 1.403f*v;
    float g = YUV.x - 0.344f*u - 1.403f*v;
    float b = YUV.x + 1.770f*u;

    /*if (r < 0.018 && g < 0.018 && b < 0.018)
    {*/
        /*r = (r < 0.018) ? 4.5*r : 1.099*pow(r, 0.45) - 0.099;

        g = (g < 0.018) ? 4.5*g : 1.099*pow(g, 0.45) - 0.099;

        b = (b < 0.018) ? 4.5*b : 1.099*pow(b, 0.45) - 0.099;*/
    /*}
    else
    {
        r = 1.099*pow(r, 0.45) - 0.099;

        g = 1.099*pow(g, 0.45) - 0.099;

        b = 1.099*pow(b, 0.45) - 0.099;
    }*/

    return float3(r, g, b);
}

float3 rgb_to_yuv(float3 RGB)
{
    float y = dot(RGB, float3(0.299, 0.587, 0.114));
    float u = (RGB.z - y) * 0.565;
    float v = (RGB.x - y) * 0.713;
    return float3(y, u, v);
}

float3 rgb_to_yuv1(float3 RGB)
{
    float y = RGB.x * 0.299 + RGB.y * 0.587 + RGB.z * 0.114;
    float u = -RGB.x * 0.169 - RGB.y * 0.331 + RGB.z * 0.500;
    float v = RGB.x * 0.500 - RGB.y * 0.419 - RGB.z * 0.081;
    return float3(y, u, v);
}

float3 yuv_to_rgb1(float3 YUV)
{
    float u = YUV.y;
    float v = YUV.z;
    float r = YUV.x + 1.400*v;
    float g = YUV.x - 0.343*u - 0.711*v;
    float b = YUV.x + 1.765*u;

    return float3(r, g, b);
}

float3 yuv_to_rgb2(float3 YUV)
{
    float y = YUV.x;
    float u = YUV.y;
    float v = YUV.z;
    float r = y + 1.140*v;
    float g = y - 0.395*u - 0.581*v;
    float b = y + 2.032*u;

    return float3(r, g, b);
}


float4 PS(PS_INPUT input) : SV_Target
{
    //这一行从三个纹理(txY,txU,txV)中分别采样Y、U和V通道的值,并将它们存储在一个4维向量中。
    float4 yuva = {txY.Sample(samLinear, input.Tex).r, txU.Sample(samLinear, input.Tex).r, txV.Sample(samLinear, input.Tex).r, 0};

//YUV to RGB uncomment the below 2 lines
    yuva -= float4(0, .5f, .5f, 0);
    float4 f=  float4(yuv_to_rgb2(yuva.xyz), yuva.w); // don't lose alpha
    return f;
}

具体的介绍详见:https://www.vaczh.com/article/detail-27.html

PixelShader.hlsl经过编译后为PixelShader.h。和顶点着色器类似:

const BYTE g_PS[] =
{
...
}

在D3D11中:

    ID3D11PixelShader* m_PixelShader;

    Size = ARRAYSIZE(g_PS);
    hr = m_Device->CreatePixelShader(g_PS, Size, nullptr, &m_PixelShader);
    if (FAILED(hr))
    {
        return ProcessFailure(m_Device, L"Failed to create pixel shader in OUTPUTMANAGER", L"Error", hr, SystemTransitionsExpectedErrors);
    }

    m_DeviceContext->PSSetShader(m_PixelShader, nullptr, 0);

0 篇笔记 写笔记

D3D11像素着色器
这段像素着色器的代码实现了从YUV图像到RGB图像的转换,并保留了原始图像的alpha通道。让我们逐行解释代码:float4 yuva = {txY.Sample(samLinear, input.Tex).r, txU.Sample(samLinear, input.Tex).r, txV.S......
像素着色器PixelShader
什么是像素着色器像素着色器是针对逐个像素进行的。在光栅化阶段,一个三角形在其所覆盖的每个像素处使用插值来计算相应顶点的各个属性,然后把插值后的顶点传递给像素着色器像素着色器也是一组指令,这组指令在顶点中像素被渲染时执行。在每个执行时间,都会有很多像素被渲染。(像素的数目依靠屏幕的分辨率决定)......
3.11像素着色器
光栅化器将基本体转换为片段后,片段将传递到像素着色器阶段。像素着色器阶段是渲染管道中的最后一个可编程着色器阶段。它通过调用其像素着色器程序来单独处理每个片段。每个像素着色器调用都是独立运行的——在被处理的单个片段之间不可能进行直接通信。像素着色器完成后,结果是处理后的输出片段,该片段被传递到输出合......
3.11.1像素着色器管道输出
像素着色器阶段从光栅化器阶段接收其输入片段。这意味着像素着色器程序将使用的输入属性也由光栅化器生成。我们已经在光栅化器部分看到,它基于被光栅化的基元内片段的采样位置生成插值属性数据,该位置通常是像素的中心(尽管有时来自其他采样位置)。我们还看到,可以在像素着色器程序中指定各种插值修改器关键字,该程序......
3.11.2像素着色器状态配置
在清楚了解像素着色器程序可以接收哪些数据后,我们现在将考虑应用程序可以使用哪些类型的状态配置。像素着色器阶段是一个可编程阶段,这意味着它可以访问我们在各个管道阶段看到的标准通用着色器核心功能。再一次,我们不会在这里重复任何代码列表,因为它们本质上与我们在顶点着色器部分中看到的相同。下面列出了这些常见......
3.11.3像素着色器阶段处理
我们现在已经看到了像素着色器阶段从光栅化阶段接收的信息类型,以及可以提供哪些额外资源来增加可用的数据。在本节中,我们将首先考虑像素着色器层如何履行其职责的一些机制。接下来,我们将通过考虑像素着色器如何在传统渲染场景中表示对象的材质属性来进一步探索像素着色器。之后,我们将研究新无人机的一些可能用途,并......
3.11.3像素着色器阶段处理-简单示例
现在我们继续考虑如何使用像素着色器阶段来实现渲染模型。此阶段的主要职责是生成将融合到管道末端绑定的渲染目标中的输出颜色。因此,开发人员必须做出的最终决定是执行什么类型的计算,以及为该计算输入什么数据。算法的类型可以从渲染的所有像素的单色输出,一直到在执行最终渲染之前需要几个模拟步骤的完整全局照明系统......
作者信息
站长漫谈
取消
感谢您的支持,我会继续努力的!
扫码支持
扫码打赏,你说多少就多少

打开支付宝扫一扫,即可进行扫码打赏哦

您的支持,是我们前进的动力!