欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  移动技术

OpenGL Shader实例分析(8)彩色光圈效果

程序员文章站 2022-03-08 16:35:52
本文实例为大家分享了opengl实现彩色光圈效果的具体代码,供大家参考,具体内容如下 研究了一个彩色光圈效果,感觉挺不错的,分享给大家,效果如下: 代码如下:...

本文实例为大家分享了opengl实现彩色光圈效果的具体代码,供大家参考,具体内容如下

研究了一个彩色光圈效果,感觉挺不错的,分享给大家,效果如下:

OpenGL Shader实例分析(8)彩色光圈效果

代码如下:

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 
}

代码分析

代码分两部分,颜色 * 光圈,如下图:

OpenGL Shader实例分析(8)彩色光圈效果 * OpenGL Shader实例分析(8)彩色光圈效果 = OpenGL Shader实例分析(8)彩色光圈效果

彩色的算法

代码如下:

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实例分析(8)彩色光圈效果=》OpenGL Shader实例分析(8)彩色光圈效果=》OpenGL Shader实例分析(8)彩色光圈效果

画光圈的算法和《【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时,分别参考下图: 

OpenGL Shader实例分析(8)彩色光圈效果 =》 OpenGL Shader实例分析(8)彩色光圈效果 =》OpenGL Shader实例分析(8)彩色光圈效果=》 OpenGL Shader实例分析(8)彩色光圈效果=》OpenGL Shader实例分析(8)彩色光圈效果

式2的作用,把tt的值做一个包装,使其为0到10之间的整数

式1的作用,起周期作用,值域为[-5,15]; 其值如左下图所示; 又由于式2做了clamp,把大于10和小于0的值去掉,最终的动画如右下图所示:

OpenGL Shader实例分析(8)彩色光圈效果 ====》OpenGL Shader实例分析(8)彩色光圈效果

把光圈和颜色整合起来就看到了和文章开头的动画一样的效果了。

最后吧所有的效果整合起来,如下图:

【彩色】 => 【彩色旋转】 =》【彩色旋转+动画】 =》【彩色旋转+动画+光圈】

OpenGL Shader实例分析(8)彩色光圈效果=》OpenGL Shader实例分析(8)彩色光圈效果=》OpenGL Shader实例分析(8)彩色光圈效果=》OpenGL Shader实例分析(8)彩色光圈效果

本次分析到此结束,欢迎讨论。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。