Céu linear
Uma mistura vertical de um horizonte quente até um zênite profundo, com início e fim que você pode mover.
- 01ObjetivoCor
- 02TécnicaDegradês
- 03ExecuçãoCéu linear
Parâmetros
Copie para a sua plataforma
- GLSLCopiar
- GodotCopiar
Cadeia de nós
Montada passo a passo, no estilo do GLSL, com os nomes de nós dele.
Montada passo a passo, no estilo do Godot, com os nomes de nós dele.
Este card ainda não tem versão para Unreal Engine 5, então os nós mostram os nomes do GLSL.
Este card ainda não tem versão para Unity, então os nós mostram os nomes do GLSL.
Este card ainda não tem versão para Blender, então os nós mostram os nomes do GLSL.
i.uv.yUV + VectorDecomposei.uv.yi.uv.yi.uv.y UV01 Altura no quad
(x - a) / (b - a)Remap(x - a) / (b - a)(x - a) / (b - a)(x - a) / (b - a) Entrada02 Remapear para a faixa
clampClampclampclampclamp Entrada03 Limitar entre 0 e 1
mixMixmixmixmix Entrada04 Misturar as duas cores
Como funciona
Um degradê precisa de um número que vá de 0 a 1 e de duas cores para misturar por ele. Aqui o número vem da altura no quad, e as cores são um horizonte quente e um azul profundo lá em cima.
- Altura.
i.uv.yé a coordenada vertical da UVUma posição 2D numa superfície ou na tela, em geral de 0 a 1 nos dois eixos. Shaders desenham formas e padrões como funções dela.FundamentoCoordenadas UV
Uma posição 2D numa superfície ou na tela, em geral de 0 a 1 nos dois eixos. Shaders desenham formas e padrões como funções dela.
uv = gl_FragCoord.xy / resolutionFontes: 0 na borda de baixo, 1 na de cima. Mostrada como cor, ela já é um degradê, do preto ao branco.- gl_FragCoord (abre em uma nova aba)Referência
- UV mapping (abre em uma nova aba)Referência
- Remapear. Um céu de verdade não muda de cor por igual do chão até o topo do quadro: ele fica claro perto do
horizonte e escurece mais para cima.
(height - p_bottom) / (p_top - p_bottom)leva a mistura para uma faixa: 0 na altura de início, 1 na altura de fim. É o inverso de um mix: pergunta quanto do caminho pela faixa o pixel já percorreu. - Limitar. Abaixo do início o remapeamento fica negativo, e acima do fim passa de 1. O
clampo segura nas pontas, então a cor do horizonte preenche tudo abaixo da faixa e a do zênite tudo acima dela. Sem ele, o mixMistura de a até b por um fator t, em linha reta. O GLSL chama de mix; o HLSL e a maioria dos editores de nós chamam de lerp.FundamentoInterpolação linear (mix)
Mistura de a até b por um fator t, em linha reta. O GLSL chama de mix; o HLSL e a maioria dos editores de nós chamam de lerp.
mix(a, b, t) = a (1 − t) + b tFontesdo próximo passo extrapolaria além das duas cores.- mix (abre em uma nova aba)Referência
- Linear interpolation (abre em uma nova aba)Referência
- Misturar.
mix(p_horizon, p_zenith, t)mistura as duas cores canal a canal: vermelho, verde e azul andam cada um em linha reta de uma ponta à outra.
As cores chegam em luz linear, porque o frame decodifica os parâmetros de cor antes de o shader vê-los e codifica o
resultado uma única vez no final. Então o mix mistura luz do jeito que luzes sobrepostas se misturam, e o meio continua
claro. Misturar direto os valores sRGBA codificação padrão das cores de tela. Os valores guardados seguem uma curva próxima de uma potência 1/2.2 da luz, então precisam ser decodificados antes de iluminar ou mesclar. sRGB A codificação padrão das cores de tela. Os valores guardados seguem uma curva próxima de uma potência 1/2.2 da luz, então precisam ser decodificados antes de iluminar ou mesclar.linear = ((c + 0.055) / 1.055)^2.4 for c > 0.04045
Aproxime o início e o fim e a faixa vira uma linha de horizonte dura; afaste-os até as bordas e o degradê ocupa a
altura toda. Uma tela de oito bits tem só 256 níveis por canal, então um degradê longo e lento entre cores parecidas
pode mostrar degraus discretos (bandingBanding são as faixas em que um degradê suave se parte quando guardado com poucos níveis. O dithering soma um ruído minúsculo por pixel antes do arredondamento, e as faixas viram uma granulação fina. Banding e dithering Banding são as faixas em que um degradê suave se parte quando guardado com poucos níveis. O dithering soma um ruído minúsculo por pixel antes do arredondamento, e as faixas viram uma granulação fina.
Monte no GLSL
O código copiado é um shader de fragmento GLSL ES 3.00 completo para WebGL2. Ele lê v_uv do shader de vértice, então
desenhe-o em qualquer quad ou triângulo de tela cheia cujo shader de vértice passe UVs de 0 no canto inferior esquerdo
a 1 no superior direito. Ele também declara v_position, v_normal e v_view; um shader de vértice 2D pode escrever
constantes neles.
- Compile-o com um shader de vértice que gere
v_uv(e os outros três varyings) e ligue os dois. - Envie os quatro uniforms:
p_horizonep_zenithcomovec3em luz linear,p_bottomep_topcomo floats entre 0 e 1. Decodifique o valor sRGB de um seletor em cada canal comc <= 0.04045 ? c / 12.92 : ((c + 0.055) / 1.055) ** 2.4. - Desenhe. O
main()do shader limita o resultado e o codifica para sRGB sozinho, porque um canvas WebGL2 não faz isso.
Para usar o céu dentro de um shader maior, pegue só o effect() e chame-o com i.uv preenchido; depois codifique uma
única vez no fim do seu shader, não dentro do céu.
Monte no Godot
O shader supõe o HDR 2D desligado (o padrão do projeto), então ele mesmo decodifica os uniforms de cor e codifica o resultado. Com Rendering > Viewport > HDR 2D ligado, faça u_toLinear() e u_toSrgb() devolverem c sem mudança.
A exportação é um shader canvas_item, então desenha em qualquer nó 2D.
- Adicione um ColorRect e ponha o layout em Full Rect (ou no tamanho do painel que você quer atrás da interface).
- Em Material, crie um ShaderMaterial, depois um Shader novo, e cole o código por cima do modelo.
- Os quatro uniforms aparecem em Shader Parameters: escolha as cores do horizonte e do zênite e mova o início e o fim entre 0 e 1.
No VisualShader a mesma cadeia é UV → VectorDecompose (y) → Remap (faixa de entrada do início ao fim, saída de 0 a 1) →
Clamp → Mix entre dois nós ColorParameter. Para um céu que gira com uma câmera 3D, escreva um shader sky que misture
por EYEDIR.y: o mesmo remapeamento e o mesmo mix, outro número no lugar do t.
Ainda não há tutorial de Unreal Engine 5 para este card.
Ainda não há tutorial de Unity para este card.
Ainda não há tutorial de Blender para este card.
Código
#version 300 es// Gradients → Linear sky, web GLSL (GLSL ES 3.00). From Creative Center, MIT license.precision highp float;uniform float u_time;uniform vec2 u_resolution; // this pass's output size in pixelsuniform vec3 p_horizon; // Horizon color: vec3(0.99, 0.72, 0.5), sRGB; upload it decoded to linearuniform vec3 p_zenith; // Zenith color: vec3(0.16, 0.3, 0.68), sRGB; upload it decoded to linearuniform float p_bottom; // Gradient start: 0.1 (0.0 to 0.45)uniform float p_top; // Gradient end: 0.9 (0.55 to 1.0)in vec2 v_uv;in vec3 v_position;in vec3 v_normal;in vec3 v_view;out vec4 fragColor;struct Inputs { vec2 uv; vec3 position; vec3 normal; vec3 view; float time; vec2 fragCoord; vec2 resolution;};vec3 u_toSrgb(vec3 c) { return mix(c * 12.92, 1.055 * pow(c, vec3(1.0 / 2.4)) - 0.055, step(0.0031308, c));}// The colors arrive linear, so this mix blends light; mixing their sRGB values instead darkens the middle// (the RGB vs OKLab ramp card shows the difference).vec4 effect(Inputs i) { float height = i.uv.y; float ramp = (height - p_bottom) / (p_top - p_bottom); float t = clamp(ramp, 0.0, 1.0); vec3 sky = mix(p_horizon, p_zenith, t); return vec4(sky, 1.0);}void main() { Inputs i; i.uv = v_uv; i.position = v_position; // Interpolation shortens the vectors between vertices i.normal = normalize(v_normal); i.view = normalize(v_view); i.time = u_time; i.fragCoord = gl_FragCoord.xy; i.resolution = u_resolution; vec4 frag_out = effect(i); // The output is sRGB: clamped and encoded once, here, with no tone mapping; opaque, so alpha is 1 fragColor = vec4(u_toSrgb(clamp(frag_out.rgb, 0.0, 1.0)), 1.0);}// Gradients → Linear sky, Godot 4. From Creative Center, MIT license.shader_type canvas_item;// Unshaded shows the effect's color as is, like the site's preview; scene lights don't touch itrender_mode unshaded;uniform vec3 horizon : source_color = vec3(0.99, 0.72, 0.5);uniform vec3 zenith : source_color = vec3(0.16, 0.3, 0.68);uniform float bottom : hint_range(0.0, 0.45, 0.01) = 0.1;uniform float top : hint_range(0.55, 1.0, 0.01) = 0.9;struct Inputs { vec2 uv; vec3 position; vec3 normal; vec3 view; float time; vec2 fragCoord; vec2 resolution;};// Godot's 2D renderer works in sRGB (HDR 2D off, the default), so the frame decodes color params and sRGB// textures to linear itself and encodes the result. With HDR 2D on, make these return c unchanged.vec3 u_toLinear(vec3 c) { return mix(c / 12.92, pow((c + 0.055) / 1.055, vec3(2.4)), step(0.04045, c));}vec3 u_toSrgb(vec3 c) { return mix(c * 12.92, 1.055 * pow(c, vec3(1.0 / 2.4)) - 0.055, step(0.0031308, c));}// The colors arrive linear, so this mix blends light; mixing their sRGB values instead darkens the middle// (the RGB vs OKLab ramp card shows the difference).vec4 effect(Inputs i) { float height = i.uv.y; float ramp = (height - bottom) / (top - bottom); float t = clamp(ramp, 0.0, 1.0); vec3 sky = mix(u_toLinear(horizon), u_toLinear(zenith), t); return vec4(sky, 1.0);}void fragment() { Inputs i; // UV starts at the top-left; the effect expects GLSL's bottom-left i.uv = vec2(UV.x, 1.0 - UV.y); // A flat quad facing the viewer, the same as the site's 2D preview i.position = vec3(i.uv * 2.0 - 1.0, 0.0); i.normal = vec3(0.0, 0.0, 1.0); i.view = vec3(0.0, 0.0, 1.0); i.time = TIME; // FRAGCOORD's origin is the top-left too i.resolution = 1.0 / SCREEN_PIXEL_SIZE; i.fragCoord = vec2(FRAGCOORD.x, i.resolution.y - FRAGCOORD.y); vec4 frag_out = effect(i); COLOR = vec4(u_toSrgb(clamp(frag_out.rgb, 0.0, 1.0)), 1.0);}Ainda não há código de Unreal Engine 5 para este card.
Ainda não há código de Unity para este card.
Ainda não há código de Blender para este card.
Leitura complementar
- mix (abre em uma nova aba)Referência
- clamp (abre em uma nova aba)Referência
- Colors (abre em uma nova aba)Livro
- CanvasItem shaders (abre em uma nova aba)Documentação