Jump to content

Bem vindo à Unidev
Registre para ter acesso a todos os recursos do site. Uma vez registrado e logado, você poderá criar tópicos, postar em tópicos já existentes, gerenciar seu perfil e muito mais. Se você já tem uma conta, faça login aqui - ou então crie aqui uma conta agora mesmo!
- - - - -
Photo

Se aprofundando em Tesselação no Direct3D 11 (D3D11)


por Seth Hoffert

O PIPELINE

Considere o fluxo típico de dados através do pipeline programável:

Input assembler - > Vertex shader -> Pixel shader

Os buffers contendo dados por vértice são ligados ao input assembler. O shader de vértice é executado uma vez por vértice, e cada execução é dado um valor de vértice de dados do input assembler.Digamos, no entanto, que pretendemos processar os pontos de controle e patches em vez disso. Um patch consiste de uma coleção ordenada de pontos de controle que vamos usar na construção de uma curva ou superfície. Um ponto de controle é composto por todos os dados que podemos precisar durante a construção da curva ou superfície. Por exemplo, podemos definir um ponto de controle como representando informações sobre a posição e cor.
Para relacionar os pontos de controle e patches de volta para algo mais familiar, considere os tipos primitivos padrão, tais como linhas e triângulos. Pense na linha primitiva como um patch que consiste em dois pontos de controle, e pensar no triângulo primitivo como um patch que consiste em três pontos de controle. Normalmente, os pontos de controle conterão, no mínimo, informações sobre a posição, mas mais provável que não, nós também gostaríamos de armazenar outras coisas que seriam úteis nas fases de shading programáveis, como dados normais de cor e superfície. O D3D11 nos permite ir além de três pontos de controle por patch. O vértice shader por si só não é particularmente bem adequado para o manuseamento de manipulação de patches; poderíamos armazenar os pontos de controle em um buffer e índice com SV_VertexID, mas isso não é muito eficaz, especialmente quando se lida com mais de 16 pontos de controle por patch.

Para resolver este problema, o D3D11 adiciona dois novos estágios programáveis: o hull shader e o domain shader. Considere o seguinte pipeline.

Input assembler -> Vertex shader -> Hull shader -> Tessellator -> Domain shader -> Pixel shader

Normalmente , o Input assembler pode ser configurado para tratar de pontos, linhas, segmentos de linha, triângulos e tiras triangulares. Acontece que é muito elegante adicionar novos tipos primitivos para patches. D3D11 acrescenta 32 novos tipos primitivos: cada um representa um patch com um número diferente de pontos de controle. Ou seja, é possível descrever um patch com qualquer lugar de 1 a 32 pontos de controle.

Para o propósito deste exemplo, digamos que você configurou o Input assembler para lidar com patches com 16 pontos de controle, e também que estamos apenas renderizando um patch. Vamos usar um domain patch triangular.

Desde que nós estamos renderizando um patch, vamos precisar de um buffer com 16 pontos em que - neste contexto, esses pontos são pontos de controle. Este buffer é ligado ao Input assembler como de costume. O vertex shader é executado uma vez por ponto de controle, e cada execução é dado um ponto de controle que vale a pena inserir dados do Input assembler. Similar aos tipos primitivos não-patch, o shader de vértice pode ver apenas um ponto de controle de cada vez; ele não pode ver todos os 16 pontos de controle sobre o patch.

Quando não estiver usando tesselação, a próxima fase do shader é executada uma vez que o shader de vértice tem operado em todos os vértices de uma única primitiva. Por exemplo, ao usar o tipo primitivo triângulo, o próximo estágio é executado uma vez por cada três execuções do shader de vértice. O mesmo princípio vale quando usando tesselação: a próxima fase não é executada até que todos os 16 pontos de controle foram transformados por 16 execuções do shader de vértice.

Uma vez que todos os 16 pontos de controle foram transformados, o hull shader é executado. O hull shader é composto por duas partes: uma função constante do patch e o programa hull. A função constante do patch é responsável por computar dados que se mantém constante ao longo de todo o patch. O programa hull é executado por ponto de controle, mas ao contrário do shader de vértice, é possível ver todos os pontos de controle para todo o patch.

Você pode estar se perguntando qual o propósito do programa hull. Afinal, já se transformou os pontos de controle no shader de vértice. A parte importante é que o programa hull pode levar em conta todos os pontos de controle ao computar os pontos de controle de saída mais transformados. O D3D11 nos permite a saída de um número diferente de pontos de controle do programa hull do que levamos dentro.

Isso significa que podemos realizar transformações base - por exemplo, usando um pouco de matemática, poderíamos transformar 32 pontos de controle em 16 pontos de controle, o que nos salva algum tempo de processamento mais tarde abaixo da pipeline. Neste ponto, mais esclarecimentos são úteis: o programa hull é executado uma vez por ponto de controle de saída. Então, se você configurou o programa hull para sair 4 pontos de controle, ele será executado 4 vezes total por patch. Ele não será executado 16 vezes, apesar de ter 16 pontos de controle de entrada.

A próxima etapa é a própria unidade tessellator. Esta fase não é programável com HLSL, mas tem um número de propriedades que podem ser definidas. O tessellator é responsável pela produção de uma grade tesselada e nada mais; ele não se importa com os dados definidos pelo usuário ou qualquer um dos nossos pontos de controle. A única coisa que ele se importa, no entanto, são fatores de tesselação - ou, quanto tesselar as regiões do patch. Você pode estar se perguntando onde realmente é a saída desses valores. Uma vez que os fatores de tesselação são determinados uma vez por patch, calculamos estes na função constante do patch. Assim, a única coisa dada ao tessellator são os fatores de tesselação da função constante do patch.

As topologias produzidas pelo tessellator variam dependendo de como ele está configurado. Para este exemplo, usando um domínio triangular significa que o tessellator produzirá uma topologia triângulo tesselada descrito pelas coordenadas baricentricas 3D. Legal, não é?

Então, até agora temos transformado cada ponto de controle no shader de vértice, realizou uma possível transformação base nos pontos de controle no programa hull, e determinaram os fatores de tesselação para este patch na função constante do patch, juntamente com quaisquer outros dados definidos pelo usuário. Os fatores de tesselação foram executados através do hardware tessellation, que criou uma nova grade tesselada: neste caso, um triângulo tesselado descrito com coordenadas baricêntricas. Eu gostaria de enfatizar mais uma vez que o tessellator não se preocupa em absoluto com nada além dos fatores de tesselação e um pequeno número de propriedades de configuração definidos pelo shader compile-time. Isto é o que torna a implementação D3D11 tão bonita: é muito geral e muito poderosa.

Você provavelmente está desejando que pudéssemos transformar a grade tesselada de forma arbitrária, e, bem ... nós podemos! A próxima parada é o domain shader. O domain shader pode ser pensado como um shader de vértice pós-tesselação; ele é executado uma vez por vértice tesselado. É entregue a ele todos os nossos pontos de controle de saída, os dados constantes de patch, bem como um valor especial do sistema que descreve a coordenada baricêntrica do vértice tesselado em que estamos operando.

Coordenadas baricêntricas são muito úteis quando se trabalha em áreas triangulares, uma vez que nos permitem interpolar dados muito facilmente sobre o triângulo.

Neste ponto, o fluxo de dados é familiar: a saída do domain shader é entregue ao pixel shader. É importante notar que, em geral, 32 float4s pode ser passado entre cada etapa de sombreamento . Podemos passar 32 float4s do shader de vértice ao hull shader, 32 float4s da função constante do patch para o domain shader, 32 float4s do programa hull para o domain shader e 32 float4s do domain shader para o pixel shader. Em outras palavras, uma grande quantidade de dados podem ser passados usando registros entre estágios, para não mencionar que também pode vincular views de recursos do shader para os estágios de vértice, do hull shader, domain shader, shader de geometria e do pixel shader.

Eu deixei o shader de geometria fora desta explicação para simplificar as coisas, mas é muito possível jogar um shader de geometria na mistura para fazer algumas coisas muito interessantes - um exemplo que vem à mente é eliminar partes de um patch, ou quebra-lo em triângulos individuais para formar novas topologias. Também é possível a utilização de fluxo de saída, com tesselação.

Devido à natureza geral do pipeline, que pode até mesmo usar tesselação sem ligar quaisquer dados reais do ponto de controle para o pipeline. Considere que o vertex shader é capaz de ver o ID do vértice (ID do ponto de controle, neste caso) e ID de instância. Os hull shaders e domain shaders podem ver o ID primitivo (que é basicamente um ID do patch). Usando esta informação por si só, coisas muito interessantes e úteis podem ser feitas: um bom exemplo é a produção de uma grande rede composta por muitos patchs individuais. Os patchs podem ser colocados de forma apropriada usando o ID primitivo.

No início eu mencionei os estágios de tesselação com configurações de tempo de compilação. Essas configurações são especificadas com o programa hull. Aqui está um exemplo de declaração de configurações.

[domain("tri")]
[partitioning("integer")]
[outputtopology("triangle_cw")]
[outputcontrolpoints(16)]
[patchconstantfunc("HSConst")]

domain(x) - Este atributo especifica qual o domínio que estamos usando para os nossos patches. Neste exemplo, eu especifiquei um domínio triângulo, mas também é possível especificar um quadrilátero ou domínio isolineo.

partitioning(x) - Este atributo diz ao tessellator como é interpretar os nossos factores de tesselação. Particionamento Integer significa que os fatores de tesselação são interpretados como valores integrais; não há vértices tesselados "intermediários". Os outros esquemas de particionamento são fractional_even, fractional_odd e pow2.

outputtopology(x) - Este atributo diz ao tessellator que tipo de primitivas queremos tratar depois da tesselação. Neste caso, triangle_cw significa triângulos sentido horário. Outras possibilidades são triangle_ccw e line.

outputcontrolpoints(x) - Este atributo descreve quantos pontos de controle que serão a saída do programa hull. Nós podemos escolher a saída em qualquer lugar de 0-32 pontos de controle que são então alimentados no domain shader.

patchconstantfunc(x) - Este atributo especifica o nome da função constante do patch, que é executado uma vez por patch.

Cada estágio é dado dados diferentes. Para ilustrar isso, vou mostrar uma possível assinatura da função para cada fase.

VS_OUTPUT VS(IA_OUTPUT input, uint vertid : SV_VertexID, uint instid : SV_InstanceID);


HS_CONSTANT_OUTPUT HSConst(InputPatch<VS_OUTPUT, n> ip, OutputPatch<HS_OUTPUT, m> op, uint pid : 


SV_PrimitiveID);
HS_OUTPUT HS(InputPatch<VS_OUTPUT, n> ip, uint cpid : SV_OutputControlPointID, uint pid : 


SV_PrimitiveID);


DS_OUTPUT DomainShader(HS_CONSTANT_OUTPUT constdata, OutputPatch<HS_OUTPUT, m> op, uint pid : 


SV_PrimitiveID, float3 coord : SV_DomainLocation);

O tipo de SV_DomainLocation depende do domínio de patch escolhido. Para o domínio triangular, SV_DomainLocation é um float3. Para o domínio do quadrilátero, é um float2. Para o domínio isolinear, é uma float2 ( por razões que serão vistas em um post futuro). n significa o número de pontos de controle de entrada e o símbolo m representa o número de pontos de controle de saída.

Como afirmado anteriormente , a função da constante de patch (HSConst neste caso) é necessária para a saída de pelo menos os fatores de tesselação. O número de elementos de tesselação depende do domínio do patch. Para o domínio triangular, há quatro fatores (3 lados , 1 internas). Para o domínio quadrilátero, existem 6 fatores (4 lados, 2 internas). Para o domínio isolinear, existem dois fatores (detalhe e densidade).

Vamos dar uma olhada na topologia produzida pelo tessellator usando o modo de rasterização wireframe, um domínio quadrilátero e particionamento inteiro (integer). Na seguinte função constante de patch, eu escolhi usar fatores de tesselação codificados (hard coded). Na prática, os elementos de tesselação são calculados de forma dinâmica. Os fatores de tesselação não são obrigados a ser constantes hard coded!

struct HS_CONSTANT_OUTPUT
{
    float edges[4] : SV_TessFactor;
    float inside[2] : SV_InsideTessFactor;
};


HS_CONSTANT_OUTPUT HSConst()
{
    HS_CONSTANT_OUTPUT output;


    output.edges[0] = 1.0f;
    output.edges[1] = 1.0f;
    output.edges[2] = 1.0f;
    output.edges[3] = 1.0f;


    output.inside[0] = 1.0f;
    output.inside[1] = 1.0f;


    return output;
}

AMOSTRAS DE TESSELAÇÕES

Os fatores de borda são mantidas constantes em 1, 1, 1, 1 e os fatores internos são de 1, 1. O tessellator produz a seguinte malha:

Posted Image
[Figura 1]

E quanto a fatores de borda de 3,1,1,1 e fatores internos de 1,1?

Posted Image
[Figura 2]

Fatores de borda de 5,5,5,5 e fatores internos de 1,1:

Posted Image
[Figura 3]

Fatores de borda de 1,1,1,1 e fatores internos de 2,1:

Posted Image
[Figura 4]

Fatores de borda de 1,1,1,1 e fatores internos de 4,1:

Posted Image
[Figura 5]

Fatores de borda de 1,1,1,1 e fatores internos de 4,4:

Posted Image
[Figura 6]

Fatores de borda de 4,4,4,4 e fatores internos de 4,4:
(O mesmo que fatores de borda de 3.5,3.8,3.9,4.0 e fatores internos de 3.1,3.22!)

Posted Image
[Figura 7]

Fatores de borda de 4,4,4,1 e fatores internos de 4,4:

Posted Image
[Figura 8]

Deve notar-se que quando se utiliza o particionamento inteiro, a implementação é essencialmente usando o teto dos fatores de tesselação escritos. Vamos dar uma olhada na saída do esquema de particionamento fractional_even.

Fatores de borda de 2,1,1,1 e fatores internos de 1,1:

Posted Image
[Figura 9]

Fatores de borda de 2.1,1,1,1 e fatores internos de 1,1:

Posted Image
[Figura 10]

Fatores de borda de 2.2,1,1,1 e fatores internos de 1,1:

Posted Image
[Figura 11]

Fatores de borda de 2.5,1,1,1 e fatores internos de 1,1:

Posted Image
[Figura 12]

Fatores de borda de 3,1,1,1 e fatores internos de 1,1:

Posted Image
[Figura 13]

Aqui está uma mais divertida com fatores de borda de 3,3,3,3 e fatores internos de 4,6, usando o esquema de particionamento fractional_odd:

Posted Image
[Figura 14]

Obviamente fatores de tesselação hard coded são apenas úteis até certo ponto. A utilidade real da tesselação entra em jogo quando o cálculo dos fatores de tesselação de forma dinâmica, por patch, em tempo real com base em fatores como o nível de detalhe em um mapa de altura, distância da câmera, ou modelo detalhes.

PATCHES E SHADERS DE GEOMETRIA

Você pode estar se perguntando como o shader de geometria interage com as novas fases de shader e os novos tipos primitivos de patches. Considere um pipeline com um shader de vértice, geometria e pixel shader. O shader de vertice é executado por vértice, e uma vez que o valor primitivo de vértices tenha sido processado, o shader de geometria é executado. O shader de geometria é executado por primitiva e vértices de saídas de um tipo primitivo potencialmente diferente.Agora adicione um hull e domain shader à mistura. Digamos que o tipo primitivo Input assembler é um patch com pontos de controle n. O shader de vértice é executado n vezes por patch, então o hull shader corre mais n vezes por patch, processando um total de pontos de controle m. O tessellator alimenta o domain shader com cada vértice tesselado, e o domain shader gera o vértice processado. A partir daqui, vamos para o shader de geometria.

Lembre-se que o tessellator pode produzir linhas ou triângulos. Isso determina o tipo primitivo de entrada para o nosso shader de geometria. Para o propósito deste exemplo, suponha que o tessellator está configurado para saída de uma topologia triangular. Digamos que estamos emitindo pontos do shader de geometria. Isto significa que a assinatura do shader de geometria é algo como isto:

void GS(triangle DOMAIN_SHADER_OUTPUT input[3], inout PointStream<geometry_shader_output> stream);

Se tivesse o tessellator configurado para lidar com isolinhas, então nós estaríamos usando line DOMAIN_SHADER_OUTPUT input[2] em seu lugar.

Então, aí está. O shader de geometria integra-se ao modelo de tesselação. Lembre-se que o domain shader é executado por vértice tesselado, e por isso temos pouco controle sobre cada triângulo individual nessa fase. Um shader de geometria pode ser usado para quebrar um patch para primitivas individuais, o que pode ser transformado de forma independente, abatidos, duplicados, etc, para não mencionar que shaders de geometria podem ser exemplificados agora ... isso é para um post futuro. :)

O que acontece se configurar o input assembler para usar um tipo primitivo de patch, mas não ligar hull shaders e domain shaders para o pipeline? Lembre-se que o shader de geometria opera em primitivas, e que os novos tipos de patches são primitivos... portanto, o shader de geometria pode operar em primitivas de patch!

Aqui estão alguns exemplos de assinaturas de shader de geometria.

-Tipo primitivo de entrada de ponto:
void GS(point VERTEX_SHADER_OUTPUT pt[1], ...);


-Tipo primitivo de entrada de linha:
void GS(line VERTEX_SHADER_OUTPUT pt[2], ...);


-Tipo primitivo de entrada de triângulo:
void GS(triangle VERTEX_SHADER_OUTPUT pt[3], ...);


-Tipo primitivo de entrada de patch de 25 pontos:
void GS(InputPatch<VERTEX_SHADER_OUTPUT, 25> pt, ...);

Animado? Pois deveria! O que isto significa, essencialmente, é que você pode fazer a seus próprios tipos primitivos (em qualquer lugar a partir de 1 ponto para 32 pontos) que o shader de geometria pode operar. Queria que você tinha um tipo primitivo quad? Use um patch de 4 pontos com um shader de geometria e emita dois triângulos!

EXEMPLO DE TESSELAÇÂO

Agora que explicamos um pouco de tesselação, é hora de um exemplo de verdade. Começaremos com um básico renderer cúbico de spline de Bézier.

Vamos começar olhando para a função paramétrica [http://en.wikipedia....3.A9zier_curves] utilizada para calcular uma curva de Bézier cúbica. Os pontos de controle são representados pela P0, P1, P2 e P3.

Shader de Vértice

Lembre-se que o shader de vértice é executado uma vez por ponto de controle. Para este exemplo, vamos apenas passar os pontos de controle para a próxima fase.

struct IA_OUTPUT
{
    float3 cpoint : CPOINT;
};


struct VS_OUTPUT
{
    float3 cpoint : CPOINT;
};


VS_OUTPUT VS(IA_OUTPUT input)
{
    VS_OUTPUT output;
    output.cpoint = input.cpoint;
    return output;
}

Hull Shader

A função constante de patch (HSConst abaixo) é executado uma vez por patch (a curva cúbica no nosso caso). Lembre-se que a função constante do patch deve ter como saída pelo menos fatores de tesselação. A função de ponto de controle (HS abaixo) é executado uma vez por ponto de controle de saída. No nosso caso, nós apenas passaremos os pontos de controle por ela inalterados.

struct VS_OUTPUT
{
    float3 cpoint : CPOINT;
};


struct HS_CONSTANT_OUTPUT
{
    float edges[2] : SV_TessFactor;
};


struct HS_OUTPUT
{
    float3 cpoint : CPOINT;
};


HS_CONSTANT_OUTPUT HSConst()
{
    HS_CONSTANT_OUTPUT output;


    output.edges[0] = 1.0f; // Detail factor (see below for explanation)
    output.edges[1] = 8.0f; // Density factor


    return output;
}


[domain("isoline")]
[partitioning("integer")]
[outputtopology("line")]
[outputcontrolpoints(4)]
[patchconstantfunc("HSConst")]
HS_OUTPUT HS(InputPatch<VS_OUTPUT, 4> ip, uint id : SV_OutputControlPointID)
{
    HS_OUTPUT output;
    output.cpoint = ip[id].cpoint;
    return output;
}

Tessellator

O tessellator real não é programável com HLSL, mas é interessante notar que o tessellator real ocorre entre o hull shader e o domain shader. Os fatores de tesselação e as configurações de tempo de compilação (domínio, particionamento, topologia de saída, etc) influenciam o tessellator.

Domain Shader

Note que, até agora, não foi usado a função paramétrica cúbica da curva de Bézier. O domain shader é onde nós usamos esta função para calcular a posição final dos vértices tesselados.


struct HS_CONSTANT_OUTPUT
{
    float edges[2] : SV_TessFactor;
};


struct HS_OUTPUT
{
    float3 cpoint : CPOINT;
};


struct DS_OUTPUT
{
    float4 position : SV_Position;
};


[domain("isoline")]
DS_OUTPUT DS(HS_CONSTANT_OUTPUT input, OutputPatch<HS_OUTPUT, 4> op, float2 uv : SV_DomainLocation)
{
    DS_OUTPUT output;


    float t = uv.x;


    float3 pos = pow(1.0f - t, 3.0f) * op[0].cpoint + 3.0f * pow(1.0f - t, 2.0f) * t * op[1].cpoint + 


3.0f * (1.0f - t) * pow(t, 2.0f) * op[2].cpoint + pow(t, 3.0f) * op[3].cpoint;


    output.position = float4(pos, 1.0f);


    return output;
}

Por este ser apenas um exemplo, omiti otimizações para deixar mais claro.

Pixel Shader

Este é um pixel shader simples que produz linhas pretas.

struct DS_OUTPUT
{
    float4 position : SV_Position;
};


float4 PS(DS_OUTPUT input) : SV_Target0
{
    return float4(0.0f, 0.0f, 0.0f, 1.0f);
}

API Setup

Pontos de controle são tratados do mesmo jeito que vértices.

Assinatura do Input Assembler:


D3D11_INPUT_ELEMENT_DESC desc[] =
{
    {"CPOINT", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0}
};
//Input assembler binding code:


UINT strides[] = {3 * sizeof(float)}; // 3 dimensions per control point (x,y,z)
UINT offsets[] = {0};
g_pd3dDC->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_4_CONTROL_POINT_PATCHLIST); // 4 control points per primitive
g_pd3dDC->IASetInputLayout(layout);
g_pd3dDC->IASetVertexBuffers(0, 1, &controlpoints, strides, offsets);


// Bind the shaders
// ...


// Render 4 control points (1 patch in this example, since we're using 4-control-point primitives).
// Rendering 8 control points simply means we're processing two 4-control-point primitives, and so forth.
// Instancing and indexed rendering works as expected.
g_pd3dDC->Draw(4, 0);

Agora que os shaders estão fora do caminho, é um bom momento para explicar o propósito de dois fatores de tesselação de isolinhas, em vez de apenas um. Lembre-se que um único fator de tesselação não pode ser superior a 64. Ao lidar com isolinhas, este número é bastante pequeno; é desejável processar um único patch de isolinha com um elevado grau de tesselação. Para minimizar esse problema, o D3D11 nos permite especificar dois fatores de tesselação de isolinha: um fator de detalhes e um fator de densidade.Para entender o que esses fatores significam, visualize um quadrado. Agora imagine que o fator de detalhes descreve o quanto a dividir o eixo y, enquanto que o fator densidade descreve quanto para dividir o eixo x. Agora imagine ligar os pontos ao longo do eixo x para formar linhas.Outra maneira de pensar sobre isso: o fator densidade descreve o quanto a tesselar uma linha, enquanto que o fator de detalhes descreve quantas vezes instanciar a linha tesselada. Podemos encontrar o local dentro de uma linha tesselada usando SV_DomainLocation.x e podemos encontrar qual a linha que estamos avaliando usando SV_DomainLocation.y . Isso efetivamente nos deixa acorrentar as linhas juntas em uma única, linha ultra-tesselada. Excelente uso do paralelismo se você me perguntar.

Voltando para o exemplo em questão: vamos executar alguns pontos de controle através deste shader e ver o que vamos conseguir com ele.

Considere os seguintes pontos de controle:

P0 = [-1, -0.8, 0]
P1 = [ 4, -1, 0]
P2 = [-4, 1, 0]
P3 = [ 1, 0.8, 0]

Posted Image
[Figura 15]

Tenha em mente que nós estamos usando um fator de densidade de tesselação hard coded de 8 aqui, que é por isso que o resultado parece de baixa resolução. Vamos até o fator 64 e veja o que temos.

Posted Image
[Figura 16]

Bem melhor.

Há uma série de coisas que podemos fazer para melhorar este exemplo. Por exemplo, para obter mais de 64 divisões por patch, podemos usar o fator de detalhe para "instanciar" a linha até 64 vezes, e juntar as linhas instanciadas, divididas no domain shader. Outra coisa que pode fazer é criar um shader de geometria que transforma linhas em triângulos. Poderíamos processualmente perturbar os pontos de controle no shader de vértice para efeitos de animação. Poderíamos calcular os fatores de tesselação como uma função dos pontos de controle.

Artigo originalmente postado em Gamedev.net
http://www.gamedev.n...-in-depth-r3059



0 Comments