http://lib.csdn.net/article/unity3d/38699

这篇文章翻译自国外的一篇文章(这里是原文链接),正在使用unity的你是否在shader toy上发现很多牛逼哄哄的shader却不知道如何使用,那么这篇文章就是帮助你来进行转换的。本文只是基础文章,那些对HLSL/CG/GLSL都很熟悉的大神相信已经会觉得太简单了。下面是索引和正文……


本文索引:

如果你正在试图涉猎shader编程这个领域,你可能或多或少听说过shaderToy这个网站,这个网站上有很多令人惊奇的shader效果,而这些效果有可能只用了几行代码来实现,就好像官方示例程序中提供的效果那样振奋人心。下面是这个网站上其中两个很厉害的例子: 
 
“Seascape” by TDM 
 
“Elevated” by iq

这个网站上提供的效果示例不仅仅令人赞叹,通过查看他们的源代码,你还可以学习到很多东西。网站上提供了可以在线实时创建和预览效果的代码框,在你的浏览器中,你可以通过修改代码,修改变量和输入来查看效果的变换。 
      网站上的代码只提供GLSL语言的支持,因为他们是通过在你的浏览器中运行WebGl来展现这些效果的。在本文中的这个例子是在unity5中实现的,但应该在其他版本的unity中也可以很好的运行。

一、 GLSL到HLSL的转换

理论上来说,应该是有将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平铺开来的效果都会差不多。

二、 在Unity中实现它

写过shader的开发者应该清楚,在片段着色器(或者说顶点着色器)中对每个像素单独做计算是非常耗性能的。如果你想使你的shader以一个流畅运行的帧率来展现的话,一个比较通用的做法是将片段着色器中的像素缩小到一个合适的比率,再通过放大到屏幕比例的方式来减少计算量。以下是本文中要用到的CS代码通用框架:

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;
}
}
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58

下面是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);
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37

下面是转换过来在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
}
}
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65

三、 最终效果

将CS代码拖到摄像机上,然后参考下图修改设置就可以看到效果啦,注意脚本组件中的分辨率要和当前屏幕保持一致才不会变形。

参考设置如下: 

最终效果如图: 

Unity中的ShaderToys——将大神们写的shader搬到unity中来吧的更多相关文章

  1. 厉害了,Google大神每天写多少行代码?

    文章转自开源中国社区,编译自:Quora Quora上有个有趣的问题:Google工程师们每天写多少行代码? Google 的 AdMob 全栈工程师 Raymond Farias 在 Quora 发 ...

  2. 通过开发工具发布web应用到tomcat服务器中--对于小白,大神可以忽略不看,勿喷,谢谢

    需要的工具 MyEclipse和TomCat 本人用的是MyEclipse2014和TomCat7 TomCat结构图 第一步:在MyEclipse中配置TomCat 如图所示: 第二步:创建Web项 ...

  3. 今天看了shell大神的写的一个统计脚本

    通过nginx日志统计接口耗时排行 grep '/bigbox?' access_log | awk '{print $7"&process="$NF}'| sed -r ...

  4. SQL 分组排序分页(大神帮写的膜拜一下)

    查询全部: SELECT P3.ID, P3.Name, P3.AddTimeFROM (SELECT Name, MAX(AddTime) AS MaxAddTime FROM Product AS ...

  5. 大神Java8写了一段逻辑,我直呼看不懂

    业务背景 首先,业务需求是这样的,从第三方电商平台拉取所有订单,然后保存到公司自己的数据库,需要判断是否有物流信息,如果有物流信息,还需要再进行上传. 而第三方接口返回的数据是 JSON 格式的,其中 ...

  6. 学习大神笔记之“MyBatis学习总结(二)”

    MyBatis对表的增删改查操作         主要有两种方式:基于XML实现和基于注解实现. 完整项目结构: 工具类:MyBatisUtil-------用于获取  sqlsession pack ...

  7. 实战经验|大神战队都在i春秋教你打CTF

    全国大学生信息安全竞赛创新实践能力赛旨在培养.选拔.推荐优秀信息安全专业人才创造条件,促进高等学校信息安全专业课程体系.教学内容和方法的改革,培养学生的创新意识与团队合作精神,普及信息安全知识,增强学 ...

  8. [ACM训练] ACM中巧用文件的输入输出来改写acm程序的输入输出 + ACM中八大输入输出格式

    ACM中巧用文件的输入输出来改写acm程序的输入输出 经常有见大神们使用文件来代替ACM程序中的IO,尤其是当程序IO比较复杂时,可以使自己能够更专注于代码的测试,而不是怎样敲输入. C/C++代码中 ...

  9. android中“下次不再提示”的对话框(修改自某大神)

    如图,我们要做得就是这个: 先上代码: 1,逻辑代码 package com.example.hello; import android.app.Activity; import android.ap ...

随机推荐

  1. 【HTML5开发系列】表单元素

    <form> 创建一个HTML表单 属性: action 表示提交表单时浏览器应该把用户填写的数据发送到什么地方 method 用来指定表单数据发送到服务器的方式.允许值有get和post ...

  2. ubuntu 17 编译BTCoin

    一. 安装开发环境 sudo apt-get update sudo apt-get install build-essential libtool autotools-dev autoconf pk ...

  3. go语言之并发编程一

    Go语言最大的优势就在于并发编程.Go语言的关键字go就是开启并发编程也就是goroutine的唯一途径.一条go语句以为着一个函数或方法的并发执行.Go语句是由go关键字和表达式组成.比如下面的这种 ...

  4. oracle 查询重复数据并且删除, 只保留一条数据重复数据

    最近面试中都遇到了这样一个数据库题: 删除表中的重复数据,有且只保留一条重复数据. 思路: 1)这个题需要用到rowid,首先找到重复数据的rowid,并找出rowid最大或最小值,作为删除的条件: ...

  5. oracle decode 用法

    含义解释: decode(条件,值1,返回值1,值2,返回值2,...值n,返回值n,缺省值) 该函数的含义如下:IF 条件=值1 THEN RETURN(翻译值1)ELSIF 条件=值2 THEN ...

  6. Oracle分页总汇

    Oracle分页总汇 select * from (select a.*,rownum row_num from (select * from mytable t order by t.id desc ...

  7. var妙用

    var广泛使用其实也有用的.比如在一些不太确定类型的地方 (比如要区分int/uint/long/double的时候),用泛型太牛刀而不用又觉得不灵活的时候,其实是比较推荐var的比如设计某种类的时候 ...

  8. python的property属性

    最近看书中关于Python的property()内建函数属性内容时<python核心编程>解释的生僻难懂,但在网上看到了一篇关于property属性非常好的译文介绍. http://pyt ...

  9. Flask框架的学习与实战(三):登陆管理

    继续flask的学习之旅.今天介绍flask的登陆管理模块,还记得上一篇中的blog小项目么,登录是咱们自己写的验证代码,大概有以下几个步骤: 1.在登录框中输入用户名和密码 2.flask view ...

  10. /etc/init.d目录和/etc/rc.local脚本

    一.关于/etc/init.d 如果你使用过Linux系统,那么你一定听说过init.d目录.这个目录到底是干嘛的呢?它归根结底只做了一件事情,但这件事情非同小可,是为整个系统做的,因此它非常重要.i ...