2018/12/14日补充:后来发现compute shader里用AppendStructuredBuffer可以解决这类问题,请看这里:https://www.cnblogs.com/hont/p/10122129.html
1.简介
在日常开发中会遇到诸如判断某张图的某颜色像素百分比占多少的问题,由于gpu运算并行的原因并不能对其进行累加操作。网上一些针对此类问题
的做法是将一张大图分成多个小块逐步处理并逐步合并,保留关键像素的向下采样:
但我在思考一种更简便的方法,于是想到在顶点shader里做判断检测,在像素shader里获取结果这样一个形式:
用一组顶点去读单个像素,判断失败的顶点坐标提交到屏幕外,而判断成功的顶点坐标放在屏幕内。
最后在CPU中获取是否有屏幕内顶点这样一个结果,来进行简单的识别操作。
而在开启透明之后,还可以用透明度叠加来获取更复杂的结果。
2.实践
首先实践结果并没有想象的那么好,因为如果纯用三角面来做顶点部分的判断未免太费效率了。
所以我改成了传入顶点判断并生成面的方式,并且缩小了传入图片的像素大小。
Graphics.DrawProcedural(MeshTopology.Points, blueTex.width * blueTex.height, 1);
毕竟更多的运用场合是用来做刮刮卡或者擦除的识别。只需要检测mask图片。
上代码:
Shader "Hidden/FooShader" { Properties { } SubShader { Blend One One tags { "Queue" = "Transparent" "RenderType" = "Transparent" } Pass { CGPROGRAM #pragma target 4.0 #pragma vertex vert #pragma geometry geom #pragma fragment frag #include "UnityCG.cginc" struct v2f { float4 color : COLOR; float4 vertex : SV_POSITION; }; sampler2D _Image; float4 _ImageSize; v2f vert(uint vid : SV_VertexID) { v2f o = (v2f)0; half y = floor(vid / _ImageSize.x); half x = (vid - y * _ImageSize.x) / _ImageSize.x; y = y / _ImageSize.y; o.vertex = 0; float4 image_col = tex2Dlod(_Image, half4(x,y,0,0)); if (all(image_col.rgb == half3(0, 0, 1))) //if (all(image_col.rgb == half3(0, 1, 1))) /*error*/ { o.color = 1; } else { o.color = 0; } return o; } [maxvertexcount(4)] void geom(point v2f vertElement[1], inout TriangleStream<v2f> triStream) { if (vertElement[0].color.r <= 0) return; float size = 10; float4 v1 = vertElement[0].vertex + float4(-size, -size, 0, 0); float4 v2 = vertElement[0].vertex + float4(-size, size, 0, 0); float4 v3 = vertElement[0].vertex + float4(size, -size, 0, 0); float4 v4 = vertElement[0].vertex + float4(size, size, 0, 0); v2f r = (v2f)0; r.vertex = mul(UNITY_MATRIX_VP, v1); r.color = vertElement[0].color; triStream.Append(r); r.vertex = mul(UNITY_MATRIX_VP, v2); r.color = vertElement[0].color; triStream.Append(r); r.vertex = mul(UNITY_MATRIX_VP, v3); r.color = vertElement[0].color; triStream.Append(r); r.vertex = mul(UNITY_MATRIX_VP, v4); r.color = vertElement[0].color; triStream.Append(r); } fixed4 frag(v2f i) : SV_Target { return i.color; } ENDCG } } }