前几周作了一个AR小项目,主要功能就是展现模型动画,想作一个分享,可是AR是基于APP的,不太好分享~。。脑袋疼~。。好在AR其实本质就是3d,就想着用webGL讲讲里面的一些东西。c++
项目逻辑主要是 搜索平面-> 建立模型-> 模型操做(矩阵变换以及动画播放)web
其中,建立模型和模型的缩放、位移、移动以及播放相应模型动画这些不作解释,彻底能够用threejs、babylonjs去找对应API,这篇文章主要是讲搜索平面所用到的材质是怎么作的。typescript
这里的逻辑是捕捉到一个有效平面后出现一个具备延申效果的平面提示材质。windows
材质制做思路:api
//babylon.js this.tracking = BABYLON.Mesh.CreateGround('Ground', 1, 1, 1, this.scene); 复制代码
自定义材质markdown
因为开发文档没有须要的材质因此我选择自定义材质。oop
//shaderCode BABYLON.Effect.ShadersStore["trackingVertexShader"] = require('./tracking.vert'); BABYLON.Effect.ShadersStore["trackingFragmentShader"] = require('./tracking.frag'); this.tracking.material = new BABYLON.ShaderMaterial("trackingShader", this.scene, { vertex: "tracking", fragment: "tracking", }, { attributes: ["position", "normal", "uv"], uniforms: ["world", "worldView", "worldViewProjection", "view", "projection","uPosition","uTexture","uTime"] //uniform 我只用到了 uPosition,uTexture,uTime 分别是mesh的位置,白点素材和时间 }); 复制代码
//顶点着色器 precision highp float; attribute vec3 position; attribute vec2 uv; uniform mat4 worldViewProjection; varying vec2 vUv; void main(void) { vec3 _position = position*vec3(1.0,0.0,1.0); gl_Position = worldViewProjection * vec4(_position, 1.0); vUv = uv; } 复制代码
其中顶点着色器没啥说的,传入的uniform
都是传给片元着色器的。动画
//片元着色器 precision highp float; varying vec2 vUv; uniform sampler2D uTexture; //白点素材 uniform vec3 uPosition; //当前mesh的位置 uniform float uTime; //时间 void main(void) { float _distance = distance(vec2(0.5),vUv); //mask 第一步:半径超过0.5的颜色丢弃; if(_distance<.5){ //白点:基于mesh位置作偏移,能够实现移动mesh时 白点相对于世界的位置不变。 vec2 uv = vUv*5.+uPosition.xz*5.0/5.0; //白点:作repeat处理 vec2 uv = mod(abs(uv),1.0); //这一段判断不用在乎 我这个图片不知道为啥边缘会有一条线。。 if(uv.x>0.05&&uv.x<0.95&&uv.y>0.05&&uv.y<0.95){ vec4 color = texture2D(uTexture,uv); //mask 第二步:作透明度渐变mesh; gl_FragColor = color*vec4(vec3(1),1.0-pow(_distance*2.,2.)); if(gl_FragColor.a==0.0) discard; }else{ discard; } }else{ discard; } } 复制代码
剩下的就是传入uniform数据就能够了。ui
//uTexture const texture = new BABYLON.Texture(require('../assets/Artboard.png'), this.scene); texture.wrapU = BABYLON.Texture.MIRROR_ADDRESSMODE; texture.wrapV = BABYLON.Texture.MIRROR_ADDRESSMODE; (<BABYLON.ShaderMaterial>this.tracking.material).setTexture("uTexture", texture); //uPosition //this.tracking.position -> BABYLON.Vector3 (<BABYLON.ShaderMaterial>this.tracking.material).setVector3('uPosition',this.tracking.position); 复制代码
效果以下(白点有延申效果且每一个白点相对于世界静止的):
感受放在webGL不是很好看,哈哈哈,随便改了改片元着色器,根据时间作了一个涟漪的效果。
//片元着色器 precision highp float; varying vec2 vUv; uniform sampler2D uTexture; uniform vec3 uPosition; uniform float uTime; void main(void) { float _distance = distance(vec2(0.5),vUv); if(_distance<.5){ //涟漪start vec2 offset = vec2(0); float ripple = mod(uTime/1000.,1.5)-_distance; if(abs(ripple)<.1){ offset=normalize(vUv-vec2(0.5))*-1.*(cos(ripple*31.42)+1.)/8.; } vec2 uv = mod(abs(vUv*5.+offset+uPosition.xz*5.0/5.0),1.0); //涟漪end if(uv.x>0.05&&uv.x<0.95&&uv.y>0.05&&uv.y<0.95){ vec4 color = texture2D(uTexture,uv); gl_FragColor = color*vec4(vec3(1),1.0-pow(_distance*2.,2.)); if(gl_FragColor.a==0.0) discard; }else{ discard; } }else{ discard; } } 复制代码
涟漪效果以下:
ps:场景是本身实现的,以为windows 10 3d查看器的场景挺好看的就仿照作了一个。哈哈。