您的位置:首页 > 其它

3d游戏中人物被遮挡后以其它颜色显示的方法

2016-09-19 11:20 926 查看
好久没有更新博客,最近忙于其他事情了。

今天玩了一下九阴真经,偶然发现里边有一个效果,如图显示:



我们一步步来解释这个效果的原理,涉及的方面其实还挺多的。

首先我们必须清楚地知道,在角色被遮挡的时候,已经暴露出来模型其实是分两次渲染,也就是该模型的着色器必然是存在两个通道的。第一个通道便是遮挡后显示出来的蓝色,第二个通道就是普通情况下显示出来的模型。

第一步:前面的屋子没有能够遮挡住角色的渲染,那么说明角色的渲染一定是在屋子的模型渲染之后进行渲染的并且能通过深度测试,于是第一步里,我们要做的就是将角色模型的渲染队列设置为在屋子的模型队列之后渲染,一般情况下是设置为Tags { "Queue" = "Transparent" },当然你也可以设置其他的,只要保证是在遮挡物之后渲染就可以了。而且明显角色被遮挡并且是在最后渲染,也就是说角色不可能通过深度测试,于是,我们需要加上一条命令ZTest Always,保证一定能覆盖原像素。

第二步:我们知道在没有遮挡的时候显示的模型是正常的,不会显示里面蓝色的部分,所以我们前面说的角色模型的两个着色器通道里面的第二个通道就必须能保证覆盖第一个通道渲染的蓝色像素值,我们可以设置第一个通道的深度值是不写入的,于是就保证了第二个通道的绝对覆盖。所以在第一个通道里面,我们还需要加上ZWrite Off。

第三步:我们理一下第二步,第二步里面说第一个通道的深度值是不写入的,那么在写入之前深度缓冲区中缓存的是哪里的深度值呢?正是屋子模型的深度,也就是说,(1)在被遮挡的时候,当渲染第一个通道的时候,由于ZTest Always和ZWrite Off的存在,使得不需要测试深度,计算机就把像素替换成了模型的像素,但是却保留了屋子模型的深度。当开始渲染第二个通道的时候,却没办法通过深度测试,所以最终输出了第一个通道的颜色;(2)当角色模型没有被遮挡的时候,第一个通道输出后,深度缓冲区缓存的是地面的深度值,而角色模型的深度明显是小于地面的深度值的,所以第二个通道的深度测试通过了,也就覆盖了第一个通道,所以没有遮挡的时候输出了第二个通道的模型颜色。

下面奉上源码:

Shader "Outlined/Silhouetted Bumped Diffuse" {
Properties {
_Color ("Main Color", Color) = (.5,.5,.5,1)
_OutlineColor ("Outline Color", Color) = (0,0,0,1)
_Outline ("Outline width", Range (0.0, 0.03)) = .005
_MainTex ("Base (RGB)", 2D) = "white" { }
_BumpMap ("Bumpmap", 2D) = "bump" {}
}

CGINCLUDE
#include "UnityCG.cginc"

struct appdata {
float4 vertex : POSITION;
float3 normal : NORMAL;
};

struct v2f {
float4 pos : POSITION;
float4 color : COLOR;
};

uniform float _Outline;
uniform float4 _OutlineColor;

v2f vert(appdata v) {
// just make a copy of incoming vertex data but scaled according to normal direction
v2f o;
o.pos = mul(UNITY_MATRIX_MVP, v.vertex);

float3 norm   = mul ((float3x3)UNITY_MATRIX_IT_MV, v.normal);
float2 offset = TransformViewToProjection(norm.xy);

o.pos.xy += offset * o.pos.z * _Outline;
o.color = _OutlineColor;
return o;
}
ENDCG

SubShader {
Tags { "Queue" = "Transparent" }

// note that a vertex shader is specified here but its using the one above
Pass {
Name "OUTLINE"
Tags { "LightMode" = "Always" }
Cull Off
ZWrite Off
ZTest Always

// you can choose what kind of blending mode you want for the outline
Blend SrcAlpha OneMinusSrcAlpha // Normal
//Blend One One // Additive
//Blend One OneMinusDstColor // Soft Additive
//Blend DstColor Zero // Multiplicative
//Blend DstColor SrcColor // 2x Multiplicative

CGPROGRAM
#pragma vertex vert
#pragma fragment frag

half4 frag(v2f i) : COLOR {
return i.color;
}
ENDCG
}

CGPROGRAM
#pragma surface surf Lambert
struct Input {
float2 uv_MainTex;
float2 uv_BumpMap;
};
sampler2D _MainTex;
sampler2D _BumpMap;
uniform float3 _Color;
void surf(Input IN, inout SurfaceOutput o) {
o.Albedo = tex2D(_MainTex, IN.uv_MainTex).rgb * _Color;
o.Normal = UnpackNormal(tex2D(_BumpMap, IN.uv_BumpMap));
}
ENDCG

}

Fallback "Outlined/Silhouetted Diffuse"
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: