前幾周作了一個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查看器的場景挺好看的就仿照作了一個。哈哈。