我有一个 c# 脚本和一个着色器脚本,它们应该创建两个游戏对象并根据相机渲染纹理中显示的像素的 b 值是否等于先前的 b 值来丢弃第二个游戏对象的像素在该游戏对象的着色器脚本中设置并返回。 C#
private void Start() {
//Create two slime game objects
//Set one of their layers to depth
//Set one of their shaders that is applied to the material to Blend mode no pass
//Material.SetFloat(_Depth) -> for that specific material
//Graphics.Blit for that specific render texture(game object sprite itself)
//The shader pass should return rgba for each pixel where r is passed depth.
//However, it must only do so for pixels that constitute the game object, not background.
//
//Review Instantiating game objects
Debug.Log("Start called.");
GameObject depthSlime1 = Instantiate(slime);
Material depthMaterial1 = depthSlime1.GetComponent<Renderer>().material;
depthMaterial1.renderQueue = 0;
depthMaterial1.SetFloat("_Depth", 1);
Graphics.Blit(null, null, depthMaterial1, 1);
GameObject depthSlime2 = Instantiate(slime2);
Material depthMaterial2 = depthSlime2.GetComponent<Renderer>().material;
depthMaterial2.renderQueue = 1;
depthMaterial2.SetFloat("_Depth", 2);
Graphics.Blit(null, null, depthMaterial2, 1);
//After this Blit, shader successfully writes 2 to the b value of the rgba
//of the pixels of depthSlime2
//However, it does not seem to write the same b value in the pixel of depthSlime2
//in depth camera target texture
//I have figured that an object with lower renderQueue will overwrite pixels of
//an object with higher render queue.
//Experiment if it still works when I Blit arbitrary depth values to alpha.
//It works!
//Sample alpha and see if it matches _Depth for purple slime
depthMaterial2.SetVector("_CenterPos", depthSlime2.transform.position);
//Did depthCameraRender change at this point?
depthMaterial2.SetTexture("_DepthTex", depthCameraRender);
Graphics.Blit(depthCameraRender, null, depthMaterial2, 2);
}
着色器
Shader "Unlit/TestShader1"
{
Properties
{
_MainTex ("Texture", 2D) = "" {}
_Depth ("Depth", Float) = 0
_CenterPos ("Center Position of this Game Object", Vector) = (0,0,0,0)
_DepthTex ("Texture", 2D) = "" {}
}
SubShader
{
Tags { "RenderType"="Transparent" } //"QUEUE"="Transparent" } //"RenderType"="Transparent" }
LOD 100
//Cull Front
Blend SrcAlpha OneMinusSrcAlpha
Pass
{
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
// make fog work
//#pragma multi_compile_fog
#include "UnityCG.cginc"
struct appdata
{
float4 vertex : POSITION;
float2 uv : TEXCOORD0;
};
struct v2f
{
float2 uv : TEXCOORD0;
//UNITY_FOG_COORDS(1)
float4 vertex : SV_POSITION;
};
sampler2D _MainTex;
float4 _MainTex_ST;
float _Depth;
v2f vert (appdata v)
{
v2f o;
o.vertex = UnityObjectToClipPos(v.vertex);
o.uv = TRANSFORM_TEX(v.uv, _MainTex);
//UNITY_TRANSFER_FOG(o,o.vertex);
return o;
}
float4 frag (v2f i) : SV_Target
{
// sample the texture
float4 col = tex2D(_MainTex, i.uv);
// apply fog
//UNITY_APPLY_FOG(i.fogCoord, col);
//col.a = 0.5;
if(_Depth > 0) {
//Checking if this shader is part of depth storing game object
col.a = _Depth;
}
return col;
}
ENDCG
}
Pass
{
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
// make fog work
//#pragma multi_compile_fog
#include "UnityCG.cginc"
struct appdata
{
float4 vertex : POSITION;
float2 uv : TEXCOORD0;
};
struct v2f
{
float2 uv : TEXCOORD0;
//UNITY_FOG_COORDS(1)
float4 vertex : SV_POSITION;
};
sampler2D _MainTex;
float4 _MainTex_ST;
float _Depth;
v2f vert (appdata v)
{
v2f o;
o.vertex = UnityObjectToClipPos(v.vertex);
o.uv = TRANSFORM_TEX(v.uv, _MainTex);
//UNITY_TRANSFER_FOG(o,o.vertex);
return o;
}
fixed4 frag (v2f i) : SV_TARGET
{
// sample the texture
fixed4 col = tex2D(_MainTex, i.uv);
// apply fog
//UNITY_APPLY_FOG(i.fogCoord, col);
//col.a = 0.5;
if(_Depth == 2) {
//This block definitely runs!
col.b = _Depth / 255;
}
return col;
}
ENDCG
}
Pass
{
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
// make fog work
//#pragma multi_compile_fog
#include "UnityCG.cginc"
struct appdata
{
float4 vertex : POSITION;
float2 uv : TEXCOORD0;
};
struct v2f
{
float2 uv : TEXCOORD0;
//UNITY_FOG_COORDS(1)
float4 vertex : SV_POSITION;
};
sampler2D _MainTex;
float4 _MainTex_ST;
sampler2D _DepthTex;
float4 _DepthTex_ST;
float4 _CenterPos;
float _Depth;
v2f vert (appdata v)
{
v2f o;
o.vertex = UnityObjectToClipPos(v.vertex);
o.uv = TRANSFORM_TEX(v.uv, _MainTex);
//UNITY_TRANSFER_FOG(o,o.vertex);
return o;
}
float4 frag (v2f i) : SV_TARGET
{
// Get the screen position and UV coordinates
float4 screenPos = UnityObjectToClipPos(i.vertex);
//float2 uv = screenPos.xy / screenPos.w * 0.5 + 0.5;
float2 uv = i.uv * 0.25;
// sample the texture
float4 col = tex2D(_MainTex, i.uv);
//_MainTex = texture of depthSlime2
// apply fog
//UNITY_APPLY_FOG(i.fogCoord, col);
//col.a = 0.5;
//_CenterPos.xy must also be in translated uv
//ComputeScreenPos(_CenterPos).xy = Not quite
//The code below does not seem to run.
//Even when changing the material shader's return color,
//This does not seem to change the target texture(rendered image)
//of the depth camera.
//DepthTex = depth camera target texture
if(tex2D(_DepthTex, uv + ComputeScreenPos(_CenterPos).xy).b == 2 / 255) {
//This block does run but instead of discarding pixels from depthSlime2
//It turns them yellow.
discard;
}
return col;
}
ENDCG
}
}
}
当 2d 正交相机创建渲染纹理时,将为应该覆盖另一个游戏对象像素的对象设置越来越低的渲染队列。我的问题是:为什么着色器脚本没有正确丢弃被另一个游戏对象部分覆盖的较大游戏对象的剩余像素?它不会丢弃任何未覆盖的像素。相反,它看起来像这样:
这是非常奇怪的行为,因为当我注释掉执行丢弃的条件块时,相机的渲染纹理发生变化,证明条件块至少运行。如果这一点得到证实,则意味着 _Depth 被正确编码为相机渲染纹理中构成 depthSlime2 的每个像素的每个 b 值的 2 / 255。那为什么着色器脚本不丢弃未覆盖的像素??
一个更深层次的问题是,如果我将着色器应用于材质并将该材质附加到 2d 游戏对象,相机是否更新其渲染纹理(目标纹理)以匹配着色器脚本所做的更改写入游戏对象的像素?或者它是否保留原始渲染纹理而忽略着色器脚本对游戏对象所做的所有更改?绝对不是后者,因为我已经看到相机渲染纹理的一些视觉变化。因此,一定是相机在创建其渲染纹理时没有完全遵守编码为着色器脚本制作的每个像素的 b 值的 _Depth 值。