OpenGL Shader實(shí)例分析(8)彩色光圈效果
本文實(shí)例為大家分享了OpenGL實(shí)現(xiàn)彩色光圈效果的具體代碼,供大家參考,具體內(nèi)容如下
研究了一個(gè)彩色光圈效果,感覺(jué)挺不錯(cuò)的,分享給大家,效果如下:

代碼如下:
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
// 屏幕中的坐標(biāo),以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
}
代碼分析
代碼分兩部分,顏色 * 光圈,如下圖:
*
= 
彩色的算法
代碼如下:
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中的,也就是說(shuō),每個(gè)像素點(diǎn)的渲染都會(huì)調(diào)用這段代碼。
a) vec2 p = (2.0*gl_FragCoord.xy-iResolution.xy)/iResolution.y;
p表示把當(dāng)前的坐標(biāo)軸縮小到原來(lái)的1/2,原點(diǎn)移動(dòng)到屏幕中間,并把x,y軸的坐標(biāo)范圍縮小到1左右的值(即p的y軸范圍在-1到1之間,x軸的范圍也在附近);
b)float a = atan(p.x, p.y);
a表示p點(diǎn)繞原點(diǎn)的角度,范圍為[-π,π];所以u(píng)v.x = a/tau的范圍為[-1/2, 1/2];
float xCol = (uv.x - (iGlobalTime / 3.0)) * 3.0; xCol=mod(xCol, 3)的范圍為 [0,3]
c) xCol經(jīng)過(guò)上面處理,其范圍為[0,3]; 現(xiàn)在把這個(gè)范圍平均分成3份,每一份做一個(gè)顏色的混合:
[0,1]:Red和Green混合;[1,2]:Green和Blue混合;[2,3]:Blue和Red混合。
光圈的算法
a)畫光圈
式子:abs(1.0 / (30.0*uv.y))
知識(shí):在shader中,如果color的值為負(fù)數(shù),則認(rèn)為是0,不顯示該顏色。
uv變量中uv.y表示點(diǎn)到原點(diǎn)的距離,值的范圍為 [0, ]
a-1) uv = (2.0 * uv) - 1.0; 先把uv縮小到原來(lái)的1/2,然后向外移動(dòng)1單位。uv.y的值為[-1/2, ];由于負(fù)值color不被顯示,如下圖A:
a-2) 1.0/(30.0* uv.y); 縮小到原來(lái)的1/30,并做個(gè)倒數(shù),如下圖B
a-3) abs(1.0/(30.0* uv.y)); 然后做個(gè)絕對(duì)值,如下圖C
=》
=》
畫光圈的算法和《【OpenGL】Shader實(shí)例分析(一)-Wave》中畫線的算法很類似。
b)光圈動(dòng)畫
式子:(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,如果當(dāng)param為0,、1、2、3、10時(shí),分別參考下圖:
=》
=》
=》
=》
式2的作用,把tt的值做一個(gè)包裝,使其為0到10之間的整數(shù)
式1的作用,起周期作用,值域?yàn)閇-5,15]; 其值如左下圖所示; 又由于式2做了clamp,把大于10和小于0的值去掉,最終的動(dòng)畫如右下圖所示:
====》
把光圈和顏色整合起來(lái)就看到了和文章開(kāi)頭的動(dòng)畫一樣的效果了。
最后吧所有的效果整合起來(lái),如下圖:
【彩色】 => 【彩色旋轉(zhuǎn)】 =》【彩色旋轉(zhuǎn)+動(dòng)畫】 =》【彩色旋轉(zhuǎn)+動(dòng)畫+光圈】
=》
=》
=》
本次分析到此結(jié)束,歡迎討論。
以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
Flutter實(shí)現(xiàn)固定header底部滑動(dòng)頁(yè)效果示例
這篇文章主要為大家介紹了Flutter實(shí)現(xiàn)固定header底部滑動(dòng)頁(yè)效果示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-12-12
Android中的SQLite數(shù)據(jù)庫(kù)簡(jiǎn)介
SQLite是Android系統(tǒng)采用的一種開(kāi)源的輕量級(jí)的關(guān)系型的數(shù)據(jù)庫(kù)。這篇文章主要介紹了Android中的SQLite數(shù)據(jù)庫(kù)簡(jiǎn)介,需要的朋友可以參考下2017-03-03
AndriodStudio使用listview實(shí)現(xiàn)簡(jiǎn)單圖書(shū)管理
這篇文章主要為大家詳細(xì)介紹了AndriodStudio使用listview實(shí)現(xiàn)簡(jiǎn)單圖書(shū)管理,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2022-03-03
Android AsyncTask實(shí)現(xiàn)機(jī)制詳細(xì)介紹及實(shí)例代碼
這篇文章主要介紹了Android AsyncTask實(shí)現(xiàn)機(jī)制詳細(xì)介紹及實(shí)例代碼的相關(guān)資料,這里附有示例代碼,幫助大家學(xué)習(xí)理解,需要的朋友可以參考下2016-12-12
android實(shí)現(xiàn)文字水印效果 支持多行水印
這篇文章主要為大家詳細(xì)介紹了android添加文字水印,并支持多行水印,自定義角度和文字大小,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2018-10-10
SurfaceView開(kāi)發(fā)[捉小豬]手機(jī)游戲 (二)
這篇文章主要介紹了用SurfaceView開(kāi)發(fā)[捉小豬]手機(jī)游戲 (二)本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2021-08-08
Android開(kāi)發(fā)Jetpack組件LiveData使用講解
LiveData是Jetpack組件的一部分,更多的時(shí)候是搭配ViewModel來(lái)使用,相對(duì)于Observable,LiveData的最大優(yōu)勢(shì)是其具有生命感知的,換句話說(shuō),LiveData可以保證只有在組件( Activity、Fragment、Service)處于活動(dòng)生命周期狀態(tài)的時(shí)候才會(huì)更新數(shù)據(jù)2022-08-08

