Unity实现桌面宠物之透明效果和直接进入程序

Unity实现桌面宠物之透明效果

注意:只适合windows平台

直接贴代码吧,其实这些代码也不是我自己写的。使用的是网上的。谢谢前辈们的
踩坑。

实现的思路是这样的,将相机给成纯色,然后进行抠图。具体是怎么回事我
也不是很清楚。如果有明白的,还希望能教我一下。

using System.Collections;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using System;
using UnityEngine;
using System.Diagnostics;

public class WindowManager : MonoBehaviour
{
    private static WindowManager instance;

    public static WindowManager Instance
    {
        get
        {
            return instance;
        }
    }
    // Use this for initialization
    [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);

    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);


    // Definitions of window styles
    const int GWL_STYLE = -16;
    const uint WS_POPUP = 0x80000000;
    const uint WS_VISIBLE = 0x10000000;
    public const int width = 300;
    public const int height = 300;
    void Start()
    {
        SetWindowScreen(width, height);
        var margins = new MARGINS() { cxLeftWidth = -1 };
        var hwnd = GetProcessWnd();
        SetWindowLong(hwnd, GWL_STYLE, WS_POPUP | WS_VISIBLE);
        DwmExtendFrameIntoClientArea(hwnd, ref margins);

    }

    void SetWindowScreen(int width, int height)
    {
        Screen.SetResolution(width, height, false);
    }

    void OnRenderImage(RenderTexture from, RenderTexture to)
    {
        Graphics.Blit(from, to, m_Material);
    }

    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;
    }

}

我只是在别人的代码上修改了一下,设置了些别的东西。

将这个脚本挂在到摄像机,但是还需要给它一个材质球,使用shader将背景色该去掉。

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 200

            CGPROGRAM

            #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 colour
                float 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 pixel
                if (deltaR < _TransparencyTolerance && deltaG < _TransparencyTolerance && deltaB < _TransparencyTolerance)
                {
                    return float4(0.0f, 0.0f, 0.0f, 0.0f);
                }

                // Otherwise, return the regular colour
                return colour;
            }
            ENDCG
        }
    }
}

注意,材质球的颜色要和相机的背景色设置成一样的。(具体是因为什么我也不是很清楚)


打包成可执行程序之后,双击程序会进入选择分辨率的界面。但是我不想这样,我想双击直接就进入宠物界面。

PlayerSetting->Resolution下,将Display Resolution Dialog设置为Disabled就可以了。

猜你喜欢

转载自blog.csdn.net/heiannitian/article/details/80606146