目录
inspector基本操作
1、在场景想要通过鼠标点击选中模型
2、鼠标点击场景内的小桌子,选中模型后,可以通过左边的眼睛开关,确认是否选择正确。
3、inspector左侧面板的上方的可以单选控制模型的transform值(移动、旋转、放大)
额外补充:中心点pivot最好是模型师修改,也可以代码设置坐标点,查询api→Mesh→pivot。
(1)点亮移动图标选项后,鼠标拖拽红绿蓝可以让模型沿着xyz轴移动,
(2)点亮旋转图标选项后,红绿蓝圈可拖拽,分别表示绕着xyz轴旋转。【正常情况】
(3)点亮缩放图标选项后,红绿蓝线可拖拽,分别表示沿着xyz轴放大缩小。
额外补充:基础教程101里面的Position篇有世界坐标和自身坐标案例,以及画坐标系
(4)点亮左边面板第四个图标,显示模型边框,可以拖拽边框上的不同节点,分别操作移动、旋转、拉伸。 拖拽面控制移动;线中的点 拖拽控制旋转;8个顶点拖拽控制缩放;
额外补充:可以通过代码给模型开启boundingBox相关功能 gizmo
(5)在编辑器调整好模型尺寸后,可以通过代码设置模型transform的三维向量值(坐标、选择、缩放)
额外补充:如果是导入的glb、gltf模型,模型可能自带四元数,rotation.y设置失效,需要通过特殊处理才能设置rotation
(6)根据 id name Uniqueid 找到场景内的模型,Uniqueid每次加载完成后都被重新分配
(7)vertices 和 faces 三角顶点和面数,对于web项目来说,一定需要找模型师优化面数
(8)面板的is enabled属性,模型的显示隐藏控制,控制隐藏的内存性价比查看内存章节
额外补充:有isEnabled方法,只不过是给节点使用,检查父类用的
(9)visibility 设置显示、隐藏、半透明 0~1变动,可以制作隐藏但是有碰撞的空气墙使用
(10)Alpha Index 没用过不了解,记录官方文档
(11)ReceiveShadows,必须设置为true后,才能有物体的实时光倒影
(12)InfiniteDistance 无限远,常用于天空盒
(13)RenderingGroupID 渲染组 图层是按ID升序渲染的,从默认的图层开始(ID为0)可用于处理广告牌标签的面板永远在最上层显示
(14)Layer mask 和摄像机进行位与计算 A&B的值不为0,就显示。
(15)collisions 碰撞
(16)uv set 2套UV,添加了烘焙好的光影贴图,这个场景使用了材质中的lightmap
(17)occlusions 遮挡 (性能优化方面查阅另一篇内存相关的文章)
(18)edge rendering 边缘、边框渲染 ,会增加1次drawCall(下文对比renderOutline)
(19)renderOutline 渲染轮廓边框线,对比如图,只有边框,没有中间那条线,增加2次drawcall
额外补充:后处理时,注意drawcall
(20)debug模式常用wireframe选项,查看模型是否优化到位,normal 法线查看是否反了,如果反了,贴图就是黑色一块
本章节使用的例子代码:
上一章节详细介绍了inspectorcamera类(FreeCamera)的各个参数和使用方法,
接下来章节介绍Mesh Material Texture在sandbox基础操作,
进阶内容为材质的部分贴图通道,贴图的uv通道,固有色贴图,光影贴图,反射光设置
因为很多小伙伴没接触过3dmax maya blender u3d ue4这类的3d编辑器,
babylon的inspector操作类似上述的3d编辑器,本章节从最基本的操作讲解;
基本在babylon的inspector编辑器内的操作为控制模型的transform值(位置、旋转、缩放),
模型Mesh 引用了 材质Material,材质Material 引用了贴图Texture;替换材质和贴图,修改参数查看效果。
额外补充:(基于gltf2.0标准,1个mesh只有1个Material,.babylon文件除外,在.babylon模型代码中可实现复合模型和复合材质)
官方操作文档的末尾有拓展进阶链接 The Inspector | Babylon.js Documentationhttps://doc.babylonjs.com/how_to/debug_layer
Display and Use the Inspector
本次模型用到glb资源可以下载,只设置1分。
babylonjs官方虚拟展厅.glb模型资源_glb模型下载,babylon加载glb模型-互联网文档类资源-CSDN下载https://download.csdn.net/download/maki077/13061978
方便直接把.glb 丢到官方在线沙盒查看,或者是本地加载配合inspector调试。
如果不想下载,也可以查看官方在线运行地址:
模型为两个展厅和lightmap二套uv技术展示
Babylon.js Playgroundhttps://www.babylonjs-playground.com/#4AJ16M#5
Babylon.js - Glowing Espilit demohttps://www.babylonjs.com/demos/glowingespilit/
Vernissagehttps://vernissage.phire.de/
以下说明使用glowingespilit的例子,也可以从上述链接里下载模型拖拽到sandbox中
首先需要在左边面板打开picking mode,确认按钮常亮后,
这是点击场景的模型,就可以选中模型了。
缺点:piking常亮后,很容易误触点到其他模型。
避免点击到玻璃等模型。(隐藏后还能看到影子,是因为使用了光影贴图,非实时光影)
但是根据模型建模时,模型有中心点pivot,控制transform的坐标系位置就中心点位置。旋转则是绕着中心点旋转。
例如一扇门,中心点在正中心,绕y轴(绿轴)旋转,则是龙卷风或者轮胎旋转
中心点在门的一侧,绕y轴(绿轴)旋转就是正常的开门
中心点在门外,绕y轴(绿轴)旋转就是 卫星绕地运动
展厅中的小桌子中心点就在模型外
【特殊情况】这个小屏风模型的中心点在模型边缘,
它的xyz朝向为z-up的左手坐标系,
它绕y轴旋转的方向则应该是如图垂直于地面的绿色圆圈,平行于xz平面。
但是拖拽圆圈时则乱动bug,例如下方gif图
猜测bug原因可能是因为模型制作时的y-up和z-up坐标系不同
也可能是因为模型制作时是垂直放置,然后再水平摆放,才导致绕y轴的绿圈垂直地面(大胆猜测)
但是通过右侧面板调整旋转值则正常,所以拖拽右边面的旋转y值时,正常的绕y轴旋转。
类似于在ue4场景全局坐标系中修改某个物体的坐标系
【就很神奇,不是y-up,结果修改rotation-y值,却按照y-up的方式旋转】如gif图
符合正常的xyz旋转的红绿蓝圈,绕y轴旋转的绿圈平行于地面,控制绕y旋转可以通过拖拽绿圈,也可以右边面板调试。
Babylon.js Playgroundhttps://www.babylonjs-playground.com/#UBWFJT#2
可以试着拖拽旋转小模型,查看坐标系变化,就非常正常,和上面的小屏风不是一个手感
缺点:在场景里非常容易误操作点到其他模型
API:BoundingBoxGizmo | Babylon.js Documentationhttps://doc.babylonjs.com/api/classes/babylon.boundingboxgizmo
案例:Playground search page | Babylon.js Documentationhttps://doc.babylonjs.com/playground/?code=Boundingbox
在模型加载完毕后,通过加载返回值的模型数组,或是通过模型名字找到模型对象
scene.getMeshByName("bloc.000").position = new BABYLON.Vector3(-1,0, -9);
mesh[0].rotation = new BABYLON.Vector3(0, Math.PI/2, 0);//绕y周旋转90°,弧度和角度的换算
mesh[i].scaling = new BABYLON.Vector3(0.5, 0.6, 0.5);
官方提示信息,有四元数存在,三维向量会被忽视
处理方法①:四元数设置为空
mesh.rotationQuaternion = null; //Any version of Babylon.js
mesh.rotation = BABYLON.Vector3(); //babylon.js versions > 4.00
mesh.rotate(BABYLON.Axis.Y, yaw, BABYLON.Space.LOCAL);
mesh.rotate(BABYLON.Axis.X, pitch, BABYLON.Space.LOCAL);
mesh.rotate(BABYLON.Axis.Z, roll, BABYLON.Space.LOCAL);
//Math.PI
mesh.rotation = new BABYLON.Vector3(pitch, yaw, roll);
参考论坛地址链接:
Can't get skull rotator (playground) to work with GLTF model - #2 by Evgeni_Popov - Questions - Babylon.js
摘要:
rotation.y不起作用原因:
The meshes loaded from a .gltf file use the rotationQuaternion property instead of rotation.
If you want to switch to using rotation instead, use:
scene.getMeshByName("Cube").rotationQuaternion = null;
By default, your camera is far from your object, that’s why it appears small on the screen.
You can use scene.createDefaultCamera(true, true, true);
in the ImportMesh callback to set a camera that will display your mesh with a good size on the screen.
scene.getMeshByName("Cube").rotationQuaternion = null;
scene.getMeshByName("Cube").rotation.y += 0.005;
②可以new一个三维向量值给rotation
e.source.rotation = new BABYLON.Vector3(0, 30, 0);//OK
e.source.scaling=new BABYLON.Vector3(1,1,1);//或者
e.source.rotation.y = Math.PI/2 ;//先用上方Vector重新设置,就可以这样设置值
③【个人习惯】可以new一个单位的三维向量值给scale值(代码调用为.scaling =)
//个人习惯用赋予scale的方法,来使rotation position生效
e.source.scaling=new BABYLON.Vector3(1,1,1);//放大缩小值为1
e.source.rotation.y = Math.PI/2 ;//先用上方Vector重新设置,就可以这样设置值
//在BABYLON.SceneLoader.ImportMesh加载成功的回调函数中查找模型
//注意3dmax里面配置名字时可能带空格,或者同名情况发生,babylon会另外命名
scene.getMeshById("bloc.000").position.y = 1;
scene.getMeshByName("bloc.000").scaling = new BABYLON.Vector3(1,1.5,1);
//scene.getMeshByUniqueId(512).rotation.y = Math.PI //[不推荐使用]
//或者通过scene类的数组变量meshes,通过下标找到对应的模型
//【注意】数组下标0经常为整个模型对象,多看打印log数据和inspector列表节点scene.transformNodes
scene.meshes[0].rotation.y=Math.PI;
右侧mesh面板最下方可以打开线框模式,查看当前模型的面是否密集
//用setEnabled(Boolean)控制
scene.getMeshByName("bloc.000").setEnabled(false);
scene.getMeshByName("bloc.000").alphaIndex=1.7976931348623157e+308
Transparent Rendering | Babylon.js Documentationhttps://doc.babylonjs.com/divingDeeper/materials/advanced/transparent_rendering#alpha-index
上面例子用的都是lightmap贴图烘焙出来的虚拟影子,使用lightmap可以节约内存资源。
scene.getMeshByName("bloc.000").receiveShadows = true;
scene.getMeshByName("bloc.000").infiniteDistance = true;
设置infiniteDistance 为true后,不在原地,变成远处物体
把mesh的renderingGroupId改成大于0的数,可以让mesh最后绘制
Transparent Rendering | Babylon.js Documentation
例如猴子RenderingGroupID为3,在柱子上一层,所以柱子无法遮挡猴子
scene.getMeshByName("bloc.000").renderingGroupId = 1 ;
scene.getMeshByName("suzanne.000").renderingGroupId = 3 ;
类似u3d的,每一位都是一种状态。
所以默认值为0xFFFFFFF0,16进制除了个位所有值都为1,位与计算后不为0,则显示。
API:限制摄像机查看具有相同 layerMask 的对象。
layerMask为1的摄像机将渲染mesh.layerMask & camera.layerMask!==0。
API:Restricts the camera to viewing objects with the same layerMask. A camera with a layerMask of 1 will render mesh.layerMask & camera.layerMask!== 0
Playground search page | Babylon.js Documentationhttps://doc.babylonjs.com/playground/?code=layerMask
要想与镜头有碰撞效果,镜头也需要添加checkCollisions为true;
空气墙的做法就是隐藏visibility = 0,且有碰撞
scene.getMeshByName("bloc.000").checkCollisions = true
scene.cameras[0].checkCollisions = true
material.diffuseColor = BABYLON.Color3.Black();
material.lightmapTexture = lightmapTexture;
material.lightmapTexture.coordinatesIndex = 1;// 0 1 2 3,使用第二套uv通道
material.useLightmapAsShadowmap = true;//设置允许光影贴图
绘制对象之前在目标网格上绘制一个透明的边界框,并创建一个查询,与WebGL引擎检查边界框是否可见。如果边界框可见,对象就会被绘制,如果不可见,对象就不会被绘制。
sphere.occlusionQueryAlgorithmType
= BABYLON.AbstractMesh.OCCLUSION_ALGORITHM_TYPE_CONSERVATIVE;
sphere.isOccluded = true;
sphere.occlusionType = BABYLON.AbstractMesh.OCCLUSION_TYPE_STRICT;
algorith算法 分为 Conservative保守 和 Accurate精确
Occlusion Queries | Babylon.js DocumentationLearn all about leveraging occlusion queries in Babylon.js.https://doc.babylonjs.com/divingDeeper/occlusionQueries
官方例子,看不到墙后的球,背景为绿色
看到墙后的球,背景为蓝色
Babylon.js Playgroundhttps://playground.babylonjs.com/#QDAZ80#5
scene.getMeshByName("bloc.000").enableEdgesRendering(); //0.95 1.1 0.5
//.enableEdgesRendering(0.95);//默认值
scene.getMeshByName("bloc.000").edgesWidth = 2;
//【注意】颜色要4维向量才能生效
// scene.getMeshByName("bloc.000").edgesColor = new BABYLON.Color4(0,1,0,1);
// scene.getMeshByName("bloc.000").edgesColor = new BABYLON.Color4.FromHexString("#FF00FFFF");
scene.getMeshByName("bloc.000").edgesColor = new BABYLON.Color4.FromInts(0,255,255,255);
// scene.getMeshByName("bloc.000").disableEdgesRendering();//停止边框渲染
// instance实例化的也有边框,【特殊不额外增加drawcall】
// scene.getMeshByName("bloc.000").edgesShareWithInstances = true;
点积是矢量之间角度的余弦,所以对于默认的epsilon 0.95,角度是acos(.95) ~= 18度--所以如果两个面之间的角度小于这个角度,则不会画线。
sourceMesh.edgesShareWithInstances = true;//影分身也添加边框,不影响drawcall
Babylon.js Playgroundhttps://playground.babylonjs.com/#7BY3TM
//scene.getMeshByName("bloc.000").renderOverlay = true;
scene.getMeshByName("bloc.000").renderOutline = true;
scene.getMeshByName("bloc.000").outlineWidth = 0.01
scene.getMeshByName("bloc.000").outlineColor = BABYLON.Color3.Red();
再加个dof(depth of field)景深效果,
每个模型的drawcall又会增加
再开bloom辉光特效,增加一个mesh要多出来3次drawcall
再加一个outline,加一个mesh会总计多出来5个drawcall
如果场景有多个模型,每个模型多5次drawcall,在优化时请多注意,毕竟特效越多就越卡
bloom辉光测试drawcall:
Babylon.js Playgroundhttps://playground.babylonjs.com/#LRFB2D#159
剩下vertex colors 和 vertex normals 顶点颜色 和 顶点法线 ,
以及面法线和顶点法线区别 涉及shader着色器相关,请参阅其他文章
Babylon.js Playgroundhttps://www.babylonjs-playground.com/#4AJ16M#366
function assignLightmapOnMaterial(material, lightmap) {
material.diffuseColor = BABYLON.Color3.Black();
material.lightmapTexture = lightmap;
material.lightmapTexture.coordinatesIndex = 1;
material.useLightmapAsShadowmap = true;
}
var delayCreateScene = function () {
var scene = new BABYLON.Scene(engine);
BABYLON.SceneLoader.ImportMesh(
"",
"https://models.babylonjs.com/CornellBox/",
"cornellBox.babylon",
scene,
function (meshes) {
scene.createDefaultCameraOrLight(true, true, true);
scene.createDefaultEnvironment();
scene.ambientColor = BABYLON.Color3.White();
// we have to cycles through objects to assign their lightmaps
let lightmappedMeshes = ["bloc.000", "suzanne.000", "cornellBox.000"];
console.log(scene);
// scene.transformNodes
scene.getMeshById("bloc.000").position.y=1;
scene.getMeshByName("bloc.000").scaling=new BABYLON.Vector3(1,1.5,1);
// scene.getMeshByUniqueId(651).rotation.y=Math.PI;
// scene.getMeshByName("bloc.000").setEnabled(false);
// scene.rootNodes[0].isEnabled (false) ;//no
// scene.getMeshByName("bloc.000").visibility = 0.5
// scene.getMeshByName("bloc.000").alphaIndex=1.7976931348623157e+308
// scene.getMeshByName("bloc.000").receiveShadows = true;
// scene.getMeshByName("bloc.000").infiniteDistance = true;
// scene.getMeshByName("cornellBox.000").renderingGroupId = 0 ;
// scene.getMeshByName("bloc.000").renderingGroupId = 1 ;
// scene.getMeshByName("suzanne.000").renderingGroupId = 3 ;
// scene.getMeshByName("bloc.000").checkCollisions = true
// scene.cameras[0].checkCollisions = true
scene.getMeshByName("bloc.000").occlusionType
= BABYLON.AbstractMesh.OCCLUSION_TYPE_OPTIMISTIC;
scene.getMeshByName("bloc.000").isOccluded = true;
scene.getMeshByName("bloc.000").occlusionQueryAlgorithmType
= BABYLON.AbstractMesh.OCCLUSION_ALGORITHM_TYPE_CONSERVATIVE;
for (let i = 0; i < lightmappedMeshes.length; i++) {
let currentMesh = scene.getMeshByName(lightmappedMeshes[i]);
// lightmap texture creation
let currentLightmap = new BABYLON.Texture(
"https://models.babylonjs.com/CornellBox/" + currentMesh.name + ".lightmap.jpg",
scene);
// if only one material
if (!currentMesh.material.subMaterials) {
assignLightmapOnMaterial(currentMesh.material, currentLightmap);
} else {
// subMaterials
for (let j = 0; j < currentMesh.material.subMaterials.length; j++) {
assignLightmapOnMaterial(currentMesh.material.subMaterials[j], currentLightmap);
}
}
}
});
return scene;
};