Pular para o conteúdo
Luz · FresnelIniciante

Luz de contorno

Um brilho ao longo da silhueta que acompanha a câmera.

NormalVisãoSuperfície
  1. 01ObjetivoLuz
  2. 02TécnicaFresnel
  3. 03ExecuçãoLuz de contorno
Malha de teste

Parâmetros

3.0
#59bfff
1.50

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.

  1. dotDotProductdotdotdot
    Normal
    Visão

    01 Quanto está de frente

  2. 1.0 - xOneMinus1.0 - x1.0 - x1.0 - x

    02 Inverter

  3. powPowpowpowpow

    03 Estreitar a faixa

  4. *Multiply***

    04 Colorir

Como funciona

Texto provisório do esqueleto. Israel o substitui.

O produto escalar entre a normal da superfície e a direção da câmera vale 1 onde a superfície está de frente para você e 0 na silhueta. Invertê-lo dá um valor claro só nas bordas. Elevar esse valor a uma potência estreita a faixa, e multiplicá-lo por uma cor e uma intensidade o colore.

Monte no GLSL

Texto provisório do esqueleto. Israel o substitui.

Cole a função num shader de fragmento que receba a normal em espaço de mundo e a direção da câmera.

Monte no Godot

O VisualShader também tem um nó Fresnel nativo que faz os três primeiros passos.

Texto provisório do esqueleto. Israel o substitui.

Cole o shader num novo ShaderMaterial de um MeshInstance3D. Ele escreve o contorno em EMISSION sobre uma cor base preta e desliga o especular e a luz ambiente, então a malha mostra só a cor do contorno e, com o Glow ligado no WorldEnvironment, ela brilha.

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

rim-light.fragGLSL
#version 300 es// Fresnel → Rim light, 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_power; // Power: 3.0 (0.5 to 8.0)uniform vec3 p_color; // Color: vec3(0.35, 0.75, 1.0), sRGB; upload it decoded to linearuniform float p_intensity; // Intensity: 1.5 (0.0 to 4.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));}// i.view points from the surface toward the camera, so dot(normal, view) is 1 where the surface faces the camera// and 0 at the silhouette. max() drops back faces, which would otherwise go above 1 after the inversion.vec4 effect(Inputs i) {	float facing = max(dot(i.normal, i.view), 0.0);	float edge = 1.0 - facing;	float rim = pow(edge, p_power);	vec3 glow = rim * p_color * p_intensity;	return vec4(glow, 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);}
rim-light.gdshaderShader do Godot
// Fresnel → Rim light, Godot 4. From Creative Center, MIT license.shader_type spatial;// Emission: a black base color, no specular or ambient light, and the effect as EMISSION, which glow catchesrender_mode specular_disabled, ambient_light_disabled;uniform float power : hint_range(0.5, 8.0, 0.1) = 3.0;uniform vec3 color : source_color = vec3(0.35, 0.75, 1.0);uniform float intensity : hint_range(0.0, 4.0, 0.05) = 1.5;struct Inputs {	vec2 uv;	vec3 position;	vec3 normal;	vec3 view;	float time;	vec2 fragCoord;	vec2 resolution;};// i.view points from the surface toward the camera, so dot(normal, view) is 1 where the surface faces the camera// and 0 at the silhouette. max() drops back faces, which would otherwise go above 1 after the inversion.vec4 effect(Inputs i) {	float facing = max(dot(i.normal, i.view), 0.0);	float edge = 1.0 - facing;	float rim = pow(edge, power);	vec3 glow = rim * color * intensity;	return vec4(glow, 1.0);}void fragment() {	Inputs i;	// Godot's UV starts at the top-left; the effect expects GLSL's bottom-left	i.uv = vec2(UV.x, 1.0 - UV.y);	// VERTEX, NORMAL and VIEW are in view space here; the effect works in world space	i.position = (INV_VIEW_MATRIX * vec4(VERTEX, 1.0)).xyz;	i.normal = normalize((INV_VIEW_MATRIX * vec4(NORMAL, 0.0)).xyz);	i.view = normalize((INV_VIEW_MATRIX * vec4(VIEW, 0.0)).xyz);	i.time = TIME;	// FRAGCOORD's origin is the top-left too	i.resolution = VIEWPORT_SIZE;	i.fragCoord = vec2(FRAGCOORD.x, i.resolution.y - FRAGCOORD.y);	vec4 frag_out = effect(i);	ALBEDO = vec3(0.0);	EMISSION = frag_out.rgb;}

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