http://lib.csdn.net/article/unity3d/38699 html
這篇文章翻譯自國外的一篇文章(這裏是原文連接),正在使用unity的你是否在shader toy上發現不少牛逼哄哄的shader殊不知道如何使用,那麼這篇文章就是幫助你來進行轉換的。本文只是基礎文章,那些對HLSL/CG/GLSL都很熟悉的大神相信已經會以爲太簡單了。下面是索引和正文……編程
本文索引:windows
若是你正在試圖涉獵shader編程這個領域,你可能或多或少據說過shaderToy這個網站,這個網站上有不少使人驚奇的shader效果,而這些效果有可能只用了幾行代碼來實現,就好像官方示例程序中提供的效果那樣振奮人心。下面是這個網站上其中兩個很厲害的例子:
「Seascape」 by TDM
「Elevated」 by iq瀏覽器
這個網站上提供的效果示例不只僅使人讚歎,經過查看他們的源代碼,你還能夠學習到不少東西。網站上提供了能夠在線實時建立和預覽效果的代碼框,在你的瀏覽器中,你能夠經過修改代碼,修改變量和輸入來查看效果的變換。
網站上的代碼只提供GLSL語言的支持,由於他們是經過在你的瀏覽器中運行WebGl來展示這些效果的。在本文中的這個例子是在unity5中實現的,但應該在其餘版本的unity中也能夠很好的運行。app
理論上來講,應該是有將GLSL直接轉換爲HLSL的工具,但據我所知,至少目前我尚未發現這樣的工具。所以,我只能手動將代碼一行行轉換過來。幸運的是,通常來講,一個shader文件的代碼都不會很長,大部分也就一百來行吧,聽起來可能只須要幾分鐘就能夠完成這個過程。
微軟已經發布過一篇文章專門介紹了GLSL和HLSL之間的差異。Unity中也有一篇相似的頗有用的文章在這裏。而下面是我在轉換shader的過程當中常常用到的一些方法:
- 將 iGlobalTime shader 輸入值轉換爲(用來驅動shader中動畫的時間,相似C#中的Time.deltaTime(單位爲秒)) _Time.y
- 將 iResolution.xy (「視口的像素分辨率」) 轉換爲 _ScreenParams.xy
- 將元素爲float2, mat2的向量 vec2 類型轉換爲float2x2 等.
- 將 vec3(1) 簡寫的構造器改寫爲全部份量都爲1的 float3(1,1,1)
- 將 Texture2D 改寫爲 Tex2D
- 將 atan(x,y) 改寫爲 atan2(y,x) <- 注意參數的順序!
- 將 mix() 改寫爲 lerp()
- 將 *= 改寫爲 mul()
- 將紋理Texture2D查找函數的第三個參數(偏移量bias)移除
- mainImage(out vec4 fragColor, in vec2 fragCoord) 是一個片斷着色器, 在unity中等同於 float4 mainImage(float2 fragCoord : SV_POSITION) : SV_Target
- GLSL中紋理座標Y方向的原點在頂部,而HLSL中紋理座標Y方向的原點在底部,因此你須要使用這個公式uv.y = 1 – uv.y 對每一個點從新定義紋理座標框架
ShaderToys上的這些效果都沒有用到頂點着色器函數,他們經過在像素着色器中計算屏幕上每一個點對應的UV座標來肯定每一個像素對應的顏色值。所以,shadertoy上的這些效果特別適合用來作全屏特效(或者,你能夠將他們直接賦給一個面板或者四邊形),只要是UV從0到1平鋪開來的效果都會差很少。ide
寫過shader的開發者應該清楚,在片斷着色器(或者說頂點着色器)中對每一個像素單獨作計算是很是耗性能的。若是你想使你的shader以一個流暢運行的幀率來展示的話,一個比較通用的作法是將片斷着色器中的像素縮小到一個合適的比率,再經過放大到屏幕比例的方式來減小計算量。如下是本文中要用到的CS代碼通用框架:wordpress
using System; using UnityEngine; [ExecuteInEditMode] public class ShaderToy : MonoBehaviour { public int horizontalResolution = 320; public int verticalResolution = 240; public Shader shaderToy; private Material shaderToyMaterial = null; public Material material { get { shaderToyMaterial = CheckShaderAndCreateMaterial(shaderToy, shaderToyMaterial); return shaderToyMaterial; } } // Called by camera to apply image effect void OnRenderImage(RenderTexture source, RenderTexture destination) { // To draw the shader at full resolution, use: // Graphics.Blit (source, destination, material); // To draw the shader at scaled down resolution, use: RenderTexture scaled = RenderTexture.GetTemporary(horizontalResolution, verticalResolution); Graphics.Blit(source, scaled, material); Graphics.Blit(scaled, destination); RenderTexture.ReleaseTemporary(scaled); } protected Material CheckShaderAndCreateMaterial(Shader shader, Material material) { if (shader == null) { return null; } if (shader.isSupported && material && material.shader == shader) return material; if (!shader.isSupported) { return null; } else { material = new Material(shader); material.hideFlags = HideFlags.DontSave; if (material) return material; else return null; } } }
下面是ShaderToy網站上的源碼:函數
// Created by inigo quilez - iq/2013 // License Creative Commons Attribution-NonCommercial-ShareAlike 3.0 Unported License. void mainImage( out vec4 fragColor, in vec2 fragCoord ) { vec2 uv = -1.0 + 2.0*fragCoord.xy / iResolution.xy; uv.x *= iResolution.x / iResolution.y; // background vec3 color = vec3(0.8 + 0.2*uv.y); // bubbles for( int i=0; i<40; i++ ) { // bubble seeds float pha = sin(float(i)*546.13+1.0)*0.5 + 0.5; float siz = pow( sin(float(i)*651.74+5.0)*0.5 + 0.5, 4.0 ); float pox = sin(float(i)*321.55+4.1) * iResolution.x / iResolution.y; // buble size, position and color float rad = 0.1 + 0.5*siz; vec2 pos = vec2( pox, -1.0-rad + (2.0+2.0*rad)*mod(pha+0.1*iGlobalTime*(0.2+0.8*siz),1.0)); float dis = length( uv - pos ); vec3 col = mix( vec3(0.94,0.3,0.0), vec3(0.1,0.4,0.8), 0.5+0.5*sin(float(i)*1.2+1.9)); // col+= 8.0*smoothstep( rad*0.95, rad, dis ); // render float f = length(uv-pos)/rad; f = sqrt(clamp(1.0-f*f,0.0,1.0)); color -= col.zyx *(1.0-smoothstep( rad*0.95, rad, dis )) * f; } // vigneting color *= sqrt(1.5-0.5*length(uv)); fragColor = vec4(color,1.0); }
下面是轉換過來在Unity中使用的Shader代碼:工具
// See https://www.shadertoy.com/view/4dl3zn // GLSL -> HLSL reference: https://msdn.microsoft.com/en-GB/library/windows/apps/dn166865.aspx Shader "Custom/Bubbles" { SubShader { Pass { CGPROGRAM #pragma vertex vert #pragma fragment frag struct v2f{ float4 position : SV_POSITION; }; v2f vert(float4 v:POSITION) : SV_POSITION { v2f o; o.position = mul (UNITY_MATRIX_MVP, v); return o; } fixed4 frag(v2f i) : SV_Target { float2 uv = -1.0 + 2.0*i.position.xy/ _ScreenParams.xy; uv.x *= _ScreenParams.x/ _ScreenParams.y ; // Background fixed4 outColour = fixed4(0.8+0.2*uv.y,0.8+0.2*uv.y,0.8+0.2*uv.y,1); // Bubbles for (int i = 0; i < 40; i++) { // Bubble seeds float pha = sin(float(i)*546.13+1.0)*0.5 + 0.5; float siz = pow( sin(float(i)*651.74+5.0)*0.5 + 0.5, 4.0 ); float pox = sin(float(i)*321.55+4.1); // Bubble size, position and color float rad = 0.1 + 0.5*siz; float2 pos = float2( pox, -1.0-rad + (2.0+2.0*rad)*fmod(pha+0.1*_Time.y*(0.2+0.8*siz),1.0)); float dis = length(uv-pos); float3 col = lerp( float3(0.94,0.3,0.0), float3(0.1,0.4,0.8), 0.5+0.5*sin(float(i)*1.2+1.9)); // Add a black outline around each bubble col+= 8.0*smoothstep( rad*0.95, rad, dis ); // Render float f = length(uv-pos)/rad; f = sqrt(clamp(1.0-f*f,0.0,1.0)); outColour.rgb -= col.zyx *(1.0-smoothstep( rad*0.95, rad, dis )) * f; } // Vignetting outColour *= sqrt(1.5-0.5*length(uv)); return outColour; } ENDCG } } }
將CS代碼拖到攝像機上,而後參考下圖修改設置就能夠看到效果啦,注意腳本組件中的分辨率要和當前屏幕保持一致纔不會變形。
參考設置以下:
最終效果如圖: