纯Shading Language绘制HTML5时钟

纯Shading Language绘制HTML5时钟,第1张

概述今天是2014年的最后一天,这个时刻总会让人想起时钟,再过几个小时地球人都要再老了一岁,于是搞个HTML5版的时钟就是我们今天要完成的任务,实现HTML5的时钟绘制一般会采用三种方式,第一种采用CSS的实现方式,例如http://www.css-tricks.com/examples/CSS3Clo

今天是2014年的最后1天,这个时刻总会让人想起时钟,再过几个小时地球人都要再老了1岁,因而弄个HTML5版的时钟就是我们今天要完成的任务,实现HTML5的时钟绘制1般会采取3种方式,第1种采取CSS的实现方式,例如 http://www.css-tricks.com/examples/CSS3Clock/ ;第2种采取SVG的实现方式,例如 http://www.css-tricks.com/examples/CSS3Clock/;第3种采取Cavnas的2D绘制方式,如HT for Web中《矢量手册》中自定义绘制的clock例子,HT的例子的实现效果以下,其实现代码附在本文的最后部份。

以上3种方式都是较容易理解的实现方式,今天我们将采取的则是较为少见的WebGL纯Shading Language实现方式,这类方式极为高效,毕竟我们采取的是可利用GPU硬件加速的WebGL技术,cpu代码角度看唯一两个3角形的绘制,真正表盘的绘制逻辑完全在GPU对两个3角形进行Fragment Shading时实现。

可通过这里 http://Js.do/hightopo/glsl-clock 玩玩最后的实现效果和实现代码,采取GLSL的实现最重要的就是决定当前坐标位置的gl_Fragcolor的色彩,我们将始终分为表盘、外圈、刻度、时针、分针和秒针几个部份,代码后部份的留个连续Blend代码相当于逐层绘制的逻辑,以下几个函数技术点说明:

Rect函数中的clamp(uv,-size/2.0,size/2.0))是我们决定点是不是在矩形区域的技能函数Rotate(vec2 uv,float angle)将坐标点旋转到水平或垂直位置方便我们肯定Rect和line参数进行对照Blend函数mix(shapecolor,backcolor,smoothstep(0.0,0.005,shape))是经常使用的混合mix和smoothstep到达更好处理边沿平滑效果GLSL经常使用技能

为了说明mix和smoothstep的融会效果,我弄了个 http://Js.do/hightopo/glsl-smooth-clrcle 的例子,你可以尝试去掉#define SMOOTH后边沿锯齿较明显的问题,也能够调理smoothstep(0.49,0.5,d)的0.49为0.3等较小的参数体验渐进的效果,以下为几种效果的综合对照

GLSL的Fragment Shader实现代码以下:

#ifdef GL_ESprecision mediump float;#endifuniform float time;uniform vec2 resolution;float pi = 3.1415926; float tau = pi * 2.0;vec2 Rotate(vec2 uv,float angle);float Circle(vec2 uv,float r);float Rect(vec2 uv,vec2 size,float r);float line(vec2 uv,vec2 start,vec2 end,float r);float Merge(float a,float b);float Outline(float a,float r);vec3 Blend(vec3 backcolor,vec3 shapecolor,float shape);float SecStep(float x); voID main( voID ) { vec2 res = resolution / resolution.y; vec2 uv = ( gl_FragCoord.xy / resolution.y ); uv -= res / 2.0; float secAng = (SecStep(time) / 60.0) * tau; float minAng = (time / 3600.0) * tau; float hourAng = (time / 43200.0) * tau; float clockFace = Circle(uv,0.45); float clockTrim = Outline(clockFace,0.01); vec2 secDomain = Rotate(uv,secAng); float clockSec = line(secDomain,vec2(0.0,-0.15),0.35),0.001); clockSec = Merge(clockSec,Circle(uv,0.01)); clockSec = Merge(clockSec,Rect(secDomain - vec2(0.0,-0.08),vec2(0.012,0.07),0.0)); float clockMin = line(Rotate(uv,minAng),0.005); float clockHour = line(Rotate(uv,hourAng),-0.05),0.3),0.007); clockHour = Merge(clockHour,0.02)); float tickMarks = 1.0; vec2 tickDomain = uv; for(int i = 0;i < 60;i++) { tickDomain = Rotate(tickDomain,tau / 60.0); vec2 size = (mod(float(i + 1),5.0) == 0.0) ? vec2(0.08,0.01) : vec2(0.04,0.002); tickMarks = Merge(tickMarks,Rect(tickDomain - vec2(0.38,0.0),size,0.0)); } vec3 facecolor = mix(vec3(1.0,1.0,vec3(1.0,1.0),uv.x+0.5); vec3 trimcolor = mix(vec3(0.0,vec3(0.0,0.0,uv.y + 0.5); vec3 seccolor = vec3(1.0,0.0); vec3 handcolor = vec3(0.0,0.0); vec3 color = mix(vec3(1.0,uv.y+0.5); color = Blend(color,facecolor,clockFace); color = Blend(color,trimcolor,clockTrim); color = Blend(color,tickMarks); color = Blend(color,handcolor,clockHour); color = Blend(color,clockMin); color = Blend(color,seccolor,clockSec); gl_Fragcolor = vec4(color,1.0);}float SecStep(float x){ float interp = smoothstep(0.80,mod(x,1.0)); return floor(x) + interp + (sin(interp * pi)) ;} float line(vec2 uv,float r){ return Rect(uv-(end+start)/2.0,vec2(r,end.y - start.y),r);}float Rect(vec2 uv,float r){ return length(uv - clamp(uv,size/2.0)) - r; } vec2 Rotate(vec2 uv,float angle){ return mat2(cos(angle),sin(angle),-sin(angle),cos(angle)) * uv;}float Circle(vec2 uv,float r){ return length(uv) - r; }float Merge(float a,float b){ return min(a,b); }float Outline(float a,float r){ return abs(a) - r; }vec3 Blend(vec3 backcolor,float shape){ return mix(shapecolor,shape));}HT for Web中《矢量手册》中自定义绘制的clock例籽实现代码以下:

function init() { dataModel = new ht.DataModel(); graphVIEw = new ht.graph.GraphVIEw(dataModel); vIEw = graphVIEw.getVIEw(); vIEw.classname = 'main'; document.body.appendChild(vIEw); window.addEventListener('resize',function(e) { graphVIEw.invalIDate(); },false); ht.Default.setCompType('clock-face',function(g,rect,comp,data,vIEw) { var cx = rect.x + rect.wIDth / 2; var cy = rect.y + rect.height / 2; var theta = 0; var r = Math.min(rect.wIDth,rect.height)/2 * 0.92; g.strokeStyle = "#137"; for (var i = 0; i < 60; i++) { g.beginPath(); g.arc( cx + Math.cos(theta) * r,cy + Math.sin(theta) * r,i % 5 === 0 ? 4 : 1,Math.PI * 2,true); g.closePath(); g.linewidth = i % 5 === 0 ? 2 : 1; g.stroke(); theta = theta + (6 * Math.PI / 180); } }); ht.Default.setimage('clock',{ wIDth: 500,height: 500,comps: [ { type: 'circle',relative: true,rect: [0,1,1],background: 'yellow',gradIEnt: 'linear.northeast' },{ type: 'clock-face',1] },{ type: function(g,vIEw) { // get current time var date = data.a('date'); if(!date){ return; } var hours = date.getHours(); var minutes = date.getMinutes(); var seconds = date.getSeconds(); hours = hours > 12 ? hours - 12 : hours; var hour = hours + minutes / 60; var minute = minutes + seconds / 60; var clockRadius = 250; // save current context g.save(); g.translate(clockRadius,clockRadius); g.beginPath(); // draw numbers g.Font = '36px Arial'; g.fillStyle = '#000'; g.textAlign = 'center'; g.textBaseline = 'mIDdle'; for (var n = 1; n <= 12; n++) { var theta = (n - 3) * (Math.PI * 2) / 12; var x = clockRadius * 0.75 * Math.cos(theta); var y = clockRadius * 0.75 * Math.sin(theta); g.fillText(n,x,y); } // draw hour g.save(); var theta = (hour - 3) * 2 * Math.PI / 12; g.rotate(theta); g.beginPath(); g.moveto(⑴5,⑸); g.lineto(⑴5,5); g.lineto(clockRadius * 0.5,1); g.lineto(clockRadius * 0.5,⑴); g.fill(); g.restore(); // draw minute g.save(); var theta = (minute - 15) * 2 * Math.PI / 60; g.rotate(theta); g.beginPath(); g.moveto(⑴5,⑷); g.lineto(⑴5,4); g.lineto(clockRadius * 0.8,1); g.lineto(clockRadius * 0.8,⑴); g.fill(); g.restore(); // draw second g.save(); var theta = (seconds - 15) * 2 * Math.PI / 60; g.rotate(theta); g.beginPath(); g.moveto(⑴5,⑶); g.lineto(⑴5,3); g.lineto(clockRadius * 0.9,1); g.lineto(clockRadius * 0.9,⑴); g.fillStyle = '#0f0'; g.fill(); g.restore(); g.restore(); } } ] }); var node = new ht.Node(); node.setposition(150,150); node.setSize(250,250); node.setimage('clock'); node.a('date',new Date()); node.s('image.stretch','centerUniform'); dataModel.add(node); graphVIEw.setEditable(true); setInterval(function(){ node.a('date',new Date()); },1000);}


总结

以上是内存溢出为你收集整理的纯Shading Language绘制HTML5时钟全部内容,希望文章能够帮你解决纯Shading Language绘制HTML5时钟所遇到的程序开发问题。

如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/web/1018889.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-05-23
下一篇 2022-05-23

发表评论

登录后才能评论

评论列表(0条)

保存