三、组件
(4)光源
引擎自带有多种光源,现示例如下:
点光源示例,核心代码如下:
javascript
1 var createScene = function () { //创建场景的方法
2 var scene = new BABYLON.Scene(engine); //获取场景对象
3 var camera = new BABYLON.ArcRotateCamera("camera1",
4 0, 0, 0, new BABYLON.Vector3(0, 0, 0), scene); //创建弧度旋转相机
5 camera.setPosition(new BABYLON.Vector3(0,30,35)); //设置相机的位置
6 camera.attachControl(canvas, true); //开启控制
7 //创建点光源并指定位置
8 var light = new BABYLON.PointLight("light", new BABYLON.Vector3(-20, 20, 20),
scene);
9 light.diffuse=new BABYLON.Color3(1, Math.random(), Math.random());
10 light.range=100; //设置光源的照射范围
11 light.intensity=1.1; //设置光源的强度
12 ......//此处省略了向场景中添加网格对象的方法,读者可自行查看随书源代码
13 return scene; //返回场景对象
14 };
说明:此段代码的功能为创建场景和弧度旋转相机,设置相机位置并开启控制,创建点光源对象并指定点光源的位置、颜色、照射范围和光照强度。其中向场景添加网格对象的方法与前面案例中的网格对象代码相同,读者可自行查看随书源代码。
聚光灯光源示例,核心代码:
javascript
var createScene = function () { //创建场景
2 var ambientColor=new BABYLON.Color3(0.2,0.2,0.2); //地板环境色
3 var scene = new BABYLON.Scene(engine); //设置环境色
4 scene.ambientColor=new BABYLON.Color3(1,1,1); //设置场景环境色
5 var camera = new BABYLON.ArcRotateCamera("Camera",
6 0, 0.8, 90, BABYLON.Vector3.Zero(), scene); //创建弧度旋转相机
7 camera.lowerBetaLimit = 0.1; //设置相机最小的旋转角度
8 camera.upperBetaLimit = (Math.PI / 2) * 0.9; //设置相机最大的旋转角度
9 camera.lowerRadiusLimit = 1; //设置相机最小的旋转半径
10 camera.upperRadiusLimit = 150; //设置相机最大的旋转半径
11 camera.attachControl(canvas, true); //开启控制
12 camera.setPosition(new BABYLON.Vector3(-20, 11, -20)); //设置摄像机位置
13 var light = new BABYLON.SpotLight("spotLight", new BABYLON.Vector3(-40, 40, -40),
14 new BABYLON.Vector3(1, -1, 1), Math.PI / 5, 30, scene); //创建聚光灯光源
15 light.position = new BABYLON.Vector3(-40, 40, -40); //设置聚光灯位置
16 light.shadowMaxZ = 100; //设置阴影投射的最远距离
17 light.shadowMinZ = 10; //设置阴影投射的最近距离
18 var shadowGenerator = new BABYLON.ShadowGenerator(1024, light); //创建阴影计算对象
19 shadowGenerator.bias = 0.001; //设置阴影偏移量
20 shadowGenerator.normalBias = 0.02; //设置正常偏移量
21 shadowGenerator.useContactHardeningShadow = true; //开启接触硬化阴影
22 shadowGenerator.contactHardeningLightSizeUVRatio = 0.05; //设置阴影的软化速度
23 shadowGenerator.setDarkness(0.5); //设置暗值
24 var meshArray=[]; //网格对象数组
25 ......//此处省略了创建网格对象的代码,读者可自行查看随书源代码
26 var groundMaterial = new BABYLON.StandardMaterial("groundMaterial", scene);
//创建地板的材质
27 groundMaterial.ambientColor=ambientColor; //设置地板环境色
28 var ground =BABYLON.MeshBuilder.CreateGround("gd", {width: 60, height:60 ,
subdivsions: 4}, scene);
29 ground.material=groundMaterial; //设置地板材质
30 ground.receiveShadows = true; //设置地板接收阴影
31 var meshMaterial=new BABYLON.StandardMaterial("meshMaterial", scene); //创建材质
32 meshMaterial.ambientColor=ambientColor; //设置材质的环境色
33 for(var i=0; i<meshArray.length; i++){ //遍历网格对象数组
34 shadowGenerator.getShadowMap().renderList.push(meshArray[7-i]);
35 meshArray[i].material=meshMaterial; //设置各个网格对象的材质
36 meshArray[i].material.diffuseColor=new BABYLON.Color3(1, Math.random(),
Math.random());
37 meshArray[i].position.x=-16+Math.floor(i/2)*10; //设置各个网格对象的 x坐标
38 meshArray[i].position.y=4; //设置各个网格对象的 y坐标
39 meshArray[i].position.z=(i%2==0)? -4:6; //设置各个网格对象的 z坐标
40 }}
、 ❑ 第1~12行代码的功能为创建场景并设置场景的环境色,创建弧度旋转相机并设相机的最小旋转角度、最大旋转角度、最小旋转半径、最大旋转半径和位置以及开启相机控制。
❑ 第13~23行的功能为创建聚光灯光源并设置聚光灯光源的阴影投射范围,创建阴影计算对象并设置阴影偏移量、正常偏移量、阴影类型和暗值。其中,接触硬化阴影仅限WebGL 2.0中有。
❑ 第24~39行代码的功能为创建地板网格对象并设置其材质与位置,创建不同形状的网格对象并设置材质和位置,以及将它们放入阴影计算列表。
平行光源示例,核心代码 :
平行光源,示例如下:
javascript
QQQ:
1 var createScene = function () {
2 var scene = new BABYLON.Scene(engine); //创建场景
3 var camera = new BABYLON.ArcRotateCamera("camera1",
4 0, 0, 0, new BABYLON.Vector3(0, 0, 0), scene); //创建弧度旋转摄像机
5 camera.setPosition(new BABYLON.Vector3(0,30,35)); //设置弧度旋转相机的位置
6 camera.attachControl(canvas, true); //开启控制
7 var light = new BABYLON.DirectionalLight("DirectionalLight",
8 new BABYLON.Vector3(-1, -1, -1), scene); //创建平行光并指定方向
9 light.diffuse=new BABYLON.Color3(1, Math.random(), Math.random());
//设置光的颜色
10 light.position=new BABYLON.Vector3(30,30,30); //设置阴影投放的位置
11 light.shadowMaxZ = 100; //设置最大的投影距离
12 light.shadowMinZ = 10; //设置最小的投影距离
13 ......//此处省略了阴影计算和创建网格对象的代码,读者可自行查看随书源代码
14 return scene; //返回场景对象
15 };
此段代码的功能为创建场景对象和弧度旋转摄像机,并设置其位置以及开启相机控制,创建平行光并指定其方向、阴影投放位置和投影范围。创建平行光中的第二个参数为光源照射的方向。此外,需特别注意光源的position属性,其设置不当可能导致部分网格对象无法投射出阴影。
(5) 材质
对网格对象进行材质设置,网格对象才能更美观地呈现在场景中。材质决定了此网格的颜色、透明度等外观信息。
1.标准材质
标准材质允许在网格对象上覆盖颜色和纹理,并且需要光线才能看,
示例搭建基本场景,创建4个球体网格对象和标准材质,核心代码如下:
javascript
1 var canvas = document.getElementById("renderCanvas"); //获取Canvas DOM对象
2 var engine = new BABYLON.Engine(canvas, true); //获取Babylon引擎对象
3 var createScene = function () {
4 var scene = new BABYLON.Scene(engine); //获取场景对象
5 var camera = new BABYLON.ArcRotateCamera("Camera",
6 -Math.PI / 2, 3 * Math.PI / 16, 15, BABYLON.Vector3.Zero(), scene);
//创建弧度旋转相机
7 camera.attachControl(canvas, true); //开启相机控制
8 var redMat = new BABYLON.StandardMaterial("redMat", scene); //创建标准材质
9 redMat.emissiveColor = new BABYLON.Color3(1, 0, 0); //设置自发光颜色为红色
10 ......//此处省略创建其他球体标准材质的代码,读者可自行查看随书源代码
11 var sphereCenter=BABYLON.MeshBuilder.CreateSphere("sphere", {diameter: 0.0
1}, scene);
12 var lightRed = new BABYLON.SpotLight("spotLight",
13 new BABYLON.Vector3(), new BABYLON.Vector3(0, -1, 0), Math.PI / 2, 1.5,
scene);
14 lightRed.diffuse = new BABYLON.Color3(1, 0, 0); //设置聚光灯颜色为红色
15 lightRed.position.set(3,2,3); //设置红色聚光灯的位置
16 lightRed.parent=sphereCenter; //将其父类属性指向中心球
17 ......//此处省略创建其他颜色聚光灯光源的代码,读者可自行查看随书源代码
18 var redSphere = BABYLON.MeshBuilder.CreateSphere("sphere", {diameter:
0.25}, scene);
19 redSphere.material = redMat; //设置其材质
20 redSphere.position = lightRed.position; //球体位置设为红色聚光灯的位置
21 redSphere.parent=sphereCenter; //将其父类属性指向中心球
22 ......//此处省略创建其他颜色球体网格对象的代码,读者可自行查看随书源代码
23 var groundMat = new BABYLON.StandardMaterial("groundMat", scene);
//创建地板的标准材质
24 var ground = BABYLON.MeshBuilder.CreateGround("ground", {width: 15, height
: 15}, scene);
25 ground.material = groundMat; //设置地板的材质
26 var angle=0; //旋转角度
27 scene.onBeforeRenderObservable.add(()=>{ //场景渲染之前的执行函数
28 angle=angle+0.01; //角度增加
29 sphereCenter.rotation.set(0, angle,0);
30 ......//此处省略Babylon中GUI界面的搭建和控制方法的代码,它将在下文进行详细介绍
31 }
❑ 第1~6行的功能为获取Canvas DOM对象、Babylon引擎对象、场景对象,创建弧度旋转相机,开启相机控制。
❑ 第7~25行为创建4种标准材质并设置为自发光颜色。创建4种不同颜色的聚光灯光源,创建4种不同颜色的球体网格对象,将球体位置设置为对应颜色聚光灯光源的位置,将聚光灯和球体的父类属性都指向中心球,最后创建地板并设置其材质为标准材质。
❑ 第26~31行代码为不断旋转中心球,从而实现旋转聚光灯光源和球体网格对象。将聚光灯和球体的父类属性都指向中心球,此时中心球中包含聚光灯和球体。旋转中心球,就会同时旋转聚光灯光源和球体网格对象,读者可以将这个作为一个开发技巧积累下来。
示例中GUI界面的开发和控制方法的开发。具体代码如下。
javascript
1 var advancedTexture = BABYLON.GUI.AdvancedDynamicTexture.CreateFullscreenUI("UI");
//全屏纹理
2 var sceneAmbientColorFlag=false; //场景环境色开启标志
3 var leftPanel= createPanel(advancedTexture,
4 BABYLON.GUI.Control.VERTICAL_ALIGNMENT_CENTER,
5 BABYLON.GUI.Control.HORIZONTAL_ALIGNMENT_LEFT); //左侧面板
6 var senceCheckBox=createCheckbox(leftPanel, "开启场景环境颜色",
7 BABYLON.GUI.Control.HORIZONTAL_ALIGNMENT_LEFT); //创建单选框
8 senceCheckBox.onIsCheckedChangedObservable.add(function (value){//单选框控制方法
9 sceneAmbientColorFlag=value; //更改场景环境色开启标志
10 if(! sceneAmbientColorFlag) { //如果没开启
11 scene.ambientColor=new BABYLON.Color3(0,0,0); }}) //场景环境色设置为黑色
12 var senceColorPicker=createColorPicker(leftPanel, false, "",
13 scene.ambientColor, BABYLON.GUI.Control.HORIZONTAL_ALIGNMENfuT_CENTER);
14 senceColorPicker.onValueChangedObservable.add(function(value) { //颜色改变事件
15 if(sceneAmbientColorFlag) { //如果开启场景环境色
16 scene.ambientColor.copyFrom(value); }}); //将场景环境色指定为选择的颜色值
17 ......//此处省略其他颜色选择器的创建和控制方法的代码,读者可自行查看随书源代码
18 function createCheckbox(panel, text, horizontalAlignment) { //创建单选框
19 var checkbox = new BABYLON.GUI.Checkbox(); //新建单选框
20 checkbox.width = "20px"; //单选框的宽
21 checkbox.height = "20px"; //单选框的高
22 checkbox.isChecked = false; //单选框的状态
23 checkbox.color = "green"; //单选框的颜色
24 var header = BABYLON.GUI.Control.AddHeader(checkbox, text, "180px", {
//给单选框添加文字头
25 isHorizontal: true,
26 controlFirst: true});
27 header.height = "30px"; //设置文字头的高度
28 header.color = "white"; //设置文字的颜色
29 header.outlineWidth ="4px"; //轮廓宽度
30 header.outlineColor ="black"; //轮廓颜色
31 header.horizontalAlignment=horizontalAlignment; //水平布局
32 panel.addControl(header); //将文字头添加进面板
33 return checkbox; } //返回单选框对象
34 function createPanel(advancedTexture, verticalAlignment, horizontalAlignment) {
//创建面板
35 var panel = new BABYLON.GUI.StackPanel(); //创建静态的面板
36 panel.width = "200px"; //面板的宽
37 panel.verticalAlignment = verticalAlignment; //面板的垂直布局
38 panel.horizontalAlignment = horizontalAlignment; //面板的水平布局
39 advancedTexture.addControl(panel); //添加控制
40 return panel; } //返回面板
41 function createColorPicker(panel, usetext, text, defultColor, horizontalAlignment)
{//创建颜色控件
42 if(usetext){ //如果使用文本控件
43 var textBlock = new BABYLON.GUI.TextBlock(); //创建文本控件
44 textBlock.text = text; //设置文本内容
45 textBlock.color = "white"; //设置文本颜色
46 textBlock.height = "30px"; //文本颜色
47 panel.addControl(textBlock); } //面板中添加文本控件
48 var picker = new BABYLON.GUI.ColorPicker(); //创建颜色控件
49 picker.value =defultColor; //默认颜色
50 picker.height = "150px"; //颜色控件的高
51 picker.width = "150px"; //颜色控件的宽
52 picker.horizontalAlignment =horizontalAlignment; //水平布局方式
53 panel.addControl(picker) //添加控制
54 return picker; } //返回颜色控件
❑ 第1~18行的功能为创建GUI全屏纹理、左右侧面板、单选框和颜色选择器,其中单选框添加状态改变事件,颜色选择器添加状态改变事件。单选框控制场景环境色的开启,颜色选择器会改变地板材质的环境颜色、漫反射颜色、自发光颜色和镜面颜色。
❑ 第18~33行为创建GUI单选框,设置单选框的宽度、高度、状态、颜色,并添加文字头说明单选框的作用。然后设置文字头的高度、文字颜色、轮廓宽度、轮廓颜色和水平布局方式,最后将文字头添加进面板和返回单选框对象。
❑ 第34~40行为创建面板,设置面板的宽度,垂直布局和水平布局方式,并添加进GUI全屏纹理,最后返回面板对象。
❑ 第41~54行为创建颜色控件,添加文本控件以及设置文本控件的内容、颜色和文本的高度,设置颜色控件的宽度、高度和水平布局方式,最后将颜色控件添加进面板并返回面板对象。
2.着色器材质
它允许开发人员使用自定义的着色器进行渲染。通过该材质可以开发出很多酷炫的特效,对画面的提升有巨大作用。
示例中创建着色器材质,将着色器材质应用到圆环结网格对象,具体代码如下所示:
javascript
1 var createScene = function() { //创建场景的函数
2 var scene = new BABYLON.Scene(engine); //创建场景
3 var camera = new BABYLON.ArcRotateCamera("Camera",
4 0, Math.PI / 2, 12, BABYLON.Vector3.Zero(), scene); //创建弧度旋转摄像机
5 camera.attachControl(canvas, false); //设置摄像机的控制
6 ......//此处省略顶点着色器和片元着色器的代码,它们将在下文进行详细介绍
7 var shaderMaterial = new BABYLON.ShaderMaterial("shader", scene, {//创建着色器材质
8 vertex: "custom", //着色器传入方式
9 fragment: "custom", }, {
10 attributes: ["position", "normal"], //attribute变量
11 uniforms: ["world", "worldView", "worldViewProjection", "view",
"projection"]});
12 var refTexture = new BABYLON.Texture("textures/ref.jpg", scene);
//加载计算所需纹理
13 refTexture.wrapU = BABYLON.Texture.CLAMP_ADDRESSMODE; //设置 U轴纹理拉伸方式
14 refTexture.wrapV = BABYLON.Texture.CLAMP_ADDRESSMODE; //设置 V轴纹理拉伸方式
15 shaderMaterial.setTexture("refSampler", refTexture); //将纹理送入着色器
16 shaderMaterial.backFaceCulling = false; //材质关闭背面剪裁
17 var mesh = BABYLON.Mesh.CreateTorusKnot("mesh", 2, 0.5, 128, 64, 2, 3, scene);
//创建圆环结
18 mesh.material = shaderMaterial; //将圆环结的材质设置为着色器材质
19 var angle=0; //旋转角度
20 scene.onBeforeRenderObservable.add(()=>{ //渲染之前对应的函数
21 angle=angle+0.01; //增加旋转角度
22 mesh.rotation.set(0, angle,0); //修改圆环结的旋转角度
23 })
24 return scene; //返回场景
25 }
此段代码的作用主要是创建场景和弧度旋转摄像机,然后创建着色器材质,并且指定着色器传入方式,传入attribute变量和uniform变量。然后加载纹理,设置纹理UV轴的拉伸方式,关闭背面剪裁并将纹理送入GPU管线。最后将圆环结的材质设置为着色器材质,并不断旋转圆环结。本案例采用了加载程序中着色器字符串的方法,读者可以自行体验其他两种着色器加载方式。
示例中着色器代码的开发,包括顶点着色器和片元着色器。着色器代码具体如下所示:
javascript
1 BABYLON.Effect.ShadersStore["customVertexShader"]= //顶点着色器
2 "in vec3 position; \r\n"+ //顶点坐标
3 "in vec3 normal; \r\n"+ //顶点法向量
4 "uniform mat4 worldViewProjection; \r\n"+ //总变换矩阵
5 "out vec4 vPosition; \r\n"+ //输出片元着色器的顶点坐标
6 "out vec3 vNormal; \r\n"+ //输出片元着色器的法向量
7 "void main() {\r\n"+
8 " vec4 p = vec4( position, 1. ); \r\n"+ //顶点坐标
9 " vPosition = p; \r\n"+ //顶点坐标传递给片元着色器
10 " vNormal = normal; \r\n"+ //法向量传递给片元着色器
11 " gl_Position = worldViewProjection * p; \r\n"+ //根据总变换矩阵计算此次绘制的顶
点位置
12 "}\r\n";
13 BABYLON.Effect.ShadersStore["customFragmentShader"]= //片元着色器
14 "precision highp float; \r\n"+ //浮点数精度
15 "uniform mat4 worldView; \r\n"+ //视图矩阵
16 "in vec4 vPosition; \r\n"+ //从顶点着色器接收的顶点坐标
17 "in vec3 vNormal; \r\n"+ //从顶点着色器接收的法向量
18 "uniform sampler2D refSampler; \r\n"+ //纹理数据
19 "void main() {\r\n"+
20 " vec3 e = normalize( vec3( worldView * vPosition ) ); \r\n"+ //将顶点坐标
变换至相机坐标系下并单位化
21 " vec3 n = normalize( worldView * vec4(vNormal, 0.0) ).xyz; \r\n"+//将法向量变
换至相机坐标系下并单位化
22 " vec3 r = reflect( e, n ); \r\n"+ //求反射向量
23 " float m = 2. * sqrt(\r\n"+ //求球形纹理的反射向量长度
24 " pow( r.x, 2. ) +\r\n"+
25 " pow( r.y, 2. ) +\r\n"+
26 " pow( r.z + 1., 2. )\r\n"+
27 " ); \r\n"+
28 " vec2 vN = r.xy / m + .5; \r\n"+ //单位化纹理的反射向量 xy坐标并右移0.5
29 " vec3 base = texture2D( refSampler, vN).rgb; \r\n"+ //纹理采样
30 " glFragColor = vec4( base, 1. ); \r\n"+ //输出到片元的颜色
31 "}\r\n";
❑ 第1~12行为此程序的顶点着色器。其功能是根据总变换矩阵计算出每次绘制的顶点位置,并将顶点坐标和顶点法向量传递给片元着色器。
❑ 第13~31行为此程序的片元着色器。其功能是将顶点坐标和顶点法向量变化到摄像机坐标系,并求出顶点的反射向量,然后求出球形纹理上对应的反射向量,并计算出球形纹理的采样坐标,最后将纹理采样的颜色输出到片元。