Как я понимаю Input Assembler используется, в обобщение, чтобы хранить вершины и индексы модели. Потом эти вершины читаются из Vertex Shader, обрабатываются и посылаются дальше по pipeline.
Вопрос у меня такой, можно ли каким-то образом проигнорировать Input Assembler создать вершины напрямую в Vertex Shader. К примеру таким образом:
1. Я создаю Constant Buffer и прописываю туда координаты центра квадрата и расстояние до одной из вершин.
2. Vertex Shader считывает эту информацию и осздаёт 6 вершин, которые потом перешлёт дальше по pipeline.
Я написал програмку которая в принципе делает частично то что мне надо, но не всё. Я не знаю почему. Треугольник она рисует, но только 1. Если в shader-e я swap 0,1,2 с 3,4,5 то 2-й треугольник нарисуется, но 1-й нет.
ID3DBlob* pVSBlob = NULL; hr = CompileShaderFromFile( L"Tutorial02.fx", "vshader", "vs_4_0", &pVSBlob ); // Create the vertex shader hr = g_pd3dDevice->CreateVertexShader( pVSBlob->GetBufferPointer(), pVSBlob->GetBufferSize(), NULL, &g_pVertexShader ); // Compile the pixel shader ID3DBlob* pPSBlob = NULL; hr = CompileShaderFromFile( L"Tutorial02.fx", "PS", "ps_4_0", &pPSBlob ); // Create the pixel shader hr = g_pd3dDevice->CreatePixelShader( pPSBlob->GetBufferPointer(), pPSBlob->GetBufferSize(), NULL, &g_pPixelShader ); pPSBlob->Release(); // Set primitive topology g_pImmediateContext->IASetPrimitiveTopology( D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST );
//-------------------------------------------------------------------------------------- // Pixel Shader //-------------------------------------------------------------------------------------- float4 PS( float4 Pos : SV_POSITION ) : SV_Target { return float4( 1.0f, 1.0f, 0.0f, 1.0f ); // Yellow, with Alpha = 1 } struct VS_OUT { float4 pos : SV_Position; // insert other vs output fields here as needed }; // vertex shader that draws a triangle without vbuffers VS_OUT vshader(uint idx : SV_VertexId) { VS_OUT ret = (VS_OUT)0; switch (idx) { case 3: ret.pos = float4(-0.1,-0.1,1,1); break; case 4: ret.pos = float4(0.1,0.1,1,1); break; case 5: ret.pos = float4(0.1,-0.1,1,1); break; case 0: ret.pos = float4(-0.1,-0.1,1,1); break; case 1: ret.pos = float4(-0.1,0.1,1,1); break; case 2: ret.pos = float4(0.1,0.1,1,1); break; } return ret; }
обожи
зачем ?
не, не так - заняться больше не чем, кроме как нагружать шейдер не нужными ветками ?
Честно говоря я думал что разгрузить CPU - это неплохая идея. Опять же - скорее всего я ошибаюсь. В принципе, чтобы хранить информацию к примеру о сфере надо только vector orientation и radius и это всё. Что остаётся мне сделать чтобы нарисовать сферу надо около 500 вершин и 1000 индексов. Есть 3 опции, как я вижу:
1. Прочитать все из файла и записать в буфферы;
2. Вычислить используя CPU;
3. Вычислить используя GPU;
PavelB
> 1. Прочитать все из файла и записать в буфферы;
> 2. Вычислить используя CPU;
> 3. Вычислить используя GPU;
Один раз загрузить одну сферу религия не позволяет?
Генерировать новые вершины умеет геометрический шейдер. Но его возможности ограничены максимальным количеством этих генерируемых вершин и примитивов, образованных ими. Поэтому для сферы действительно проще и быстрее загрузить один раз вершинки и индексы.
PavelB
так можно рисовать экранные квады, не используя InputAssembler:
// // This is used for drawing screen-aligned quads. // struct VS_ScreenInput { float4 position : Position; float2 texCoord : TexCoord0; }; struct VS_ScreenOutput { float4 position : SV_Position; float2 texCoord : TexCoord0; }; VS_ScreenOutput ScreenVertexShader(in VS_ScreenInput input ) { VS_ScreenOutput output; output.position = input.position; output.texCoord = input.texCoord; return output; } inline void GetFullScreenTrianglePosTexCoord( in uint vertexID: SV_VertexID, out float4 position, out float2 texCoord ) { // Produce a fullscreen triangle. // NOTE: z = 1 (the farthest possible distance) -> optimization for deferred lighting/shading engines: // skybox outputs z = w = 1 -> if we set depth test to 'less' then the sky won't be shaded. // or you can just set your viewport so that the skybox is clamped to the far clipping plane, which is done by setting MinZ and MaxZ to 1.0f. // if( vertexID == 0 )// lower-left { position = float4( -1.0f, -3.0f, 1.0f, 1.0f ); texCoord = float2( 0.0f, 2.0f ); } else if ( vertexID == 1 )// upper-left { position = float4( -1.0f, 1.0f, 1.0f, 1.0f ); texCoord = float2( 0.0f, 0.0f ); } else //if ( vertexID == 2 )// upper-right { position = float4( 3.0f, 1.0f, 1.0f, 1.0f ); texCoord = float2( 2.0f, 0.0f ); } /* another way to calc position ( from NVidia samples [2008] / Intel's Deferred Shading sample [2010] ): //-------------------------------------------------------------------------------------------------------- struct FullScreenTriangleVSOut { float4 positionViewport : SV_Position; }; // Parametrically work out vertex location for full screen triangle FullScreenTriangleVSOut output; float2 grid = float2((vertexID << 1) & 2, vertexID & 2); output.positionViewport = float4(grid * float2(2.0f, -2.0f) + float2(-1.0f, 1.0f), 1.0f, 1.0f); or yet another one: Out.position.x = (vertexID == 2)? 3.0 : -1.0; Out.position.y = (vertexID == 0)? -3.0 : 1.0; Out.position.zw = 1.0; //-------------------------------------------------------------------------------------------------------- See: http://anteru.net/2012/03/03/1862/ float4 VS_main (uint id : SV_VertexID) : SV_Position { switch (id) { case 0: return float4 (-1, 1, 0, 1); case 1: return float4 (-1, -1, 0, 1); case 2: return float4 (1, 1, 0, 1); case 3: return float4 (1, -1, 0, 1); default: return float4 (0, 0, 0, 0); } } All you need for rendering now is to issue a single draw call which renders a triangle strip containing four vertices, and you’re done. Note: This quad is for RH rendering, if your culling order is reversed, you’ll need to swap the second and third vertex. In the pixel shader, you can now use SV_Position, or alternatively, you can also generate UV coordinates in the vertex shader. //-------------------------------------------------------------------------------------------------------- // Without the explicit casts, this does not compile correctly using the // D3D Compiler (June 2010 SDK) float x = float ((id & 2) << 1) - 1.0; float y = 1.0 - float ((id & 1) << 2); return float4 (x, y, 0, 1); */ } //**************************************************************************************** /** FullScreenTriangle_VS rendered as a single triangle: ID3D11DeviceContext* context; (uses no vertex/index buffers) context->IASetInputLayout(nil); context->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST); context->Draw(3,0); */ VS_ScreenOutput FullScreenTriangle_VS( in uint vertexID: SV_VertexID ) { VS_ScreenOutput output; GetFullScreenTrianglePosTexCoord( vertexID, output.position, output.texCoord ); return output; } inline void GetFullScreenQuadPosTexCoord( in uint vertexID: SV_VertexID, out float4 position, out float2 texCoord ) { // Produce a fullscreen triangle. // NOTE: z = 1 (the farthest possible distance) -> optimization for deferred lighting/shading engines: // skybox outputs z = w = 1 -> if we set depth test to 'less' then the sky won't be shaded. // or you can just set your viewport so that the skybox is clamped to the far clipping plane, which is done by setting MinZ and MaxZ to 1.0f. // if( vertexID == 0 )// upper-left { position = float4( -1.0f, 1.0f, 1.0f, 1.0f ); texCoord = float2( 0.0f, 0.0f ); } else if ( vertexID == 1 )// lower-left { position = float4( -1.0f, -1.0f, 1.0f, 1.0f ); texCoord = float2( 0.0f, 1.0f ); } else if ( vertexID == 2 )// upper-right { position = float4( 1.0f, 1.0f, 1.0f, 1.0f ); texCoord = float2( 1.0f, 0.0f ); } else //if ( vertexID == 3 )// lower-right { position = float4( 1.0f, -1.0f, 1.0f, 1.0f ); texCoord = float2( 1.0f, 1.0f ); } } /** FullScreenQuad_VS rendered as a triangle strip: ID3D11DeviceContext* context; (uses no vertex/index buffers) context->IASetInputLayout(nil); context->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP); context->Draw(4,0); */ struct VS_ScreenQuadOutput { float4 position : SV_Position; float2 texCoord : TexCoord0; float3 eyeRayVS : TexCoord1; // ray to far frustum corner in view space, used for restoring view-space pixel position from depth }; VS_ScreenQuadOutput FullScreenQuad_VS( in uint vertexID: SV_VertexID ) { VS_ScreenQuadOutput output; GetFullScreenQuadPosTexCoord( vertexID, output.position, output.texCoord ); if( vertexID == 0 )// upper-left { output.eyeRayVS = frustumCornerVS_FarTopLeft.xyz; } else if ( vertexID == 1 )// lower-left { output.eyeRayVS = frustumCornerVS_FarBottomLeft.xyz; } else if ( vertexID == 2 )// upper-right { output.eyeRayVS = frustumCornerVS_FarTopRight.xyz; } else //if ( vertexID == 3 )// lower-right { output.eyeRayVS = frustumCornerVS_FarBottomRight.xyz; } return output; }
Один раз загрузить одну сферу религия не позволяет?
Честно говоря, если бы был выбор я бы предпочёл всё делать через CPU. Так я чувствовал бы больше контроля в том, что я делаю. В тоже время, если всё равно я должен использовать шайдеры, тогда почему бы не использовать на полную карушку. Хотя, я только относительно недавно начал учить всё что касается графики. С моими ограниченными знаниями я посчитал что если GPU будет вычислять вершины сам, то общая скорость будет быстрее. Но если те кто работает с графикой по много лет скажет что лучше сначала вычислить все вершины моделей в CPU. а потом передать в GPU, я приму этот ответ. Как я сказал, я предпочёл бы написать свой класс в C++ или C# чем морочить себе голову с шейдером.
PVSector
Спасибо тебе - я посмотрю если смогу это реализовать, хотя бы ради интереса.
Но конечной целью моего вопроса не было нарисование квадрата как такого. Просто квадрат - это наипростейший объект состоящий из большего чем 1 числа треугольников. Целью моего вопроса было узнать можно ли нарисовать примитив не используя InputAssembler. Вот как я бы сделал нахождение вершин програмно (схематичный код, не реальный), без шейдера:
Vertex[] GetVertices(enum type, ConstantBuffer buffer) { switch(type) { case Triangle: bufferTriangle = buffer as ConstantBufferTriangle; // return 3 vertices using some data from buffer. return GetVerticesTriangle(bufferTriangle); case Square: bufferSquare = buffer as ConstantBufferSquare; // Return 4 vertices using some data from buffer. Let's say size of the diagonal of the square. return GetVerticesSquare(bufferSquare); case Cube: bufferCube = buffer as ConstantBufferCube; // return 8 vertices using some data from buffer. Let's say the diagonal of the cube return GetVerticesCube(bufferCube); case Sphere: bufferSphere = buffer as ConstantBufferSphere; // return ~500-600 vertices using some data from buffer. Let's say the radius of the sphere return GetVerticesSphere(bufferSphere); case .....: ............... } }
PavelB
Так шейдеры использовать нельзя.
PavelB
> Честно говоря, если бы был выбор я бы предпочёл всё делать через CPU
Зачем же тогда вообще браться за ДХ?
Тема в архиве.