Ponto suave
Um ponto redondo cuja borda vai de nítida a um brilho suave com um só controle.
- 01ObjetivoForma
- 02TécnicaCírculos, caixas e linhas
- 03ExecuçãoPonto suave
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.
uv * 2.0 - 1.0MultiplyAdduv * 2.0 - 1.0uv * 2.0 - 1.0uv * 2.0 - 1.0 UVTempo01 Centralizar as coordenadas
lengthLength2Dlengthlengthlength Entrada02 Distância até o centro
smoothstepSmoothStepsmoothstepsmoothstepsmoothstep Entrada03 Borda suave
mixMixmixmixmix Entrada04 Colorir
Como funciona
O ponto é a menor forma útil que um shader de fragmento consegue desenhar, e ele já contém toda a ideia de desenhar com matemática: medir a que distância cada pixel está de alguma coisa e decidir com um limiar.
Centralize as coordenadas. A 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. Coordenadas 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 / resolutionuv * 2.0 - 1.0 leva a origem para o meio e faz cada eixo ir de -1 a 1. Só que a prévia é mais larga do que alta, então
uma unidade na horizontal ficaria mais comprida na tela do que uma unidade na vertical, e o círculo sairia oval.
Multiplicar x pela proporção da tela (largura dividida pela altura) deixa a unidade com o mesmo comprimento nas duas
direções.
Meça a distância. Vetor Um grupo de dois a quatro números tratado como um só valor (vec2, vec3, vec4). O mesmo tipo guarda uma posição, uma direção, uma cor ou uma UV.length(p) é o comprimento do vetorUm grupo de dois a quatro números tratado como um só valor (vec2, vec3, vec4). O mesmo tipo guarda uma posição, uma direção, uma cor ou uma UV.
Recorte a borda. Um limiar transforma a distância em cobertura. Smoothstep Um limiar suave. Vale 0 abaixo da primeira borda, 1 acima da segunda e segue uma curva em S com as pontas planas entre elas.step(radius, d) passaria de dentro para fora num
único pixel e, numa borda curva, isso deixa uma escadinha de pixels serrilhados. Um
smoothstepUm limiar suave. Vale 0 abaixo da primeira borda, 1 acima da segunda e segue uma curva em S com as pontas planas entre elas.t = clamp((x − e0) / (e1 − e0), 0, 1); s = t² (3 − 2t)radius - soft até radius + soft vai de 0 a 1 aos poucos, e 1.0 - …
inverte o resultado para o lado de dentro valer 1. Com uma suavidade grande, essa rampa é o brilho suave; com uma
pequena, ela encolhe até virar uma borda sem serrilhado.
A suavidade nunca fica abaixo de um pixel: p cobre 2 unidades na altura da prévia, então 2.0 / altura é um pixel
nessas unidades, e max() mantém a suavidade pelo menos desse tamanho, então a rampa de radius - soft a radius + soft sempre cobre pelo menos dois pixels. Sem isso, levar a Suavidade a 0 traz a borda serrilhada de volta.
Pinte. A cobertura é um número de 0 a 1, então ela pode escolher entre duas cores com mix: o fundo onde vale 0, a
cor do ponto onde vale 1 e uma mistura ao longo da borda.
Os mesmos quatro passos fazem a maioria das formas 2D. Troque length(p) pela distância até uma caixa ou uma linha e o
limiar continua igual. Use a cobertura como alfa em vez de misturar cores, e o ponto vira uma máscara sobre qualquer
coisa.
Monte no GLSL
O código copiado é um shader de fragmento WebGL2 completo. Ele desenha sobre qualquer coisa que cubra o canvas e tenha UVs.
- Desenhe um retângulo que cubra o canvas: dois triângulos de -1 a 1 no espaço de recorte.
- No shader de vértice, escreva
v_uvindo de 0 a 1 ao longo do retângulo, além dev_position,v_normalev_view. O shader de fragmento lê os quatro, então o WebGL2 se recusa a ligar o programa se o shader de vértice não os escrever; para os três últimos, constantes bastam. - A cada quadro, defina
u_resolutioncom o tamanho do drawing buffer em pixels eu_timecom os segundos desde o início. Este card só lê a resolução. - Defina
p_radiusep_softnesse enviep_dotColorep_backgrounddecodificadas de sRGB para linear (c <= 0.04045 ? c / 12.92 : pow((c + 0.055) / 1.055, 2.4)por canal). - Desenhe com o blending desligado. O shader escreve uma cor opaca já codificada em sRGB, que um canvas WebGL2 padrão mostra como está.
Para usar o ponto como máscara, devolva disc como alfa e desenhe com
gl.blendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA).
Monte no Godot
O shader exportado supõe o HDR 2D desligado (o padrão). Com ele ligado, faça u_toLinear e u_toSrgb devolverem a entrada sem mudança.
O código copiado é um shader canvas_item completo.
- Adicione um
ColorRecta uma cena 2D ou de interface e defina o preset de âncoras como Full Rect, para ele cobrir a viewport. - No Inspector, defina Material como um novo
ShaderMaterial, depois o Shader dele como um novoShader, e cole o código no editor de shader. - Ajuste o raio, a suavidade e as cores em Shader Parameters; o ponto se atualiza no editor.
Num VisualShader, a cadeia é UV, um MultiplyAdd (vezes 2, menos 1) e uma multiplicação pela proporção, depois
Length2D, SmoothStep com as bordas no raio menos e mais a suavidade, um OneMinus e um Mix entre as duas cores.
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// Circles, boxes & lines → Soft dot, 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 float p_radius; // Radius: 0.5 (0.05 to 1.0)uniform float p_softness; // Softness: 0.08 (0.0 to 0.5)uniform vec3 p_dotColor; // Dot color: vec3(1.0, 0.8, 0.35), sRGB; upload it decoded to linearuniform vec3 p_background; // Background: vec3(0.07, 0.08, 0.12), sRGB; upload it decoded to linearin 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));}vec4 effect(Inputs i) { // Centered, with x scaled by the aspect ratio: one unit is as long across as up, so the dot stays round vec2 p = (i.uv * 2.0 - 1.0) * vec2(i.resolution.x / i.resolution.y, 1.0); float d = length(p); // p spans 2 units over the height, so 2 / height is one pixel: softness never drops below it, so the ramp // always spans at least two pixels and never stair-steps float soft = max(p_softness, 2.0 / i.resolution.y); float disc = 1.0 - smoothstep(p_radius - soft, p_radius + soft, d); vec3 color = mix(p_background, p_dotColor, disc); return vec4(color, 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);}// Circles, boxes & lines → Soft dot, 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 float radius : hint_range(0.05, 1.0, 0.01) = 0.5;uniform float softness : hint_range(0.0, 0.5, 0.005) = 0.08;uniform vec3 dotColor : source_color = vec3(1.0, 0.8, 0.35);uniform vec3 background : source_color = vec3(0.07, 0.08, 0.12);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));}vec4 effect(Inputs i) { // Centered, with x scaled by the aspect ratio: one unit is as long across as up, so the dot stays round vec2 p = (i.uv * 2.0 - 1.0) * vec2(i.resolution.x / i.resolution.y, 1.0); float d = length(p); // p spans 2 units over the height, so 2 / height is one pixel: softness never drops below it, so the ramp // always spans at least two pixels and never stair-steps float soft = max(softness, 2.0 / i.resolution.y); float disc = 1.0 - smoothstep(radius - soft, radius + soft, d); vec3 color = mix(u_toLinear(background), u_toLinear(dotColor), disc); return vec4(color, 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.