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代码拖到摄像机上,而后参考下图修改设置就能够看到效果啦,注意脚本组件中的分辨率要和当前屏幕保持一致才不会变形。
参考设置以下:
最终效果如图: