本文实例为大家分享了opengl实现彩色光圈效果的具体代码,供大家参考,具体内容如下
研究了一个彩色光圈效果,感觉挺不错的,分享给大家,效果如下:
代码如下:
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
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
|
shader "shadertoy/totalnoob" { //https://www.shadertoy.com/view/xdlsds 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 #pragma glsl #define vec2 float2 #define vec3 float3 #define vec4 float4 #define mat2 float2x2 #define iglobaltime _time.y // #define mod fmod // mod = sign*fmod #define mix lerp #define atan atan2 #define fract frac #define texture2d tex2d // 屏幕的尺寸 #define iresolution _screenparams // 屏幕中的坐标,以pixel为单位 #define gl_fragcoord ((_iparam.srcpos.xy/_iparam.srcpos.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 srcpos : texcoord0; }; // precision highp float; v2f vert(appdata_base v){ v2f o; o.pos = mul (unity_matrix_mvp, v.vertex); o.srcpos = computescreenpos(o.pos); return o; } vec4 main(v2f _iparam); fixed4 frag(v2f _iparam) : color0 { return main(_iparam); } vec4 main(v2f _iparam) { vec2 p = ( 2.0 *gl_fragcoord.xy-iresolution.xy)/iresolution.y; float tau = 3.1415926535 * 2.0 ; float a = atan(p.x,p.y); float r = length(p)* 0.75 ; vec2 uv = vec2(a/tau,r); //get the color float xcol = (uv.x - (iglobaltime / 3.0 )) * 3.0 ; xcol = sign(xcol)*fmod(xcol, 3.0 ); vec3 horcolour = vec3( 0.25 , 0.25 , 0.25 ); if (xcol < 1.0 ) { horcolour.r += 1.0 - xcol; horcolour.g += xcol; } else if (xcol < 2.0 ) { xcol -= 1.0 ; horcolour.g += 1.0 - xcol; horcolour.b += xcol; } else { xcol -= 2.0 ; horcolour.b += 1.0 - xcol; horcolour.r += xcol; } // draw color beam uv = ( 2.0 * uv) - 1.0 ; float beamwidth = ( 0.7 + 0.5 *cos(uv.x* 10.0 *tau* 0.15 *clamp(floor( 5.0 + 10.0 *cos(iglobaltime)), 0.0 , 10.0 ))) * abs( 1.0 / ( 30.0 * uv.y)); vec3 horbeam = vec3(beamwidth,beamwidth,beamwidth); vec4 gl_fragcolor = vec4((( horbeam)* horcolour ), 1.0 ); return gl_fragcolor; } endcg subshader { pass { cgprogram #pragma vertex vert #pragma fragment frag #pragma fragmentoption arb_precision_hint_fastest endcg } } fallback off } |
代码分析
代码分两部分,颜色 * 光圈,如下图:
* =
彩色的算法
代码如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
|
vec2 p = ( 2.0 *gl_fragcoord.xy-iresolution.xy)/iresolution.y; float tau = 3.1415926535 * 2.0 ; float a = atan(p.x,p.y); float r = length(p)* 0.75 ; vec2 uv = vec2(a/tau,r); //get the color float xcol = (uv.x - (iglobaltime / 3.0 )) * 3.0 ; xcol = mod(xcol, 3.0 ); vec3 horcolour = vec3( 0.25 , 0.25 , 0.25 ); if (xcol < 1.0 ) { horcolour.r += 1.0 - xcol; horcolour.g += xcol; } else if (xcol < 2.0 ) { xcol -= 1.0 ; horcolour.g += 1.0 - xcol; horcolour.b += xcol; } else { xcol -= 2.0 ; horcolour.b += 1.0 - xcol; horcolour.r += xcol; } |
这段代码是写在fragment shader中的,也就是说,每个像素点的渲染都会调用这段代码。
a) vec2 p = (2.0*gl_fragcoord.xy-iresolution.xy)/iresolution.y;
p表示把当前的坐标轴缩小到原来的1/2,原点移动到屏幕中间,并把x,y轴的坐标范围缩小到1左右的值(即p的y轴范围在-1到1之间,x轴的范围也在附近);
b)float a = atan(p.x, p.y);
a表示p点绕原点的角度,范围为[-π,π];所以uv.x = a/tau的范围为[-1/2, 1/2];
float xcol = (uv.x - (iglobaltime / 3.0)) * 3.0; xcol=mod(xcol, 3)的范围为 [0,3]
c) xcol经过上面处理,其范围为[0,3]; 现在把这个范围平均分成3份,每一份做一个颜色的混合:
[0,1]:red和green混合;[1,2]:green和blue混合;[2,3]:blue和red混合。
光圈的算法
a)画光圈
式子:abs(1.0 / (30.0*uv.y))
知识:在shader中,如果color的值为负数,则认为是0,不显示该颜色。
uv变量中uv.y表示点到原点的距离,值的范围为 [0, ]
a-1) uv = (2.0 * uv) - 1.0; 先把uv缩小到原来的1/2,然后向外移动1单位。uv.y的值为[-1/2, ];由于负值color不被显示,如下图a:
a-2) 1.0/(30.0* uv.y); 缩小到原来的1/30,并做个倒数,如下图b
a-3) abs(1.0/(30.0* uv.y)); 然后做个绝对值,如下图c
=》=》
画光圈的算法和《【opengl】shader实例分析(一)-wave》中画线的算法很类似。
b)光圈动画
式子:(0.7+0.5*cos(uv.x*10.0*tau*0.15*clamp(floor(5.0 + 10.0*cos(iglobaltime)), 0.0, 10.0)))
为了方便,把上面的式子分解如下:
式1:float tt = 5.0 + 10.0*cos(iglobaltime);
式2:float param = clamp(floor(tt), 0.0, 10.0);
式3:float beamwidth = (0.7+0.5*cos(uv.x*pi*param));
我们把beamwidth作为颜色输出;
先理解式3,如果当param为0,、1、2、3、10时,分别参考下图:
=》 =》=》 =》
式2的作用,把tt的值做一个包装,使其为0到10之间的整数
式1的作用,起周期作用,值域为[-5,15]; 其值如左下图所示; 又由于式2做了clamp,把大于10和小于0的值去掉,最终的动画如右下图所示:
====》
把光圈和颜色整合起来就看到了和文章开头的动画一样的效果了。
最后吧所有的效果整合起来,如下图:
【彩色】 => 【彩色旋转】 =》【彩色旋转+动画】 =》【彩色旋转+动画+光圈】
=》=》=》
本次分析到此结束,欢迎讨论。
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持服务器之家。
原文链接:https://blog.csdn.net/stalendp/article/details/40690185