我记得有些时候应用程序似乎与您的Windows桌面集成 – 动画猫会沿着您的任务栏 – 这样的东西 – 一个无窗Unity游戏,使用透明的背景来揭示您的常规桌面上的任何东西由相机渲染?

您可以使用相机的OnRenderImage()事件,对Windows本机API的一些调用和自定义着色器的组合来实现此目的。就是这样:

首先,您需要创建自定义着色器,如下所示:

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 = mul (UNITY_MATRIX_MVP, 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
        }
    }
}

这段代码应该是相当不言自明的 – 它查看一个输入纹理,如果一个像素颜色在所选关键颜色的一定公差范围内,它是透明的(你可能熟悉这种技术为“chromakey”,或“绿/蓝屏”用于电影特效)。

使用此着色器创建材质,然后选择要替换的键颜色(如有必要,请更改公差)。请注意,您不需要分配主纹理属性 – 我们将使用相机的输出来提供此纹理,这是在下一步中完成的…

现在,创建以下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;
    }
    // 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
        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);
    }
}

此代码使用InterOpServices对Windows本机API进行一些调用,以更改Unity运行的窗口的属性。然后使用OnRenderImage()事件将摄像机的输出发送到rendertexture。将您分配自定义透明度着色器的材质拖动到m_Material插槽中,以便我们的抠像替换在相机的输出上起作用。

然后,这很重要:更改相机的背景颜色以匹配透明材质的_transparentColourKey属性。

图片

这可以是任何你想要的颜色,但你可能会发现它最容易使用,比如,柠檬绿(0,255,0)或粉红色(255,0,255)。

然后构建和运行你的游戏(你可以在编辑器模式下启用它,通过评论上面的#if!UNITY_EDITOR条件,但我真的不推荐它!)。这应该在Unity 4.x(Pro,因为它使用rendertextures)或者Unity 5.x的任何版本。

这里是Ethan从Unity的隐身演示走在记事本++在我的桌面…:

 

原文:https://alastaira.wordpress.com/2015/06/15/creating-windowless-unity-applications/