精华内容
下载资源
问答
  • 来源 |https://www.cnblogs.com/jr1993/p/4687877.html#top今天这篇文章带大家了解一下HTML5 canvas的线条线条属性。有一定的参...

    来源 | https://www.cnblogs.com/jr1993/p/4687877.html#top

    今天这篇文章带大家了解一下HTML5 canvas的线条及线条属性。有一定的参考价值,有需要的朋友可以参考一下,希望对大家有所帮助。

    创建 canvas

    首先创建一个canvas元素,我们只需要在html文件中加入这么一句代码:

    <canvas id="canvas">当前浏览器不支持canvas,请更换浏览器使用!</canvas>
    

    同时我们也可以通过canvas的标签属性width和height设置canvas画布的大小:

    <canvas id="canvas" width="800" height="800">当前浏览器不支持canvas,请更换浏览器使用!</canvas>
    

    当然,我们也可以通过js来设置canvas的宽高,下文会提到如何设置。

    接下来我们就在js中获取到该canvas元素,然后设置它的宽高,并获取到上下文的环境:

    var canvas = document.getElementById("canvas");//获取到canvas元素
    //设置宽高
    canvas.width = 800;
    canvas.height = 800;
    var context = canvas.getContext("2d");//获取上下文的环境
    

    接下来我们的所有操作都是基于这个context的上下文环境。

    现在画一条简单的直线:

    context.moveTo(100,100);
    context.lineTo(500,500);
    

    moveTo()方法表示一次绘制的起点坐标,lineTo()表示基于上一个坐标点到这个坐标点之间的直线连接。

    注意的是,canvas是基于状态的绘制,而不是基于对象的绘制。所以,上面代码都是状态的设置,我们还需要使用stroke()方法进行绘制:

    context.stroke();//绘制
    

    除此之外,我们还可以设置线条的一些基本属性:

    context.lineWidth = 8;//线条的宽度
    context.strokeStyle = "#333";//线条的颜色
    

    一个简单的绘制一条直线的完整例子:

    var canvas = document.getElementById("canvas");//获取到canvas元素
    //设置宽高
    canvas.width = 800;
    canvas.height = 800;
    var context = canvas.getContext("2d");//获取上下文的环境
    //canvas 是基于状态的绘制,而不是对象
    context.moveTo(100,100);
    context.lineTo(500,500);
    context.lineWidth = 8;//线条的宽度
    context.strokeStyle = "#333";//线条的颜色
    context.stroke();//绘制
    

    运行结果如下图:

    接下来我们绘制一个连续折线:

    context.moveTo(100,100);
    context.lineTo(500,100);
    context.lineTo(500,500);
    context.lineTo(100,500);
    

    运行结果如下:

    如果我们想要让这个折线闭合形成一个矩形的话,可以再设置context.lineTo(100,100);然而如果线条的宽度比较大的时候,就会出现一些瑕疵,这个的话大家自己试试看。

    所以标准的话应该使用context.closePath();这个知识点后面会讲到,这里大家可以先试试,看看运行结果是怎么样的。

    上面这个简单的例子我们是连续绘制的折线,也就是说可以一笔连续画完的折线。如果是多条间断的折线,那么我们就需要使用context.moveTo()来重新绘制一条折线的起点坐标:

    context.moveTo(100,200);
    context.lineTo(300,400);
    context.lineTo(100,600);
    
    
    context.moveTo(300,200);
    context.lineTo(500,400);
    context.lineTo(300,600);
    
    
    context.moveTo(500,200);
    context.lineTo(700,400);
    context.lineTo(500,600);
    

    运行结果如下:

    此时,如果我们想要绘制的这三条折线是不同颜色的,那该怎么办?一种常见的错误用法就是:

    context.moveTo(100,200);
    context.lineTo(300,400);
    context.lineTo(100,600);
    context.lineWidth = 8;
    context.strokeStyle = "red";
    context.stroke();//绘制context.moveTo(300,200);
    context.lineTo(500,400);
    context.lineTo(300,600);
    context.lineWidth = 8;
    context.strokeStyle = "green";
    context.stroke();//绘制context.moveTo(500,200);
    context.lineTo(700,400);
    context.lineTo(500,600);
    context.lineWidth = 8;
    context.strokeStyle = "blue";
    context.stroke();//绘制
    

    运行结果会是三条折线都是蓝色的。因为这里的第二条折线的strokeStyle属性会覆盖第一条折线的strokeStyle属性,而stroke()方法的执行会绘制当前所有的状态,所以第一条折线就变成绿色。

    同理,最终三条折线就都是蓝色。因此呢,这里就需要使用beginPath()方法来重新进行一次全新的绘制。

    context.lineWidth = 8;//线条的宽度context.beginPath();
    context.moveTo(100,200);
    context.lineTo(300,400);
    context.lineTo(100,600);
    context.strokeStyle = "red";
    context.stroke();//绘制context.beginPath();
    context.moveTo(300,200);
    context.lineTo(500,400);
    context.lineTo(300,600);
    context.strokeStyle = "green";
    context.stroke();//绘制context.beginPath();
    context.moveTo(500,200);
    context.lineTo(700,400);
    context.lineTo(500,600);
    context.strokeStyle = "blue";
    context.stroke();//绘制
    

    这里在每绘制一条折线的时候,都使用beginPath()方法来进行一次全新的路径绘制。此时再使用stroke()方法进行绘制的时候,就只会绘制beginPath()方法下面的状态。运行结果如下:

    从上面的代码我们可以看到:context.lineWidth = 8;放在了最前面,这是因为beginPath()方法不会将没有修改的属性变成默认值。

    比如这里的lineWidth,三条折线都是8,那么我们放在前面的话,在进行stroke()方法进行绘制的时候,都是会使用lineWidth = 8;来进行绘制。

    而需要修改的属性则在具体的路径绘制里进行修改,比如这里的线条颜色属性,每条折线的颜色都不一样,所以就需要各自设置。

    还有一点就是:此段代码中的moveTo()方法可以改成lineTo()方法:

    context.lineWidth = 8;//线条的宽度
    context.beginPath();
    context.lineTo(100,200);
    context.lineTo(300,400);
    context.lineTo(100,600);
    context.strokeStyle = "red";
    context.stroke();//绘制
    

    因为使用了beginPath()方法,就会对之前绘制的路径进行清空,但不会回到(0,0)原点。所以这里我们直接使用lineTo()方法同样能起到绘制起点的作用,但必须和beginPath()方法一起使用才能替换moveTo()方法。

    上面曾简单讲过context.closePath()方法,这里将具体展开介绍:context.closePath()方法和context.beginPath()方法一起使用,以绘制闭合的路径图形,这是绘制封闭多边形的标准做法。

    而且使用context.closePath()方法,最后一条线的绘制可以省略,它会自动帮我们连接到绘制起点以形成封闭的多边形。

    context.beginPath();
    context.moveTo(100,100);
    context.lineTo(500,100);
    context.lineTo(500,500);
    context.lineTo(100,500);
    context.closePath();
    context.lineWidth = 8;
    context.strokeStyle = "#333";
    context.stroke();
    

    运行结果如下:

    接下来我们介绍一下填充属性fillStyle和填充绘制方法fill():

    context.beginPath();
    context.moveTo(100,100);
    context.lineTo(500,100);
    context.lineTo(500,500);
    context.lineTo(100,500);
    context.closePath();
    context.lineWidth = 8;
    context.strokeStyle = "#333";
    context.stroke();
    context.fillStyle = "red";   //填充颜色context.fill(); //填充
    

    最后两行代码就是设置了填充的颜色(红色)和进行闭合图形的颜色填充,运行结果如下:


    可以看到图形的边框宽度比没有填充颜色的图形的边框宽度小,这是因为我们先绘制边框,再填充颜色。而实际上应该是先填充颜色,再绘制边框。

    而且fill()方法和stroke()方法的原理是一样的,都是基于当前状态进行绘制。

    所以,为了可读性,我们可以将属性设置放在一起,最后在使用fill()和stroke()方法:

    context.beginPath();
    context.moveTo(100,100);
    context.lineTo(500,100);
    context.lineTo(500,500);
    context.lineTo(100,500);
    context.closePath();
    context.lineWidth = 8;
    context.strokeStyle = "#333";
    context.fillStyle = "red";
    
    
    context.fill(); //先填充context.stroke(); //再绘制边框
    

    这次的运行结果:

    可以看到,这次的结果就是正确的了。

    对于绘制矩形这个很常用,那么我们就可以封装成函数,方便以后调用:

    drawRect(context,100,100,400,400,8,"#333","blue");
    
    
    function drawRect(cxt,x,y,width,height,borderWidth,borderColor,fillColor){
        cxt.beginPath();
        cxt.moveTo(x,y);
        cxt.lineTo(x+width,y);
        cxt.lineTo(x+width,y+height);
        cxt.lineTo(x,y+height);
        cxt.closePath();
        cxt.lineWidth = borderWidth;
        cxt.strokeStyle = borderColor;
        cxt.fillStyle = fillColor;
        cxt.fill(); 
        cxt.stroke(); 
    }
    

    同样的,运行结果也是正常的:

    但是呢,canvas API 提供了绘制矩形更加方便的方法:rect()方法用于规划矩形的路径,fillRect()方法在规划了矩形的路径之后还填充了矩形的颜色,而strokeRect()方法则绘制了矩形的边框。

    所以上面的函数若使用context.rect()方法可以简化为:

    function drawRect(cxt,x,y,width,height,borderWidth,borderColor,fillColor){
        cxt.beginPath();
        cxt.rect(x,y,width,height);
        cxt.closePath();
        cxt.lineWidth = borderWidth;
        cxt.strokeStyle = borderColor;
        cxt.fillStyle = fillColor;
        cxt.fill(); //先填充
        cxt.stroke(); //再绘制边框
    }
    

    而使用fillRect()和strokeRect()这两个方法则可以更加简单就实现:

    function drawRect(cxt,x,y,width,height,borderWidth,borderColor,fillColor){
        cxt.lineWidth = borderWidth;
        cxt.strokeStyle = borderColor;
        cxt.fillStyle = fillColor;
        cxt.fillRect(x,y,width,height);
        cxt.strokeRect(x,y,width,height);
    }
    

    此时如果我们绘制了两个矩形:

    drawRect(context,100,100,400,400,8,"#333","blue");
    drawRect(context,300,300,400,400,8,"#333","red");
    

    运行结果是这样的:

    可以看到,后绘制的矩形会盖在前绘制的矩形之上,当然得颜色不同才体现出来。

    此时我们将第二个矩形的填充颜色改一下:

    drawRect(context,300,300,400,400,8,"#333","rgba(255,0,0,0.5)");
    

    结果如下:

    可以看到第二个矩形的填充颜色是半透明的红色。那么就需要说明一下:fillStyle 和 strokeStyle 属性的颜色值可以是CSS3支持的任何一种形式:

    #ffffff
    #333
    red
    rgb(0,0,0)
    rgba(255,0,0,0.5)
    hsl(20,50%,50%)
    hsla(20,50%,60%,0.6)
    

    线段还有其他一些属性,接下来分别讲解:

    lineCap属性就是定义线段开头和结尾处的形状,此属性有三个属性值:butt(默认值),round,square 。

    通过代码来演示这三种效果:

    context.lineWidth = 50;
    context.strokeStyle = "#005588";
    
    
    context.beginPath();
    context.moveTo(100,200);
    context.lineTo(700,200);
    context.lineCap = "butt";
    context.stroke();
    
    
    context.beginPath();
    context.moveTo(100,400);
    context.lineTo(700,400);
    context.lineCap = "round";
    context.stroke();
    
    
    context.beginPath();
    context.moveTo(100,600);
    context.lineTo(700,600);
    context.lineCap = "square";
    context.stroke();
    

    这里画了三条线段,分别设置了不同的lineCap属性值,看看有什么不同:

    从结果可以看出来,使用round属性值会比默认值butt多出一个半圆的形状包在线段的开始和结尾处,而是用square属性值会在开始和结尾处多处半个方形,这就是它们的不同之处。

    其中,round对于我们绘制一些圆角效果的图形比较有用,但是它只对线条的开头和结尾处有效果,对于线段之间的连接处没有作用,这点需要注意。

    接下来我们来绘制一个五角星:

    先看一下效果图:

    我们要绘制一个这样的五角星,其实就是要绘制出十个顶点,而且这十个顶点是有规律可循的:

    从这个图可以看到,五角星的十个顶点可以分成两组,分别在外圆和内圆上的五个顶点,通过数学公式可以得知:a是18度,b是36度,故a+b=54度,有了一个角的度数,还有大小圆的半径,就可以根据三角函数公式求出顶点的坐标了,而且大小圆上的每个顶点之间的度数都是相差72度,那么我们就可以使用函数来绘制这个五角星:

    context.lineWidth = 10;
    context.strokeStyle = "#005588";
    drawStar(context,150,300,400,400,0);
    context.stroke();
    
    
    function drawStar(cxt,r,R,x,y,rotate){
        cxt.beginPath();
        for(var i = 0; i < 5; i++){
            cxt.lineTo(Math.cos((18 + i*72 - rotate)/180*Math.PI)*R + x,
                       -Math.sin((18 + i*72 - rotate)/180 * Math.PI)*R + y);
            cxt.lineTo(Math.cos((54 + i*72 - rotate)/180*Math.PI)*r + x,
                       -Math.sin((54 + i*72 - rotate)/180 * Math.PI)*r + y);
        }
        cxt.closePath();
    }
    

    至于这里面的公式,大家就自己想一下吧,其实就是正弦和余弦函数。drawStar()方法的参数分别是上下文环境,小圆半径,大圆半径,偏移量x,偏移量y,旋转角度。

    最后还有两个线条的属性:lineJoin 和 miterLimit

    lineJoin顾名思义就是线条与线条之间的连接方式,该属性有三个属性值:miter(默认值,尖角),bevel(衔接),round(圆角)。

    我们基于上面的五角星的例子,分别设置不同的lineJoin属性值,看看有什么不同:

    context.lineJoin = "bevel";
    

    context.lineJoin = "round";
    

    这些细微的差别还是大家自己试一下才有比较直观的感受,更能理解其中的用法。

    还有一个miterLimit属性,这个属性只有当lineJoin属性值是miter时才有用,默认值是10 。那么它到底是什么呢?

    我们通过代码来演示:

    context.lineWidth = 10;
    context.strokeStyle = "#005588";
    context.lineJoin = "miter";
    drawStar(context,30,300,400,400,0);
    context.stroke();
    

    我们将小圆的半径设置得比较小,此时我们的lineJoin是miter,即尖角。那么结果会是怎么样的呢?

    可以看到它毕竟变成bevel连接方法了,这就是miterLimit属性的影响,那么它究竟怎么计算的呢?看下图:

    可以看到,它的计算还是比较复杂的,所以canvas给我们一个经验值,也就是10,当然自己也可以修改miterLimit的值,得到自己想要的结果。

    好的,以上就是线条的全部内容!未完待续….

    本文完〜

    展开全文
  • 十种不同风格的网站导航菜单

    千次阅读 2012-07-19 17:58:19
    这些导航菜单来自于Dribbble网站,出自于世界各地的优秀设计师之手,涵盖了各种不同的风格,个个都非常精美。这里我将这些导航菜单展示出来,依据自己的想法总结它们的可取之处,演示其中一些用得上的技术方法。这样...

    这些导航菜单来自于Dribbble网站,出自于世界各地的优秀设计师之手,涵盖了各种不同的风格,个个都非常精美。这里我将这些导航菜单展示出来,依据自己的想法总结它们的可取之处,演示其中一些用得上的技术方法。这样比起简单粗略的看过就忘,更能在网页设计上让我们获取很多的灵感,提高我们的设计水平。

    一、木质页面上的抽屉创意

    idea.jpg

    不看这个案例话,你能想到将木质页面上的导航菜单做成类似这样抽屉式的样式吗?我自己反正是没想到,这就是值得学习的创意。我们不要一做导航菜单就想也不想的画一个直角或者圆角的矩形背景,将文字放在上面,用竖线隔开文字。这就落入了程式化的束缚之中了。

    看过这个案例后,你可以明白一点,就是根据已有的东西(这里是木质的页面材质)去展开思考元素样式的可能性。以这个案例为例,你可以思考一下在一个木质的页面上,如果能将抽屉的开合作为导航菜单的两种状态的话,那么暂时不考虑技术上的实现问题,还可以通过什么样式来实现?弹孔?刻痕?油漆?这里你就可以放开你的想象力了,这时候就是创意迸发的时刻。有了创意之后再考虑技术的问题,而不能让技术上能否实现限制住了我们的想象空间。

    关于木质材质的创建我建议使用素材来实现,高分辨率的素材不仅细节丰富而且风格多样,上图的材质属于比较细腻的风格,这样的素材其实有很多,一搜一大把,但是关键在于平时的积累,有了不同风格的素材在手边,实现这样的效果其实非常快。

    二、重复和对比原则的应用

    shot_1299591419.jpg

    垂直导航也是网页设计中常见的设计元素。在上面的设计中,我们能够看到设计师对于重复和对比原则的充分理解和应用。其中,一级导航的样式都很类似,左边是文字,右边是简洁的小图标,每个图标虽然不同,但是风格都是统一的,这正是多样性的重复原则。所以这些父导航按钮会让人感觉是平等而有某种联系的。而当前所在的位置以非常醒目饱和度较高的黄色显示,明显区别于一般状态的导航按钮,让访问者清楚的知道自己当前所处的位置,提高了用户体验并且增强了设计感。子导航既然和父导航不属于同一层次,那么必然要在视觉上和父导航有所区别,所以在背景颜色和文字颜色以及样式上你就能看到这种差别所在。

    另外,我将这个导航按钮重新做成了PSD文件,放在这里供大家下载,你可以学习一下如何使用杂色滤镜、图层样式来实现这样细腻的导航菜单,以及如何使用铅笔工具以像素级的标准画出文字旁边那个小小的三角图标并且还要给它应用图层样式。以下是PSD文件预览图。

    vertical-navigation.jpg下载

    三、每一个元素都是有用的

    a.png

    想象我们从一张空白的白色文档开始设计一个页面的导航。首先添加链接文字,为了让文字颜色和白色的页面对比不过于强烈刺眼,我们决定不用黑色而使用灰色。这里我们将文字行距拉开,让留白区域更多一些,目的是让页面保持透气感和干净的感觉。

    各个导航栏目如果只是文字的话看上去过于类似,所以为了让它们在保持相似性的同时而有所区别,我们给每一个栏目的左侧添加上了风格简洁的图标,选择这种风格的图标一是符合页面本身干净的感觉,另外一点的考虑是图片和文字内容的关联性。我们不打算让图标比文字还吸引眼球,所以我们让它们保持比文字还浅的灰色。白色的页面上如果仅仅放上导航内容的话感觉结构不够整齐,因为没有实际上的线条来束缚视线,所以这里我们给每一个导航栏目添加非常浅的灰色水平线和垂直水平线,这种隐隐约约的线条既可以加强排版,还不至于让页面看上去条条框框过多,阻碍视线的游走。

    接下来就是鼠标悬停的效果了,这要和菜单本身的状态有较大的视觉差别,所以这里我们将文字和背景颜色更改为清爽的绿色和灰色,灰色是为了让整个页面的颜色统一,而绿色是唯一跳出整个灰色页面的颜色。这样就让页面在颜色上有了亮点,而不至于让人感觉页面上灰蒙蒙的一片。背景的材质上添加了杂色,这样看上去更加柔和,而不是光亮的冷冰冰的感觉。这基本上就是我们设计这个导航的整个考虑过程。

    这样你就看到了,这里的每一个元素和细节的应用都是经过充分考虑的,而且没有一个多于的东西无缘无故的存在,这就是简洁风格的设计理念。

    四、强质感的高光风格

    appui.png

    这个例子中的导航和我上一篇日志《强质感高光风格网页欣赏及其表现手法总结》中提高的风格比较类似,技术方法也非常简单,你可以去那篇日志中下载我做好的PSD文件,学习一下如何实现这样的效果。

    五、温暖柔和的画面

    shot_1301178085.png

    导航菜单周围一圈略深于背景色的描边让导航和背景融合的更加自然。整个导航的颜色和底部的大约10个像素的阴影让整个导航条看上去更像是电脑键盘上的一个个按键。这个案例设计师提供了PSD文件,你可以自己尝试一下创建这样的导航效果。

    下载

    六、细节决定成败

    menu-notification.jpg

    这和苹果系统上程序图标上的数字提醒很像。虽然这样的数字提醒放在导航上非常漂亮,但是实际功能性却值得商榷,但它不妨碍我们学习到一点,那就是即使这样简单的导航,在细节上也是十分讲究的,从那小小的2字的圆形背景上你就能看得出来。图层样式中的高光、阴影、渐变、描边一个都不能少。另外为了和灰色页面的色调搭配,这些数字背景的红色、黄色和蓝色都选择了饱和度偏中间调的颜色,因为灰色本身也是介于黑色和白色中间的色调。

    下载

    七、有关主题的创意

    kol_dribbble.jpg

    这是一个有关电影剧场的网页设计。所以设计师在导航部分使用了这种类似于电影票的纸质的背景图片,并且添加上了水迹的笔刷效果,让细节更为丰富。在导航条的右下方,还加上了淡淡的阴影,让其和页面保持一定的距离,加强了导航菜单的纸质的感觉。有关这样的阴影的创建,你可以在《在Photoshop中创建内容盒阴影效果》这篇日志中找到详细的方法。和案例1类似,创建一个这样的关于电影剧场的网页设计,如果展开联想的话,你会有很多关于电影剧场的设计上的创意,这种以电影票为导航背景只是其中的一个例子而已。

    八、自然质朴的布制风格

    shot_1286904854.jpg

    两条水平的白色虚线和一条灰色的垂直线仿佛是缝在布上的线脚。这种风格给人一种自然以及手工的感觉。创建这样的线脚并不难,直接用文字工具键出虚线,调整字体、大小以及间距就可以了。关键点在于页面边缘弯折的那部分,要注意绿色带子弯折后的透视关系,需要将其向下移动一定的距离。

    九、让色彩从页面跳出

    vectips_navigation.png

    在偏向于黑色的页面背景上有这样鲜亮的绿色跳出会非常吸引视觉注意力。再加上好像用大头针钉在页面上的独特样式,更是和页面本身增强了对比,所以如果这样的下拉菜单展开的话,你会忍不住将鼠标移动到其它菜单上试试效果,如果同时你能关注到导航内容的话,设计者的目的就达到了。

    十、互补色营造鲜明视觉

    shot_1286921565.png

    细腻的斜纹背景创建起来非常简单,只需用铅笔工具以1像素的粗细创建好图案,保存后在图层样式中应用图案叠加就可以了。关于这种背景的创建我在之前写的《在Photoshop中创建多种样式的网格背景图案》这篇文章中详细讲过,你可以参考这篇日志自己动手创建。

    这里值得一提的是案例中的冷色背景色和暖色的文字和图标颜色的使用,橙色和青绿色属于互补色,青绿色作为背景色饱和度很低,而橙色的饱和度非常高,通过对比让图标和文字看上去非常醒目同时又非常和谐。所以如果你打算在设计中使用互补色的话,不要同时调高两种颜色的饱和度,这样会使视觉向两边拉扯,而应该有所主次,通过将一种颜色的饱和度降低,再加入相应的白色或者黑色和另外一种饱和度较高的颜色搭配,就像这个案例向我们展示的那样。

    原文:http://startwmlife.com/the-inspiration-of-ten-exquisite-navigation-menu-and-tips/


    展开全文
  • 每一笔形其实都有不同的面相,这也是特有的,在书本里面就就已经有详解。不论是男性还是女性,面相对于一个人来讲都非常的重要。因为能够代表自己的命运,虽然不能够全信,但是也能够为人生指引方向。周易学里面所...

    每一个人的鼻子形状都不同,其实比行有很多的说法。每一种笔形其实都有不同的面相,这也是特有的,在书本里面就就已经有详解。不论是男性还是女性,面相对于一个人来讲都非常的重要。因为能够代表自己的命运,虽然不能够全信,但是也能够为人生指引方向。周易学里面所说的面相其实是有一定的道理,并且在这一方面也有很多的能人对于推算也是非常的准确。

    一、鹰钩鼻、朝天鼻

    鹰钩鼻比较长,并且鼻子也很尖,稍稍有些往里勾,所以有些像鹰嘴。拥有这种鼻型的人其实非常的精明,可以说是人中龙凤;朝天鼻稍稍有些短,但是从正面观察能够看到一个人的鼻孔,并且鼻子比较厚,这一类人群的性格非常的憨厚,并且也非常的聪明。这种人的鼻子比较短,在正面可以看到鼻孔,显得比较憨厚。

    二、扁平鼻、龙鼻

    扁平鼻形状扁扁的,并且鼻翼的位置并不是很突出,所以轮廓看起来有些圆润。属于完美的鼻形,同时也属于一种完美的面相;龙鼻的鼻形在鼻翼两侧部分会有很多的肉肉,所以有些像动画片里面的龙鼻子。属于大富大贵之相。

    三、猩猩鼻、人中鼻

    猩猩鼻型稍稍有些向内收笼,所以为人的性格也有些内敛。从外观来观察,这种鼻型有点像大猩猩的鼻子。众所周知,大星星一般都会非常的聪明,所以此类人群也会比较聪明;人中鼻型根部会非常的直,从鼻子尖处一直到人中。这一类鼻型面相非常好,并且长相也很俊朗,一般都会大富大贵,生活也比较富裕。

    四、驼峰鼻、狮子鼻

    驼峰鼻是在鼻梁子的上面会有凸起,所以像骆驼的驼峰一样。这个鼻型也是因此而得名,这一类人群会比较任劳任怨,做事情非常认真;狮子鼻就是自己能够看见鼻翼,说明鼻翼两侧肉肉非常多,这一类人群命相也比较好,因为狮子本身就是森林里面的王,所以一般都能做大官。

    五、小翘鼻、蒜头鼻

    小翘鼻其实就是鼻尖处会向上翘,并且鼻翼两侧不会出现突出的情况,这一类比型看起来会温文尔雅,不论是男性女性都是温顺的性格;蒜头鼻在中国可以说非常的普遍,就是鼻翼以及鼻头都非常有肉,并且分布也很平均。这一类人群非常的普通,也大众化,映像一般般。

    六、犹太鼻、希腊鼻

    这一类比型有些像犹太人的鼻子,并且也很普遍。鼻子非常大,并且有些像下鼻头部分肉肉很多。这一类人群的命运也是一般般,不属于大富大贵,但是属于工薪;一般大多是希腊人才会有希腊鼻,因为鼻梁骨非常的高,并且也很直,这一类人群在财源上会非常的丰富。

    七、竹筒鼻、小兽鼻

    竹筒鼻就是鼻子的形状,很像竹筒,并且也很有肉。这类人的面相其实很一般,不属于大富大贵,也不属于工薪,但是一生劳碌;小兽鼻所指的就是鼻子非常的小,并且上面没有肉,看起来非常瘦,能够看出骨骼的线条,这一类人群印象也不错,一般女生都能嫁得好老公,而男生在事业上也很顺利。

    展开全文
  • 本文由@浅墨_毛星云出品,转载请注明出处 ...故障艺术(Glitch Art),作为赛博朋克(Cyberpunk)艺术风格的核心元素之一,是一是将数字设备的软硬件故障引起的破碎变形图像,经过艺术加工而成的一...

     

            本文由@浅墨_毛星云 出品,转载请注明出处  

            CSDN版文章链接: https://qianmo.blog.csdn.net/article/details/106753402

            知乎专栏版文章链接:https://zhuanlan.zhihu.com/p/148256756

     

    故障艺术(Glitch Art),作为赛博朋克(Cyberpunk)艺术风格的核心元素之一,是一种是将数字设备的软硬件故障引起的破碎变形图像,经过艺术加工而成的一种先锋视觉艺术表现形式。近年来,故障艺术已经成为了赛博朋克风格的电影和游戏作品中主要的艺术风格之一。

     

    图 《赛博朋克 2077》 带有强烈故障艺术风格的Logo @ CD Projekt @2019 E3展

     

    本文对十种主流故障艺术(Glitch Art)系列后处理算法的原理和实现方式进行了总结,对故障艺术风格的算法实现要点进行了提炼,并提供了对应算法在Unity引擎下的一个或多个版本的实现源码。

    这十种故障艺术(Glitch Art)后处理特效分别为:

    1. RGB颜色分离故障(RGB Split Glitch)

    2. 错位图块故障(Image Block Glitch)

    3. 错位线条故障(Line Block Glitch)

    4. 图块抖动故障(Tile Jitter Glitch)

    5. 扫描线抖动故障(Scan Line Jitter Glitch)

    6. 数字条纹故障(Digital Stripe Glitch)

    7. 模拟噪点故障(Analog Noise Glitch)

    8. 屏幕跳跃故障(Screen Jump Glitch)

    9. 屏幕抖动故障(Screen Shake Glitch)

    10. 波动抖动故障(Wave Jitter Glitch)

     

     

     

    关于XPL : Unity引擎的高品质后处理库

     

    另外,本文涉及的十种故障艺术(Glitch Art)后处理的实现源码,都收录于本人开源的后处理算法库XPL中。

    X-PostProcessing Libray,简称XPL,是本人开发的Unity引擎下的高品质开源后处理算法库,旨在提供业界主流的高品质后处理特效的完整解决方案,目前已完美支持Unity Post-processing Stack v2。后续也将提供对Unity引擎URP/LWRP/HDRP的兼容支持。

    【GitHub地址】: https://github.com/QianMo/X-PostProcessing-Library

     

    截止本文发表,目前已以开源的形式放出了17种图像模糊型后处理算法、10种像素化型后处理算法、9种边缘检测型后处理算法、17种故障艺术型后处理算法。而随着后续更多内容的公开,X-PostProcessing Libray将成型为一个具有100+种后处理特效的高品质后处理开源算法库。

     

    在开始正文之前,不妨先简单认识一下赛博朋克与故障艺术这两种带有强烈科技感的艺术风格,以及他们在电影和游戏行业中的应用情况。

     

     

     

     

    零、赛博朋克与故障艺术

     

     

    赛博朋克(Cyberpunk),最早起源于上世纪六七十年代,作为未来主义科幻小说/电影/游戏的一个品类,核心理念在于低端生活与高等科技的结合。人工智能、虚拟现实、基因工程、黑客技术、反乌托邦、电脑生化、都市与贫民窟、故障艺术、霓虹灯等都是赛博朋克的主流艺术表现形式。

    故障艺术(Glitch Art),一种是将数字设备的软硬件故障引起的破碎变形图像,经过艺术加工而成的一种先锋视觉艺术表现。故障艺术的艺术表现核心形式在于图像的失真、破碎、错位、形变,以及颜色的失真、错位,并伴有条纹图形的辅助。

    无论是电影领域的《黑客帝国》、《银翼杀手》、《银翼杀手2077》、《攻壳机动队》等作品,还是游戏领域的《赛博朋克2077》,《杀出重围》等作品,都带有非常浓厚的赛博朋克风格。而在这些作品中,都能找到故障艺术的身影。

     

    图 电影《攻壳机动队》中的故障艺术表现形式

     

    图 电影《银翼杀手2049》中的故障艺术表现形式

     

    图《赛博朋克2077》中的故障艺术表现形式 @ CD Projekt

     

    图 《看门狗2》中的故障艺术表现形式 @ Ubisoft

    这里也放一段包含多种故障艺术(Glitch Art)元素的《赛博朋克2077》 2019 E3展预告片段:

    【《赛博朋克2077》 2019 E3展预告片段】 https://www.youtube.com/watch?v=qIcTM8WXFjk

    以及一个发布于2013年的《赛博朋克2077》早期宣传片:

    【《赛博朋克2077》 2013预告片】 https://www.youtube.com/watch?v=P99qJGrPNLs


     

    OK,下面开始正文,对10种主流故障艺术(Glitch Art)后处理的算法以及原理进行总结。

     

     

     

     

    一、RGB颜色分离故障(RGB Split Glitch)

     

     

    RGB颜色分离故障(RGB Split Glitch),也称颜色偏移故障(Color Shift Glitch),是故障艺术中比较常见的表达形式之一。例如,抖音短视频App的Icon,即是RGB颜色分离故障艺术风格影响下的作品,给整体产品带来了潮流与年轻的气息:

     

    RGB颜色分离故障(RGB Split Glitch),实现算法的主要要点在于红绿蓝三个通道采用不同的uv偏移值进行分别采样。一般而言,会在RGB三个颜色通道中,选取一个通道采用原始uv值,另外两个通道进行uv抖动后再进行采样。一个经过性能优化的实现版本Shader代码如下:

    float randomNoise(float x, float y)
    {
    	return frac(sin(dot(float2(x, y), float2(12.9898, 78.233))) * 43758.5453);
    }
    
    half4 Frag_Horizontal(VaryingsDefault i) : SV_Target
    {
    	float splitAmount = _Indensity * randomNoise(_TimeX, 2);
    
    	half4 ColorR = SAMPLE_TEXTURE2D(_MainTex, sampler_MainTex, float2(i.texcoord.x + splitAmount, i.texcoord.y));
    	half4 ColorG = SAMPLE_TEXTURE2D(_MainTex, sampler_MainTex, i.texcoord);
    	half4 ColorB = SAMPLE_TEXTURE2D(_MainTex, sampler_MainTex, float2(i.texcoord.x - splitAmount, i.texcoord.y));
    
    	return half4(ColorR.r, ColorG.g, ColorB.b, 1);
    }
    

    上述代码中的randomNoise函数在之前的文章《高品质后处理:十种图像模糊算法的总结与实现》的粒状模糊(Grainy Blur)中有提到一个简化版的实现。本文在则采用了基于frac方法(返回输入数值的小数部分)和三角函数,配合dot方法的封装实现。

    上述代码,得到的渲染表现如下:

     

    详细实现源码可见:

    https://github.com/QianMo/X-PostProcessing-Library/tree/master/Assets/X-PostProcessing/Effects/GlitchRGBSplitV4

    另外,可以基于三角函数和pow方法控制抖动的间隔、幅度,以及抖动的曲线:

    half4 Frag_Horizontal(VaryingsDefault i): SV_Target
    {
    	float splitAmout = (1.0 + sin(_TimeX * 6.0)) * 0.5;
    	splitAmout *= 1.0 + sin(_TimeX * 16.0) * 0.5;
    	splitAmout *= 1.0 + sin(_TimeX * 19.0) * 0.5;
    	splitAmout *= 1.0 + sin(_TimeX * 27.0) * 0.5;
    	splitAmout = pow(splitAmout, _Amplitude);
    	splitAmout *= (0.05 * _Amount);
    	
    	half3 finalColor;
    	finalColor.r = SAMPLE_TEXTURE2D(_MainTex, sampler_MainTex, fixed2(i.texcoord.x + splitAmout, i.texcoord.y)).r;
    	finalColor.g = SAMPLE_TEXTURE2D(_MainTex, sampler_MainTex, i.texcoord).g;
    	finalColor.b = SAMPLE_TEXTURE2D(_MainTex, sampler_MainTex, fixed2(i.texcoord.x - splitAmout, i.texcoord.y)).b;
    	
    	finalColor *= (1.0 - splitAmout * 0.5);
    	
    	return half4(finalColor, 1.0);
    }
    

    得到的渲染表现如下:

     

    此版本的实现源码可见:

    https://github.com/QianMo/X-PostProcessing-Library/tree/master/Assets/X-PostProcessing/Effects/GlitchRGBSplitV2

    另外,在XPL(X-PostProcessing-Library)中供实现了5种不同版本的Glitch RGB Split后处理特效,以满足不同情形下RGB颜色抖动风格的需要。除了上文提到了两种,剩余三种的更多细节,篇幅原因这里就不展开了。以下整理了一个汇总列表,若有需要,可以直接转到XPL查看具体渲染表现以及源码:

    其中GlitchRGBSplitV1和GlitchRGBSplitV3具有相对而言较丰富可调参数:

     

     

    以下是其中的一些效果图:

     

     

     

     

     

     

    二、错位图块故障(Image Block Glitch)

     

     

    错位图块故障(Image Block Glitch)的核心要点在于生成随机强度且横纵交错的图块,随后基于图块的强度,进行uv的抖动采样,并可以加上RGB Split等元素提升渲染表现。

     

     

     

    2.1 基础版本的错位图块故障(Image Block Glitch)

     

    对于基础版本的实现,第一步,基于uv和噪声函数生成方格块。可以使用floor方法(对输入参数向下取整)以及低成本的噪声生成函数randomNoise进行实现,代码仅需一句:

    half2 block = randomNoise(floor(i.texcoord * _BlockSize));

    基于这句代码可以生成随机强度的均匀Block图块:

     

    第二步,基于第一步得到的均匀Block图块强度值做强度的二次筛选,增加随机性,代码如下:

    half displaceNoise = pow(block.x, 8.0) * pow(block.x, 3.0);

    得到的图块强度值如下:

     

    第三步,将经过强度二次筛选的Block图块强度值,作为噪声强度的系数,分别对G和B颜色通道进行采样。实现如下:

    half ColorR = SAMPLE_TEXTURE2D(_MainTex, sampler_MainTex, i.texcoord).r;
    half ColorG = SAMPLE_TEXTURE2D(_MainTex, sampler_MainTex, i.texcoord + float2(displaceNoise * 0.05 * randomNoise(7.0), 0.0)).g;
    half ColorB = SAMPLE_TEXTURE2D(_MainTex, sampler_MainTex, i.texcoord - float2(displaceNoise * 0.05 * randomNoise(13.0), 0.0)).b;
    
    return half4(ColorR, ColorG, ColorB, 1.0);
    

    可以得到如下基础的错位图块故障(Image Block Glitch)的渲染表现:

     

    以上基础版本的错位图块故障(Image Block Glitch)实现的完整源代码可见:

    https://github.com/QianMo/X-PostProcessing-Library/tree/master/Assets/X-PostProcessing/Effects/GlitchImageBlockV3

     

     

     

    2.2 结合RGB Split的错位图块故障(Image Block Glitch)

     

    另外,也可以加上RGB Split的元素,得到更丰富的渲染表现,实现代码如下:

    inline float randomNoise(float2 seed)
    {
    	return frac(sin(dot(seed * floor(_Time.y * _Speed), float2(17.13, 3.71))) * 43758.5453123);
    }
    
    inline float randomNoise(float seed)
    {
    	return randomNoise(float2(seed, 1.0));
    }
    
    half4 Frag(VaryingsDefault i) : SV_Target
    {
    	half2 block = randomNoise(floor(i.texcoord * _BlockSize));
    
    	float displaceNoise = pow(block.x, 8.0) * pow(block.x, 3.0);
    	float splitRGBNoise = pow(randomNoise(7.2341), 17.0);
    	float offsetX = displaceNoise - splitRGBNoise * _MaxRGBSplitX;
    	float offsetY = displaceNoise - splitRGBNoise * _MaxRGBSplitY;
    
    	float noiseX = 0.05 * randomNoise(13.0);
    	float noiseY = 0.05 * randomNoise(7.0);
    	float2 offset = float2(offsetX * noiseX, offsetY* noiseY);
    
    	half4 colorR = SAMPLE_TEXTURE2D(_MainTex, sampler_MainTex, i.texcoord);
    	half4 colorG = SAMPLE_TEXTURE2D(_MainTex, sampler_MainTex, i.texcoord + offset);
    	half4 colorB = SAMPLE_TEXTURE2D(_MainTex, sampler_MainTex, i.texcoord - offset);
    
    	return half4(colorR.r , colorG.g, colorB.z, (colorR.a + colorG.a + colorB.a));
    }
    

    对应的渲染表现如下:

     

    实现的完整源代码可见:

    https://github.com/QianMo/X-PostProcessing-Library/tree/master/Assets/X-PostProcessing/Effects/GlitchImageBlockV4

     

     

     

    2.3 进阶版的错位图块故障(Image Block Glitch)

     

    进阶版的Image Block Glitch,核心要点在于双层blockLayer的生成,以及配合噪声生成函数randomNoise进行双层强度的二次筛选,对应的实现代码如下:

    	float2 blockLayer1 = floor(uv * float2(_BlockLayer1_U, _BlockLayer1_V));
    	float2 blockLayer2 = floor(uv * float2(_BlockLayer2_U, _BlockLayer2_V));
    	
    	float lineNoise1 = pow(randomNoise(blockLayer1), _BlockLayer1_Indensity);
    	float lineNoise2 = pow(randomNoise(blockLayer2), _BlockLayer2_Indensity);
    	float RGBSplitNoise = pow(randomNoise(5.1379), 7.1) * _RGBSplit_Indensity;
    	float lineNoise = lineNoise1 * lineNoise2 * _Offset  - RGBSplitNoise;
    

    上述代码可以得到更加丰富的Block图块强度:

     

    最后,基于此Block强度进行RGB通道的分别采样,可以得到更加多样的错位图块故障(Image Block Glitch)渲染表现:

     

    上述完整的实现代码可见:

    https://github.com/QianMo/X-PostProcessing-Library/tree/master/Assets/X-PostProcessing/Effects/GlitchImageBlock

    此版本的Image Block Glitch参数较为丰富,可以根据需要,调出各种风格的Image Block渲染表现:

     

    同样,在XPL(X-PostProcessing-Library)中分别实现了4种不同版本的Glitch Image Block后处理特效,以满足不同情形下的需要。部分算法的源码实现链接上文中已经有贴出一部分,这里是一个汇总列表:

     

     

     

     

     

    三、错位线条故障(Line Block Glitch)

     

    错位线条故障(Line Block Glitch)具有较强的表现力,在Glitch系列特效中的出镜率也较高。

     

     

    该算法的实现思路在于随机宽度线条的生成。我们一步一步来,先从生成均匀宽度线条开始:

    float trunc(float x, float num_levels)
    {
        return floor(x * num_levels) / num_levels;
    }
    
    //生成随机强度梯度线条
    float truncTime = trunc(_TimeX, 4.0);		
    float uv_trunc = randomNoise(trunc(uv.yy, float2(8, 8)) + 100.0 * truncTime);
    

    基于trunc函数以及randomNoise函数,配合上述调用代码,即可得到如下均匀宽度线条:

     

    接着,使用如下代码,将均匀渐变线条转为随机梯度的等宽线条:

    float uv_randomTrunc = 6.0 * trunc(_TimeX, 24.0 * uv_trunc);

     

    然后,将随机梯度的等宽线条,经过多次randomNoise操作,转换为随机梯度的非等宽线条:

    //生成随机梯度的非等宽线条
    float blockLine_random = 0.5 * randomNoise(trunc(uv.yy + uv_randomTrunc, float2(8 * _LinesWidth, 8 * _LinesWidth)));
    blockLine_random += 0.5 * randomNoise(trunc(uv.yy + uv_randomTrunc, float2(7, 7)));
    blockLine_random = blockLine_random * 2.0 - 1.0;	
    blockLine_random = sign(blockLine_random) * saturate((abs(blockLine_random) - _Amount) / (0.4));
    blockLine_random = lerp(0, blockLine_random, _Offset);	
    

    可以得到如下的渲染表现:

     

    接着,通过随机梯度的非等宽线条,去抖动uv采样生成源色调的blockLine Glitch:

    // 生成源色调的blockLine Glitch
    float2 uv_blockLine = uv;
    uv_blockLine = saturate(uv_blockLine + float2(0.1 * blockLine_random, 0));
    float4 blockLineColor = SAMPLE_TEXTURE2D(_MainTex, sampler_MainTex, abs(uv_blockLine));
    

    对应的渲染表现如下:

     

    最终,将RGB颜色转换到YUV空间,进行色度(Chrominance)和浓度(Chroma)的偏移,得到最终的渲染表现:

    // 将RGB转到YUV空间,并做色调偏移
    // RGB -> YUV
    float3 blockLineColor_yuv = rgb2yuv(blockLineColor.rgb);
    // adjust Chrominance | 色度
    blockLineColor_yuv.y /= 1.0 - 3.0 * abs(blockLine_random) * saturate(0.5 - blockLine_random);
    // adjust Chroma | 浓度
    blockLineColor_yuv.z += 0.125 * blockLine_random * saturate(blockLine_random - 0.5);
    float3 blockLineColor_rgb = yuv2rgb(blockLineColor_yuv);
    
    // 与源场景图进行混合
    float4 sceneColor = SAMPLE_TEXTURE2D(_MainTex, sampler_MainTex, i.texcoord);
    return lerp(sceneColor, float4(blockLineColor_rgb, blockLineColor.a), _Alpha);

    最终的渲染表现如下:

     

    除了水平方向的Line Block,竖直方向的表现也独具特色:

     

    当然,也可以将上述渲染效果与原始场景图进行插值混合,得到不同强度的渲染表现。

    XPL中实现的错位线条故障(Line Block Glitch)后处理,有7个可供定制调节的参数:

     

    错位线条故障(Line Block Glitch)的完整的源代码实现可见:

    https://github.com/QianMo/X-PostProcessing-Library/tree/master/Assets/X-PostProcessing/Effects/GlitchLineBlock

     

     

     

     

    四、图块抖动故障(Tile Jitter Glitch)

     

    图块抖动故障 (Tile Jitter Glitch)模拟了屏幕信号的块状抖动传输故障。

     

    其核心算法思路在于基于uv的分层抖动。可以采用取余数的形式(fmod(x,y)方法可返回x/y的余数)来对uv进行分层,且对于层内的uv数值,进行三角函数形式的抖动。

    核心实现Shader代码如下:

    	#if USING_FREQUENCY_INFINITE
    		strength = 1;
    	#else
    		strength = 0.5 + 0.5 * cos(_Time.y * _Frequency);
    	#endif
    	if(fmod(uv.y * _SplittingNumber, 2) < 1.0)
    	{
    		#if JITTER_DIRECTION_HORIZONTAL
    			uv.x += pixelSizeX * cos(_Time.y * _JitterSpeed) * _JitterAmount * strength;
    		#else
    			uv.y += pixelSizeX * cos(_Time.y * _JitterSpeed) * _JitterAmount * strength;
    		#endif
    	}
    

    上述代码经过计算后,得到的uv强度值如下:

     

    得到上述分块抖动的uv后,便可以作为uv输入,对最终的场景图进行采样:

    half4 sceneColor = SAMPLE_TEXTURE2D(_MainTex, sampler_MainTex, uv);
    

     

    上图为左右抖动的表现,这边也有上下抖动的表现,以及左右分层+上下抖动,左右分层+左右抖动的各种不同表现:

     

     

     

    图块抖动故障 ( Glitch Tile Jitter) 后处理特效可调的参数同样也比较丰富,XPL内实现的此特效的可调参数面板如下:

     

    图块抖动故障 ( Glitch Tile Jitter)完整的实现源代码可见:

    https://github.com/QianMo/X-PostProcessing-Library/tree/master/Assets/X-PostProcessing/Effects/GlitchTileJitter

     

     

     

     

    五、扫描线抖动故障(Scan Line Jitter Glitch)

     

    扫描线抖动故障(Scan Line Jitter Glitch)算法较简单,但是得到的渲染表现却非常具有冲击力:

     

    一个比较直接的实现是直接对横向或者纵向UV进行基于noise的抖动,Shader实现代码如下:

    float randomNoise(float x, float y)
    {
    	return frac(sin(dot(float2(x, y), float2(12.9898, 78.233))) * 43758.5453);
    }
    
    half4 Frag_Horizontal(VaryingsDefault i): SV_Target
    {
    	
    	float jitter = randomNoise(i.texcoord.y, _Time.x) * 2 - 1;
    	jitter *= step(_ScanLineJitter.y, abs(jitter)) * _ScanLineJitter.x;
    	
    	half4 sceneColor = SAMPLE_TEXTURE2D(_MainTex, sampler_MainTex, frac(i.texcoord + float2(jitter, 0)));
    	
    	return sceneColor;
    }
    

    得到的渲染表现如下:

     

    也可以从竖直方向进行uv的抖动: 

    扫描线抖动故障(Scan Line Jitter Glitch)完整的实现源代码可见:

    https://github.com/QianMo/X-PostProcessing-Library/tree/master/Assets/X-PostProcessing/Effects/GlitchScanLineJitter

     

     

     

     

    六、数字条纹故障(Digital Stripe Glitch)

     

    数字条纹故障(Digital Stripe Glitch)同样是出镜率较高的Glitch系后处理特效之一。例如在《赛博朋克2077》的gameplay中,就可以到它的身影:

     

    图 《赛博朋克2077》中的数字条纹故障(Digital Stripe Glitch)特效 @ CD Projekt

    数字条纹故障(Digital Stripe Glitch)需在Runtime层完成noise Texture的生成,然后传入GPU中进行最终的运算和渲染呈现。

    Runtime的核心思路为基于随机数进行随机颜色条纹贴图的生成,实现代码如下:

    for (int y = 0; y < _noiseTexture.height; y++)
    {
        for (int x = 0; x < _noiseTexture.width; x++)
        {
            //随机值若大于给定strip随机阈值,重新随机颜色
            if (UnityEngine.Random.value > stripLength)
            {
                color = XPostProcessingUtility.RandomColor();
            }
            //设置贴图像素值
            _noiseTexture.SetPixel(x, y, color);
        }
    }
    

    生成的图片如下:

     

    Shader层面的实现则分为两个主要部分,分别是uv偏移,以及可选的基于废弃帧的插值不足:

    half4 Frag(VaryingsDefault i): SV_Target
    {
    	// 基础数据准备
    	 half4 stripNoise = SAMPLE_TEXTURE2D(_NoiseTex, sampler_NoiseTex, i.texcoord);
    	 half threshold = 1.001 - _Indensity * 1.001;
    
    	// uv偏移
    	half uvShift = step(threshold, pow(abs(stripNoise.x), 3));
    	float2 uv = frac(i.texcoord + stripNoise.yz * uvShift);
    	half4 source = SAMPLE_TEXTURE2D(_MainTex, sampler_MainTex, uv);
    
        #ifndef NEED_TRASH_FRAME
    	    return source;
        #endif 	
    
    	// 基于废弃帧插值
    	half stripIndensity = step(threshold, pow(abs(stripNoise.w), 3)) * _StripColorAdjustIndensity;
    	half3 color = lerp(source, _StripColorAdjustColor, stripIndensity).rgb;
    	return float4(color, source.a);
    }
    

    得到的不进行废弃帧插值的渲染表现如下:

     

    进行废弃帧插值的渲染表现如下。除了下图中采用的类似反色的偏移颜色,也可以实现出基于RGB颜色随机,或者进行颜色空间转换后的色度校正后的偏移颜色:

     

    数字条纹故障(Digital Stripe Glitch)后处理完整的实现源码可见:

    https://github.com/QianMo/X-PostProcessing-Library/tree/master/Assets/X-PostProcessing/Effects/GlitchDigitalStripe

     

     

     

     

    七、模拟噪点故障(Analog Noise Glitch)

     

     

    模拟噪点故障(Analog Noise Glitch)的主要思路,在于用noise去扰动原先场景图的颜色值。一种常规实现的核心代码如下:

    float noiseX = randomNoise(_TimeX * _Speed + i.texcoord / float2(-213, 5.53));
    float noiseY = randomNoise(_TimeX * _Speed - i.texcoord / float2(213, -5.53));
    float noiseZ = randomNoise(_TimeX * _Speed + i.texcoord / float2(213, 5.53));
    
    sceneColor.rgb += 0.25 * float3(noiseX,noiseY,noiseZ) - 0.125;
    

    需要注意,0.25 * float3(noiseX,noiseY,noiseZ) - 0.125这句代码中的系数0.25和-0.125的作用,是让noise扰动后的画面的平均亮度和原先场景场景图相同,不能省略。但0.25和0.125两个系数可以进行合适的等幅度缩放,相对比例不变即可。

    通过以上代码,可以得到如下带非均匀噪声的渲染表现:

     

    另外,还可以加入greyScale灰度抖动,当某一刻的随机强度值大于亮度抖动阈值时,将原先的RGB颜色对应的luminance强度,呈现出黑白灰度的表现:

    half luminance = dot(noiseColor.rgb, fixed3(0.22, 0.707, 0.071));
    if (randomNoise(float2(_TimeX * _Speed, _TimeX * _Speed)) > _LuminanceJitterThreshold)
    {
        noiseColor = float4(luminance, luminance, luminance, luminance);
    }
    

    最终,将noise扰动和随机灰度抖动两个特性相结合,得到Glitch Analog Noise最终的渲染表现:

     

    模拟噪点故障(Analog Noise Glitch)完整的实现源码可见:

    https://github.com/QianMo/X-PostProcessing-Library/tree/master/Assets/X-PostProcessing/Effects/GlitchAnalogNoise

     

     

     

     

    八、屏幕跳跃故障(Screen Jump Glitch)

     

     

    屏幕跳跃故障(Screen Jump Glitch)的算法原理在于取经过时间校正后的uv数值的小数部分,并于原始uv插值,得到均匀梯度式扰动屏幕空间uv,再用此uv进行采样即可得到跳动画面的表现。核心实现Shader代码如下:

    half4 Frag_Vertical(VaryingsDefault i): SV_Target
    {
    	
    	float jump = lerp(i.texcoord.y, frac(i.texcoord.y + _JumpTime), _JumpIndensity);		
    	half4 sceneColor = SAMPLE_TEXTURE2D(_MainTex, sampler_MainTex, frac(float2(i.texcoord.x, jump)));	
    	return sceneColor;
    }
    

    其中,扰动后的uv强度分布,随时间变化的数值如下:

     

    基于此uv进行采样,得到的渲染表现如下:

     

    以上为竖直方向的阶梯式uv采样,当然,我们也可以进行水平方向的阶梯式采样:

    half4 Frag_Horizontal(VaryingsDefault i): SV_Target
    {		
    	float jump = lerp(i.texcoord.x, frac(i.texcoord.x + _JumpTime), _JumpIndensity);	
    	half4 sceneColor = SAMPLE_TEXTURE2D(_MainTex, sampler_MainTex, frac(float2(jump, i.texcoord.y)));		
    	return sceneColor;
    }
    

    得到的渲染表现如下:

     

    屏幕跳跃故障(Screen Jump Glitch)完整的实现源码可见:

    https://github.com/QianMo/X-PostProcessing-Library/tree/master/Assets/X-PostProcessing/Effects/GlitchScreenJump

     

     

     

     

    九、屏幕抖动故障(Screen Shake Glitch)

     

     

    类似上文的Screen Jump,Screen Shake屏幕抖动的算法原理也在于对屏幕空间uv的抖动,但不同的是,Screen Shake屏幕抖动需采用noise噪声函数来随机扰动uv,而不是均匀梯度式的形式。核心实现代码如下:

    half4 Frag_Horizontal(VaryingsDefault i): SV_Target
    {
    	float shake = (randomNoise(_Time.x, 2) - 0.5) * _ScreenShake;
    	
    	half4 sceneColor = SAMPLE_TEXTURE2D(_MainTex, sampler_MainTex, frac(float2(i.texcoord.x + shake, i.texcoord.y)));
    	
    	return sceneColor;
    }
    

    得到扰动uv的可视化强度值如下:

     

    渲染表现则如下:

     

    同样,也可以做竖直方向的抖动:

    half4 Frag_Vertical(VaryingsDefault i): SV_Target
    {
    	
    	float shake = (randomNoise(_Time.x, 2) - 0.5) * _ScreenShake;
    	
    	half4 sceneColor = SAMPLE_TEXTURE2D(_MainTex, sampler_MainTex, frac(float2(i.texcoord.x, i.texcoord.y + shake)));
    	
    	return sceneColor;
    }
    

     

    屏幕抖动故障(Screen Shake Glitch)完整的实现源码可见:

    https://github.com/QianMo/X-PostProcessing-Library/tree/master/Assets/X-PostProcessing/Effects/GlitchScreenShake

     

     

     

    十、波动抖动故障(Wave Jitter Glitch)

     

    波动抖动故障(Wave Jitter Glitch)相较于上述的9种Glitch算法而言,用到了更为复杂的噪声生成函数。

     

     

    10.1 噪声生成函数库 XNoiseLibrary

     

    对此,XPL参考了paper《Simplex noise demystified 》webgl-noise库NoiseShader库,实现一个单文件版的多维度噪声生成库 [XNoiseLibrary]

    XNoiseLibrary具有如下三种类型的Noise噪声生成函数:

    • 2D/3D/4D Simplex Noise

    • 2D/3D textureless classic Noise

    • Re-oriented 4 / 8-Point BCC Noise

    XNoiseLibrary的优势在于使用较为方便,直接include单个文件XNoiseLibrary.hlsl即可进行其中封装的多版本噪声函数的调用。

    XNoiseLibrary的实现源码可见:

    https://github.com/QianMo/X-PostProcessing-Library/blob/master/Assets/X-PostProcessing/Shaders/XNoiseLibrary.hlsl

     

     

    10.2 波动抖动故障(Wave Jitter Glitch)的实现算法

     

    OK,回到我们的波动抖动故障(Wave Jitter Glitch)后处理中来。

    波动抖动故障(Wave Jitter Glitch)后处理的核心思路是用双层的noise实现波浪形扭动uv,核心代码如下:

    float uv_y = i.texcoord.y * _Resolution.y;
    float noise_wave_1 = snoise(float2(uv_y * 0.01, _Time.y * _Speed * 20)) * (strength * _Amount * 32.0);
    float noise_wave_2 = snoise(float2(uv_y * 0.02, _Time.y * _Speed * 10)) * (strength * _Amount * 4.0);
    float noise_wave_x = noise_wave_1 / _Resolution.x;
    float uv_x = i.texcoord.x + noise_wave_x;
    
    float4 color = SAMPLE_TEXTURE2D(_MainTex, sampler_MainTex, float2(uv_x, i.texcoord.y));
    

    若是单层的noise波浪,表现力会稍弱,具体表现如下:

     

    而双层的noise波浪,表现力更强,具体表现如下:

     

    所以XPL中的Wave Jitter实现,采用了双层的形式。

    有了基于双层noise的Wave Jitter Glitch表现,还可以加上RGB Split算法,进一步提升表现力:

    float4 Frag_Horizontal(VaryingsDefault i): SV_Target
    {
    	half strength = 0.0;
    	#if USING_FREQUENCY_INFINITE
    		strength = 1;
    	#else
    		strength = 0.5 + 0.5 *cos(_Time.y * _Frequency);
    	#endif
    	
    	// Prepare UV
    	float uv_y = i.texcoord.y * _Resolution.y;
    	float noise_wave_1 = snoise(float2(uv_y * 0.01, _Time.y * _Speed * 20)) * (strength * _Amount * 32.0);
    	float noise_wave_2 = snoise(float2(uv_y * 0.02, _Time.y * _Speed * 10)) * (strength * _Amount * 4.0);
    	float noise_wave_x = noise_wave_1 * noise_wave_2 / _Resolution.x;
    	float uv_x = i.texcoord.x + noise_wave_x;
    
    	float rgbSplit_uv_x = (_RGBSplit * 50 + (20.0 * strength + 1.0)) * noise_wave_x / _Resolution.x;
    
    	// Sample RGB Color
    	half4 colorG = SAMPLE_TEXTURE2D(_MainTex, sampler_MainTex, float2(uv_x, i.texcoord.y));
    	half4 colorRB = SAMPLE_TEXTURE2D(_MainTex, sampler_MainTex, float2(uv_x + rgbSplit_uv_x, i.texcoord.y));
    	
    	return  half4(colorRB.r, colorG.g, colorRB.b, colorRB.a + colorG.a);
    }
    

    得到的渲染表现如下:

     

    当然,除了横向的Wave Jitter,纵向的Wave Jitter也具有不错的效果:

     

    波动抖动故障 ( Glitch Tile Jitter) 后处理特效可调参数也比较丰富,XPL内实现的此特效的可调参数面板如下:

     

    波动抖动故障(Wave Jitter Glitch)详细的实现源码,可见:

    https://github.com/QianMo/X-PostProcessing-Library/tree/master/Assets/X-PostProcessing/Effects/GlitchWaveJitter

     

     

     

    总结

     

    故障艺术追求“故障”带来的独特美感。近年来,故障艺术已经成为了赛博朋克风格电影和游戏作品中的核心艺术风格之一。而随着各种相关影视作品和游戏作品的不断发布,故障艺术的表现风格也引起了电商、综艺、快消等行业的广泛效仿。

    在看完上述十种不同的故障艺术算法后,我们可以提炼一下,若要在屏幕空间实现故障艺术风格的渲染表现,算法核心在于四点:

    • 噪声函数的选择:噪声函数是生成各式的干扰信号的源头。

    • uv抖动方式的选择:将噪声函数作用于屏幕空间uv后,基于新的uv进行采样,以产生故障的抖动表现。

    • 采样通道的选择:对RGB分别采样,或者选取特定通道进行采样,以实现多种风格的故障表现。

    • 颜色空间的转换:善用YUV、CMY、HSV、YIQ、YCbCr 、YC1C2等空间与RGB空间之间的转换,以实现多种风格的故障表现。

    熟知上述四种故障艺术的算法要点,加上一点创意,配合周边算法,则可以创造出更多富有表现力的故障艺术特效。

     

     

     

    Reference

     

    [1] Jackson R. The Glitch Aesthetic[J]. 2011. https://scholarworks.gsu.edu/cgi/viewcontent.cgi?article=1081&context=communication_theses

    [2] den Heijer E. Evolving glitch art[C]//International Conference on Evolutionary and Biologically Inspired Music and Art. Springer, Berlin, Heidelberg, 2013: 109-120.

    [3] https://zh.wikipedia.org/wiki/%E8%B5%9B%E5%8D%9A%E6%9C%8B%E5%85%8B

    [4] https://github.com/keijiro/KinoGlitch

    [5] https://github.com/ashima/webgl-noise

    [6] https://github.com/keijiro/NoiseShader

    [7] https://wallpaperswise.com/new-20-blade-runner-wallpapers/

    [8] http://www.itn.liu.se/\~stegu/simplexnoise/simplexnoise.pdf

    [9] 题图来自《Cyberpunk 2077》

    展开全文
  • 你有数据,还想对数据提问,创建图表或图形可以帮您,把数据转化成有效的可视化形式(任何种类的图表或图形)是让数据发挥作用的第一步。...如果数值数据能够顺畅归入不同类别,那么条形图就尤为有效,便于您快速...
  • matlab|plot线条属性各类使用与讲解

    千次阅读 2020-07-13 09:02:24
    本博文源于matlab基础,主要讲解plot线条属性的使用。相信大家接触过matlab会明白,没接触过线条属性画图是这样子的:
  • 接下来我们来绘制一个五角星: 先看一下效果图: 我们要绘制一个这样的五角星,其实就是要绘制出个顶点,而且这个顶点是有规律可循的: 从这个图可以看到,五角星的个顶点可以分成两组,分别在外圆和内圆上的...
  • 有一人们喜闻乐见的说法是,外星访客已经光顾过地球并且帮助我们建造了一些历史遗迹,比如巨石阵,纳斯卡线条以及埃及金字塔。他们或许也留下了一些技术帮助人类进步。 © Dean Ellis 6. 又或者,他们已经来过...
  • “自由曲线”是个铅笔绘图工具,可以用“任意多边形”工具中的其中一操作方法代替。“单箭头”和“双箭头”工具则可以用直线工具代替,方法是:画出直线后,在“设置自选图形格式”中选择直线的端点(始端或末端)为...
  • 可视化图表种类如此之多,什么场景下应该用什么图表展示,是一个让人头秃的难题。...适合用来快速检视数据集中不同类别的分布和比例,并与其他数据集的分布和比例进行比较,让人更容易找出当中模式。 点数
  • 生活中,人脑对很多事物都形成了条件反射,比如数字,习惯了进制的我们可以很方便的对数字25、27进行大小比较和数值运算,却很难对二进制数字11001、11011有直观的感受。其实想要弄清楚这些进制很简单,进制各位...
  • 每个人在待人接物上有着不同的风格,有的人豪放如张飞,有的细腻如黛玉,有人纠结于毫末之间的东西,有人致力于宏观的把握。俗话说:“一猪生九崽,连母个样。”说的就是这样的道理。人与人之间,不仅仅是外在有着...
  • 所以,我们有必要了解不同风格的装修,将自己的需求弄清楚,这样装出来的房子才不会变成四不像!一、北欧简约风格风格特色:简洁和实用是现代简约风格的基本特点,强调功能性设计,线条简约流畅,色彩对比...
  • 转载自:http://www.zhaoyanpeng.cn/archives/237当需要对同一曲线不同参数下进行模拟时需要不同的颜色来加以区分:上例根据RGB颜色,来实现不同颜色曲线的组合,考虑到matlab画图中,颜色分量是以1/255的步长变化的,...
  • 唐文斌:软硬件结合这件事情有两种不同的理解: 第一种理解,因为软件卖不上价钱,所以你要带着硬件一起卖,你就卖上价钱了,你有收入。 第二种理解,你只有软硬件的co-design(协同设计),在一起设计,才能变成更...
  • 你可能想看一下关于adding a line to an image matrix的SO问题的my answer.这是一个类似的例子,我在答案中有一个这样的例子,这将使一行从行和列索引(10,10)运行到(240,120) :img = imread('cameraman.tif');...
  • 情感目标:通过收集不同直线、曲线材料进行创作,培养学生注意观察生活细节的好习惯和热爱生活的情感.教学重点:引导学生欣赏、观察,使学生认识直线、曲线在画面中的作用,教学难点:利用身边材料的...
  • 运筹优化()--整数规划求解

    万次阅读 2019-01-17 21:50:21
    为了克服上述缺点,本节介绍的割平面法则采用另一切割办法,既要切割掉非整数解域,又不希望对原问题进行分枝。 割平面法的基础仍然是用解线性规划的方法去解整数规划问题。首先不考虑变量为整数这一约束条件。...
  • Steger算法是一精度较高的直线提取算法,可以亚像素级提取图像中线条的中心。笔者在学习过程中因没有在网络上找到较为通俗的原理解释,因此写下这篇文章,希望能让读者快速了解该算法的原理。笔者学术水平有限,...
  • 用Enterprise Architecture绘制十种UML图

    千次阅读 2014-06-06 12:33:37
    UML课程作业要求绘制十种UML图,选择Enterprise Architecture作为绘图工具,每次绘制图都要上网找教程,感觉十分麻烦,而且有些图没有找到具体教程,靠自己摸索找到了绘制方法,现在总结一下使用Enterprise ...
  • 前一篇文章讲述了分类算法的原理知识级案例,包括决策树、KNN、SVM,并通过详细的分类对比实验和...所有文章都将结合案例、代码和作者的经验讲解,真心想把自己近年的编程经验分享给大家,希望对您有所帮助,文章中不
  • 原标题:网易工作年游戏建模师,还没有女朋友,是怎样的一体验?Ⅰ、如何学习次世代游戏建模?对于有兴趣且有时间的小伙伴,相信都是选择自学,也许你会在网上寻找大量的资料、教程,然后开始你的探索之旅,当然...
  • 与传统的追求照片真实感的真实感渲染不同,非真实感渲染(Non-PhotorealisticRendering,NPR)旨在模拟艺术式的绘制风格,常用来对绘画风格和自然媒体(如铅笔、钢笔、墨水、木炭、水彩画等)进行模拟。而卡通渲染...
  • 《蛙声里出山泉》赏析

    千次阅读 2019-05-25 15:14:52
    《蛙声里出山泉》赏析 【摘要】 《蛙声里出山泉》其精髓是这幅画和文学有关:一是求画人是老舍先生,画是因文学而生的;其二,画是命题画,是按古代诗家的名句的意思而成画的。它是一个文学家和一个书画家在...
  • 这种方法的优点是可以使用非线性Normalization将线条索引转换为实际颜色。以下代码生成相同的结果:import matplotlib.pyplot as plt import matplotlib.cm as mplcm import matplotlib.colors as colors import ...
  • 您应该知道的十种 XML 模式

    千次阅读 2013-05-14 22:19:31
    本文考察了一些顶尖的 XML 模式,这些模式为各种各样的问题提供了解决方案,从基本的 Web 服务到数据描述等等。...简单对象访问协议(Simple Object Access Protocol,SOAP)实际上是一 Web 服务技术,但
  • Android开发笔记(一百五)自动识别验证码图片

    千次阅读 热门讨论 2017-09-21 09:16:20
    之所以把数字方块切成九块,是因为每个数字的形状在不同方位各有侧重点,比如数字3在正左边是空白的,而数字8的正左边有线条;又比如数字6在右上角空白、在右下角有线条,而数字9在右上角有线条、在右下角空白。分别...
  • 最早学习的DOS命令和WPS却没有引起我多大的兴趣,直到Basic语言的出现,才使我的认识有了极大的改观,编程真是神奇的东西,不仅可以进行四则运算,还可以在屏幕上呈现各种各样的线条和画面。从那一刻起,仿佛成了另...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 10,821
精华内容 4,328
关键字:

十种不同的线条