Shader: qué es, tipos de shaders y cómo funcionan

Autor: IT Sectr Publicado: 2026-06-11 Tiempo de lectura: 8 min

Shader — es un programa que se ejecuta en la GPU para procesar datos gráficos: vértices, fragmentos o tareas de cómputo. A diferencia del código normal en CPU, un shader trabaja en paralelo en cientos de núcleos, procesando cada elemento de forma independiente. Según Khronos Group (2025), los shaders se usan en el 100% de las aplicaciones 3D modernas — desde juegos móviles hasta efectos de UI en aplicaciones de sistema. Los desarrolladores escriben shaders en lenguajes especializados: GLSL, HLSL, Metal Shading Language o SPIR-V.

Puntos clave

  • Shader — un programa para GPU que se ejecuta en paralelo en cientos de núcleos para cada elemento de la escena.
  • Tipos de shaders: de vértices, de fragmentos, compute, geometry, tessellation y mesh.
  • Lenguajes: GLSL (OpenGL), HLSL (DirectX), MSL (Metal), SPIR-V (Vulkan) — todos se compilan a código máquina de GPU.
  • Shaders en desarrollo móvil se usan para efectos, post-procesado, iluminación y cálculos.
  • Optimización de shaders: precisión mediump, minimización de bifurcaciones y ATF (Adaptive Texture Fetch) para GPUs móviles.

¿Qué es un Shader?

Shader — es un pequeño programa escrito en un lenguaje especializado y ejecutado en la GPU. Cada shader procesa un elemento de dato — un vértice, fragmento (píxel) o elemento de trabajo — de forma independiente. El paralelismo de la GPU permite ejecutar miles de instancias de shader simultáneamente.

El término fue introducido por Pixar en la década de 1980 para describir programas que controlan la apariencia de superficies en RenderMan. Los shaders en tiempo real aparecieron con la NVIDIA GeForce 3 (2001) — la primera tarjeta gráfica con pipeline programable. Antes de los shaders, los gráficos se configuraban mediante parámetros fijos: color, textura, modo de mezcla.

Según Unity Technologies (2025), un juego móvil promedio usa 50–200 shaders. Cada shader tiene variantes para diferentes plataformas, niveles de calidad y configuraciones de iluminación. El número de variantes puede alcanzar las 10 000 por proyecto.

La arquitectura de un shader se divide en datos de entrada (atributos, variables uniform, texturas), código del programa y datos de salida (color, posición). Las variables uniform se establecen desde la CPU antes de ejecutar el shader y son constantes para todos los elementos del cuadro. Los atributos son datos por elemento (coordenadas de vértice, normal, coordenadas UV).

Modelo de ejecución SIMT

SIMT (Single Instruction, Multiple Threads) — el modelo de ejecución de shaders en la GPU. Una instrucción se carga una vez y se ejecuta por cientos de hilos sobre diferentes datos. Por ejemplo, un Fragment Shader para 1000 píxeles lanza 1000 hilos con el mismo código, pero cada hilo recibe sus propias coordenadas UV y atributos interpolados.

Una consecuencia importante de SIMT: las bifurcaciones en shaders son costosas. Si dentro de un bloque if la mitad de los hilos va por un camino y la otra mitad por otro, la GPU ejecuta ambas ramas secuencialmente para todos los hilos. El rendimiento cae al 50%. Evite bifurcaciones dinámicas en shaders o minimícelas mediante precálculos en la CPU.

Tipos de Shaders

Las GPUs modernas soportan varios tipos de shaders, cada uno para su etapa del pipeline gráfico o de cómputo. Revisemos los tipos principales: de vértices, de fragmentos, compute y los modernos mesh shaders.

Tipo de shaderEtapa del pipelineProcesaLenguaje
Vertex ShaderVérticesCada vérticeGLSL, HLSL
Fragment ShaderFragmentosCada píxelGLSL, HLSL
Compute ShaderCómputoDatos arbitrariosGLSL, HLSL
Geometry ShaderGeometríaPrimitivasGLSL, HLSL
Tessellation ShaderTeseladoParchesGLSL, HLSL
Mesh ShaderPipeline meshTask + MeshHLSL, MSL

Vertex Shader

Vertex Shader procesa cada vértice de la geometría: transforma coordenadas, calcula iluminación, pasa datos al fragment shader. Es una etapa obligatoria del pipeline gráfico — sin ella, los vértices no llegarán a la pantalla. El Vertex Shader se ejecuta para cada vértice de cada cuadro.

Fragment Shader

Fragment Shader (o Pixel Shader) — la etapa más intensiva en recursos. Calcula el color final de cada fragmento usando texturas, iluminación y material. El Fragment Shader se ejecuta para cada píxel cubierto por geometría, teniendo en cuenta todas las texturas y efectos superpuestos. Optimizar este shader proporciona la mayor ganancia de rendimiento.

Compute Shader

Compute Shader — un shader universal para cálculos arbitrarios en la GPU. A diferencia de los shaders gráficos, no está vinculado a geometría o píxeles. El Compute Shader trabaja con buffers de datos arbitrarios mediante grupos de trabajo. Se usa para física, simulación de partículas, post-efectos e inferencia de redes neuronales.

Mesh Shader

Mesh Shader — el tipo más nuevo de shader, aparecido con NVIDIA Turing (2018) y Metal 3. El Mesh Shader reemplaza los shaders de vértices, geometría y teselado por un único pipeline mesh. Funciona junto con Task Shader: el Task Shader decide qué grupos mesh renderizar, y el Mesh Shader genera geometría sobre la marcha.

Lenguajes para escribir shaders

Los shaders se escriben en lenguajes especializados que se compilan a código máquina de GPU. La elección del lenguaje depende de la plataforma y la API. Revisemos los lenguajes principales: GLSL, HLSL, Metal Shading Language y el formato intermedio SPIR-V.

GLSL (OpenGL Shading Language)

GLSL — el lenguaje de shaders para OpenGL, OpenGL ES y WebGL. Su sintaxis se basa en C con la adición de tipos vectoriales (vec2, vec4, mat4) y funciones integradas (texture, normalize, reflect). GLSL ES es la versión para dispositivos móviles con precisión limitada (lowp, mediump, highp). Según Khronos (2025), GLSL sigue siendo el lenguaje de shaders más extendido gracias a su compatibilidad multiplataforma.

glsl
#version 300 es
precision mediump float;
in vec2 v_texCoord;
uniform sampler2D u_texture;
out vec4 fragColor;

void main() {
    fragColor = texture(u_texture, v_texCoord);
}

Un fragment shader simple lee el color de una textura mediante coordenadas UV. precision mediump indica a la GPU que use media precisión para floats — acelera la ejecución en dispositivos móviles en un 25–40%.

HLSL (High-Level Shader Language)

HLSL — el lenguaje de shaders de Microsoft para DirectX. Su sintaxis es más cercana a C++ con soporte para clases, estructuras y plantillas. HLSL se usa en aplicaciones Windows y mediante Shader Model 6.7+ soporta Ray Tracing, Mesh Shaders y Sampler Feedback. Para desarrollo móvil, HLSL no se usa directamente pero se compila a SPIR-V para Vulkan.

Metal Shading Language

MSL (Metal Shading Language) — el lenguaje de shaders de Apple basado en C++14. A diferencia de GLSL y HLSL, MSL se compila junto con la aplicación, eliminando la compilación JIT en el dispositivo. MSL soporta punteros, plantillas y la biblioteca estándar de C++. Se usa en todos los dispositivos Apple: iPhone, iPad, Mac, Apple TV.

cpp
#include <metal_stdlib>
using namespace metal;
struct VertexOut {
    float4 position [[position]];
    float2 texCoord;
};

fragment float4
myFragment(VertexOut in [[stage_in]],
            texture2d<float> tex [[texture(0)]]) {
    constexpr sampler s = sampler(filter::linear);
    return tex.sample(s, in.texCoord);
}

MSL usa los atributos [[position]], [[stage_in]] y [[texture(N)]] para la vinculación de recursos. El compilador de Apple genera código optimizado para la GPU actual, teniendo en cuenta el número de registros y caché.

SPIR-V

SPIR-V — un formato binario intermedio para shaders, el estándar para Vulkan. Los shaders se escriben en GLSL o HLSL, se compilan a SPIR-V y se cargan en la aplicación Vulkan. SPIR-V no está vinculado a un lenguaje específico — existen compiladores desde Rust, Python, OpenCL C a SPIR-V.

Shaders en desarrollo móvil

Los shaders en plataformas móviles tienen limitaciones en comparación con los de escritorio: menos registros, precisión limitada y falta de soporte para ciertas instrucciones. Examinemos las particularidades de los shaders en Android (Vulkan/OpenGL ES) e iOS (Metal).

Shaders en Android

Android usa GLSL ES para OpenGL y SPIR-V para Vulkan. OpenGL ES 3.2 soporta shaders con mediump por defecto. Vulkan requiere compilación explícita de GLSL a SPIR-V mediante glslangValidator. En Android, los shaders se cargan desde recursos de cadena o desde archivos SPIR-V compilados.

Qualcomm Adreno GPU optimiza shaders a nivel de driver. Recomendaciones: use mediump para color y UV, highp solo para posiciones; evite muestreos de textura en vertex shaders; agrupe cálculos en vectores (vec4 en lugar de 4x float). Según Qualcomm (2025), estas optimizaciones proporcionan una mejora del 30–50%.

Shaders en iOS

iOS usa exclusivamente Metal Shading Language. Los shaders se compilan a código máquina junto con la aplicación mediante Xcode. Metal proporciona Shader Debugger y GPU Capture para la creación de perfiles de shaders. La GPU de Apple (TBDR) tiene optimizaciones específicas: early fragment test, render targets sin memoria y blending programable.

Según Apple WWDC 2024, para shaders en iOS es crítico usar half en lugar de float, limitar la presión de registros (máx. 64 registros) y evitar muestreos de textura dependientes. Los shaders de iOS deben ser compactos — el tamaño óptimo es de 50–100 instrucciones ALU.

Shaders en Unity y Unreal Engine

Los motores de juegos Unity y Unreal Engine proporcionan editores visuales de shaders (Shader Graph, Material Editor) y lenguajes abstractos (ShaderLab, USF). El desarrollador escribe shaders en un lenguaje de alto nivel, y el motor compila para la plataforma destino. Unity usa HLSL como lenguaje intermedio, Unreal usa USF (Unreal Shader Format).

Optimización de shaders

La optimización de shaders — una etapa clave en el desarrollo de gráficos para dispositivos móviles. Un shader mal escrito puede reducir los FPS de 60 a 20. Revisemos las reglas principales y técnicas de optimización.

Precisión de cálculo

Use la precisión mínima suficiente: lowp para color y UV, mediump para normales e iluminación, highp solo para posiciones y matrices. Según ARM (2025), las operaciones mediump son 2 veces más rápidas que highp en GPU Mali. En GLSL ES, esto se especifica mediante calificadores de precisión.

Minimizar muestreos de textura

Los muestreos de textura — la operación más costosa en un shader (10–30 ciclos frente a 1–2 para una instrucción ALU). Reduzca el número de muestreos: combine texturas en atlas, almacene datos en arrays uniform en lugar de texturas, almacene en caché resultados de píxeles vecinos mediante instrucciones derivadas.

Evite bifurcaciones

Las bifurcaciones dinámicas (if con variable uniform) reducen el rendimiento del pipeline SIMT. Reemplace bifurcaciones con funciones matemáticas: mix(), step(), smoothstep() y clamp(). Estas funciones se ejecutan en 1–2 instrucciones, mientras que una bifurcación puede costar 8–16 instrucciones debido a la divergencia de hilos.

glsl
// Bad: dynamic branching in shader
if (u_enableLight) {
    color *= computeLighting(normal);
}

// Good: mathematical branch replacement
color *= mix(1.0, computeLighting(normal),
              float(u_enableLight));

mix() realiza interpolación lineal entre dos valores. Cuando u_enableLight=0, devuelve 1.0 — el color no cambia. Cuando u_enableLight=1, devuelve el resultado de iluminación. Sin bifurcaciones — todos los hilos ejecutan el mismo código.

Ejemplos de shaders

Exploremos ejemplos prácticos de shaders para desarrollo móvil — desde sombreado simple hasta generación procedural de texturas. Cada ejemplo demuestra una técnica específica.

Sombreado Phong (Vertex Shader)

Modelo Phong — un modelo clásico de iluminación con componentes difusa y especular. El Vertex Shader calcula la iluminación para cada vértice, el Fragment Shader solo interpola el resultado (sombreado Gouraud). Adecuado para dispositivos móviles por su bajo coste.

glsl
#version 300 es
layout(location = 0) in vec4 a_position;
layout(location = 1) in vec3 a_normal;
uniform mat4 u_mvp;
uniform mat4 u_modelView;
out vec3 v_color;

void main() {
    vec3 normal = normalize(mat3(u_modelView) * a_normal);
    vec3 lightDir = normalize(vec3(0.0, 1.0, 1.0));
    float diff = max(dot(normal, lightDir), 0.0);
    v_color = vec3(0.8, 0.2, 0.2) * (0.3 + diff * 0.7);
    gl_Position = u_mvp * a_position;
}

El shader calcula la iluminación difusa: el producto punto de la normal y la dirección de la luz. El resultado se mezcla con los componentes ambiental (0.3) y difuso (0.7). Ejecuta 10–15 instrucciones ALU por vértice — aceptable para 100 000 polígonos a 60 FPS en una GPU móvil.

Textura procedural (Fragment Shader)

Las texturas procedurales se generan en el Fragment Shader sin cargar desde un archivo. Ahorra memoria de video y simplifica la animación. Ejemplo — un tablero de ajedrez con tamaño de celda ajustable. Solo unas pocas instrucciones ALU — carga mínima en la GPU.

glsl
#version 300 es
precision mediump float;
in vec2 v_uv;
uniform float u_cells;
out vec4 fragColor;

void main() {
    vec2 cell = floor(v_uv * u_cells);
    float isWhite = mod(cell.x + cell.y, 2.0);
    fragColor = mix(vec4(0.1, 0.1, 0.1, 1.0),
                     vec4(0.9, 0.9, 0.9, 1.0),
                     isWhite);
}

8 instrucciones ALU — un shader ideal para dispositivos móviles. u_cells establece el número de celdas por eje. floor y mod son operaciones baratas, ejecutadas en 1 ciclo en todas las GPUs móviles.

Preguntas frecuentes

¿En qué se diferencia un shader de un programa normal en C++?

Shader se ejecuta en la GPU en modo SIMT — una instrucción para cientos de hilos. Un programa normal en C++ se ejecuta en la CPU en modo MIMD. Un shader no tiene acceso al sistema de archivos, E/S ni memoria dinámica. Recibe datos a través de buffers y texturas y devuelve una posición o color.

¿Qué lenguaje de shaders aprender para desarrollo móvil?

GLSL — para OpenGL ES y WebGL, multiplataforma. Metal Shading Language — para iOS. HLSL — la base para Unity y Unreal Engine. Empiece con GLSL — la comprensión de los fundamentos se traslada a cualquier lenguaje de shaders.

¿Por qué los shaders se ralentizan en dispositivos móviles?

Razones principales: alta precisión (highp en lugar de mediump), muestreos de textura excesivos, bifurcaciones dinámicas y superación del límite de registros. Use RenderDoc o Xcode GPU Frame Debugger para analizar shaders.

¿Qué es un compute shader y para qué sirve?

Compute Shader — un shader para cálculos arbitrarios en la GPU: física de partículas, procesamiento de imágenes, simulación de telas. A diferencia del Fragment Shader, no está vinculado a píxeles y puede escribir en buffers arbitrarios.

¿Se pueden escribir shaders sin saber lenguajes de programación?

Sí, mediante editores visuales: Shader Graph en Unity, Material Editor en Unreal Engine o Metal Shader Converter. Generan código de shader basado en un grafo de nodos. Para optimización profunda se requiere comprensión del lenguaje de shaders.

Resumen

  • Shader — un programa paralelo para GPU que procesa vértices, fragmentos o datos arbitrarios de forma masiva.
  • Tipos de shaders: Vertex, Fragment, Compute, Geometry, Tessellation y Mesh — cada uno responsable de su etapa del pipeline.
  • Lenguajes: GLSL (OpenGL), HLSL (DirectX), MSL (Metal), SPIR-V (Vulkan) — se compilan a código máquina de GPU.
  • Particularidades móviles: precisión mediump, mínimos muestreos de textura, sin bifurcaciones dinámicas.
  • Optimización: mix() en lugar de if, precisión half, ATF, combinación de texturas en atlas y precálculos en CPU.
  • Aplicaciones: iluminación Phong, texturas procedurales, post-efectos, física de partículas y efectos de UI.
  • Herramientas: RenderDoc, Xcode GPU Debugger, Qualcomm Adreno Profiler y Mali Offline Compiler para análisis de shaders.

Desarrollaremos una aplicación móvil llave en mano

IT Sectr crea aplicaciones para iOS y Android para startups y empresas desde 2017. Le asesoraremos y le propondremos la mejor solución.

Discutir el proyecto

Lea también