Unity 中实现截图画笔橡皮擦工具
Unity 中實現(xiàn)截圖畫筆橡皮擦工具
好久沒寫博客了,隨著疫情的緩和,工作也忙了起來 ,寫博客也成了忙里偷閑的一項娛樂活動了,不以娛樂為目的技術(shù)博客寫手不是一個好的廚師(我一向自稱自己是碼農(nóng)界最帥的廚子)~
今天就來分享下之前項目中用shader實現(xiàn)的一個畫筆橡皮擦功能,當時是一位老師提出要在軟件里做筆記的一個需求,希望可以在軟件使用過程中劃重點,做筆記,再截圖保存,方便學生復習,真不愧是一位一切以學生為中心的好老師~
剛接到這個需求,我還在UnityAssetsStore上找了找相關(guān)插件,想著直接拿來用多好,找了一些,覺得都不太方便集成到項目, 索性自己用shader寫一個吧,也復習一下之前的shader技術(shù)。
實現(xiàn)思路:在UI最上層添加一個填充滿屏幕的畫布RenderTexture, 運用 屏幕后處理技術(shù)Graphics.Blit,對當前的畫布上的RenderTexture進行筆刷采樣處理,畫筆效果如下:
核心代碼:
point即為我們當前鼠標屏幕坐標,第一句if是我限制了截圖可畫的區(qū)域,重要的是下面的代碼,先算出當前采樣紋理UV值,然后傳入_paintBrushMat的畫筆材質(zhì)shader,在用 Graphics.Blit 去做效果疊加處理。接下來我們看下核心的_paintBrushMat的畫筆材質(zhì)shader代碼:
Shader "Unlit/PaintBrush" {Properties{_MainTex ("Texture", 2D) = "white" {}_BrushTex("Brush Texture",2D)= "white" {}_Color("Color",Color)=(1,1,1,1)_UV("UV",Vector)=(0,0,0,0)_Size("Size",Range(1,1000))=1_SizeY("SizeY",Range(1,1000))=1}SubShader{Tags { "RenderType"="Transparent" }LOD 100ZTest Always Cull Off ZWrite Off Fog{ Mode Off }Blend SrcAlpha OneMinusSrcAlpha//Blend One DstColorPass{CGPROGRAM#pragma vertex vert#pragma fragment frag#include "UnityCG.cginc"struct appdata{float4 vertex : POSITION;float2 uv : TEXCOORD0;};struct v2f{float2 uv : TEXCOORD0;float4 vertex : SV_POSITION;};sampler2D _MainTex;float4 _MainTex_ST;sampler2D _BrushTex;fixed4 _UV;float _Size;float _SizeY;fixed4 _Color;v2f vert (appdata v){v2f o;o.vertex = UnityObjectToClipPos(v.vertex);o.uv = TRANSFORM_TEX(v.uv, _MainTex);return o;}fixed4 frag (v2f i) : SV_Target{// sample the texturefloat size = _Size;float2 uv = i.uv + (0.5f / size);uv = uv - _UV.xy;uv *= size;float sizeY = _SizeY;uv.y=uv.y*sizeY/size;fixed4 col = tex2D(_BrushTex,uv);col.rgb = 1;col *= _Color;return col;}ENDCG}} }_BrushTex就是我們的筆刷圖標圖片,就是個效果圖中的那個小黑點圖片,_Color就是筆刷顏色,_UV就是我們當前要采樣的筆刷點在畫布上的UV值,_Size就是我們的畫布像素與筆刷圖片的像素比例大小,_SizeY是畫布高度與畫布跨度的比例,計算方式 float sizeY = ((float)Screen.height / (float)Screen.width) * size;(其實不需要size,shader里就不要在size了)因為我們最終的采樣結(jié)果應(yīng)該是一個規(guī)則圓形,而非寬高不一樣的橢圓,我們主要看片源著色器的代碼,這里
float2 uv = i.uv + (0.5f / size);
uv = uv - _UV.xy;
uv = size;
其實是做了一個從畫布每個UV值到采樣圖片UV值的一個坐標映射計算,
float sizeY = _SizeY;
uv.y=uv.ysizeY/size;
這里就是我們上面說的要調(diào)整uv的x,y采樣比例,無論屏幕寬高比例如何,我們都輸出圓形。
注意我們要開啟深度測試為Always,避免片元被舍棄,關(guān)閉深度寫入 ,alpha混合設(shè)置為Blend SrcAlpha OneMinusSrcAlpha;
我們再來看看橡皮擦得效果,如圖(別問我為啥用這次綠色展示,大家都不喜歡綠色,可不得擦掉它嘛,哈哈):
代碼如下:
橡皮擦,我們采用透明空心圓圈的采樣圖片, 在片元著色器代碼處理顏色時不同, float cirle = pow(uv.x-0.5f, 2)+pow(uv.y-0.5f*sizeY/size, 2);
if(cirle>0.25f)
discard;
我們關(guān)閉了alpha blend ,在需要擦除的區(qū)域之外的片元直接舍棄,這樣圓圈空心區(qū)域的顏色就直接成了透明,實現(xiàn)了擦除的效果(在shader里用if語句不太好,有待改進)。
需要注意的就是我們在對筆刷采樣應(yīng)該增大它的采樣頻率,讓它在每一幀多采樣幾次。
本人在shader編程方面的知識也是比較薄弱,歡迎留言指正,謝謝~
附上工程源碼:
工程源碼:https://github.com/ivoslove/ScreenShotPainter
總結(jié)
以上是生活随笔為你收集整理的Unity 中实现截图画笔橡皮擦工具的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 做模具设计需要知道的6大系统的设计原则,
- 下一篇: 我是梦想橡皮擦,这是我在 CSDN 所有