Este artigo explora técnicas para tornar uma janela do Unity transparente no Windows, permitindo a visualização de elementos da área de trabalho por trás da aplicação. Os métodos descritos incluem a remoção da borda da janela, a configuração de transparência, a manutenção da janela sempre no topo (always-on-top) e a permissão para que eventos de mouse passem através da janela, características úteis para criar widgets de desktop, overlays ou aplicações de HUD.
Método 1: Utilizando um Shader de Chroma Key
Esta abordagem envolve o uso de um shader customizado para tornar pixels de uma cor específica transparentes. Apesar de funcional, ela pode gerar bordas serrilhadas (aliasing) na interface.
Pré-requisitos: Um material usando o shader customizado deve ser atribuído a uma câmera. A cor sólida de fundo da câmera deve corrseponder à chave de transparência definida no shader.
Shader Customizado para Transparência
O shader abaixo implementa a lógica de transparência baseada em uma cor-chave. Pixels com cores muito próximas à cor-chave se tornam transparentes.
Shader "Custom/TransparentKeyShader" {
Properties {
_MainTex ("Texture", 2D) = "white" {}
_KeyColor ("Color Key", Color) = (0,0,0,1)
_Threshold ("Threshold", Float) = 0.01
}
SubShader {
Tags { "Queue"="Transparent" "RenderType"="Transparent" }
Blend SrcAlpha OneMinusSrcAlpha
Pass {
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
struct appdata {
float4 vertex : POSITION;
float2 uv : TEXCOORD0;
};
struct v2f {
float2 uv : TEXCOORD0;
float4 vertex : SV_POSITION;
};
sampler2D _MainTex;
float4 _MainTex_ST;
fixed4 _KeyColor;
float _Threshold;
v2f vert (appdata v) {
v2f o;
o.vertex = UnityObjectToClipPos(v.vertex);
o.uv = TRANSFORM_TEX(v.uv, _MainTex);
return o;
}
fixed4 frag (v2f i) : SV_Target {
fixed4 col = tex2D(_MainTex, i.uv);
float diff = distance(col.rgb, _KeyColor.rgb);
if (diff < _Threshold) {
col.a = 0.0;
}
return col;
}
ENDCG
}
}
}
Script de Configuração da Janela (Versão Básica)
Este script C# modifica as propriedades nativas da janela usando a API do Windows.
using System;
using System.Runtime.InteropServices;
using UnityEngine;
public class WindowTransparentBase : MonoBehaviour
{
[SerializeField]
private Material keyingMaterial;
[StructLayout(LayoutKind.Sequential)]
public struct MARGINS {
public int leftWidth;
public int rightWidth;
public int topHeight;
public int bottomHeight;
}
#region DllImports
[DllImport("user32.dll")]
private static extern IntPtr GetActiveWindow();
[DllImport("user32.dll")]
private static extern int SetWindowLong(IntPtr hWnd, int nIndex, uint dwNewLong);
[DllImport("Dwmapi.dll")]
private static extern uint DwmExtendFrameIntoClientArea(IntPtr hWnd, ref MARGINS margins);
#endregion
private const int GWL_STYLE = -16;
private const uint WS_POPUP = 0x80000000;
private const uint WS_VISIBLE = 0x10000000;
void Start()
{
#if !UNITY_EDITOR
IntPtr hwnd = GetActiveWindow();
SetWindowLong(hwnd, GWL_STYLE, WS_POPUP | WS_VISIBLE);
MARGINS margins = new MARGINS { leftWidth = -1 };
DwmExtendFrameIntoClientArea(hwnd, ref margins);
#endif
}
void OnRenderImage(RenderTexture src, RenderTexture dest)
{
Graphics.Blit(src, dest, keyingMaterial);
}
}
Método 2: Solução Completa com DwmExtendFrameIntoClientArea
Esta é a abordagem recomendada, pois fornece bordas suaves e um resultado visual superior. Requer que a câmera principal seja configurada com um fundo de cor sólida preta.
Configuração da Câmera: No Inspetor da Câmera, defina Clear Flags para Solid Color e selecione a cor preta (#000000).
Script Modular de Controle de Janela
O código abaixo foi refatorado para ser mais modular e legível, separando as responsabilidades de configurar a transparência, a posição no topo e a interação do mouse.
using UnityEngine;
using System;
using System.Runtime.InteropServices;
public class DesktopWidgetController : MonoBehaviour
{
[Header("Window Settings")]
public Vector2 windowPosition = new Vector2(10, 10);
public Vector2 windowSize = new Vector2(400, 300);
private IntPtr windowHandle;
#region Win32 API Constants
private const int GWL_STYLE = -16;
private const int GWL_EXSTYLE = -20;
private const int WS_CAPTION = 0x00C00000;
private const int WS_BORDER = 0x00800000;
private const uint WS_POPUP = 0x80000000;
private const uint WS_EX_LAYERED = 0x00080000;
private const uint WS_EX_TRANSPARENT = 0x00000020;
private const uint SWP_SHOWWINDOW = 0x0040;
#endregion
#region DllImports
[DllImport("user32.dll")]
private static extern IntPtr GetActiveWindow();
[DllImport("user32.dll")]
private static extern int SetWindowLong(IntPtr hWnd, int nIndex, uint dwNewLong);
[DllImport("user32.dll")]
private static extern uint GetWindowLong(IntPtr hWnd, int nIndex);
[DllImport("user32.dll")]
private static extern bool SetWindowPos(IntPtr hWnd, IntPtr hWndInsertAfter, int X, int Y, int cx, int cy, uint uFlags);
[DllImport("user32.dll")]
private static extern int SetLayeredWindowAttributes(IntPtr hwnd, uint crKey, byte bAlpha, uint dwFlags);
[DllImport("Dwmapi.dll")]
private static extern uint DwmExtendFrameIntoClientArea(IntPtr hWnd, ref MARGINS margins);
[StructLayout(LayoutKind.Sequential)]
public struct MARGINS {
public int cxLeftWidth;
public int cxRightWidth;
public int cyTopHeight;
public int cyBottomHeight;
}
#endregion
void Start()
{
Screen.fullScreen = false;
windowHandle = GetActiveWindow();
ConfigureTransparentWindow();
SetAlwaysOnTop();
EnableClickThrough();
}
private void ConfigureTransparentWindow()
{
// Remove bordas
uint currentStyle = GetWindowLong(windowHandle, GWL_STYLE);
SetWindowLong(windowHandle, GWL_STYLE, currentStyle & ~WS_BORDER & ~WS_CAPTION);
// Extende a área do cliente para a borda da janela, tornando-a transparente
MARGINS margins = new MARGINS { cxLeftWidth = -1 };
DwmExtendFrameIntoClientArea(windowHandle, ref margins);
}
private void SetAlwaysOnTop()
{
// HWND_TOPMOST = -1
SetWindowPos(windowHandle, (IntPtr)(-1),
(int)windowPosition.x, (int)windowPosition.y,
(int)windowSize.x, (int)windowSize.y,
SWP_SHOWWINDOW);
}
private void EnableClickThrough()
{
uint extendedStyle = GetWindowLong(windowHandle, GWL_EXSTYLE);
SetWindowLong(windowHandle, GWL_EXSTYLE, extendedStyle | WS_EX_TRANSPARENT | WS_EX_LAYERED);
}
// Função para desativar a passagem de eventos do mouse, se necessário
public void DisableClickThrough()
{
uint extendedStyle = GetWindowLong(windowHandle, GWL_EXSTYLE);
SetWindowLong(windowHandle, GWL_EXSTYLE, extendedStyle & ~WS_EX_TRANSPARENT);
}
}
Eliminando o Piscar da Janela na Inicialização
Para evitar que a janela padrão com bordas apareça por um instante antes de se tornar transparente, é possível redimensioná-la para 0 pixels ao fechar a aplicação. Na próxima execução, a janela iniciará invisível até que o script a configure.
private void OnApplicationQuit()
{
// Redimensiona a janela para zero pixels ao sair
SetWindowPos(windowHandle, IntPtr.Zero, 0, 0, 0, 0, SWP_SHOWWINDOW);
}
Método 3: Controlando a Opacidade da Janela
Este método utiliza a função SetLayeredWindowAttributes para controlar a opacidade geral da janela ou para definir uma cor-chave que se tornará completamente transparente.
using UnityEngine;
using System;
using System.Runtime.InteropServices;
public class WindowOpacityController : MonoBehaviour
{
[Range(0, 255)]
public byte windowAlpha = 100; // 0=Invisível, 255=Opaco
private IntPtr windowHandle;
[DllImport("user32.dll")]
private static extern IntPtr GetForegroundWindow();
[DllImport("user32.dll")]
private static extern int SetWindowLong(IntPtr hWnd, int nIndex, int dwNewLong);
[DllImport("user32.dll")]
private static extern bool SetLayeredWindowAttributes(IntPtr hwnd, uint crKey, byte bAlpha, uint dwFlags);
private const int GWL_EXSTYLE = -20;
private const uint WS_EX_LAYERED = 0x80000;
private const uint LWA_ALPHA = 0x2;
private const uint LWA_COLORKEY = 0x1;
void Start()
{
windowHandle = GetForegroundWindow();
SetWindowLong(windowHandle, GWL_EXSTYLE, (int)WS_EX_LAYERED);
// Aplica opacidade a toda a janela
SetLayeredWindowAttributes(windowHandle, 0, windowAlpha, LWA_ALPHA);
}
}
Dica Extra: Removendo a Borda sem Código
Para qualquer aplicação Unity compilada como .exe, é possível remover a borda da janela através de um argumento de linha de comando, sem necessidade de scripts.
- Abra o Prompt de Comando (cmd).
- Navegue até o diretório que contém o executável do jogo.
- Execute o comando:
SeuJogo.exe -popupwindow
Este comando fará com que a aplicação inicie no modo janela sem borda. Outros argumentos úteis incluem -nolog para suprimir a geração do arquivo de log. Mais informações podem ser encontradas na documentação oficial do Unity sobre argumentos de linha de comando.