babylonJs webGL 3D babylon.js -
2018-10-04 本文已影响8人
x1911
有了世界有了颜色有了光,我们要在场景里走起来,这个在每个渲染引擎里都可以实现,不过 babylon 的这个像 fps 一样移动,碰到障碍物会停,实在是比 three.js 简单太多,至少在官方例子中没有一个完备的解决方案
FPS游戏中模拟相机运动: 放在地板上的相机,与地面发生的碰撞,以及可能与场景中的任何物体发生的碰撞,这样让我们感觉和真人在场景上行动一样。
下面我们来实现一下
首先在前面的 TestGeometries 文件中我们创建了很多模型,现在就把这些模型全部都存成一个数组,让外部可以访问到,
self.bodys = [box, sphere, plane, disc, cylinder, torus, knot]
同时加入一个 self 来取代 this,方便以后我们进一步的修改,完整代码如下
'use strict';
function TestGeometries (scene) {
let self = {}
self.bodys = []
// 创建一堆材质
const material1 = new BABYLON.StandardMaterial("texture1", scene);
material1.diffuseColor = new BABYLON.Color3(0.0, 0.7, 0.95); //漫射色
const material2 = material1.clone()
// material2.emissiveColor = new BABYLON.Color3(.2, .8, .3); //发光色
material2.ambientColor = new BABYLON.Color3(.1, .3, .0); //发光色
material2.bumpTexture = new BABYLON.Texture("img/bump.png", scene); //凹凸贴图
const material3 = material1.clone()
material3.specularColor = new BABYLON.Color3(0.8, 0.2, 0.7); //反射色
material3.alpha = 0.6; //调整透明度
const material4 = material1.clone()
material4.diffuseTexture = new BABYLON.Texture('http://www.babylonjs-playground.com/textures/tree.png', scene)
material4.diffuseTexture.hasAlpha = true; //显示为透明
material4.backFaceCulling = false; //使透明在背面也显示贴图,而不是裁切后显示为空
const material5 = material1.clone()
material5.diffuseColor = new BABYLON.Color3(1.0, 0.2, 0.15); //漫射色
material5.reflectionTexture = new BABYLON.Texture("http://www.babylonjs-playground.com/textures/tree.png", scene); // 反射贴图
material5.reflectionTexture.coordinatesMode = BABYLON.Texture.SPHERICAL_MODE; // 反射模式
const materialWireframe = new BABYLON.StandardMaterial("materialWireframe", scene);
materialWireframe.wireframe = true // 显示网格
const materialGrass = new BABYLON.StandardMaterial("materialGrass", scene);
materialGrass.diffuseTexture = new BABYLON.Texture("http://www.babylonjs-playground.com/textures/grass.jpg", scene);
materialGrass.diffuseTexture.uScale = 5.0;//垂直方向重复5次
materialGrass.diffuseTexture.vScale = 5.0;//水平方向重复5次
// 创建一个盒子
//参数为: 名字,盒子大小, 它们将放到场景, 是否可更新?(如果该网格后面必须被更新) 和可选的面朝向(参见下面). 如果你需要默认表现那么最后两个参数可以忽略: BABYLON.Mesh.CreateBox("box", 6.0, scene);
const box = BABYLON.Mesh.CreateBox("box", 1.0, scene, false, BABYLON.Mesh.DEFAULTSIDE);
// box.position.x = -1; //移动一下它的默认位置,x轴移到-3的位置
//Apply the materials to meshes
box.material = material1;
// 创建一个球体
//参数为: 名字, 细分段数 (高度细节或不需), 大小, 将被放到的场景, 是否可更新?(如果该网格后面必须被更新) 和可选的面朝向(参见下面). 如果你需要默认的表现那么最后两个参数可以忽略: BABYLON.Mesh.CreateSphere("sphere", 10.0, 10.0, scene);
const sphere = BABYLON.Mesh.CreateSphere("sphere", 8.0, 1.0, scene, false, BABYLON.Mesh.DEFAULTSIDE);
sphere.position.x = -1.5; //移动一下x轴的默认位置
sphere.material = material2
// 创建一个平面 (注意这个面是竖立着的)
//参数为: 名字, 大小, 和将被放到的场景, 是否可更新?(如果该网格后面必须被更新) 和可选的面朝向
const plane = BABYLON.Mesh.CreatePlane("plane", 100.0, scene, false, BABYLON.Mesh.DOUBLESIDE); //这里怕看不出来用了双面贴图
// const plane = BABYLON.Mesh.CreatePlane("plane", 10.0, scene);
plane.position.y = -1;
plane.rotation.x = Math.PI / 2 //转动x轴成平面
plane.material = materialGrass
// 创建一个盘片 或着一个规则多边形 这里创建了一个8边型
const disc = BABYLON.Mesh.CreateDisc("disc", 1, 8, scene, false, BABYLON.Mesh.DOUBLESIDE);
// 参数为: 名字, 半径, 边数, 场景, 可更新否和可选的朝向(参见下面). 如果你需要默认的表现,那么最后两个参数参数可以忽略:
// const disc = BABYLON.Mesh.CreateDisc("disc", 1, 8, scene);
disc.position.x = -3;
disc.rotation.x = Math.PI / 2 //转动x轴成平面
disc.material = material3
//创建一个圆柱体
// 参数为: 名称, 高度, 顶直径, 底直径, 边数, 高向细分度, 场景, 可更新否和可选的朝向(参见下面). 如果你需要默认表现,那么最后两个参数可以忽略:
const cylinder = BABYLON.Mesh.CreateCylinder("cylinder", 3, 1, 1, 6, 1, scene);
cylinder.position.x = 1.5;
cylinder.material = material4
// 创建一个环体
// var torus = BABYLON.Mesh.CreateTorus("torus", 5, 1, 10, scene, false, BABYLON.Mesh.DEFAULTSIDE);
// 参数为: 名称, 直径, 厚度, 边数(高度细节或不是), 场景, 可更新否和可选的朝向(参见下面). 如果你使用默认表现那么最后两个参数可忽略 :
const torus = BABYLON.Mesh.CreateTorus("torus", 1, 0.5, 10, scene);
torus.position.x = 3;
torus.material = material5
// 创建一个结
// const knot = BABYLON.Mesh.CreateTorusKnot("knot", 2, 0.5, 128, 64, 2, 3, scene, false, BABYLON.Mesh.DEFAULTSIDE);
// 参数为: 名称, 半径, tube, 半径上分段数, tubularSegments, p, q, 场景, 可更新否和可选的朝向(参见下面). 如果你使用默认的表现那么最后的两个参数可以忽略 :
const knot = BABYLON.Mesh.CreateTorusKnot("knot", 1, 0.2, 32, 16, 2, 3, scene);
knot.position.x = 5.5;
knot.material = materialWireframe // 赋予材质
// 创建线
// 参数为: 名称, [都好分隔的向量数组], 场景.
const lines = BABYLON.Mesh.CreateLines("lines", [
new BABYLON.Vector3(-2, 0, 0),
new BABYLON.Vector3(2, 0, 0),
new BABYLON.Vector3(0, 0, -2),
new BABYLON.Vector3(0, 0, 2),
new BABYLON.Vector3(-2, 0, 0)
], scene);
lines.position.y = 3
//绘制点划线
// 参数为 : 名称, [三元向量数组], 划线大小, 间隙大小, 段划线数, 场景. 作为许多线段, 每条段先都是以三元向量组的方式呈现在空间里. 上面函数设置了这条点划线里线段的数量, 每段都是由两个连续三元向量定义. 划线大小 和 间隙大小 是指点划线里每个划线和之间间隙的相对大小.
const dashedlines = BABYLON.Mesh.CreateDashedLines("dashedLines",
[
new BABYLON.Vector3(-2, 0, 0),
new BABYLON.Vector3(2, 0, 0),
new BABYLON.Vector3(0, 0, -2),
new BABYLON.Vector3(0, 0, 2)
]
, 1, 1, 100, scene);
dashedlines.position.x = -4
dashedlines.position.y = 3
self.bodys = [box, sphere, plane, disc, cylinder, torus, knot]
return self
}
接下来在 scene 文件中要将相机替换成freecamera
// 创建一个 FreeCamera,设置位置到 (x:0, y:5, z:-10)
var camera = new BABYLON.FreeCamera('camera1', new BABYLON.Vector3(0, 5,-10), scene);
// camera.setTarget(BABYLON.Vector3.Zero()); //指向原点 这里会冲突 所以我们先取消
// 原来的围绕相机在这里先取消
// var camera = new BABYLON.ArcRotateCamera("Camera", 1.0, 1.0, 12, BABYLON.Vector3.Zero(), scene);
为了区分这种碰撞和不碰撞的情况,所以我们专门建立一个 Physic 处理需要给相机加入 FPS碰撞效果的情况
const Physic = function (sceneObj) {
let self = {}
function init() {
// 传入整个场景参数
sceneObj.scene.gravity = new BABYLON.Vector3(0, -9.81, 0);
sceneObj.camera.applyGravity = true;
//Set the ellipsoid around the camera (e.g. your player's size)
sceneObj.camera.ellipsoid = new BABYLON.Vector3(1, 1, 1);
// Enable Collisions
sceneObj.scene.collisionsEnabled = true;
sceneObj.camera.checkCollisions = true;
}
self.addCollision = function (o) { // 将物体加入和相机碰撞
o.checkCollisions = true;
}
init()
return self
}
接下来记得在html中引入这个文件
同时main 文件也要作出一点点内容的增加
'use strict';
let DB = {} //全局可控内容
window.addEventListener('DOMContentLoaded', function() {
var canvas = document.getElementById('renderCanvas'); // 获取html的元素
start(canvas)
});
function start (canvas) {
const s = new Scene(canvas)
const phy = new Physic(s)
DB.engine = s.engine //保存两个内容到全局
DB.scene = s.scene
const objs = new TestGeometries(DB.scene) // 创建基本元素
for(let i = 0; i<objs.bodys.length; i++){
phy.addCollision(objs.bodys[i])
}
}
哒哒,现在可以像 FPS 游戏一样自由遨游我们创建的场景了
image.png注意要鼠标点击左键才能切换镜头角度,方向键控制前进后退,这里 WASD 还不起作用