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

本文介绍如何使用Unity创建一个类似桌面宠物的程序,通过自定义Shader和C#脚本实现透明窗口效果,包括代码实现和操作步骤。适用于Unity 2019及以上版本,需注意特定设置。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

最近浏览博客发现了一个比较好玩的程序,用Unity实现类似桌面宠物的程序,还是挺有趣的

1.代码:

当然是看了大佬的文章搬运过来…哈哈
原文:
原文1 原文2
代码,只需要两个脚本:
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);
    }
}

2.操作:

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#脚本里有鼠标穿透的代码提示,注释取消一下即可

评论 16
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值