webgl——实现物体描边效果

        终于把手头的事结束了,可以有时间来研究研究技术~作为一名3D开发人员,仅仅使用现有的引擎来开发项目不免有些浮于表面,多研究研究底层的实现更利于对3D开发整体的把控~于是我决定最近开始研究webgl一些特效的实现,希望能在秋招前对底层有更深入的理解。

        在webgl中实现描边的效果有很多种方式,比如我写卡通风格着色器那篇文章讲到的(将视线投影到每个点的法线上,这个值越小越说明这个点靠近边缘),所以接下来介绍实现的另一种方式:法线延展法。

        这种方法不用进行法线与视线之间的计算,而是将物体每个点的x、y、z坐标沿着该点的法线扩大一定的距离并且添加描边的颜色,然后在绘制原来的物体覆盖到上面,这样便实现了描边的效果。

        这里将原物体覆盖到描边物体上面就有两种实现的方式:

        1.先关闭深度检测,然后绘制描边物体,开启深度检测,绘制原物体。这样由于绘制描边物体时深度检测被关闭了,原物体就会覆盖在描边物体上绘制从而实现描边效果。缺点:当两个物体重合时会出现重合位置没有描边的情况,这是由于第二次绘制的东西覆盖到了第一次描边的物体上,所以先画的边自然就会被遮挡啦~

        2.不关闭深度检测,开启背面剪裁,绘制描边物体时将卷绕方向置为顺时针方向(默认是逆时针),在进行绘制,绘制完成之后将卷绕方向设置回顺时针方向。这样背面剪裁的开启使得描边物体只能绘制出它的背面,这样便实现了描边效果,而且由于没有关闭深度测试,该物体的描边效果会根据其位置决定是否遮挡。

        //绘制一帧画面的方法
       function drawFrame()
       {          
           //若还没有加载完则不绘制
           if(!ooTri || !mbTri) {return;}
           
           //清除着色缓冲与深度缓冲
           gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);  
           
           //保护现场
           ms.pushMatrix();         
           //绕Y轴旋转
           ms.rotate(currentAngle,0,1,0);
//方法1
//            gl.disable(gl.DEPTH_TEST);                     //启用深度缓冲写入
//            mbTri.drawSelf(ms);//绘制描边物体
//            gl.enable(gl.DEPTH_TEST);                      //关闭深度缓冲写入
//            ooTri.drawSelf(ms);//绘制原物体
//方法2
            gl.enable(gl.CULL_FACE);                        //开启剪裁
            gl.cullFace(gl.BACK);                          //剪裁背面
            gl.frontFace(gl.CW);                           //绘制顺序为顺时针
            mbTri.drawSelf(ms);//绘制描边物体
            gl.frontFace(gl.CCW);                          //绘制顺序为逆时针
            ooTri.drawSelf(ms);//绘制原物体


            //恢复现场
            ms.popMatrix();
          
            //修改旋转角度
           currentAngle += incAngle;
           if (currentAngle > 360)
           {
              currentAngle -= 360;   
           }         
       }   
        其着色器代码如下:

uniform mat4 uMVPMatrix;                            //总变换矩阵
attribute  vec3 aPosition;                                   //顶点位置
attribute vec3 aNormal;                                   //顶点法向量
void main(){
    vec3 position=aPosition;                     //获取此顶点位置
    position.xyz+=aNormal*0.4;                //将顶点位置沿法线方向挤出
    gl_Position = uMVPMatrix * vec4(position.xyz,1);//根据总变换矩阵计算此次绘制此顶点位置
}
<#BREAK_BN#>
precision mediump float;                              //设置浮点默认精度

void main(){
    gl_FragColor = vec4(0.0,1.0,0.0,0.0);                    //给此片元颜色值
}

        其实这两种描边方法还是有着一些区别(第二种对于复杂物体会产生类似包裹的效果)具体效果还得根据具体的场景来决定。

        PS:这里还要注意一点,WebGL是个状态机。我们可以这么理解,假设WebGL中的属性P的值为1,你在某一次操作中,把P的值设置成了2,那么在你下一次设置P的值之前,P的值永远是2。这一点很重要!

Github地址:https://github.com/StringKun/WebGL-object-of-stroke


  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 5
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值