前言:
由于最近在做游戏魔改,很多功能在游戏里面没法实现(没错,说的就是排行榜),所以准备用Unity3D开发一个类似于桌面精灵的功能部件,实现效果如下:
PS:有需要定制的老板请私信联系
要实现这个效果,需要分两步:
1,背景透明
2,程序始终在前面
一,背景透明实现核心代码
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;}// Define function signatures to import from Windows APIs[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);// Definitions of window stylesconst int GWL_STYLE = -16;const uint WS_POPUP = 0x80000000;const uint WS_VISIBLE = 0x10000000;void Start(){//return;
#if !UNITY_EDITORvar margins = new MARGINS() { cxLeftWidth = -1 };// Get a handle to the windowvar hwnd = GetActiveWindow();// Set properties of the window// See: https://msdn.microsoft.com/en-us/library/windows/desktop/ms633591%28v=vs.85%29.aspxSetWindowLong(hwnd, GWL_STYLE, WS_POPUP | WS_VISIBLE);// Extend the window into the client area//See: https://msdn.microsoft.com/en-us/library/windows/desktop/aa969512%28v=vs.85%29.aspx DwmExtendFrameIntoClientArea(hwnd, ref margins);
#endif}// Pass the output of the camera to the custom material// for chroma replacementvoid OnRenderImage(RenderTexture from, RenderTexture to){Graphics.Blit(from, to, m_Material);}}
shader代码如下:
Shader "Custom/ChromakeyTransparent" {Properties{_MainTex("Base (RGB)", 2D) = "white" {}_TransparentColourKey("Transparent Colour Key", Color) = (0,0,0,1)_TransparencyTolerance("Transparency Tolerance", Float) = 0.01}SubShader{Pass{Tags{ "RenderType" = "Opaque" }LOD 200CGPROGRAM#pragma vertex vert#pragma fragment frag#include "UnityCG.cginc"struct a2v{float4 pos : POSITION;float2 uv : TEXCOORD0;};struct v2f{float4 pos : SV_POSITION;float2 uv : TEXCOORD0;};v2f vert(a2v input){v2f output;output.pos = UnityObjectToClipPos(input.pos);output.uv = input.uv;return output;}sampler2D _MainTex;float3 _TransparentColourKey;float _TransparencyTolerance;float4 frag(v2f input) : SV_Target{// What is the colour that *would* be rendered here?float4 colour = tex2D(_MainTex, input.uv);// Calculate the different in each component from the chosen transparency colourfloat deltaR = abs(colour.r - _TransparentColourKey.r);float deltaG = abs(colour.g - _TransparentColourKey.g);float deltaB = abs(colour.b - _TransparentColourKey.b);// If colour is within tolerance, write a transparent pixelif (deltaR < _TransparencyTolerance && deltaG < _TransparencyTolerance && deltaB < _TransparencyTolerance){return float4(0.0f, 0.0f, 0.0f, 0.0f);}// Otherwise, return the regular colourreturn colour;}ENDCG}}
}
将脚本绑定在摄像机上,并用该shader创建材质A,放到脚本下。
摄像机渲染模式改为只渲染颜色,颜色和材质A一样。
二,程序始终在前面核心代码
using System;
using System.Diagnostics;
using System.Runtime.InteropServices;public class C
{public delegate bool WNDENUMPROC(IntPtr hwnd, uint lParam);[DllImport("user32.dll", SetLastError = true)]public static extern bool EnumWindows(WNDENUMPROC lpEnumFunc, uint lParam);[DllImport("user32.dll", SetLastError = true)]public static extern IntPtr GetParent(IntPtr hWnd);[DllImport("user32.dll")]public static extern uint GetWindowThreadProcessId(IntPtr hWnd, ref uint lpdwProcessId);[DllImport("kernel32.dll")]public static extern void SetLastError(uint dwErrCode);public static IntPtr GetProcessWnd(){IntPtr ptrWnd = IntPtr.Zero;uint pid = (uint)Process.GetCurrentProcess().Id; // 当前进程 ID bool bResult = EnumWindows(new WNDENUMPROC(delegate (IntPtr hwnd, uint lParam){uint id = 0;if (GetParent(hwnd) == IntPtr.Zero){GetWindowThreadProcessId(hwnd, ref id);if (id == lParam) // 找到进程对应的主窗口句柄 {ptrWnd = hwnd; // 把句柄缓存起来 SetLastError(0); // 设置无错误 return false; // 返回 false 以终止枚举窗口 }}return true;}), pid);return (!bResult && Marshal.GetLastWin32Error() == 0) ? ptrWnd : IntPtr.Zero;}
}
[DllImport("User32.dll")]extern static bool SetForegroundWindow(IntPtr hWnd);[DllImport("User32.dll")]extern static bool ShowWindow(IntPtr hWnd, short State);[DllImport("user32.dll ")]public static extern bool SetWindowPos(IntPtr hWnd, IntPtr hWndInsertAfter, int X, int Y, int cx, int cy, uint uFlags);static readonly IntPtr HWND_TOPMOST = new IntPtr(-1);const UInt32 SWP_NOSIZE = 0x0001;const UInt32 SWP_NOMOVE = 0x0002;IntPtr hWnd;//public float Wait = 0;//延迟执行//public float Rate = 1;//更新频率public bool KeepForeground = true;//保持最前/// <summary>/// 激活窗口/// </summary>void Active(){if (KeepForeground){ShowWindow(hWnd, 1);SetForegroundWindow(hWnd);SetWindowPos(hWnd, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE);}}
hWnd = C.GetProcessWnd();Active();
三,打包设置如下
四,优化扩展
步骤和道理同上
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_EDITORMARGINS 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 "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 200CGPROGRAM#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}}
}