本来之前已经决定不再碰渲染相关了,因为自己的数学实在是太差了,也没那个天分学渲染。但是上周帮同事想一个过滤正弦波的算法的时候发现还是很想研究这些的。于是就照着其他大佬的想法,有时间的时候就去搬搬ShaderToy的效果吧~
前几篇准备还是纯抄大佬们已经搬到Unity内的思路找找感觉,大概第四篇左右就开始自己研究和搬运效果。
1.ShaderToy的特点
ShaderToy中的shader都是绘制在整个屏幕范围的,也就是pixel shader。在Unity中shader都是贴在material上然后贴在具体的游戏物体上的。
所以ShaderToy的shader就相当于Unity内生成了一个刚好铺满整个屏幕的全屏方形平板,然后这个平板的材质上贴了对应的shader。
和Unity差不多,ShaderToy内也是分为顶点着色和片元着色,所以在ShaderToy上面的Shader Input内,可以看到顶点着色器提供了哪些公共变量进行访问,我们后面在Unity进行修改时,大多也是对这些公共变量进行转换。
2.Unity中的模板
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 66 67 68 69 70 71 72 |
Shader "Shadertoy/Template" { Properties{ iMouse ("Mouse Pos", Vector) = (100, 100, 0, 0) iChannel0("iChannel0", 2D) = "white" {} iChannelResolution0 ("iChannelResolution0", Vector) = (100, 100, 0, 0) } CGINCLUDE #include "UnityCG.cginc" #pragma target 3.0 #define vec2 float2 #define vec3 float3 #define vec4 float4 #define mat2 float2x2 #define mat3 float3x3 #define mat4 float4x4 #define iGlobalTime _Time.y #define mod fmod #define mix lerp #define fract frac #define texture2D tex2D #define iResolution _ScreenParams #define gl_FragCoord ((_iParam.scrPos.xy/_iParam.scrPos.w) * _ScreenParams.xy) #define PI2 6.28318530718 #define pi 3.14159265358979 #define halfpi (pi * 0.5) #define oneoverpi (1.0 / pi) fixed4 iMouse; sampler2D iChannel0; fixed4 iChannelResolution0; struct v2f { float4 pos : SV_POSITION; float4 scrPos : TEXCOORD0; }; v2f vert(appdata_base v) { v2f o; o.pos = mul (UNITY_MATRIX_MVP, v.vertex); o.scrPos = ComputeScreenPos(o.pos); return o; } vec4 main(vec2 fragCoord); fixed4 frag(v2f _iParam) : COLOR0 { vec2 fragCoord = gl_FragCoord; return main(gl_FragCoord); } vec4 main(vec2 fragCoord) { return vec4(1, 1, 1, 1); } ENDCG SubShader { Pass { CGPROGRAM #pragma vertex vert #pragma fragment frag #pragma fragmentoption ARB_precision_hint_fastest ENDCG } } FallBack Off } |
代码是从乐乐老师那边抄来的,主要功能是在开头定义了一系列宏来和ShaderToy中的GLSL进行衔接,因为GLSL内的预定义的一些变量CG内并没有,所以在开头声明了一下。
顶点着色器内只包含了一个把模型坐标转换到屏幕坐标的计算,因为ShaderToy内的pixel shader都是基于屏幕的~
此外,为了响应鼠标操作,我们还可以定义一个C#脚本,来把鼠标位置传递给shader
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 |
using UnityEngine; using System.Collections; public class ShaderToyHelper : MonoBehaviour { private Material _material = null; private bool _isDragging = false; // Use this for initialization void Start () { Renderer render = GetComponent<Renderer>(); if (render != null) { _material = render.material; } _isDragging = false; } // Update is called once per frame void Update () { Vector3 mousePosition = Vector3.zero; if (_isDragging) { mousePosition = new Vector3(Input.mousePosition.x, Input.mousePosition.y, 1.0f); } else { mousePosition = new Vector3(Input.mousePosition.x, Input.mousePosition.y, 0.0f); } if (_material != null) { _material.SetVector("iMouse", mousePosition); } } void OnMouseDown() { _isDragging = true; } void OnMouseUp() { _isDragging = false; } } |