惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

S
Secure Thoughts
Recent Commits to openclaw:main
Recent Commits to openclaw:main
H
Heimdal Security Blog
SecWiki News
SecWiki News
H
Hacker News: Front Page
N
News | PayPal Newsroom
L
LINUX DO - 最新话题
N
News and Events Feed by Topic
TaoSecurity Blog
TaoSecurity Blog
AI
AI
C
Cybersecurity and Infrastructure Security Agency CISA
Scott Helme
Scott Helme
PCI Perspectives
PCI Perspectives
S
Securelist
Exploit-DB.com RSS Feed
Exploit-DB.com RSS Feed
Cyberwarzone
Cyberwarzone
A
Arctic Wolf
Forbes - Security
Forbes - Security
T
Tor Project blog
Spread Privacy
Spread Privacy
WordPress大学
WordPress大学
I
Intezer
Martin Fowler
Martin Fowler
Help Net Security
Help Net Security
P
Proofpoint News Feed
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
Cisco Talos Blog
Cisco Talos Blog
Latest news
Latest news
博客园 - 司徒正美
W
WeLiveSecurity
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
V
V2EX
P
Palo Alto Networks Blog
Google DeepMind News
Google DeepMind News
IT之家
IT之家
阮一峰的网络日志
阮一峰的网络日志
V
Vulnerabilities – Threatpost
Jina AI
Jina AI
S
Security Affairs
Hacker News - Newest:
Hacker News - Newest: "LLM"
Simon Willison's Weblog
Simon Willison's Weblog
Project Zero
Project Zero
T
Threatpost
P
Privacy International News Feed
人人都是产品经理
人人都是产品经理
cs.CL updates on arXiv.org
cs.CL updates on arXiv.org
Application and Cybersecurity Blog
Application and Cybersecurity Blog
博客园 - Franky
Hugging Face - Blog
Hugging Face - Blog
Apple Machine Learning Research
Apple Machine Learning Research

DEV Community

Authentication Security Deep Dive: From Brute Force to Salted Hashing (With Java Examples) Why AI Systems Don’t Fail — They Drift Spilling beans for how i learn for exam😁"Reinforcement Learning Cheat Sheet" I Replaced Chrome with Safari for AI Browser Automation. Here's What Broke (and What Finally Worked) How Python Borrows Other People's Work The $40 Architecture: Processing 1 Billion API Requests with 99.99% Uptime Vibe Coding: A Workflow Guide (From Zero to SaaS) Most webhook security guides protect the wrong side. The scary part is delivery. Headless CMS for TanStack Start: Build a Blog with Cosmic EU Age Verification App "Hacked in 2 Minutes" — What Actually Happened Comfy Cloud’s delete function does not actually remove files Running AI Models on GPU Cloud Servers: A Beginner Guide Event-driven media intelligence with AWS Step Functions and Bedrock I scored 500 AI prompts across 8 quality dimensions — here's what broke How to Call Google Gemini API from Next.js (Free Tier, No Backend Needed) The Portal Protocol: Reclaiming Human Connection in the Age of AI How to Fix Your Team's Scattered Knowledge Problem With a Self-Hosted Forum Intro to tc Cloud Functors: A Graph-First Mental Model for the Modern Cloud Designing Multi-Tenant Backends With Both Ownership and Team Access I Built a Neumorphic CSS Library with 77+ Components — Here's What I Learned PostgreSQL Performance Optimization: Why Connection Pooling Is Critical at Scale Cómo construí un SaaS multi-rubro para gestionar expensas en Argentina con FastAPI + Vue 3 🚀 I Built an Ethical Hacking Scanner Tool – Open Source Project I Replaced /usage and /context in Claude Code With a Single Statusline A Pythonic Way to Handle Emails (IMAP/SMTP) with Auto-Discovery and AI-Ready Design I Collected 8.9 Million Polymarket Price Points — Here's What I Found About How Markets Really Move EcoTrack AI — Carbon Footprint Tracker & Dashboard Everyone's Using AI. No One Agrees How. 5 self-hosted ebook managers worth trying in 2026 Building Your First AI Agent with LangChain: From Chatbot to Autonomous Assistant Common SOC 2 Failures (Real World) Stop Vibe-Checking Your AI App: A Practical Guide to Evals How to Use SonarQube and SonarScanner Locally to Level Up Your Code Quality Your Next To-Do App Is Dead — I Replaced Mine with an OpenClaw AI Sign a Nostr event in 60 lines of Python using coincurve — no nostr-sdk, no nbxplorer, no rust toolchain ITGC Audit Explained Like You’re in Big 4 Patch Tuesday abril 2026: Microsoft parcha 163 vulnerabilidades y un zero-day en SharePoint Stop scraping everything: a better way to track competitor price changes Listing on MCPize + the Official MCP Registry while routing payments OUTSIDE the marketplace — how I kept 100% of my x402 revenue Building an AI-Powered Risk Intelligence System Using Serverless Architecture Why We Ripped Function Overloading Out of Our AI Toolchain Testing AI-Generated Code: How to Actually Know If It Works SaaS Churn Is Killing Your Business. Here Is What to Do About It (Without a Support Team) The Speed of AI Is No Longer Linear - And Self-Improving Models Are Why How to Implement RBAC for MCP Tools: A Practical Guide for Engineering Teams From Standard Quote to Persuasive Proposal: AI Automation for Arborists I built a CLI that scaffolds complete multi-tenant SaaS apps Axios CVE-2025–62718: The Silent SSRF Bug That Could Be Hiding in Your Node.js App Right Now The dashboard that ended our friendship Data Pipelines Explained Simply (and How to Build Them with Python) The Hidden Cost of AI Systems Nobody Talks About. undefined vs undeclared, and how typeof behaves Switching from file-based jobs to NATS/Kafka in Rust without changing code io_uring Adventures: Rust Servers That Love Syscalls Why Agentic AI is Killing the Traditional Database The POUR principles of web accessibility for developers and designers Quantum Neural Network 3D — A Deep Dive into Interactive WebGL Visualization How To Install Caveman In Codex On macOS And Windows Automation Pipeline Reliability: Why Your Workflow Breaks When Nobody Is Watching I Built an 'Open World' AI Coding Agent — It Works From ANY Folder From Freelancing to Product: A Tech Service Company's SaaS Transformation China's AI Giants: Adding Tencent Hunyuan & ByteDance Doubao to AI University (74 Providers) On the Vibe Coders and Their Lies clerk: Auto-Summarize Your Claude Code Sessions AI Weekly — 2026/04/10–04/17 | The Model Lockdown Is Here, but the Toolchain Is the Real Battleground AI 週報 — 2026/04/10–2026/04/17 模型封鎖潮來了,但工具鏈才是真戰場 Maybe this is how Open-Source apps are born... 🚀 Fine-Tune LLMs with LoRA and QLoRA: 2026 Guide tRPC v11 + Next.js App Router: End-to-End Type Safety Without the Boilerplate ShadCN UI in 2026: Why I Stopped Installing Component Libraries and Started Owning My Components SaaS Billing in React Server Components: Stripe + Supabase Without a Single `useEffect` Join our DEV Weekend Challenge — $1,000 in Prizes Across TEN winners! Submissions Due April 20 at 6:59 AM UTC. Implementing FSRS Spaced Repetition in Flutter + Supabase — Adding Memory Science to an AI Learning App "I Texted My Localhost From the Train — Claude Code Fixed the Bug Before I Got Home" I Built a Sales Prep AI and It Went Deeper Than Expected Design to Code #2: One JSON, Eleven Outputs Solving the 100M-Row Problem: A Summary Table Pattern for High-Volume Push Notification Logs Flutter Web With Wasm: What Actually Changes For Developers I Built 50 Royalty-Free Soundtracks for My Side Project in a Weekend Using AI Music Generation The Vibe Coding Security Checklist: 7 Things to Check Before You Ship Stop Letting Googlebot Guess Fix Your React App's SEO Right Desconstruindo o Streaming do LinkedIn: Como Criar um Engine de Extração de Vídeo de Alta Performance com HLS e FFmpeg (EDA Part-1) EDA (Exploratory Data Analysis) Explained With Real Life — Why Looking at Your Data Is the Most Important Step in Machine Learning Brand Relationship Management at Scale: Our 4-Touch Outreach System for 200+ Brands Why String.fromEnvironment() Might Return an Empty String in Dart JGuardrails 1.0.0 — Hardening Java LLM Apps Against Jailbreaks, Toxicity, and Prompt Injection Plan and Schedule a Full Week of Threads Content From One Claude Conversation Coding Cat Oran Ep3, Five Tables Changed Everything Updated: BFF Pattern I'm done watching freelancers get buried by 200 proposals. So I'm building the alternative. This is my first post BFS Algorithm in Java Step by Step Tutorial with Examples Tracking LLM Pricing Monthly: An Open Dataset for 22 AI Models How We Measure Content ROI on a Comparison Site: Revenue Attribution Without Perfect Data Introducing Nova AI Ops: The AI-Native Operating System for SRE Teams I built a free desktop video downloader for Windows — Grabbit How Talkie OCR Helps Vision-Impaired & Dyslexic Users Read the World Around Them VRCFaceTracking安装和iPhone面捕配置教程,有bug Even CrowdStrike Can't See Your Agents The Automation Gold Rush: What n8n Workflows and Claude Are Opening Up for Developers Right Now
Colored Shadow Penumbra: sombras con color en Unreal Engine 5.7
lu1tr0n · 2026-05-08 · via DEV Community

El colored shadow penumbra es uno de esos efectos que pasan inadvertidos hasta que alguien los apaga: ver una escena sin él hace que las sombras parezcan, de repente, demasiado limpias, demasiado neutras, demasiado 3D. La técnica reproduce un fenómeno óptico real (la transición coloreada entre la zona iluminada y la sombra dura) y, hasta hace poco, implementarla en Unreal Engine 5 implicaba pelearse con post-procesos frágiles que rompían con Lumen o con ciclos día/noche. La nueva implementación que el artista técnico Romain Durand puso de moda en redes y que Chosker liberó este mes resuelve el problema editando directamente los shaders del motor, con un costo de rendimiento prácticamente cero.

En este artículo desarmamos cómo funciona, copiamos línea por línea el código HLSL que se inyecta en los shaders de iluminación diferida, explicamos por qué necesita penumbras anchas para verse y discutimos cuándo conviene activarlo en producción. Si trabajás con UE5 desde LATAM, ya sea en un estudio indie o haciendo arch-viz, el colored shadow penumbra es una de esas mejoras de pulido que separan un render técnicamente correcto de uno que se siente vivo.

Qué es exactamente colored shadow penumbra

La luz, cuando atraviesa el borde de un objeto, no proyecta una sombra binaria entre iluminado y oscuro. Hay una región de transición llamada penumbra, donde la fuente de luz queda parcialmente ocluida y solo aporta una fracción de su intensidad. En esa franja, los rebotes indirectos (la luz que viene de paredes, suelos y el ambiente general) tienen relativamente más peso que la directa, y como la luz indirecta arrastra el color de las superficies que rebota, la penumbra termina teñida de los colores de la escena.

El fenómeno se conoce también como shadow terminator coloring en literatura de raytracing offline. Renderizadores no-real-time como Arnold, V-Ray o Cycles lo computan de forma natural porque trazan rayos secundarios. En tiempo real, Unreal Engine 5 simplifica el cálculo: usa un único término de sombra (SurfaceShadow) que va de 0 (en sombra completa) a 1 (totalmente iluminado) y modula la luminancia diffuse por ese factor. Esa simplificación es rápida pero borra la información cromática de la transición.

La técnica de Chosker reintroduce el efecto sin pagar el costo de un trazado real. La idea es ingeniosa: en la región donde SurfaceShadow es intermedio (la penumbra), saturar artificialmente el color base de la superficie. Con un colored shadow penumbra bien calibrado, una pared roja en sombra muestra rojos más vivos en su transición, una camisa azul deja un halo azulado al borde de su sombra y los materiales metálicos ganan profundidad sin lookdev adicional.
El efecto se nota más en bordes suaves de luces grandes y materiales saturados.

Por qué editar el shader del motor (y no un post-process)

Existen al menos tres caminos para introducir colored shadows en una escena de UE5: un Material Function aplicado por objeto, un Post Process Material global, o editar los shaders del engine directamente. Chosker descartó las primeras dos por una razón concreta: con Lumen activado o con ciclos día/noche, los valores que llegan al post-process ya están mezclados (luz directa, GI, especulares) y reconstruir cuál fragmento corresponde a sombra y cuál a iluminación se vuelve un ejercicio de adivinanza. Editar el shader de iluminación diferida resuelve el problema en su origen: ahí todavía existe la separación clara entre DiffuseLuminance y SurfaceShadow.

La ventaja adicional es que funciona con todos los tipos de luz (direccionales, puntuales, focales, rectangulares) sin código extra y se ejecuta una sola vez por píxel, en el mismo pase donde ya se está mezclando la sombra. El costo en GPU es marginal: un dot product y dos lerp, instrucciones que cualquier hardware moderno absorbe sin pestañear.

📌 Nota: Editar los shaders del motor no requiere clonar el repositorio completo de Epic ni compilar Unreal desde código fuente. Basta con la versión Launcher: los shaders del engine son archivos .usf/.ush en la carpeta Engine\Shaders\Private y se recompilan en frío con Ctrl + Shift + . dentro del editor.

Implementación con Substrate (UE 5.7)

Substrate es el nuevo sistema de materiales de Unreal Engine introducido como experimental en 5.2 y promovido a beta en 5.7. Si tu proyecto lo tiene activado (lo que es cada vez más común en producciones nuevas), el shader que necesitás editar es Engine\Shaders\Private\Substrate\SubstrateDeferredLighting.ush. Alrededor de la línea 190 vas a encontrar la línea que calcula la luminancia especular:

float3 SpecularLuminance = BSDFEvaluate.IntegratedSpecularValue * LightData.SpecularScale;

Enter fullscreen mode Exit fullscreen mode

Inmediatamente después, agregás el bloque de colored shadow penumbra:

// Colored shadow penumbra - Start
const float PenumbraSaturation = 4.0f;

float3 LuminanceFactors = float3(0.3f, 0.59f, 0.11f);
float3 PenumbraColor = dot(DiffuseLuminance, LuminanceFactors);
PenumbraColor = lerp(PenumbraColor, DiffuseLuminance, PenumbraSaturation);
DiffuseLuminance = lerp(DiffuseLuminance, PenumbraColor, 1.0f - BSDFShadowTerms.SurfaceShadow);
// Colored shadow penumbra - End

Enter fullscreen mode Exit fullscreen mode

El valor PenumbraSaturation = 4.0f es un punto de partida agresivo, pensado para que el efecto se vea en capturas comparativas. En producción, valores entre 1.5 y 2.5 dan un resultado más natural. Con 1.0 el efecto desaparece completamente (el lerp de saturación se cancela).

Implementación clásica sin Substrate

Si tu proyecto sigue usando el pipeline tradicional de iluminación diferida, el archivo objetivo es Engine\Shaders\Private\DeferredLightPixelShaders.usf. Alrededor de la línea 397 buscás:

OutColor += Radiance;

Enter fullscreen mode Exit fullscreen mode

Y agregás justo después:

// Colored shadow penumbra - Start
const float PenumbraSaturation = 4.0f;

float3 LuminanceFactors = float3(0.3f, 0.59f, 0.11f);
float3 PenumbraColor = dot(OutColor.xyz, LuminanceFactors);
PenumbraColor = lerp(PenumbraColor, OutColor.xyz, PenumbraSaturation);
OutColor.xyz = lerp(OutColor.xyz, PenumbraColor, 1.0f - SurfaceShadow);
// Colored shadow penumbra - End

Enter fullscreen mode Exit fullscreen mode

La lógica es idéntica; solo cambian los nombres de las variables porque el flujo de Substrate usa una estructura distinta para encapsular el resultado de la BSDF.

Cómo funciona el código línea por línea

Vale la pena desarmar las cinco líneas porque condensan tres conceptos importantes de teoría de color y composición:

  • Vector de luminancia (0.3, 0.59, 0.11) — son los pesos perceptuales del estándar Rec. 601 para convertir RGB a una intensidad gris equivalente. El verde pesa más porque el ojo humano es más sensible a esa banda. Hacer un dot entre el color y este vector colapsa cualquier color a su luminancia.- Saturación inversa — el primer lerp mueve el color desde su versión gris (PenumbraColor) hacia el color original (DiffuseLuminance) usando un factor mayor a 1. Cuando el factor pasa de 1, el lerp extrapola y produce una versión más saturada que la original. Es el mismo truco que usan los nodos de saturación de Photoshop o After Effects.- Mezcla por shadow term — el segundo lerp combina el color saturado con el color original usando 1.0 - SurfaceShadow como peso. En zonas totalmente iluminadas (SurfaceShadow = 1) el peso es 0 y no pasa nada. En zonas totalmente en sombra (SurfaceShadow = 0) el peso es 1 pero el color a mezclar ya es muy oscuro, así que tampoco se nota. Solo en la franja de transición se ve la versión saturada.

Es elegante porque no necesita detectar dónde está la penumbra: la propia función 1.0 - SurfaceShadow tiene su pico justo en esa región (cerca de 0.5) y cae hacia los extremos. La saturación se modula sola.

Visualización del flujo

graph LR
  A["Luz directa"] --> B["BSDF + Shadow Term"]
  B --> C["DiffuseLuminance RGB"]
  C --> D["Luminancia gris (Rec. 601)"]
  D --> E["Saturación inversa (lerp > 1)"]
  E --> F["Mezcla por (1 - SurfaceShadow)"]
  F --> G["Color final con penumbra coloreada"]

Enter fullscreen mode Exit fullscreen mode

Ajustar PenumbraSaturation: el parámetro que importa

El único hiperparámetro de la técnica es PenumbraSaturation. Vale la pena dedicar tiempo a calibrarlo, porque el rango útil es estrecho:

  • 1.0 — desactiva el efecto. Útil como sentinela durante debugging.- 1.2 a 1.8 — efecto sutil, perceptible solo en escenas con materiales saturados o luces grandes. Buen rango para arch-viz fotorrealista.- 2.0 a 3.0 — sweet spot para juegos estilizados, escenas con paleta artística o cinemáticas. El efecto se ve sin gritar.- 4.0 o más — exagerado a propósito, ideal para capturas de marketing pero rompe el realismo.

💡 Tip: Como el valor está hardcodeado en el shader, cada cambio implica recompilar shaders (varios minutos la primera vez, segundos después). Si vas a iterar mucho, conviene exponerlo como una console variable usando FAutoConsoleVariableRef en C++ o, más rápido todavía, parametrizarlo desde un material function global.

Limitaciones y casos donde no se ve

El colored shadow penumbra tiene tres limitaciones honestas que conviene comunicar al equipo de arte antes de venderlo como solución mágica:

  • Solo luces dinámicas — la sombra baked se calcula offline antes de que el shader corra, así que no hay penumbra que colorear. Si tu proyecto depende de iluminación pre-baked (común en mobile o VR de bajos requerimientos), esta técnica no aporta nada.- Necesita penumbras anchas — luces puntuales pequeñas con shadow maps duros producen penumbras de pocos píxeles, donde el efecto pasa desapercibido. Funciona mejor con luces rectangulares grandes, sky lights con soft shadows o virtual shadow maps con kernel amplio.- No se ve en grises ni saturados — un material totalmente gris no tiene color que saturar, y un material ya saturado al máximo tampoco gana. El efecto luce mejor en colores medios y materiales con reflectividad media.

Por qué importa para estudios indie en LATAM

El argumento más fuerte para adoptar la técnica no es estético sino económico. Un estudio indie en LATAM compite contra producciones AAA con presupuestos de iluminación cien veces mayores: lookdev artists dedicados, lighters senior, herramientas propietarias para comp y grading. El colored shadow penumbra es una de esas técnicas asimétricas que cierran parte de esa brecha sin contratar a nadie nuevo: cinco líneas de HLSL aplicadas una vez al engine fork del proyecto y todas las escenas heredan el mejor pulido visual.

Es también una excusa perfecta para subir el nivel del equipo en programación de shaders. Modificar SubstrateDeferredLighting.ush obliga a entender qué hace cada paso del pipeline diferido, qué información sobrevive entre el G-Buffer y el shading pass, y cómo Unreal estructura su evaluación de BSDFs. Es el tipo de conocimiento que en estudios grandes se aprende osmóticamente con el código fuente del engine, y que en LATAM se logra raras veces porque el acceso al source code de Epic sigue siendo un trámite que pocos completan.
El efecto suma profundidad cromática sin afectar la performance en runtime.

Qué sigue para colored shadows en tiempo real

El siguiente paso natural es exponer PenumbraSaturation a nivel de cada luz, no global del proyecto. La forma elegante sería agregar un campo FloatProperty a FLightData, llenarlo desde C++ y leerlo en el shader. Eso permitiría que un foco rojizo de una habitación cálida tenga saturación distinta a una luz fría de exterior, lo cual es más fiel a cómo se trabaja la luz en cinematografía.

Otra dirección interesante es separar el factor para diffuse y para specular. La implementación actual modifica solo el componente diffuse (que es donde el efecto tiene sentido físico) pero hay artistas que quisieran un control independiente para empujar el look hacia algo más estilizado. Y a más largo plazo, integrar la técnica con Lumen para que la saturación respete la información de GI ya calculada parece la evolución natural: ahí mismo está el color real que aporta la radiosidad, sin necesidad de aproximarlo con un truco.

📖 Resumen en Telegram: Ver resumen

Preguntas frecuentes

¿Funciona en proyectos comerciales sin pagar licencia adicional a Epic?

Sí. Modificar los shaders del motor en la versión Launcher cae dentro del EULA estándar de Unreal Engine. No es lo mismo que distribuir un fork modificado del engine: solo estás cambiando archivos de shader que ya viven en tu proyecto. La licencia royalty del 5% sobre el millón de dólares se aplica por el uso del engine, no por las modificaciones.

¿Funciona con Lumen activado?

Sí, y es justamente uno de los argumentos a favor de editar el shader directamente en lugar de un post-process. Lumen aporta la GI; el colored shadow penumbra opera sobre la luz directa antes de que se sume al resultado final. No interfieren entre sí.

¿Cuál es el costo en GPU?

Despreciable en cualquier hardware compatible con UE5. Son 5 líneas de aritmética sin lecturas adicionales de texturas ni branching. En profilers como RenderDoc o el GPU Visualizer interno, el incremento del pase de iluminación es del orden del 0.1% o menos. La penalidad real viene una sola vez: la recompilación de shaders cuando el archivo cambia.

¿Por qué mi escena se ve igual después de aplicar el código?¿Cómo lo desactivo si causa problemas en producción?

Comentás las cinco líneas con /* */ y guardás el archivo. Unreal recompila los shaders en el siguiente arranque y la escena vuelve al comportamiento original. Por eso conviene siempre dejar los marcadores // Colored shadow penumbra - Start y // Colored shadow penumbra - End en el código: facilitan localizar el bloque para revertirlo en cualquier momento.

¿Puedo combinarlo con otros mods de shaders del engine?

Sí, mientras los bloques no toquen las mismas variables. La regla práctica es mantener cada mod en su propio archivo o en una sección bien delimitada del archivo del engine, documentar el cambio en un README del proyecto y versionar las modificaciones del engine en el mismo repo del juego para que otros desarrolladores no las pierdan al actualizar Unreal.

Referencias

📱 ¿Te gusta este contenido? Únete a nuestro canal de Telegram @programacion donde publicamos a diario lo más relevante de tecnología, IA y desarrollo. Resúmenes rápidos, contenido fresco todos los días.