Appearance
Unity 实现透明背景桌面
以下代码实测于 unity2020.3 / Windows 10 系统
步骤:
将以下脚本命名为TransparentWindow
添加到Camera
效果
不带操作栏,鼠标点击不可穿透
第一
csharp
using System;
using System.Runtime.InteropServices;
using UnityEngine;
public class TransparentWindow : MonoBehaviour
{
struct MARGINS
{
public int cxLeftWidth;
public int cxRightWidth;
public int cyTopHeight;
public int cyBottomHeight;
}
#region 定义外部函数
// 获取显示在最上面的窗口
[DllImport("user32.dll")]
static extern IntPtr GetForegroundWindow();
[DllImport("user32.dll")]
static extern IntPtr SetForegroundWindow(IntPtr hWnd);
// 注意要编写与 32 位和 64 位版本的 Windows 兼容的代码 请使用SetWindowLongPtr
[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);
[DllImport("user32.dll")]
static extern bool SetWindowPos(IntPtr hWnd, int hWndInsertAfter, int X, int Y, int cx, int cy, uint uFlags);
[DllImport("user32.dll")]
public static extern bool ReleaseCapture();
[DllImport("user32.dll")]
public static extern bool SendMessage(IntPtr hwnd, int wMsg, int wParam, int lParam);
#endregion
// 窗口句柄
IntPtr Handle;
void Start()
{
#if !UNITY_EDITOR
// 获取窗口句柄
Handle = GetForegroundWindow();
// 设置窗口的属性
SetWindowLong(Handle, -16, 0x80000000);
var margins = new MARGINS() { cxLeftWidth = -1 };
// 将窗口框架扩展到工作区
DwmExtendFrameIntoClientArea(Handle, ref margins);
// 设置窗口位置
SetWindowPos(Handle, -1, 0, 0, 0, 0, 2 | 1 | 64);
#endif
}
void Update()
{
#if !UNITY_EDITOR
// 保持窗口始终在最前面
if (Handle != GetForegroundWindow()) SetForegroundWindow(Handle);
// 左键拖动
if (Input.GetMouseButtonDown(0))
{
ReleaseCapture();
SendMessage(Handle, 0xA1, 0x02, 0);
SendMessage(Handle, 0x0202, 0, 0);
}
#endif
}
}
第二
以下这段代码的效果是半透明的感觉,而且游戏对象也半透明了。鼠标可点击
csharp
//Note: Inspired by and uses some code found here: http://forum.unity3d.com/threads/windows-api-calls.127719/
using UnityEngine;
using System.Collections;
using System;
using System.Runtime.InteropServices; // Pro and Free!!!
//WARNING!! Running this code inside Unity when not in a build will make the entire development environment transparent
//Restarting Unity would however resolve
public class TransparentWindow : MonoBehaviour
{
[DllImport("user32.dll", EntryPoint = "SetWindowLongA")]
static extern int SetWindowLong(int hwnd, int nIndex, long dwNewLong);
[DllImport("user32.dll")]
static extern bool ShowWindowAsync(int hWnd, int nCmdShow);
[DllImport("user32.dll", EntryPoint = "SetLayeredWindowAttributes")]
static extern int SetLayeredWindowAttributes(int hwnd, int crKey, byte bAlpha, int dwFlags);
[DllImport("user32.dll", EntryPoint = "GetActiveWindow")]
private static extern int GetActiveWindow();
[DllImport("user32.dll", EntryPoint = "GetWindowLong")]
private static extern long GetWindowLong(int hwnd, int nIndex);
[DllImport("user32.dll", EntryPoint = "SetWindowPos")]
private static extern int SetWindowPos(int hwnd, int hwndInsertAfter, int x, int y, int cx, int cy, int uFlags);
void Start()
{
int handle = GetActiveWindow();
int fWidth = Screen.width;
int fHeight = Screen.height;
//Remove title bar
long lCurStyle = GetWindowLong(handle, -16); // GWL_STYLE=-16
int a = 12582912; //WS_CAPTION = 0x00C00000L
int b = 1048576; //WS_HSCROLL = 0x00100000L
int c = 2097152; //WS_VSCROLL = 0x00200000L
int d = 524288; //WS_SYSMENU = 0x00080000L
int e = 16777216; //WS_MAXIMIZE = 0x01000000L
lCurStyle &= ~(a | b | c | d);
lCurStyle &= e;
SetWindowLong(handle, -16, lCurStyle);// GWL_STYLE=-16
// Transparent windows with click through
SetWindowLong(handle, -20, 524288 | 32);//GWL_EXSTYLE=-20; WS_EX_LAYERED=524288=&h80000, WS_EX_TRANSPARENT=32=0x00000020L
SetLayeredWindowAttributes(handle, 0, 51, 2);// Transparency=51=20%, LWA_ALPHA=2
SetWindowPos(handle, 0, 0, 0, fWidth, fHeight, 32 | 64); //SWP_FRAMECHANGED = 0x0020 (32); //SWP_SHOWWINDOW = 0x0040 (64)
ShowWindowAsync(handle, 3); //Forces window to show in case of unresponsive app // SW_SHOWMAXIMIZED(3)
}
}
第三
可透明 可鼠标穿透
csharp
using System;
using System.Runtime.InteropServices;
using UnityEngine;
public class TransparentWindow : MonoBehaviour
{
[SerializeField]
private Material m_Material;
private struct MARGINS
{
public int cxLeftWidth;
public int cxRightWidth;
public int cyTopHeight;
public int cyBottomHeight;
}
[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);
[DllImport("user32.dll", EntryPoint = "SetWindowPos")]
private static extern int SetWindowPos(IntPtr hwnd, IntPtr hwndInsertAfter, int x, int y, int cx, int cy, int uFlags);
[DllImport("user32.dll")]
static extern bool ShowWindowAsync(IntPtr hWnd, int nCmdShow);
[DllImport("user32.dll", EntryPoint = "SetLayeredWindowAttributes")]
static extern int SetLayeredWindowAttributes(IntPtr hwnd, int crKey, byte bAlpha, int dwFlags);
[DllImport("User32.dll")]
private static extern bool SetForegroundWindow(IntPtr hWnd);
const int GWL_STYLE = -16;
const int GWL_EXSTYLE = -20;
const uint WS_POPUP = 0x80000000;
const uint WS_VISIBLE = 0x10000000;
const uint WS_EX_TOPMOST = 0x00000008;
const uint WS_EX_LAYERED = 0x00080000;
const uint WS_EX_TRANSPARENT = 0x00000020;
const int SWP_FRAMECHANGED = 0x0020;
const int SWP_SHOWWINDOW = 0x0040;
const int LWA_ALPHA = 2;
private IntPtr HWND_TOPMOST = new IntPtr(-1);
private IntPtr _hwnd;
void Start()
{
#if !UNITY_EDITOR
MARGINS margins = new MARGINS() { cxLeftWidth = -1 };
_hwnd = GetActiveWindow();
int fWidth = Screen.width;
int fHeight = Screen.height;
SetWindowLong(_hwnd, GWL_STYLE, WS_POPUP | WS_VISIBLE);
SetWindowLong(_hwnd, GWL_EXSTYLE, WS_EX_TOPMOST | WS_EX_LAYERED | WS_EX_TRANSPARENT);
DwmExtendFrameIntoClientArea(_hwnd, ref margins);
SetWindowPos(_hwnd, HWND_TOPMOST, 0, 0, fWidth, fHeight, SWP_FRAMECHANGED | SWP_SHOWWINDOW);
ShowWindowAsync(_hwnd, 3); //Forces window to show in case of unresponsive app // SW_SHOWMAXIMIZED(3)
#endif
}
void OnRenderImage(RenderTexture from, RenderTexture to)
{
Graphics.Blit(from, to, m_Material);
}
}
创建一个shader
csharp
Shader "Custom/MakeTransparent" {
Properties {
_MainTex ("Base (RGB)", 2D) = "white" {}
_TransparentColorKey ("Transparent Color Key", Color) = (0,1,0,1)
_TransparencyMargin ("Transparency Margin", Float) = 0.01
}
SubShader {
Pass {
Tags { "RenderType"="Opaque" }
LOD 200
CGPROGRAM
#pragma vertex VertexShaderFunction
#pragma fragment PixelShaderFunction
#include "UnityCG.cginc"
struct VertexData
{
float4 position : POSITION;
float2 uv : TEXCOORD0;
};
struct VertexToPixelData
{
float4 position : SV_POSITION;
float2 uv : TEXCOORD0;
};
VertexToPixelData VertexShaderFunction(VertexData input)
{
VertexToPixelData output;
output.position = UnityObjectToClipPos (input.position);
output.uv = input.uv;
return output;
}
sampler2D _MainTex;
float3 _TransparentColorKey;
float _TransparencyMargin;
float4 PixelShaderFunction(VertexToPixelData input) : SV_Target
{
float4 color = tex2D(_MainTex, input.uv);
float deltaR = abs(color.r - _TransparentColorKey.r);
float deltaG = abs(color.g - _TransparentColorKey.g);
float deltaB = abs(color.b - _TransparentColorKey.b);
if (deltaR < _TransparencyMargin && deltaG < _TransparencyMargin && deltaB < _TransparencyMargin)
{
return float4(0.0f, 0.0f, 0.0f, 0.0f);
}
return color;
}
ENDCG
}
}
}
新建Material(材质球),选择shader: c#脚本挂在摄像机上,摄像机的Clear Flags选择Solid Color模式,脚本上挂载刚刚新建的材质球