Войти
ПрограммированиеФорумГрафика

Нарисовать квадрат не используя InputAssembler

#0
2:48, 14 мая 2012

Как я понимаю 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;
}
#1
3:02, 14 мая 2012

обожи

зачем ?
не, не так - заняться больше не чем, кроме как нагружать шейдер не нужными ветками ?

#2
3:39, 14 мая 2012

Честно говоря я думал что разгрузить CPU - это неплохая идея. Опять же - скорее всего я ошибаюсь. В принципе, чтобы хранить информацию к примеру о сфере надо только vector orientation и radius и это всё. Что остаётся мне сделать чтобы нарисовать сферу надо около 500 вершин и 1000 индексов. Есть 3 опции, как я вижу:
1. Прочитать все из файла и записать в буфферы;
2. Вычислить используя CPU;
3. Вычислить используя GPU;

#3
7:03, 14 мая 2012

PavelB
> 1. Прочитать все из файла и записать в буфферы;
> 2. Вычислить используя CPU;
> 3. Вычислить используя GPU;
Один раз загрузить одну сферу религия не позволяет?

#4
9:45, 14 мая 2012

Генерировать новые вершины умеет геометрический шейдер. Но его возможности ограничены максимальным количеством этих генерируемых вершин и примитивов, образованных ими. Поэтому для сферы действительно проще и быстрее загрузить один раз вершинки и индексы.

#5
12:55, 14 мая 2012

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;
}
#6
8:11, 20 мая 2012

Один раз загрузить одну сферу религия не позволяет?

Честно говоря, если бы был выбор я бы предпочёл всё делать через 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 .....:
              ...............
    }
}
#7
13:49, 20 мая 2012

PavelB
Так шейдеры использовать нельзя.

#8
14:07, 20 мая 2012

PavelB
> Честно говоря, если бы был выбор я бы предпочёл всё делать через CPU
Зачем же тогда вообще браться за ДХ?

ПрограммированиеФорумГрафика

Тема в архиве.