注意:只适合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就可以了。