Lenguaje de sombreado de alto nivel
High Level Shading Language (HLSL) es un lenguaje de programación desarrollado para DirectX que se utiliza para programar módulos de sombreado . Ocasionalmente, todo el grupo de lenguajes de programación de sombreadores de alto nivel se denomina HLSL.
tarea
En los gráficos por computadora, el sombreado significa cambiar vértices o fragmentos individuales dentro de la canalización de gráficos . El trabajo se lleva a cabo lo más cerca posible del hardware, lo que hizo necesario el uso del ensamblador durante mucho tiempo . Sin embargo, la programación con ensamblador es poco práctica, propensa a errores y depende del fabricante del hardware. Los lenguajes de sombreado de alto nivel están destinados a solucionar este problema. Proporcionan estructuras de lenguaje de alto nivel que simplifican la programación y, por lo tanto, permiten al programador concentrarse en su objetivo. Un compilador traduce el código de lenguaje de alto nivel al lenguaje de máquina para el procesador de gráficos. El lenguaje HLSL de alto nivel específico de DirectX se traduce al lenguaje ensamblador adecuado para el hardware de gráficos actual desde la biblioteca de DirectX con la ayuda del controlador de gráficos durante el tiempo de ejecución de la aplicación. Ya no son necesarios diferentes sombreadores para tarjetas gráficas Nvidia o ATI / AMD.
Elementos del lenguaje
HLSL no ofrece enfoques de programación orientada a objetos como otros lenguajes. Está fuertemente orientado hacia C, pero proporciona tipos de datos y operaciones optimizadas para la programación de sombreadores.
Parámetros de sombreado global
Los parámetros que se pasan a un sombreador están disponibles globalmente en HLSL en el código completo. Están escritos fuera de métodos o estructuras, principalmente al principio del código.
float4x4 world; // Definiert eine 4x4-Fließkomma-Matrix, hier die Welt-Matrix
float4x4 worldViewProj; // Die Welt-View-Projektionsmatrix, gerechnet als World*View*Proj.
float3 lightDir; // Ein 3-Element Vektor.
float4 LightColor = {0.5,0.5,0.5,1}; // Lichtfarbe (Vektor mit vordefiniertem Wert)
float4 Ambient = {0.5,0.5,0.5,1}; // Lichtfarbe des Umgebungslichtes
float4 LightDir={0,0,-1, 0}; // Richtung des Sonnenlichtes (hier: Senkrecht von oben)
texture2D Tex0; // Eine Textur
SamplerState DefaultSampler // Der "Sampler" definiert die Parameter für das Texture-Mapping
{
filter=MIN_MAG_MIP_LINEAR; // Interpolationsfilter für Texturstreckung
AddressU = Clamp; // Texturkoordinaten ausserhalb [0..1] beschneiden
AddressV = Clamp;
};
Para conocer el significado de las matrices anteriores, consulte el artículo de canalización gráfica .
Entrada y salida del sombreador de vértices
En lugar de escribir cada parámetro individualmente en la lista de parámetros de un método de sombreado, las estructuras uniformes son comunes en la práctica. Esto ahorra papeleo y crea más claridad. En principio, cualquier valor y vector se puede transferir con la estructura de entrada, pero casi siempre se incluye una posición.
// Eingabe für den Vertex-Shader.
struct MyShaderIn
{
float4 Position : POSITION; // Dem Compiler wird bekannt gegeben, was die Variable "bedeutet". Hier: Das ist eine Position
float4 Normal: NORMAL0; // Die Vertex-Normale, wird für die Beleuchtung verwendet
float2 TexCoords: TEXCOORD0; // Texturkoordinaten
}
struct MyShaderOut
{
float4 Position : POSITION;
float4 TexCoords TEXCOORD0;
float4 Normal : TEXCOORD1;
}
El "In-Struct" especifica la estructura de datos a medida que se pasa del modelo de estructura de alambre al sombreador, es decir, al sombreador de vértices. Esto procesa los datos y devuelve un "Out-Struct" como tipo de retorno. Esto luego se pasa al PixelShader, que al final solo devuelve un float4 o algo similar con el color final del píxel.
Método de sombreado de vértices / píxeles
Debe existir un método para los sombreadores de vértices y los sombreadores de píxeles . Esto toma una estructura de datos y la procesa en consecuencia. El sombreador de vértices se llama una vez para cada vértice, el sombreador de píxeles una vez para cada píxel de textura que se va a representar.
MyShaderOut MyVertexShader(MyShaderIn In)
{
MyShaderOut Output = (MyShaderOut)0;
// Die nächste Zeile ist die Projektionsmultiplikation. Sie multipliziert die Position des aktuellen Punktes mit
// der aus Welt-, Kamera- und Projektionsmatrix kombinierten 4x4-Matrix, um die Bildschirmkoordinaten zu erhalten
Output.Position = mul(In.Position, WorldViewProj);
Output.TexCoords = In.TexCoords; // Texturkoordinaten werden in diesem einfachen Beispiel einfach durchgereicht
Output.Normal = normalize(mul(In.Normal, (float3x3)World)); // Die Normale wird rotiert
return Output;
}
// Eine Hilfsfunktion
float DotProduct(float3 lightPos, float3 pos3D, float3 normal)
{
float3 lightDir = normalize(pos3D - lightPos);
return dot(-lightDir, normal);
}
// Der Pixel-Shader gibt als Rückgabewert lediglich eine Farbe (ggf. mit Alpha) zurück
float4 MyPixelShader(MyShaderIn In): COLOR0
{
// Beleuchtungsstärke der Fläche (Das Skalarprodukt aus negativem Lichtvektor und
// Normalvektor der Fläche ist > 0 wenn die Fläche der Lichtquelle zugewandt ist)
float sunLight=dot((float3)-LightDir, In.Normal);
float4 sunLightColor=float4(sunLight,sunLight,sunLight,1); // Den Alphakanal setzen
sunLightColor *= LightColor; // Die Lichtfarbe anbringen
sunLightColor = saturate(sunLightColor); // Die Farbwerte auf [0..1] beschneiden
// Die Texturfarbe an der zu zeichnenden Stelle abholen. Um die Interpolation der Texturkoordinaten
// brauchen wir uns nicht zu kümmern, das übernehmen Hardware und Compiler.
float4 baseColor = Tex0.Sample(DefaultSampler, In.TexCoords);
float4 brightnessColor = baseColor*(sunLightColor + Ambient); // Helligkeit und Kontrast einrechnen
brightnessColor=(brightnessColor + OffsetBrightness) * (1.0 + OffsetContrast);
return brightnessColor;
}
Sombreador de geometría
La implementación de un sombreador de geometría es opcional y permite asignar una primitiva a 0 an nuevas primitivas. Sin embargo, se anunciará el tipo de primitivas de salida, así como el número máximo de vértices producidos que se necesita para compilar el tiempo . La implementación tiene lugar aquí de forma procedimental y utiliza estructuras de datos especialmente introducidas (PointStream <T>, LineStream <T> y TriangleStream <T>).
También es posible acceder a los triángulos y líneas vecinas. Esto se puede lograr con la ayuda de los modificadores de entrada trianglead y lineadj . Las aplicaciones típicas de los sombreadores de geometría son la generación de sprites de puntos y el renderizado en texturas CubeMap. Aquí hay un sombreador de geometría simple que encoge cada triángulo al que se aplica hacia su centroide:
[maxvertexcount(3)]
void GS(triangle MyShaderOut[3] input, inout TriangleStream<MyShaderOut> OutputStream)
{
MyShaderOut point;
float4 centroid = (input[0].Position + input[1].Position + input[2].Position) / 3.0;
point = input[0];
point.Position = lerp(centroid, input[0].Position, 0.9);
OutputStream.Append(point);
point = input[1];
point.Position = lerp(centroid, input[1].Position, 0.9);
OutputStream.Append(point);
point = input[2];
point.Position = lerp(centroid, input[2].Position, 0.9);
OutputStream.Append(point);
OutputStream.RestartStrip();
}
tecnicas
Finalmente, los métodos definidos deben asignarse en forma de técnicas y ejecuciones para que el compilador pueda implementarlos en consecuencia. La sintaxis de los sombreadores ha cambiado ligeramente con DirectX 10, por lo que la versión de destino también se especifica explícitamente nuevamente en la tecnología.
technique10 MyTechnique // Für DirectX 10+
{
pass Pass0
{
VertexShader = compile vs_4_0 MyVertexShader();
PixelShader = compile ps_4_0 MyPixelShader();
}
}
Alternativas
- RenderMan (lenguaje de sombreado de Pixar Animation Studios )
- CG ( C para gráficos)
- Lenguaje de sombreado OpenGL
- Lenguaje de sombreado OpenGL ES