Прежде чем вдаваться в подробности, я хочу наметить проблему:Как я могу передать результаты вычисления шейдера в вершинный шейдер без использования буфера вершин?
Я использую RWStructuredBuffers для хранения выходных данных моих вычислительных шейдеров (CS). Так как вершинные и пиксельные шейдеры не могут считывать данные из RWStructuredBuffers, я сопоставить StructuredBuffer на тот же временный интервал (U0/t0) и (U4/t4):
cbuffer cbWorld : register (b1)
{
float4x4 worldViewProj;
int dummy;
}
struct VS_IN
{
float4 pos : POSITION;
float4 col : COLOR;
};
struct PS_IN
{
float4 pos : SV_POSITION;
float4 col : COLOR;
};
RWStructuredBuffer<float4> colorOutputTable : register (u0); // 2D color data
StructuredBuffer<float4> output2 : register (t0); // same as u0
RWStructuredBuffer<int> counterTable : register (u1); // depth data for z values
RWStructuredBuffer<VS_IN>vertexTable : register (u4); // triangle list
StructuredBuffer<VS_IN>vertexTable2 : register (t4); // same as u4
я использую ShaderRecourceView предоставлять пиксель и/или вершину шейдерный доступ к буферам. Эта концепция отлично работает для моих пиксельных шейдеров, вершинные шейдеры, однако, кажется, не только для чтения 0 значения (я использую SV_VertexID как индекс для буферов):
PS_IN VS_3DA (uint vid : SV_VertexID)
{
PS_IN output = (PS_IN)0;
PS_IN input = vertexTable2[vid];
output.pos = mul(input.pos, worldViewProj);
output.col = input.col;
return output;
}
Нет сообщений об ошибках или предупреждений от HLSL компилятора, запускается renderloop с 60 fps (используя vsync), но экран остается черным. Так как я пустую экран с Color.White до вызова Draw (..), конвейер визуализации, кажется, активен.
Когда я прочитал содержание треугольника данных через UAView из ГПУ в «vertArray» и кормить его обратно в буфер вершин, все работает, однако:
Программа:
let vertices = Buffer.Create(device, BindFlags.VertexBuffer, vertArray)
context.InputAssembler.SetVertexBuffers(0, new VertexBufferBinding(vertices, Utilities.SizeOf<Vector4>() * 2, 0))
HLSL:
PS_IN VS_3D (VS_IN input)
{
PS_IN output = (PS_IN)0;
output.pos = mul(input.pos, worldViewProj);
output.col = input.col;
return output;
}
Здесь определено определение 2D-вершин/пикселов. Обратите внимание, что PS_2D доступа к буферам «output2» в слоте t0 - и это именно «трюк», что я хочу повторить для того 3D вершинного шейдера «VS_3DA»:
float4 PS_2D (float4 input : SV_Position) : SV_Target
{
uint2 pixel = uint2(input.x, input.y);
return output2[ pixel.y * width + pixel.x];
}
float4 VS_2D (uint vid : SV_VertexID) : SV_POSITION
{
if (vid == 0)
return float4(-1, -1, 0, 1);
if (vid == 1)
return float4(1, -1, 0, 1);
if (vid == 2)
return float4(-1, 1, 0, 1);
return float4(1, 1, 0, 1);
}
За три дня я искал и экспериментировал но безрезультатно. Вся информация, которую я собрал, кажется, подтверждает, что мой подход с использованием SV_VertexID должен работать.
Можно ли дать совет? Спасибо, что прочитали мой пост!
==================================================================================================================================== =======================
ДЕТАЛИ:
Мне нравится концепция DirectX 11 вычислительными шейдерами очень много, и я хочу, чтобы использовать его для алгебраических вычислений. В качестве тестового примера я делаю фракталы (наборы Мандельброта) в 3D. Все работает так, как ожидалось, - кроме одного последнего кирпича в стене отсутствует.
Вычисление принимает следующие шаги:
с использованием CS для вычисления 2D текстуры (выход «counterTable» и «colorOutbutTable» (работы)
Необязательно вынести эту текстуру на экран (работ)
Использование другой CS для создания сетки (список треугольников). Эта CS принимает значения x, y и цвета с шага 1, вычисляет координату z и, наконец, создает квадрат для каждого пикселя. хранится ed в "vertexTable". (работы)
Подача списка треугольников вершинному шейдеру (проблема !!!)
Render to screen (работает - используя буфер вершин).
Для программирования я использую F # 3.0 и SharpDX как .NET-оболочку. ShaderRessourceView для обоих шейдеров (пиксельных & вершина) устанавливается с теми же параметрами (за исключением параметров размера):
let mutable descr = new BufferDescription()
descr.BindFlags <- BindFlags.UnorderedAccess ||| BindFlags.ShaderResource
descr.Usage <- ResourceUsage.Default
descr.CpuAccessFlags <- CpuAccessFlags.None
descr.StructureByteStride <- xxx // depends on shader
descr.SizeInBytes <- yyy // depends on shader
descr.OptionFlags <- ResourceOptionFlags.BufferStructured
Ничего особенного здесь. Создание 2D-буфера (связывается с буфером "output2" в слот-t0):
outputBuffer2D <- new Buffer(device, descr)
outputView2D <- new UnorderedAccessView (device, outputBuffer2D)
shaderResourceView2D <- new ShaderResourceView (device, outputBuffer2D)
Создание 3D-буфера (связывается с "vertexTable2" в слот-t4):
vertexBuffer3D <- new Buffer(device, descr)
shaderResourceView3D <- new ShaderResourceView (device, vertexBuffer3D)
// UAView not required here
Настройка ресурсов для 2D :
context.InputAssembler.PrimitiveTopology <- PrimitiveTopology.TriangleStrip
context.OutputMerger.SetRenderTargets(renderTargetView2D)
context.OutputMerger.SetDepthStencilState(depthStencilState2D)
context.VertexShader.Set (vertexShader2D)
context.PixelShader.Set (pixelShader2D)
визуализации 2D:
context.PixelShader.SetShaderResource(COLOR_OUT_SLOT, shaderResourceView2D)
context.PixelShader.SetConstantBuffer(CONSTANT_SLOT_GLOBAL, constantBuffer2D)
context.ClearRenderTargetView (renderTargetView2D, Color.White.ToColor4())
context.Draw(4,0)
swapChain.Present(1, PresentFlags.None)
Настройка ресурсов для 3D:
context.InputAssembler.PrimitiveTopology <- PrimitiveTopology.TriangleList
context.OutputMerger.SetTargets(depthView3D, renderTargetView2D)
context.VertexShader.SetShaderResource(TRIANGLE_SLOT, shaderResourceView3D)
context.VertexShader.SetConstantBuffer(CONSTANT_SLOT_3D, constantBuffer3D)
context.VertexShader.Set(vertexShader3D)
context.PixelShader.Set(pixelShader3D)
рендеринга 3D (не работает - черный экран в качестве выходного результата)
context.ClearDepthStencilView(depthView3D, DepthStencilClearFlags.Depth, 1.0f, 0uy)
context.Draw(dataXsize * dataYsize * 6, 0)
swapChain.Present(1, PresentFlags.None)
Наконец игровые номера:
static let CONSTANT_SLOT_GLOBAL = 0
static let CONSTANT_SLOT_3D = 1
static let COLOR_OUT_SLOT = 0
static let COUNTER_SLOT = 1
static let COLOR_SLOT = 2
static let TRIANGLE_SLOT = 4
Вы когда-нибудь исправляли это? Я ищу, чтобы сделать почти то же самое, но это не работает для меня. Как вы это исправили? – Miguel