Yotsuba Shader
Español

SHADERS EN C#

Tu shader, escrito en C#.

Utiliza clases, structs y métodos para describir tu shader. Los atributos identifican las etapas, los valores que pasan entre ellas y los recursos que proporciona tu aplicación.

Esta es una API de autoría previa al lanzamiento. Los ejemplos siguientes utilizan declaraciones presentes en el repositorio; la compilación completa de shaders sigue en desarrollo. HLSL es la sintaxis predeterminada de esta guía.

01

Etapas

Un método declara trabajo vertex, fragment o compute.

02

Entradas y salidas

Los structs describen los valores que recibe y devuelve una etapa.

03

Recursos

Los buffers, texturas y samplers representan datos proporcionados por tu aplicación.

04

Tus tipos

Las anotaciones describen cómo se relacionan los datos C# compatibles con tipos de shader.

Una clase. Dos etapas conectadas.

El método vertex recibe una posición y un color. Escribe una posición en el espacio de recorte y pasa el color al método fragment, que devuelve el color interpolado.

Ambos métodos comparten VS_Output. No necesitas otro struct para recibir los mismos datos en la etapa fragment.

La aplicación proporciona los datos de los vértices, configura el pipeline gráfico y emite las llamadas de dibujo. Estos atributos describen el shader; no realizan esas tareas de la aplicación.

Este ejemplo utiliza tipos de MonoGame por familiaridad. Sus nombres por sí solos no los convierten en vectores nativos GPU; el mapeo nativo requiere metadatos de tipos compatibles.

BasicColorShader.cs
using Microsoft.Xna.Framework;
using YotsubaShader.Language;
using YotsubaShader.HlslSyntax;

public class BasicColorShader
{
    public struct VS_Input
    {
        [POSITION]
        public Vector2 Position;

        [COLOR]
        public Vector4 Color;
    }

    public struct VS_Output
    {
        [SV_Position]
        public Vector4 Position;

        [COLOR]
        public Vector4 Color;
    }

    [ShaderStage(Stage.Vertex)]
    public VS_Output VS(VS_Input input)
    {
        VS_Output output = new VS_Output();

        output.Position = new Vector4(
            input.Position.X,
            input.Position.Y,
            0.0f,
            1.0f
        );

        output.Color = input.Color;

        return output;
    }

    [ShaderStage(Stage.Fragment)]
    [return: SV_Target(0)]
    public Vector4 FS(VS_Output input)
    {
        return input.Color;
    }
}

Qué indica cada atributo

AtributoPropósito
[ShaderStage(Stage.Vertex)]Marca el punto de entrada vertex.
[ShaderStage(Stage.Fragment)]Marca el punto de entrada fragment.
[POSITION]Identifica una posición de vértice proporcionada por la aplicación.
[COLOR]Identifica datos de color, incluido el valor transmitido entre etapas.
[SV_Position]Declara la posición vertex en el espacio de recorte; como entrada fragment describe la posición rasterizada.
[return: SV_Target(0)]Dirige el valor devuelto por fragment al destino de color 0.

Para datos adicionales de vértices, utiliza semánticas HLSL como [TEXCOORD(0)] o [NORMAL]. El vocabulario separado SPIR-V también ofrece locations numeradas; no necesitas mezclarlo en un ejemplo HLSL.

Declara lo que proporciona tu aplicación.

Utiliza cbuffer para datos uniformes y register para identificar los slots de recursos. El prefijo distingue buffers de constantes (b), texturas (t), samplers (s) y recursos de escritura (u).

Estas son declaraciones de recursos. Tu motor crea y enlaza los recursos GPU reales. Los tipos de metadatos actuales no proporcionan un método de muestreo de texturas ni un sistema completo de binding en ejecución.

Conoce los recursos y bindings →
SurfaceResources.cs
using YotsubaShader.HlslSyntax.Resources;
using YotsubaShader.HlslSyntax.Resources.Types;

public struct MaterialData
{
    public float Exposure;
    public float Roughness;
}

public class SurfaceResources
{
    [cbuffer, register(RegisterPrefix.b, 0)]
    public MaterialData Material;

    [register(RegisterPrefix.t, 0)]
    public Texture2D Albedo;

    [register(RegisterPrefix.s, 0)]
    public SamplerState Sampler;
}

Conserva los tipos compatibles de tu proyecto.

Un struct C# puede describir un vector nativo de shader cuando su tipo y sus componentes llevan las anotaciones correspondientes. Así el mapeo es explícito y no depende del nombre del tipo.

Anota los tipos que controlas. Importar un namespace externo no añade metadatos a sus tipos. Puedes compartir declaraciones como bibliotecas NuGet, mientras que la compilación GPU de métodos arbitrarios de bibliotecas sigue incompleta.

Aprende a mapear tus tipos →
Float2.cs
using YotsubaShader.Language.Native.Types.Vector;

[Vector]
public struct Float2
{
    [VectorComponent(0)] public float X;
    [VectorComponent(1)] public float Y;

    public Float2(float x, float y)
    {
        X = x;
        Y = y;
    }
}

Compute es una etapa independiente.

Un método compute utiliza Stage.Compute. En el vocabulario HLSL, numthreads(8, 8, 1) declara las dimensiones locales del workgroup. No utiliza una conexión vertex-fragment.

El ejemplo declara un punto de entrada compute vacío. Ejecutar trabajo GPU útil requiere operaciones de cuerpo compatibles, una salida compilada, bindings de recursos y un dispatch desde tu aplicación.

ComputeShader.cs
using YotsubaShader.Language;
using YotsubaShader.HlslSyntax;

public class ComputeShader
{
    [ShaderStage(Stage.Compute)]
    [numthreads(8, 8, 1)]
    public void CS()
    {
    }
}

Empieza con HLSL. Explora otros vocabularios cuando los necesites.

La sintaxis determina los nombres de los atributos que escribes. No selecciona la API gráfica de salida. Los atributos de autoría inspirados en WGSL ya existen; generar salida WGSL está previsto para 2027.

Conoce cómo se compila el shader →