神说要有光,便有了光
神说光是好的,于是把光与暗分开了
在所有的3d游戏或者动画中,光与阴影都是非常重要的一部分,阴影可以影响到很多东西,一个游戏,阴影可以说是分辨一个游戏画面的好坏。
这一章中涉及到:
- 物体材质
- 添加光源
- 添加阴影
- 添加阴影的受体
在前面已经介绍过怎么样创建场景添加相机与物体,那么就直接贴创建场景的代码了
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<!--<script src="../three.min.js"></script>--><!--我发现我用的这个three.min.js本地版本没有辅助线-->
<script src='https://threejs.org/build/three.js'></script>
<title>场景</title>
<style>
body{
margin:0;padding:0;
overflow:hidden;
}
</style>
</head>
<body>
<div id="WebGL-output"></div>
<script>
//初始化函数。在加载three之后调用,初始化所有的东西
function init(){
//创建场景。所有的物体对象都在场景上相当于是一个舞台
var scene = new THREE.Scene();
//创建透视相机
var camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 0.1, 1000);
//辅助线
var axes = new THREE.AxesHelper(20);
scene.add(axes);
//渲染器
var renderer = new THREE.WebGLRenderer();
renderer.setClearColor(new THREE.Color(0xEEEEEE));
renderer.setSize(window.innerWidth,window.innerHeight);
//THREE.PCFSoftShadowMap THREE.PCFShadowMap BasicShadowMap
//创建平面
//材质种类:MeshLambertMaterial MeshPhongMaterial MeshBasicMaterial
var planeGeometry = new THREE.PlaneGeometry(60, 30);//框架
var planeMaterial = new THREE.MeshBasicMaterial({color: 0xaaaaaa});//材质
var planeMaterial1 = new THREE.MeshPhongMaterial( { color: 0xaaaaaa, dithering: true } );
var plane = new THREE.Mesh(planeGeometry, planeMaterial);//填充
//更改平面位置
plane.rotation.x = -0.5 * Math.PI;
plane.position.x = 15;
plane.position.y = 0;
plane.position.z = 0;
scene.add(plane);
//创建立方体
var cubeGeometry = new THREE.BoxGeometry(4,4,4);
var cubeMaterial = new THREE.MeshBasicMaterial({color: 0xdd4444,wireframe: true});
//wireframe用于表现几何体的框架 默认为false
var cube = new THREE.Mesh(cubeGeometry, cubeMaterial);
//立方体位置
cube.position.x = -4;
cube.position.y = 3;
cube.position.z = 0;
//将立方体添加进入场景
scene.add(cube);
//添加球体
var sphereGeometry = new THREE.SphereGeometry(4, 20 ,20);
var sphereMaterial = new THREE.MeshBasicMaterial({color:0xcc44cc});
var sphere = new THREE.Mesh(sphereGeometry, sphereMaterial);
//球体位置
sphere.position.x = 18;
sphere.position.y = 4;
sphere.position.z = 2;
//将球体加入到场景中
scene.add(sphere);
//柱体
var cylinderGeometry = new THREE.CylinderGeometry( 4, 4, 5, 5);
var material = new THREE.MeshBasicMaterial({color:0xcccc33});
var cylinder = new THREE.Mesh(cylinderGeometry,material);
//设定位置
cylinder.position.x = 2;
cylinder.position.y = 2.5;
cylinder.position.z = 6;
//添加柱体
scene.add(cylinder);
//变化相机位置以及方向
camera.position.x = -30;
camera.position.y = 40;
camera.position.z = 30;
camera.lookAt(scene.position);
//创建canvas
document.getElementById("WebGL-output").appendChild(renderer.domElement);
//渲染
renderer.render(scene,camera);
}
window.onload = init;
</script>
</body>
</html>
相比起上一章的内容,我稍微变大了底部的plane 平台的面积,将柱体和球体的wireframe去掉了,这样就能看到基本材质的效果,效果如下:
emm这个材质看起来非常渣,勉强能认出是一个立体的东西,各个面的颜色都是一样的
THREE.MeshBasicMaterial 这种材质并不会对光源产生反应,所以我们要先修改材质
修改平面的材质以及所有物体对象的材质,将其都变成 THREE.MeshLambertMaterial(朗伯材质)
这种材质会对光有反应,它不包括任何镜面属性,对粗糙物体来说,是非常有用的,它不会反射出周围的环境
...
var planeMaterial = new THREE.MeshLambertMaterial({color: 0xaaaaaa});//平面材质
...
var cubeMaterial = new THREE.MeshLambertMaterial({color: 0xdd4444});//立方体材质
...
var sphereMaterial = new THREE.MeshLambertMaterial({color: 0xcc44cc});//球体材质
...
var material = new THREE.MeshLambertMaterial({color:0xcccc33});//无棱柱材质
材质都更改完毕之后,我们再刷新一下页面:
发现一片漆黑–。从辅助线被遮掉的部分可以隐约看出有黑色的东西。那是因为没有光-。-
添加光源
var spotLight = new THREE.SpotLight(0xffffff);//白色光线
spotLight.position.set(-40,80,-10);//位置
spotLight.castShadow = true;//会产生影子
scene.add(spotLight);//添加光源进入场景
此处添加的是聚光灯光源,是从一个点出发按照一定角度散开的光源
光源有很多类型,比如环境光源AmbientLight 就是在场景中的物体都有的光源,这个光源在所有的物体表面都是随机分布的,
平行光 DirectionalLight 太阳光对于地球来说就类似于平行光
点光源 PointLight 类似于小灯泡那样四散开来的光源
除此之外还有很多,请自行寻找 光源
添加光源之后的样子:
嗯好像有那么点回事了,但是为啥还是没有影子?
原因是,虽然光源已经写了有产生影子的可能性,但是还需要三点:
- 哪些物体能产生影子(比如吸血鬼就没有影子哈那是因为他自己是吸血鬼,他本身自带的属性)
- 产生的影子放在哪(能接受影子的地方)
- 渲染器允许产生影子
为啥这么复杂呢,因为产生影子是一个非常消耗资源的工作,我们得知道在什么地方要产生影子,这个影子可以投到什么地方上面。
添加下面的代码:
renderer.shadowMap.enabled = true;//渲染器将会渲染影子
plane.receiveShadow = true;//让平面能够接受影子
//让物体们能够有自己的影子
cube.castShadow = true;
sphere.castShadow = true;
cylinder.castShadow = true;
完成后发现:
有影子了,但是这影子咋是马赛克影子-,-,虽然站远一点的确看不出来
但是我还是希望影子能够真实一点啊
其实是:在默认情况下为了避免影子渲染过多,设置里面就是有这样的马赛克。同时本来几何体的大小设置的就比较小=。=
所以导致这样的状况出现了。
添加代码
spotLight.shadow.mapSize.width = 2000; // 默认512
spotLight.shadow.mapSize.height = 2000; // 默认512
影子在两个方向上的细致程度,越高表示越细致,到2000的时候感觉差不多可以用了
效果:
我觉得还行。嗯 下一章应该讲到动画与 dat.GUI 组件库便于测试不同数值对表现产生的影响嗯,
(翻书。。。)