我正在尝试编写一个非常简单的着色器,它可以为适用的对象添加随机闪烁.我想这样做的方法是在像素着色器中为像素值添加一个白色的随机阴影(R = G = B).
它似乎noise()不像我希望的那样工作:
float multiplier = noise(float3(Input.Position[0], Input.Position[1], time));
Run Code Online (Sandbox Code Playgroud)
它给我"错误X4532:无法将表达式映射到像素着色器指令集",指的是调用noise().
由于我不知道在着色器调用之间保留数字的方法,我认为我不能只根据渲染前传入的种子编写一个简单的随机数生成函数.
有没有办法从像素着色器内部生成一个随机数?如果有办法,怎么样?
我还在开发一个图像处理项目,该项目利用HLSL着色器添加Photoshop-esque过滤器,如投影,斜角等.现在我正在寻找一种在HLSL中实现外部发光效果的方法.
我目前正在尝试以下想法:
1)缩放当前纹理以创建光晕(参数:glowSize,用于设置轮廓的大小)
2)模糊水平
3)模糊垂直,改变模糊颜色以发光颜色并在顶部添加原始纹理
我正在使用以下多次传递HLSL着色器来渲染光晕:
float4 PS_Scale(VS_OUTPUT IN) : COLOR0
{
float2 tex = IN.texture0;
float2 scaleCenter = float2(0.5f, 0.5f);
float2 scaleTex = (tex - scaleCenter) * glowSize + scaleCenter;
return tex2D(foreground, scaleTex);
}
float4 PS_GlowH(VS_OUTPUT IN) : COLOR0
{
float2 Tex = IN.texture0;
float4 sum = float4(0.0, 0.0, 0.0, 0.0);
sum += tex2D(secondForeground, float2(Tex.x - 4.0*blur, Tex.y))*0.05;
sum += tex2D(secondForeground, float2(Tex.x - 3.0*blur, Tex.y))*0.09;
sum += tex2D(secondForeground, float2(Tex.x - 2.0*blur, Tex.y))*0.12;
sum += tex2D(secondForeground, float2(Tex.x - blur, Tex.y))*0.15; …Run Code Online (Sandbox Code Playgroud) 我和我的教练/实验室助理一样难以理解.
出于某种原因,以下HLSL代码在输出窗口中返回:
error X8000 : D3D11 Internal Compiler error : Invalid Bytecode: Invalid operand type for operand #1 of opcode #86 (counts are 1-based).
Run Code Online (Sandbox Code Playgroud)
这是导致问题的HLSL中的函数:
// Projects a sphere diameter large in screen space to calculate desired tesselation factor
float SphereToScreenSpaceTessellation(float3 p0, float3 p1, float diameter)
{
float3 centerPoint = (p0 + p1) * 0.5f;
float4 point0 = mul( float4(centerPoint,1.0f) , gTileWorldView);
float4 point1 = point0;
point1.x += diameter;
float4 point0ClipSpace = mul(point0, gTileProj);
float4 point1ClipSpace = mul(point1, gTileProj);
point0ClipSpace …Run Code Online (Sandbox Code Playgroud) 如何使用HSLS像素着色器有效地计算图像中所有像素的总和?我对Pixel Shader 2.0很感兴趣,我可以调用它作为WPF着色器效果.
我是DirectCompute技术的新手,并且一直试图从msdn网站上的文档中学习,至少可以说是密集的.
我想制作一个基本的hlsl文件,它接受一个4x4矩阵和一个4xN矩阵并返回相乘的结果.但是花了一些时间玩代码之后,我发现了一些我不理解的奇怪的东西 - 主要是我传递的线程如何处理缓冲区和输出数据.
通过所有这些示例,我传入两个16浮点缓冲区并获得一个16浮点缓冲区,然后使用4x1x1分组调度 - 我可以向您显示代码,但老实说,我还不知道什么可以帮助您.如果您想看到我的C++代码的一部分,请告诉我.
使用以下代码:
StructuredBuffer<float4x4> base_matrix : register(t0); // byteWidth = 64
StructuredBuffer<float4> extended_matrix : register(t1); // byteWidth = 64
RWStructuredBuffer<float4> BufferOut : register(u0); // byteWidth = 64, zeroed out before reading from the GPU
[numthreads(1, 1, 1)]
void CSMain( uint3 DTid : SV_DispatchThreadID )
{
BufferOut[DTid.x].x = 1;
}
Run Code Online (Sandbox Code Playgroud)
我得到以下值:
1.000 0.000 0.000 0.000
1.000 0.000 0.000 0.000
1.000 0.000 0.000 0.000
1.000 0.000 0.000 0.000
Run Code Online (Sandbox Code Playgroud)
这对我来说很有意义 - 缓冲区被解析为4个线程,每个线程执行1个float4分组.
使用以下代码:
StructuredBuffer<float4x4> base_matrix : register(t0); // …Run Code Online (Sandbox Code Playgroud) 我有一个着色器,我想在顶点着色器中移动一半顶点.我试图从性能的角度来决定最好的方法,因为我们处理的是超过100,000个顶点,因此速度至关重要.我看了3种不同的方法:(伪代码,但足以给你这个想法.<complex formula>我不能给出,但我可以说它涉及一个sin()函数,以及一个函数调用(只是返回一个)数字,但仍然是函数调用),以及浮点数的一堆基本算术).
if (y < 0.5)
{
x += <complex formula>;
}
Run Code Online (Sandbox Code Playgroud)
这样做的优点<complex formula>是只执行了一半的时间,但缺点是肯定会导致分支,实际上可能比公式慢.它是最具可读性的,但在这种情况下我们更关心速度而不是可读性.
x += step(y, 0.5) * <complex formula>;
Run Code Online (Sandbox Code Playgroud)
使用HLSL的step()函数(如果第一个参数更大则返回0,如果更少则返回1),可以消除分支,但现在<complex formula>每次都调用它,并且其结果乘以0(因此浪费了精力)一半的时间.
x += (y < 0.5) ? <complex formula> : 0;
Run Code Online (Sandbox Code Playgroud)
这个我不知道.是否?:会导致一个分支?如果不是,那么等式的两边都要进行评估,还是只考虑相关的一方?
最后的可能性是<complex formula>可以将其卸载回CPU而不是GPU,但我担心在计算sin()和其他操作时会更慢,这可能会导致净损失.此外,这意味着必须将另外一个数字传递给着色器,这也可能导致开销.任何人都有任何见解,哪个是最好的行动方案?
附录:
根据http://msdn.microsoft.com/en-us/library/windows/desktop/bb509665%28v=vs.85%29.aspx
该step()函数在?:内部使用,所以它可能并不比我的第三个解决方案更好,并且可能更糟,因为<complex formula>每次都会被调用,而它可能只用一半时间调用?:.(目前还没有人回答这部分问题.)虽然避免使用和使用:
x += (1.0 - y) * <complex formula>;
Run Code Online (Sandbox Code Playgroud)
可能比其中任何一个都好,因为在任何地方都没有比较.(并且y始终为0或1.)仍然执行<complex formula>不必要的一半时间,但可能值得完全避免分支.
我现在有点困惑,只是想请大家帮我弄清楚一些想法.
在HLSL着色器(例如计算着色器)中,我可以声明StructuredBuffer sb,对吗?我是否必须将其绑定到寄存器,例如:register(t0)?
从应用程序端,我可以调用CSSetShaderResources(...).第一个参数(StartSlot),是否与寄存器声明中"t"后面的小数字有关?
如果我将StartSlot设置为0(例如),并将第二个参数设置为2.我告诉API我将绑定两个着色器资源视图,一个在寄存器(t0)中,另一个在寄存器中(t1)?
如果我声明Texture2D tex [10]:register(t0)我可以通过调用CSSetShaderResources(0,10,...)来设置它.这是否意味着寄存器(t0~t9)都用完了?
对于这样一个问题的"快速解雇"感到抱歉,但我真的很困惑,我的一些测试似乎给出了令人难以置信的结果......
任何帮助,将不胜感激.
我想在一个32位浮点变量中存储两个浮点值.编码将在C#中进行,而解码将在HLSL着色器中完成.
到目前为止,我发现的最佳解决方案是将编码值中的小数偏移硬连接,并将它们存储为"载波"浮点的整数和小数:
123.456 -> 12.3 and 45.6
Run Code Online (Sandbox Code Playgroud)
它无法处理负值,但没关系.
但是我想知道是否有更好的方法来做到这一点.
编辑:有关该任务的更多细节:
我正在使用Unity中的固定数据结构,其中顶点数据存储为浮点数.(Float2表示UV,float3正常,依此类推.)显然没有办法正确添加额外的数据,所以我必须在这些限制范围内工作,这就是为什么我认为这完全是一个更普遍的编码数据问题.例如,我可以牺牲二级UV数据来传输2x2额外数据通道.
目标是着色器模型3.0但我不介意解码是否在SM2.0上合理地工作.
只要它"合理",数据丢失就可以了.预期的值范围是0..64,但是当我想到它时,0..1也会很好,因为重新映射到着色器内的任何范围都很便宜.重要的是保持尽可能高的精度.负值并不重要.
我刚刚开始在DirectX 11中使用Compute着色器阶段,并且在Compute着色器中写入输出资源时遇到了一些不需要的行为.我似乎只得到零作为输出,据我的理解,这意味着已在Compute着色器中执行了越界读取.(越界写入导致无操作)
输入资源
首先,我创建一个ID3D11Buffer*输入数据.在创建用于输入Compute着色器阶段的SRV时,它将作为资源传递.如果输入数据永远不会改变,那么我们可以ID3D11Buffer*在创建SRV之后释放该对象,因为SRV将充当资源的句柄.
但是,我想每帧更新输入数据,所以我只是将缓冲区留给我处理以进行映射.
// Create a buffer to be bound as Compute Shader input (D3D11_BIND_SHADER_RESOURCE).
D3D11_BUFFER_DESC constantDataDesc;
constantDataDesc.Usage = D3D11_USAGE_DYNAMIC;
constantDataDesc.ByteWidth = sizeof(ParticleConstantData) * NUM_PARTICLES;
constantDataDesc.BindFlags = D3D11_BIND_SHADER_RESOURCE;
constantDataDesc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
constantDataDesc.StructureByteStride = sizeof(ParticleConstantData);
constantDataDesc.MiscFlags = D3D11_RESOURCE_MISC_BUFFER_STRUCTURED;
hr = device->CreateBuffer ( &constantDataDesc, 0, &mInputBuffer );
Run Code Online (Sandbox Code Playgroud)
使用新创建的缓冲区作为资源创建SRV
D3D11_SHADER_RESOURCE_VIEW_DESC srvDesc;
srvDesc.Format = DXGI_FORMAT_UNKNOWN;
srvDesc.ViewDimension = D3D11_SRV_DIMENSION_BUFFEREX;
srvDesc.BufferEx.FirstElement = 0;
srvDesc.BufferEx.Flags = 0;
srvDesc.BufferEx.NumElements = NUM_PARTICLES;
hr = device->CreateShaderResourceView( mInputBuffer, &srvDesc, &mInputView );
Run Code Online (Sandbox Code Playgroud)
输出资源
现在我需要为Compute着色器创建一个要写入的资源.我还将创建一个系统内存版本的缓冲区来读取.我将使用ID3D11DeviceContext …

我是HLSL的新手.我正在尝试将使用DXGI桌面复制API从BGRA捕获的图像的色彩空间转换为使用纹理作为渲染目标的YUV444.
我已设置像素着色器以执行所需的转换.从渲染目标纹理中取4:2:0子采样YUV并使用ffmpeg将其编码为H264,我可以看到图像.
问题是 - 它是绿色的.
着色器的输入颜色信息是浮点数据类型,但RGB到YUV转换的系数矩阵假定整数颜色信息.
如果我使用钳位功能并将整数从输入颜色中取出,我将失去准确性.
欢迎任何建议和指示.如果有任何其他信息有帮助,请告诉我.
我怀疑我写的Pixel着色器,因为我第一次使用它.这是像素着色器.
float3 rgb_to_yuv(float3 RGB)
{
float y = dot(RGB, float3(0.29900f, -0.16874f, 0.50000f));
float u = dot(RGB, float3(0.58700f, -0.33126f, -0.41869f));
float v = dot(RGB, float3(0.11400f, 0.50000f, -0.08131f));
return float3(y, u, v);
}
float4 PS(PS_INPUT input) : SV_Target
{
float4 rgba, yuva;
rgba = tx.Sample(samLinear, input.Tex);
float3 ctr = float3(0, 0, .5f);
return float4(rgb_to_yuv(rgba.rgb) + ctr, rgba.a);
}
Run Code Online (Sandbox Code Playgroud)
渲染目标映射到CPU可读纹理,并将YUV444数据复制到3个BYTE阵列并提供给ffmpeg libx264编码器.编码器将编码的数据包写入视频文件.
在这里,我考虑每个2X2像素矩阵一个U(Cb)和一个V(Cr)和4个Y值.
我从纹理中检索yuv420数据: …