使用threejs实现辉光&大气层效果

        最近想使用threejs实现辉光的特效,在查阅了一些资料之后,不仅实现了辉光的特效,还顺带实现了大气层特效,在写着色器的过程中有了一些理解~

        首要目标:为了实现辉光的着色器,我们把辉光分为几个步骤来实现:

        1.创建两个球体,一个作为原始物体,一个略大一些作为它的辉光。

        2.作为辉光的球体从内到外片元透明度逐渐减小(线性减小或是指数减小都可以)

        3.将覆盖原始物体的部分丢弃掉

        有了这3点步骤,做起来就会容易很多,这里我着重介绍一下着色器的部分:

        首先是片元着色器

'varying vec3   vVertexWorldPosition;',
'varying vec3  vVertexNormal;',

'varying vec4  vFragColor;',

'void main(){',
'  vVertexNormal  = normalize(normalMatrix * normal);',//将法线转换到视图坐标系中

'  vVertexWorldPosition   = (modelMatrix * vec4(position, 1.0)).xyz;',//将顶点转换到世界坐标系中

'  // set gl_Position',
'  gl_Position    = projectionMatrix * modelViewMatrix * vec4(position, 1.0);',
'}'

        这里做的事情比较简单,主要就是把法线转换到视图坐标系中和把顶点转换到世界坐标系中,因为在片元着色器中需要用到这两个参数,必须对他们进行一下转换,这里还要说一下的就是OpenGL用的是左乘,也就是顶点左乘矩阵,进行转换(对坐标系转换不熟悉的同学可以看一下我之前总结的文章:http://blog.csdn.net/srk19960903/article/details/77970630)。

        然后是辉光的片元着色器:

'uniform vec3   glowColor;',
'uniform float coeficient;',
'uniform float power;',

'varying vec3  vVertexNormal;',
'varying vec3  vVertexWorldPosition;',

'varying vec4  vFragColor;',

'void main(){',
'  vec3 worldVertexToCamera= cameraPosition - vVertexWorldPosition;', //世界坐标系中顶点位置到相机位置到的距离
'  vec3 viewCameraToVertex    = (viewMatrix * vec4(worldVertexToCamera, 0.0)).xyz;',//视图坐标系中
'  viewCameraToVertex = normalize(viewCameraToVertex);',//规一化
'  float intensity       = coeficient + dot(vVertexNormal, viewCameraToVertex);',
'  if(intensity > 0.55){ intensity = 0.0;}',
'  gl_FragColor      = vec4(glowColor, intensity);',
        这里首先得到了两个向量,一是顶点到相机的向量然后将其转换到视图坐标系中,在进行归一化。二是直接传过来的视图坐标系中的法向量,这时将两个向量进行点乘就可以获得它们夹角的cos值,从圆心到圆边这个角度依次增大,所以乘积依次减小,最后把这个值加上一个常量赋给最终片元的不透明度,从而实现辉光的效果。

        这里的难点主要在于两个:1.将顶点到相机的距离和法向量,统统转换到view坐标系中来计算。

                                                    2.两个向量的乘积所代表的意义,所夹角度的cos值,通过观察cos的函数图像我们可以看出他的变换规律,再根据规律写着色器。

大气层着色器

        既然我们会写从内向外透明度逐渐降低的着色器,那么从外向内透明度逐渐降低的呢~

        还记得在算点积的时候我们用的是那两个向量吗?顶点到摄像机&顶点向外的法向量,嗯,那么我们可以用从摄像机到顶点&顶点向外的法向量来重新算一次!这次由于角度开始就是大于180度的,从球心到球边,cos值从负值到正值进行变换,我们再用一个指数函数的形式来影响它的变换过程,就是这么简单,大气层的着色器就研究出来啦!

         'uniform vec3  glowColor;',
         'uniform float    coeficient;',
         'uniform float    power;',

         'varying vec3 vVertexNormal;',
         'varying vec3 vVertexWorldPosition;',

         'varying vec4 vFragColor;',

         'void main(){',
         ' vec3 worldCameraToVertex= vVertexWorldPosition - cameraPosition;', //世界坐标系中从相机位置到顶点位置的距离
         ' vec3 viewCameraToVertex    = (viewMatrix * vec4(worldCameraToVertex, 0.0)).xyz;',//视图坐标系中从相机位置到顶点位置的距离
         ' viewCameraToVertex = normalize(viewCameraToVertex);',//规一化
         ' float intensity       = pow(coeficient + dot(vVertexNormal, viewCameraToVertex), power);',
         ' gl_FragColor      = vec4(glowColor, intensity);',
         '}'//vVertexNormal视图坐标系中点的法向量
//viewCameraToVertex视图坐标系中点到摄像机的距离向量
//dot点乘得到它们的夹角的cos值
//从中心向外面角度越来越小(从钝角到锐角)从cos函数也可以知道这个值由负变正,不透明度最终从低到高

效果如图:

使用threejs实现辉光&大气层效果_第1张图片

使用threejs实现辉光&大气层效果_第2张图片

Github:https://github.com/StringKun/ThreeJSGlow-Atmosphere

你可能感兴趣的:(threejs)