美文网首页
Unity exe程序背景透明化+鼠标穿透(转)

Unity exe程序背景透明化+鼠标穿透(转)

作者: 雄关漫道从头越 | 来源:发表于2023-02-06 15:59 被阅读0次

    Unity exe程序背景透明化+鼠标穿透

    代码
    1. shader:
    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
        }
      }
    }
    
    2.C#:
    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);
        }
    }
    
    操作:
    1. 新建Material(材质球),选择shader:
    2. c#脚本挂在摄像机上,摄像机的Clear Flags选择Solid Color模式,脚本上挂载刚刚新建的材质球:
    3. 摄像机的Background属性要和材质球的Transparent Color Key属性一致:
    4. 最重要的一点!!!我这里的Unity开发版本为2019.4.2f1版本,2019以上的版本需要取消勾选一个属性,不然是没有效果的,若是2019以下的版本则可能不需要设置,题主在2018.3.8f1上就不需要设置,如图:

    2019版本若是有这个设置,则必须要关闭,设置位置:
    Edit——ProjectSettings——Player——ResolutionandPresentation——UseDXGIFlipModelSwapchainforD3D11
    至于是什么原因,暂时还不了解,如果有同学知道,望能指教一二

    发布效果如下:

    PS:我这个程序是没有鼠标穿透的,C#脚本里有鼠标穿透的代码提示,注释取消一下即可

    相关文章

      网友评论

          本文标题:Unity exe程序背景透明化+鼠标穿透(转)

          本文链接:https://www.haomeiwen.com/subject/fhutkdtx.html