【温故知新】——BABYLON.js学习之路·前辈经验(一)

前言:公司用BABYLON作为主要的前端引擎,同事们在长时间的项目实践中摸索到有关BABYLON的学习路径和问题解决方法,这里只作为温故知新。 一、快速学习BABYLON 1. 阅读Babylon[基础教程](http://doc.babylonjs.com/babylon101/) 2. 阅读[一些BABYLON的新特性](http://doc.babylonjs.com/features/) 3. 阅读[代码片段](http://doc.babylonjs.com/samples) 4. 一些[更深入的教程详解](http://doc.babylonjs.com/how_to/) 5. [在游乐场玩耍](http://doc.babylonjs.com/playground/) 二、需要掌握的基本技能 1. engine,scene等创建,抗锯齿,像素比,深度缓冲区等配置项 2. 灯光的创建,基本属性,作用域 3. 相机的创建,基本属性,多相机的切换,绑定等 4. 材质的创建,不同纹理类型等 5. 场景中的元素,雾化,天空盒,阴影,地形图,世界坐标系,本地坐标系等 6. 事件,actionManager,onPointerDownObservable,pick,pickWithRay, onViewMatrixChangedObservable,onLightRemovedObservable等基本事件 7. UI 三、项目开发中遇到的一些问题及重点功能 # 灯光 复制代码 //设置作用物体 light.includedOnlyMeshes //设置排除物体 light.excludedMeshes 复制代码 # 相机 1、相机多个动画的正确顺序 targetScreenOffet->target->beta->alpha->radius 2、相机运动触发的事件 camera.onViewMatrixChangedObservable 3、漫游相机定制跳跃转向碰撞等功能 复制代码 //有两种方法可以根据世界矢量进行碰撞位移 //1. camera._collideWithWorld(camera.getFrontPosition(10).subtract(camera.position)) //2. camera.cameraDirection.addInPlace(camera._transformedDirection); //如跳跃,则相对世界向上 scene.activeCamera.cameraDirection.addInPlace(new BABYLON.Vector3(0, 4, 0)); //重力回到地面 camera._needMoveForGravity = true; //定制位移方向 var speedXX=camera._computeLocalCameraSpeed()*(左右惯性因子*panel) var speed=camera._computeLocalCameraSpeed()*(前后惯性因子*panel) camera._localDirection.copyFromFloats(speedX, 0, speedZ); camera.getViewMatrix().invertToRef(camera._cameraTransformMatrix); BABYLON.Vector3.TransformNormalToRef(camera._localDirection, camera._cameraTransformMatrix, camera._transformedDirection); camera.cameraDirection.addInPlace(camera._transformedDirection); //定制旋转方向 camera.rotation.x=(beta惯性因子*panel) camera.rotation.y=(alpha惯性因子*panel) 复制代码 # 重力 复制代码 //添加重力 scene.gravity = new BABYLON.Vector3(0, -9.81, 0); camera.applyGravity = true; //添加碰撞 scene.collisionsEnabled = true; camera.checkCollisions = true; ground.checkCollisions = true; box.checkCollisions = true; //相机碰撞椭圆体 camera.ellipsoid = new BABYLON.Vector3(.5, 1, .5); //arcRotateCamera的碰撞椭圆体 camera.collisionRadius =new BABYLON.Vector3(0.5, 0.5, 0.5) //防止向上跳后无法落地 camera._needMoveForGravity = true; //物体碰撞 mesh.moveWithCollisions(vec3); //使用webworker运行碰撞检测 scene.workerCollisions = true|false 复制代码 ## 第二视图 复制代码 var camera = new BABYLON.ArcRotateCamera("Camera", 0, 0, 0, BABYLON.Vector3.Zero(), scene); camera.setPosition(); var followCamera = new BABYLON.FollowCamera("follow", new BABYLON.Vector3(400, 500, 1000), scene, ground) followCamera.radius = 0 followCamera.heightOffset = 400; scene.activeCameras.push(followCamera); scene.activeCameras.push(camera); followCamera.viewport = new BABYLON.Viewport(0, 0, 0.3, 0.3) camera.viewport = new BABYLON.Viewport(0, 0.3, 1, 0.7) 复制代码 ## 四元数转换为欧拉角 复制代码 sphere2.lookAt(sphere.position) camera.position=sphere2.position; camera.rotation.x=-sphere2.rotationQuaternion.toEulerAngles().x; camera.rotation.y=sphere2.rotationQuaternion.toEulerAngles().y+Math.PI; camera.rotation.z=sphere2.rotationQuaternion.toEulerAngles().z; 复制代码 ## 漫游相机和旋转相机的转换 旋转相机 -> 漫游相机 复制代码 var radiusv3 = pickInfo.pickedPoint var radius = radiusv3.length(); var alpha = Math.acos(radiusv3.x / Math.sqrt(Math.pow(radiusv3.x, 2) + Math.pow(radiusv3.z, 2))); if (radiusv3.z < 0) { alpha = 2 * Math.PI - alpha; } var beta = Math.acos(radiusv3.y / radius); 复制代码 漫游相机-> 旋转相机 复制代码 var radiusv3 = zxz.camera2.position; var radius = radiusv3.length(); var alpha = Math.acos(radiusv3.x / Math.sqrt(Math.pow(radiusv3.x, 2) + Math.pow(radiusv3.z, 2))); if (radiusv3.z < 0) { alpha = 2 * Math.PI - alpha; } var beta = Math.acos(radiusv3.y / radius); 复制代码 # 材质 1、材质特殊参数 复制代码 material.maxSimultaneousLights //最多可接受灯光个数,默认4个 material.useLogarithmicDepth material.needDepthPrePass //深度判断 material.transparencyMode=2; 复制代码 2、 dynamicTexture 复制代码 var dynamicTexture = new BABYLON.DynamicTexture("DynamicTexture", {width:50,height:50}, scene, true); dynamicTexture.hasAlpha = true; dynamicTexture.drawText(text, 10, 50, "bold 100px Arial", color , "transparent", true,true); var plane = new BABYLON.Mesh.CreatePlane("TextPlane", size, scene, true); plane.material = new BABYLON.StandardMaterial("TextPlaneMaterial", scene); plane.material.backFaceCulling = false; plane.material.specularColor = new BABYLON.Color3(0, 0, 0); plane.material.diffuseTexture = dynamicTexture; 复制代码 3、镜面反射材质 复制代码 Material.diffuseColor = new BABYLON.Color3(0.4, 0.4, 0.4); Material.reflectionTexture = new BABYLON.MirrorTexture("mirror", 1024, scene, true); //Create a mirror texture Material.reflectionTexture.mirrorPlane = new BABYLON.Plane(0, -1.0, 0, -10.0); Material.reflectionTexture.renderList = [ground,skybox]; Material.reflectionTexture.level = 0.6;//Select the level (0.0 > 1.0) of the reflection 复制代码 4、 探针 复制代码 var box = BABYLON.Mesh.CreateBox("box", 5000, scene); //直接贴反射贴图 //material.reflectionTexture = new BABYLON.CubeTexture('img/bg/4', scene); //box.material = new BABYLON.StandardMaterial("boxMaterial", scene); //box.material.reflectionTexture = new BABYLON.CubeTexture('img/bg/4', scene); //box.material.reflectionTexture.coordinatesMode = BABYLON.Texture.SKYBOX_MODE; //box.material.backFaceCulling = false; //box.rotation.z = Math.PI / 2; var probe = new BABYLON.ReflectionProbe("main", 512, scene); probe.renderList.push(yellowSphere); probe.renderList.push(greenSphere); probe.renderList.push(blueSphere); probe.renderList.push(mirror); mainMaterial.diffuseColor = new BABYLON.Color3(1, 0.5, 0.5); mainMaterial.reflectionTexture = probe.cubeTexture; mainMaterial.reflectionFresnelParameters = new BABYLON.FresnelParameters(); mainMaterial.reflectionFresnelParameters.bias = 0.02; 复制代码 5、 菲涅尔 复制代码 //所有菲涅尔类型 StandardMaterial.diffuseFresnelParameters StandardMaterial.reflectionFresnelParameters StandardMaterial.opacityFresnelParameters StandardMaterial.emissiveFresnelParameters StandardMaterial.refractionFresnelParameters //用法 var saturne = BABYLON.Mesh.CreateSphere("saturne", 16, 80, scene); var saturne_material = new BABYLON.StandardMaterial("saturne_material", scene); saturne_material.reflectionTexture = new BABYLON.CubeTexture("../../assets/skybox/nebula", scene); saturne_material.reflectionFresnelParameters = new BABYLON.FresnelParameters(); saturne_material.reflectionFresnelParameters.bias = 0.2; saturne_material.emissiveFresnelParameters = new BABYLON.FresnelParameters(); saturne_material.emissiveFresnelParameters.bias = 0.6; saturne_material.emissiveFresnelParameters.power = 4; saturne_material.emissiveFresnelParameters.leftColor = BABYLON.Color3.White(); saturne_material.emissiveFresnelParameters.rightColor = new BABYLON.Color3(0.6, 0.6, 0.6); saturne.material = saturne_material; 复制代码 # 动画 1. 创建animation对象 var animation = new BABYLON.Animation(name, targetProperty, framePerSecond, dataType, loopMode, enableBlending); 2. 绑定键值对 animation.setKeys([{frame:0,value:0},...]) 3. 设置运动函数 复制代码 var bezierEase = new BABYLON.BezierCurveEase(.97, .2, 0, .58); bezierEase.setEasingMode(BABYLON.EasingFunction.EASINGMODE_EASEOUT); animation.setEasingFunction(bezierEase); 复制代码 4. 将动画对象push到mesh的animations属性中 mesh.parent.animations.push(animationPosition); 5. 开始运行动画 复制代码 var animatable=beginAnimation(target, from, to, loop, speedRatio, onAnimationEnd, animatable) animatable.pause() //暂停 animatable.restart() //从暂停的地方开始播放 animatable.stop() //停止动画,不能恢复 animatable.reset() //重新开始,从0 frame的地方,不管循环模式 复制代码 ** 注意: * bug :从0到0 整个场景会抖动 * 由3Dmax导入动画,直接开始运行,bug:如果scene.stopAnimation,下次begin一定要通过事件才能正常触发。 * 就算没有给对象设置动画对象,但是开始运行动画了,也能通过scene.getAnimatableByTarget(mesh)获取到animatable对象(虽然animations为空数组) * 如果loop 设置为了ture,那么根据loopMode来进行循环,并且永远处于运动状态,不会触发onAnimationEnd回调函数,除非stopAnimation或者再运行一遍beginAnimation, 或者使用 BABYLON.Animation.CreateAndStartAnimation(且使用ANIMATIONLOOPMODE_CONSTANT模式) * 如果loop设置为false,动画只执行一次,然后触发onAnimationEnd回调函数 * 在动画运行过程中如果手动更新了animation.setKeys(),那么继续当前的动画且currentFrame不变,但是更新了keys,也就是跳到了新的keys的当前frame画面,所以会有一个突变的卡顿现象 * 如果当前处于运动状态,又运行了一遍beginAnimation,那么会stopAnimation,并重置当前帧数,可以解决卡顿现象。 * animatable.stop直接停止运动状态,restart结束暂停状态,不会变化位置,如果stop等停止了运动状态,restart无效,reset是直接回到动画刚开始的位置 * createAndStartAnimation不会打断其他动画,但是beginAnimation会打断所有animation包括createAndStartAnimation * beginAnimation会打断createAndStartAnimation,createAndStartAnimation不会打断beginAnimation # 粒子 复制代码 1、发射方向类型 particleSystem.particleEmitterType = new BABYLON.SphereParticleEmitter(10,false); //或者 particleSystem.createSphereEmitter(10);//GPUParticle没有这个API 2、子粒子,放烟花 particleSystem.subEmitters = [particleSystem,..] 3、members particleSystem.disposeOnStop=true; 复制代码 # mesh 1、facet Data 复制代码 //获得三角形的中心 mesh.getFacetPosition(faceId) //the 50th facet local position var localPositions = mesh.getFacetLocalPositions(); // returns the array of facet positions in the local space var localPos = localPositions[50]; //normal var norm = mesh.getFacetNormal(faceId); // var localNormals = mesh.getFacetLocalNormals(); // returns the array of facet normals in the local space var localPos = localNormals[50]; // Vector3 : the 50th facet local position //All the methods dealing with the world coordinates use the mesh world matrix. As you may know, this matrix is automatically computed on the render call. If you've just moved, scaled or rotated your mesh before calling the facetData methods using the world values and you're not sure about this, you can ever force the world matrix computation. mesh.rotate.y += 0.2; // the mesh will be rotated on the next render call, but I need a rotated normal mesh.computeWorldMatrix(true); // force the world matrix computation var norm = mesh.getFacetNormal(50); // returns the world normal of the mesh 50th facet 复制代码 2、 获取轴心 复制代码 //如果之前有freeze矩阵,则需要先重新计算 mesh.computeWorldMatrix(true) mesh.getAbsolutePivotPoint() 复制代码 3、设置本身轴偏差 mesh.setPivotPoint(vec3) 4、画线 复制代码 var lines=new BABYLON.Mesh.CreateLines("line",[v0,v1,v2,v3],scene) //画线默认是以gl.LINES方法绘画,例子中虽然只传入了4个顶点,但是默认0,1 1,2 2,3 //颜色:lines.color 复制代码 5、自定义geometry 复制代码 //简单的使用verticesData mesh.setVerticesData(kind:string,data:array,updatable:boolean,stride:number) //demo: mesh.setVerticesData("position", positions, true) //stride :position,normal 默认3,uv 默认2 //或者使用buffer,可以更多的配置offset,size,stride等选项 mesh.setVerticesBuffer(new vertexBuffer(engine,data:array,kind:string,updatable:boolean,postponeInternalCreation:boolean,stride:number,instanced:Boolean,offset:number,size:number)) //demo: var aRotation = new Float32Array(pointLength*2); mesh.setVerticesBuffer(new BABYLON.VertexBuffer(engine, aRotation, "aRotation", true, false, 2)); //最后必须设置索引 mesh.setIndices(Array) 复制代码 6、使用自定义的attribute传入着色器 复制代码 var material = new BABYLON.ShaderMaterial("particle", scene, "./js/particle", { uniforms: ["worldViewProjection", "uTime", "uTranslation", "axis", "alpha", /*"resolution",*/ "pointSize", "baseColor", /*"rebuilding",*/ "status", "scatter", "uvMode", "mobile"], attributes: ["position", "uv", "aRotation", "aAnimation", "raxis"], needAlphaBlending:true //通过material.alphaMode=来设置混合模式 }); material.fillMode = 2; material.setFloat("uTime", 0.); material.setVector3("axis", new BABYLON.Vector3(0, 1, 0)); material.setVector3("uTranslation", new BABYLON.Vector3(0, 500, 0)); material.setColor3("baseColor", new BABYLON.Color3(1, 1, 1)); material.setFloat("status", .5); material.setFloat("scatter", 0); material.setFloat("uvMode", 0); 复制代码 7、一般用到的创建着色器程序的两种方法 View Code 复制代码 //方法一. BABYLON.Effect.ShadersStore["customVertexShader"] var shaderMaterial = new BABYLON.ShaderMaterial("shader", scene, { vertex: "custom", fragment: "custom", }, { attributes: ["position", "normal", "uv"], uniforms: ["world", "worldView", "worldViewProjection", "view", "projection"] }); 复制代码 复制代码 //方法二.创建单独的文件basename.vertex.fx和basename.fragment.fx var cloudMaterial = new BABYLON.ShaderMaterial("cloud", scene, "./basename", { attributes: ["position", "uv"], uniforms: ["worldViewProjection"], needAlphaBlending:true //通过material.alphaMode=来设置混合模式 }); 复制代码 ## 传参方法 setTexture,setFloat,setFloats,setColor3,setColor4,setVector2,setVector3,setVector4,setMatrix attributes: mesh.setVerticesBuffer(new BABYLON.VertexBuffer(engine, aRotation, "aRotation", true, false, 2)); ## BABYLON默认传入的参数 1、自动传入的uniform变量 复制代码 world, view, projection, worldView, worldViewProjection cameraPosition 复制代码 2、自动传入的attribute变量 复制代码 position normal uv uv2 复制代码 ## 通过索引创建submesh BABYLON.SubMesh.CreateFromIndices(subMesh.materialIndex, offset, Math.min(subdivisionSize, totalIndices - offset), mesh); ## CSG 复制代码 union 相加 subtract 相减` intersect 相交 var sphereCSG = BABYLON.CSG.FromMesh(sphere); sphereCSG.subtractInPlace(BABYLON.CSG.FromMesh(cylinderMesh)); sphereCSG.toMesh("bowling ball", sphere.material, scene, false); copyTransformAttributes(csg) 复制代码 默认是源CSG的变换矩阵,如果需要改变,比如intersect的CSG,那么可以设置相交部分的CSG为变换矩阵,轴就在新建物体的原点 ## polygonMeshBuilder 通过path2创建的polygon是动态创建的,会根据scaling来增加顶点 # 场景 1、自己创建天空盒 复制代码 var skybox = BABYLON.Mesh.CreateBox("skyBox", 100.0, scene); var skyboxMaterial = new BABYLON.StandardMaterial("skyBox", scene); skyboxMaterial.backFaceCulling = false; skyboxMaterial.reflectionTexture = new BABYLON.CubeTexture("../../Assets/skybox/skybox", scene); skyboxMaterial.reflectionTexture.coordinatesMode = BABYLON.Texture.SKYBOX_MODE; skyboxMaterial.diffuseColor = new BABYLON.Color3(0, 0, 0); skyboxMaterial.specularColor = new BABYLON.Color3(0, 0, 0); skybox.material = skyboxMaterial; skybox.material.disableLighting = true; skybox.infinit
50000+
5万行代码练就真实本领
17年
创办于2008年老牌培训机构
1000+
合作企业
98%
就业率

联系我们

电话咨询

0532-85025005

扫码添加微信