一、ShaderToy作品

如果你对 Shader 有一定的了解,那么你或多或少听说过 shaderToy 这个网站,这个网站上有很多令人振奋的 shader 效果,而这些效果有可能只用了几行代码来实现。就如同画家绘画,在这里片段着色器就是画笔,屏幕就是画纸:

网站中对于任意一个作品,都提供了完整的 GLSL 片段着手器代码,它们是通过在你的浏览器中运行 WebGl 来展现这些效果的。你也可以通过修改代码,修改变量和输入来直接在网页上查看效果的变幻

把它搬运到 Unity 上并不难,由于它们都是在片段着色器中进行逐像素的绘制和处理,所以在 Unity 中,我们可以用屏幕后处理的方式来处理这些 Shader

二、在Unity中实现

C# 后处理脚本如下:

为了能提高某些高复杂度 Shader 的性能,所以可以指定画布的分辨率

using System;
using UnityEngine;[ExecuteInEditMode]
public class ForShaderToy: PostEffectsBase
{public int horizontal = 1920;public int vertical = 1080;public Shader shaderToy;private Material _material;public Material material{get{_material = CheckShaderAndCreateMaterial(shaderToy, _material);return _material;}}void OnRenderImage(RenderTexture src, RenderTexture dest){if (material != null){RenderTexture scaled = RenderTexture.GetTemporary(horizontal, vertical, 24);Graphics.Blit(src, scaled, material);Graphics.Blit(scaled, dest);RenderTexture.ReleaseTemporary(scaled);}elseGraphics.Blit(src, dest);}
}
using UnityEngine;
using System.Collections;[ExecuteInEditMode]
//当在物体上添加该脚本时,Camera组件也会被自动被添加上去(如果没有的话)
[RequireComponent(typeof(Camera))]
public class PostEffectsBase: MonoBehaviour
{protected void Start(){//如果显卡支持图像后期处理效果if (!SystemInfo.supportsImageEffects){//设置当前组件为关闭状态enabled = false;}}protected Material CheckShaderAndCreateMaterial(Shader shader, Material material){//判断当前着色器是否可在当前显卡设备上使用,如果对应的着色器的所有Fallback都不可支持或者传入的着色器就不存在,返回nullif (shader == null || !shader.isSupported)return null;if (material && material.shader == shader)return material;else{material = new Material(shader);//设置当前材质不会被保存在场景中material.hideFlags = HideFlags.HideAndDontSave;if (material)return material;elsereturn null;}}

搞定之后,就是将 ShaderToy 上的 Shader 搬运过来了,如果想要在 UnityShader 中使用 HLSL,那么就需要自己去实现 GLSL 到 HLSL 的转换

这个可以参考 https://alastaira.wordpress.com/2015/08/07/unity-shadertoys-a-k-a-converting-glsl-shaders-to-cghlsl/ 以及 https://msdn.microsoft.com/en-GB/library/windows/apps/dn166865.aspx

没问题了,接下来把上面的 C# 挂到摄像机下,组件指定 Shader 就好,一个例子如下:

//https://www.shadertoy.com/view/XlfGRj
//https://msdn.microsoft.com/en-GB/library/windows/apps/dn166865.aspxShader "ShaderToy/StarNest"
{Properties{_Zoom("Zoom", Float) = 0.8    //缩放_Speed("Speed", Float) = 0.01   //速度_Volsteps("Volsteps", Int) = 20_Tile("Tile", Float) = 0.85_Iterations("Iterations", Int) = 17_Formuparam("Formuparam", Float) = 0.53_Brightness("Brightness", Float) = 0.0015_Darkmatter("Darkmatter", Float) = 0.300_Distfading("Distfading", Float) = 0.730_Saturation("Saturation", Float) = 0.850_StepSize("StepSize", Float) = 0.1}SubShader{PASS{CGPROGRAM#pragma vertex vert#pragma fragment frag#include "UnityCG.cginc"float _Zoom;float _Speed;int _Volsteps;float _Tile;float _Formuparam;int _Iterations;float _Brightness;float _Darkmatter;float _Distfading;float _Saturation;float _StepSize;struct _2v{float4 vertex: POSITION;};struct v2f{float4 pos: SV_POSITION;};v2f vert(_2v v){v2f o;o.pos = UnityObjectToClipPos(v.vertex);return o;}fixed4 frag(v2f i): SV_Target{//iResolution -> _ScreenParams//fragCoord -> pos(SV_POSITION)//iTime:ShaderToy提供的时间函数 -> _Time.yfixed2 uv = i.pos.xy / _ScreenParams.xy - 0.5;uv.y *= _ScreenParams.y / _ScreenParams.x;float3 dir = float3(uv * _Zoom, 1.0);float time = _Time.y * _Speed + 0.25;float a1 = 0.5 + 0.5 / _ScreenParams.x * 2.0;float a2 = 0.8 + 0.5 / _ScreenParams.y * 2.0;float2x2 Rot1 = float2x2(cos(a1), sin(a1), -sin(a1), cos(a1));float2x2 Rot2 = float2x2(cos(a2), sin(a2), -sin(a2), cos(a2));dir.xz = mul(dir.xz, Rot1);dir.xy = mul(dir.xy, Rot2);float3 from = float3(1.0, 0.5, 0.5);from += float3(time * 2.0, time, -2.0);from.xz = mul(from.xz, Rot1);from.xy = mul(from.xy, Rot2);float s = 0.1;float fade = 1.0;float3 v = float3(0.0, 0.0, 0.0);for (int r = 0; r < _Volsteps; r++){float pa = 0.0;float a = 0.0;float3 p = from + s * dir * 0.5;p = abs(float3(_Tile, _Tile, _Tile) - float3(fmod(p.x, _Tile * 2.0), fmod(p.y, _Tile * 2.0), fmod(p.z, _Tile * 2.0)));  //tiling foldfor (int i = 0; i < _Iterations; i++){ p = abs(p) / dot(p, p) - _Formuparam;        //the magic formulaa += abs(length(p) - pa);                   //absolute sum of average changepa = length(p);}float dm = max(0.0, _Darkmatter - a * a * 0.001);    //dark mattera *= a*a;           //add contrastif (r > 6)fade *= 1.0 - dm;           //dark matter, don't render nearv += fade;v += float3(s, s * s, s * s * s * s) * a * _Brightness * fade;       //coloring based on distancefade *= _Distfading;           //distance fadings += _StepSize;}//mix -> lerpv = lerp(float3(length(v), length(v), length(v)), v, _Saturation);          //color adjustfixed4 fragColor = float4(v * 0.01, 1.0);return fragColor;}ENDCG}}
}

漫天的星空:https://www.shadertoy.com/view/XlfGRj

三、支持鼠标输入控制

要知道,ShaderToy 对这些大神级的 Shader 做了额外的支持,其中就包括提供每时每刻鼠标在屏幕中的坐标,也因此,我们可以在效果预览窗口移动鼠标来欣赏动态的效果

同理,我们也可以在 C# 脚本中通过 Input.mousePosition 和 Input.GetMouseButton() API 来传递当前鼠标屏幕坐标到着色器,下面是完整的版本:

using System;
using UnityEngine;[ExecuteInEditMode]
public class ForShaderToy: PostEffectsBase
{public int horizontal = 1920;public int vertical = 1080;public bool isMouseScreenPos = false;public float mouseSpeed = 0.4f;public Shader shaderToy;private Material _material;private float mouse_x = 0.5f;private float mouse_y = 0.5f;public Material material{get{_material = CheckShaderAndCreateMaterial(shaderToy, _material);return _material;}}void OnRenderImage(RenderTexture src, RenderTexture dest){if (material != null){RenderTexture scaled = RenderTexture.GetTemporary(horizontal, vertical, 24);if (Input.GetMouseButton(0)){mouse_x = Mathf.Clamp(Input.mousePosition.x / Screen.width, 0, 1);mouse_y = Mathf.Clamp(Input.mousePosition.y / Screen.height, 0, 1);if (!isMouseScreenPos){mouse_x = Input.mousePosition.x;mouse_y = Input.mousePosition.y;}mouse_x *= mouseSpeed;mouse_y *= mouseSpeed;}material.SetFloat("_MouseX", mouse_x);material.SetFloat("_MouseY", mouse_y);Graphics.Blit(src, scaled, material);Graphics.Blit(scaled, dest);RenderTexture.ReleaseTemporary(scaled);}elseGraphics.Blit(src, dest);}
}
//https://www.shadertoy.com/view/XlfGRj
//https://msdn.microsoft.com/en-GB/library/windows/apps/dn166865.aspxShader "ShaderToy/StarNest"
{Properties{_Zoom("Zoom", Float) = 0.8    //缩放_Speed("Speed", Float) = 0.01   //速度_Volsteps("Volsteps", Int) = 20_Tile("Tile", Float) = 0.85_Iterations("Iterations", Int) = 17_Formuparam("Formuparam", Float) = 0.53_Brightness("Brightness", Float) = 0.0015_Darkmatter("Darkmatter", Float) = 0.300_Distfading("Distfading", Float) = 0.730_Saturation("Saturation", Float) = 0.850_StepSize("StepSize", Float) = 0.1_MouseX("MouseX", Range(0.0, 1.0)) = 0.5_MouseY("ouseY", Range(0.0, 1.0)) = 0.5}SubShader{PASS{CGPROGRAM#pragma vertex vert#pragma fragment frag#include "UnityCG.cginc"float _Zoom;float _Speed;int _Volsteps;float _Tile;float _Formuparam;int _Iterations;float _Brightness;float _Darkmatter;float _Distfading;float _Saturation;float _StepSize;float _MouseX;float _MouseY;struct _2v{float4 vertex: POSITION;};struct v2f{float4 pos: SV_POSITION;};v2f vert(_2v v){v2f o;o.pos = UnityObjectToClipPos(v.vertex);return o;}fixed4 frag(v2f i): SV_Target{//iResolution -> _ScreenParams//fragCoord -> pos(SV_POSITION)//iTime:ShaderToy提供的时间函数 -> _Time.yfixed2 uv = i.pos.xy / _ScreenParams.xy - 0.5;uv.y *= _ScreenParams.y / _ScreenParams.x;float3 dir = float3(uv * _Zoom, 1.0);float time = _Time.y * _Speed + 0.25;float a1 = 0.5 + _MouseX / _ScreenParams.x * 2.0;float a2 = 0.8 + _MouseY / _ScreenParams.y * 2.0;float2x2 Rot1 = float2x2(cos(a1), sin(a1), -sin(a1), cos(a1));float2x2 Rot2 = float2x2(cos(a2), sin(a2), -sin(a2), cos(a2));dir.xz = mul(dir.xz, Rot1);dir.xy = mul(dir.xy, Rot2);float3 from = float3(1.0, 0.5, 0.5);from += float3(time * 2.0, time, -2.0);from.xz = mul(from.xz, Rot1);from.xy = mul(from.xy, Rot2);float s = 0.1;float fade = 1.0;float3 v = float3(0.0, 0.0, 0.0);for (int r = 0; r < _Volsteps; r++){float pa = 0.0;float a = 0.0;float3 p = from + s * dir * 0.5;p = abs(float3(_Tile, _Tile, _Tile) - float3(fmod(p.x, _Tile * 2.0), fmod(p.y, _Tile * 2.0), fmod(p.z, _Tile * 2.0)));  //tiling foldfor (int i = 0; i < _Iterations; i++){ p = abs(p) / dot(p, p) - _Formuparam;        //the magic formulaa += abs(length(p) - pa);                   //absolute sum of average changepa = length(p);}float dm = max(0.0, _Darkmatter - a * a * 0.001);    //dark mattera *= a*a;           //add contrastif (r > 6)fade *= 1.0 - dm;           //dark matter, don't render nearv += fade;v += float3(s, s * s, s * s * s * s) * a * _Brightness * fade;       //coloring based on distancefade *= _Distfading;           //distance fadings += _StepSize;}//mix -> lerpv = lerp(float3(length(v), length(v), length(v)), v, _Saturation);          //color adjustfixed4 fragColor = float4(v * 0.01, 1.0);return fragColor;}ENDCG}}
}

四、GLHL转HLSL备忘

GLSL(ShaderToy) HLSL(Unity3D)  
iResolution.xy _ScreenParams.xy 视口分辨率
fragCoord pos(SV_POSITION) 当前片元坐标
iTime _Time.y 时间函数
vec3 float3/fixed3/half3 向量
mat3 float3x3 矩阵
mix() lerp() 平滑插值
mat *= mat mul(mat, mat) 矩阵/向量乘法

参考资料:

  • https://alastaira.wordpress.com/2015/08/07/unity-shadertoys-a-k-a-converting-glsl-shaders-to-cghlsl/
  • https://alastaira.wordpress.com/2015/08/07/unity-shadertoys-a-k-a-converting-glsl-shaders-to-cghlsl/

将ShaderToy中的Shader搬运到Unity相关推荐

  1. 在Unity 3D中,shader是何时编译的,在何时加载入显存中的?

    在Unity 3D中,shader是何时编译的,在何时加载入显存中的? 是某一对象在实例化时,加载其相关的material与shader还是游戏开始时? 添加评论 分享 按时间排序按投票排序 4 个回 ...

  2. 2.在unity中创建shader模板

    知识提要: Mesh Filter : 存储一个Mesh(网格,模型的网格,就是模型的由哪些三角面组成,组成一个什么样子的模型,三角面的一些顶点信息) Mesh Renderer:用来渲染一个模型的外 ...

  3. 【个人UNITY笔记】{基础} 2D游戏中使用Shader或Camera解决Sprite前后遮挡关系

    因为个人制作的奇葩游戏2D游戏是用Sprite当作角色和物体,然而Unity里不应该使用带透视的相机来渲染Sprite,因为会2个Sprite距离太近会出现闪烁,但是我就是想保留透视,同时使用Spri ...

  4. Ventuz中的shader 学习笔记(一)

    Ventuz目前主要用于一些大型展会,三维实时交互,工业流程以及数据的可视化展示. Shader在Ventuz中的使用可以使得效果变得更加炫酷. 1.搬运shadertoy中的效果 首先按照网上已有的 ...

  5. maximum number (256) of shader keywords exceeded unity的报错解决方法

    https://bitbucket.org/ArtIsDarkGames/shader-keywords-tool-unity3d/src/master/ https://eternity429.wo ...

  6. Unity3D中的shader基础知识

    1.Unity中配备了强大的阴影和材料的语言工具称为ShaderLab,以程式语言来看,它类似于CgFX和Direct3D的效果框架语法,它描述了材质所必须要的一切咨询,而不仅仅局限于平面顶点/像素着 ...

  7. SRP中的shader

    SRP中的shader 在Unity中使用SRP时,我们需要使用HLSL来编写shader.HLSL语法与GLSL类似,在使用HLSL的地方我们需要用HLSLPROGRAM和ENDHLSL来包裹: S ...

  8. 【Cocos Creator 3.x】ShaderToy 中的 iTime 对应 Cocos Effect 中是什么?

    前言 在网上 ShaderToy 中找了很久的一个 Shader 效果,不知道怎么移至到 Cocos Creator 中. 介绍 ShaderToy 中的 iTime 是 Shader 着色器播放时间 ...

  9. osg中运用Shader(osg初级篇2)

    关于shader的概念,可以参见我的另一篇博客<opengl版本发展史及各种概念的厘清>,这里列举一个例子,用来实现一个特效,屏幕的左半部显示为红色.首先我们准备好两个shader程序: ...

最新文章

  1. cpu烤机工具_MySQL常用工具选择和建议
  2. 突发!Windows XP源代码泄露
  3. 2018蓝桥杯省赛---java---B---2(方格计数)
  4. 进程和线程的关系与区别是什么?如何创建多线程?
  5. Springboot2.0 集成 Elasticsearch 6.x 未添加 transport-netty4-client 依赖 启动时报错
  6. python-元组,列表,字典常用方法
  7. CCF201812-4 数据中心(100分)【Kruskal算法】
  8. C++实现读取图片的长度和宽度
  9. 多版本Python共存的配置和使用
  10. YY直播产品体验报告
  11. (翻译)用户友好的表格的9种设计技巧
  12. QGraphicsItem的使用
  13. lixnu 启动php,好奇怪的代码
  14. 小米34寸带鱼屏显示器的耗电计算
  15. qt linux 下的u盘检测,Qt-detect-Udisk老外写的qt检测U盘
  16. vue-cli中出现这个错误[WDS] Disconnected!解决!!!
  17. redis 哈希hash实例应用
  18. Squid - 403 Forbidden (SSH via HTTP Proxy)
  19. Java 社区平台 Sym 2.6.0 发布,增加帖子列表渲染方式
  20. ubuntu ufw 防火墙使用

热门文章

  1. 零基础学python难吗-学习python12小时后,告诉你,学python真没你想的那么难!
  2. python教程推荐-关于推荐系统的详细介绍
  3. python自学看什么书-如何自学Python ?自学看什么书比较好?
  4. 0基础学python要多久-零基础自学python要多久?
  5. python自学-新手如何自学python课程?
  6. php和python-python与php比较
  7. 数字语音识别 - 源码下载|数值算法/人工智能|matlab例程|源代码 - 源码中国
  8. vue项目中使用lib-flexible解决移动端适配
  9. 最简单的视音频播放示例2:GDI播放YUV, RGB
  10. ffdshow 源代码分析 5: 位图覆盖滤镜(总结)