Unity3D:Windows透明窗口,桌面精灵

之前一直在想Unity在开发Win游戏的时候,启动游戏的时候那个界面实在是太难看了,就想有没有办法做成类似倩女幽魂那种异形的界面,然后找了找还真有类似的功能,但是我试过了好像按钮什么的点击效果可能就不能触发了,具体的没有详细测试。如果有兴趣的可以做个详细的测试,然后在评论里写出来分享给大家。

其他废话就不多说了,下面我先说一下原理,原理是通过纯色抠像的方法,这也可能是按钮等事件无法响应的问题所在。下面是代码。

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 styles
    const int GWL_STYLE = -16;
    const uint WS_POPUP = 0x80000000;
    const uint WS_VISIBLE = 0x10000000;

    void Start()
    {
#if !UNITY_EDITOR && UNITY_STANDALONE_WIN
        var margins = new MARGINS() { cxLeftWidth = -1 };

        // Get a handle to the window
        var hwnd = GetActiveWindow();

        // Set properties of the window
        // See: https://msdn.microsoft.com/en-us/library/windows/desktop/ms633591%28v=vs.85%29.aspx
        SetWindowLong(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 replacement
    void 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 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
	}
	}
}

新建一个材质将,选择我们刚刚写好的Shader,将TransparentWindow挂载到摄像机上,摄像机的Clear Flags选择Solid Color,Background选择和材质的Transparent Color Key相同的颜色(建议选择与模型边缘颜色相近的颜色,不然会出现较明显的毛边),将材质拖拽给TransparentWindow的Material变量。

然后发布运行就OK了。

You May Also Like

About the Author: 大腿Plus

发表评论