Three.js场景的基本组件
1.场景Scene
THREE.Scene被称为场景图,可以用来保存所有图形场景的必要信息。每个添加到Scene的对象,包括Scene自身都继承自名为THREE.Object3D对象。Scene不仅仅是一个数组,还包含了场景图树形结构中的所有节点。
THREE.Scene最常用的方法和属性如下:
1.场景的基本功能
场景可以添加物体、删除物体、获取物体的数量以及获取物体数组,如下代码:
<!DOCTYPE html> <html> <head>
<title>Example 02.01 - Basic Scene</title>
<script type="text/javascript" src="../libs/three.js"></script> <script type="text/javascript" src="../libs/stats.js"></script>
<script type="text/javascript" src="../libs/dat.gui.js"></script>
<style>
body {
/* set margin to 0 and overflow to hidden, to go fullscreen */
margin: 0;
overflow: hidden;
}
</style>
</head>
<body> <div id="Stats-output">
</div>
<!-- Div which will hold the Output -->
<div id="WebGL-output">
</div> <!-- Javascript code that runs our Three.js examples -->
<script type="text/javascript"> // once everything is loaded, we run our Three.js stuff.
function init() { var stats = initStats(); // create a scene, that will hold all our elements such as objects, cameras and lights.
var scene = new THREE.Scene(); // create a camera, which defines where we're looking at.
var camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 0.1, 1000);
scene.add(camera); // create a render and set the size
var renderer = new THREE.WebGLRenderer(); renderer.setClearColor(new THREE.Color(0xEEEEEE, 1.0));
renderer.setSize(window.innerWidth, window.innerHeight);
renderer.shadowMapEnabled = true; // create the ground plane
var planeGeometry = new THREE.PlaneGeometry(60, 40, 1, 1);
var planeMaterial = new THREE.MeshLambertMaterial({color: 0xffffff});
var plane = new THREE.Mesh(planeGeometry, planeMaterial);
plane.receiveShadow = true; // rotate and position the plane
plane.rotation.x = -0.5 * Math.PI;
plane.position.x = 0;
plane.position.y = 0;
plane.position.z = 0; // add the plane to the scene
scene.add(plane); // position and point the camera to the center of the scene
camera.position.x = -30;
camera.position.y = 40;
camera.position.z = 30;
camera.lookAt(scene.position); // add subtle ambient lighting
var ambientLight = new THREE.AmbientLight(0x0c0c0c);
scene.add(ambientLight); // add spotlight for the shadows
var spotLight = new THREE.SpotLight(0xffffff);
spotLight.position.set(-40, 60, -10);
spotLight.castShadow = true;
scene.add(spotLight); // add the output of the renderer to the html element
document.getElementById("WebGL-output").appendChild(renderer.domElement); // call the render function
var step = 0; var controls = new function () {
this.rotationSpeed = 0.02;
this.numberOfObjects = scene.children.length; this.removeCube = function () {
var allChildren = scene.children;
var lastObject = allChildren[allChildren.length - 1];
if (lastObject instanceof THREE.Mesh) {
scene.remove(lastObject);
this.numberOfObjects = scene.children.length;
}
}; this.addCube = function () { var cubeSize = Math.ceil((Math.random() * 3));
var cubeGeometry = new THREE.BoxGeometry(cubeSize, cubeSize, cubeSize);
var cubeMaterial = new THREE.MeshLambertMaterial({color: Math.random() * 0xffffff});
var cube = new THREE.Mesh(cubeGeometry, cubeMaterial);
cube.castShadow = true;
cube.name = "cube-" + scene.children.length; // position the cube randomly in the scene cube.position.x = -30 + Math.round((Math.random() * planeGeometry.parameters.width));
cube.position.y = Math.round((Math.random() * 5));
cube.position.z = -20 + Math.round((Math.random() * planeGeometry.parameters.height)); // add the cube to the scene
scene.add(cube);
this.numberOfObjects = scene.children.length;
}; this.outputObjects = function () {
console.log(scene.children);
}
}; var gui = new dat.GUI();
gui.add(controls, 'rotationSpeed', 0, 0.5);
gui.add(controls, 'addCube');
gui.add(controls, 'removeCube');
gui.add(controls, 'outputObjects');
gui.add(controls, 'numberOfObjects').listen(); render(); function render() {
stats.update(); // rotate the cubes around its axes
scene.traverse(function (e) {
if (e instanceof THREE.Mesh && e != plane) { e.rotation.x += controls.rotationSpeed;
e.rotation.y += controls.rotationSpeed;
e.rotation.z += controls.rotationSpeed;
}
}); // render using requestAnimationFrame
requestAnimationFrame(render);
renderer.render(scene, camera);
} function initStats() { var stats = new Stats(); stats.setMode(0); // 0: fps, 1: ms // Align top-left
stats.domElement.style.position = 'absolute';
stats.domElement.style.left = '0px';
stats.domElement.style.top = '0px'; document.getElementById("Stats-output").appendChild(stats.domElement); return stats;
}
}
window.onload = init </script>
</body>
</html>
结果:
解释:
上面addCube方法给每个添加的正方体添加了一个name属性, cube.name = "cube-" + scene.children.length; 将名称设为"cube-"加上scene的物体的数量(scene.children.length),name属性对于调试非常重要们可以通过scene.getObjectByName(name)获取到物体,然后进行其他移动位置等操作。在dat.GUI界面中用 numberOfObjects 实时的检测scene的物体(这种方式也可以实现监测作用)
点击GUI中的removeCube会调用下面方法移除最后一个添加进去的物体:并且代码中检查该对象是不是THREE.Mesh对象,这样做的原因是避免移除摄像机和光源。当我们移除对象之后需要更新场景中的numberOfObjects
this.removeCube = function () {
var allChildren = scene.children;
var lastObject = allChildren[allChildren.length - 1];
if (lastObject instanceof THREE.Mesh) {
scene.remove(lastObject);
this.numberOfObjects = scene.children.length;
}
};
控制界面的最后一个按钮的标签是 outputObjects,这个函数的作用是在console控制台打印所有对象信息,这样做对于代码调试是非常有用的,对于在有name属性的情况下调试代码非常有用。例如已经知道name值为cube-5,也可使用 console.log(scene.getObjectByName("cube-5")); 打印结果如下:
2.雾化效果:
使用fog属性可以为整个场景添加雾化效果。雾化效果就是场景中的物体离得越远就会变得越模糊。
添加雾化非常简单,如下:
var scene = new THREE.Scene();
scene.fog = new THREE.Fog(0xffffff, 0.015, 100);
效果:
2.相机
Three.js提供了两种相机,正交投影摄像机(THREE.OrthographicCamera)和透视摄像机(PerspectiveCamera),大多数使用的是透视摄像机,更接近于现实世界。
2.1 透视摄像机
透视摄像机接受的参数如下:
这些属性组合到一起影响你所看到的景象,如图:
摄像机的fov属性决定了横向视场。基于aspect属性,纵向视场也就相应地确定了。near属性决定了近面距离,far属性决定了远面距离。近面距离和远面距离之间的区域将会被渲染。
2.2 正交摄像机
正交投影摄像机渲染出的物体大小都是一样,所以不关心使用什么长宽比或者以什么样的视角来观察场景。当使用正交投影摄像机时,你要定义一个被渲染的方块区域。如下属性:
总结起来如下:
3.摄像机聚焦在指定点上
在前面介绍了摄像机需要放在场景中的某个位置,以及摄像机能够看到的区域将会被渲染。通常来说,摄像机会指向场景的中心,用坐标表示就是position(0,0,0)。但是改变摄像机的位置非常容易,如下:
camera.lookAt(new THREE.Vector3(x,y,z));
当然你还可以使摄像机追随场景中某个物体。由于THREE.Mesh对象的位置都是THREE.Vector3对象,所以可以使用camera.lookAt(mesh.position)使摄像机指向某个物体。
3. 渲染器(基于摄像机的角度来计算场景对象在浏览器中会渲染成什么样子。)
Three.js提供了许多的渲染器,如下:
CanvasRenderer
DOMRenderer
SVGRenderer
WebGLRenderer
WebGLRenderTarget
WebGLRenderTargetCube
WebGLShaders
使用最多的是WebGLRenderer,new THREE.WebGLRenderer()来新建一个WebGL渲染器。下面介绍其主要的参数:
antialias:
值:true/false
含义:是否开启反锯齿,设置为true开启反锯齿。
precision:
值:highp/mediump/lowp
含义:着色精度选择。
alpha:
值:true/false
含义:是否可以设置背景色透明。
premultipliedAlpha:
值:true/false
含义:?
stencil:
值:true/false
含义:?
preserveDrawingBuffer:
值:true/false
含义:是否保存绘图缓冲,若设为true,则可以提取canvas绘图的缓冲。
maxLights:
值:数值int
含义:最大灯光数,我们的场景中最多能够添加多少个灯光。
2.制定渲染器的宽高,我们用renderer.setSize(width,height)来设置;
而且一般采用下面直接设置为窗口大小:
renderer.setSize(window.innerWidth, window.innerHeight);
3.追加生成的canvas元素到容器元素中。canvas对象的获取方法为renderer.domElement;
// add the output of the renderer to the html element
document.getElementById("WebGL-output").appendChild(renderer.domElement);
4.设置canvas背景色(clearColor)和背景色透明度(clearAlpha),renderer.setClearColor(clearColor,clearAlpha);
renderer.setClearColor(new THREE.Color(0xEEEEEE, 1.0));
4.几何体和网格
在前面已经使用了几何体和网格。比如向场景中添加球体时代码如下:
var sphereGeometry = new THREE.SphereGeometry(4, 20, 20);
var sphereMaterial = new THREE.MeshLambertMaterial({color: 0x7777ff});
var sphere = new THREE.Mesh(sphereGeometry, sphereMaterial);
我们使用 THREE.SphereGeometry(4, 20, 20) 定义了物体的形状、使用 THREE.MeshLambertMaterial 定义了物体的外观和材质,并将他们合并成能添加到场景中的网格(THREE.Mesh)。
1.几何体的属性和方法
Three.js提供的几何体如下:
代码如下:
<!DOCTYPE html> <html> <head>
<title>Example 02.04 - Geometries</title>
<script type="text/javascript" src="../libs/three.js"></script>
<script type="text/javascript" src="../libs/ParametricGeometries.js"></script>
<script type="text/javascript" src="../libs/ConvexGeometry.js"></script> <script type="text/javascript" src="../libs/stats.js"></script>
<script type="text/javascript" src="../libs/dat.gui.js"></script>
<style>
body {
/* set margin to 0 and overflow to hidden, to go fullscreen */
margin: 0;
overflow: hidden;
}
</style>
</head>
<body> <div id="Stats-output">
</div>
<!-- Div which will hold the Output -->
<div id="WebGL-output">
</div> <!-- Javascript code that runs our Three.js examples -->
<script type="text/javascript"> // once everything is loaded, we run our Three.js stuff.
function init() { var stats = initStats(); // create a scene, that will hold all our elements such as objects, cameras and lights.
var scene = new THREE.Scene(); // create a camera, which defines where we're looking at.
var camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 0.1, 1000); // create a render and set the size
var renderer = new THREE.WebGLRenderer(); renderer.setClearColor(new THREE.Color(0xEEEEEE, 1.0));
renderer.setSize(window.innerWidth, window.innerHeight);
renderer.shadowMapEnabled = true; // create the ground plane
var planeGeometry = new THREE.PlaneGeometry(60, 40, 1, 1);
var planeMaterial = new THREE.MeshLambertMaterial({color: 0xffffff});
var plane = new THREE.Mesh(planeGeometry, planeMaterial);
plane.receiveShadow = true; // rotate and position the plane
plane.rotation.x = -0.5 * Math.PI;
plane.position.x = 0;
plane.position.y = 0;
plane.position.z = 0; // add the plane to the scene
scene.add(plane); // position and point the camera to the center of the scene
camera.position.x = -50;
camera.position.y = 30;
camera.position.z = 20;
camera.lookAt(new THREE.Vector3(-10, 0, 0)); // add subtle ambient lighting
var ambientLight = new THREE.AmbientLight(0x090909);
scene.add(ambientLight); // add spotlight for the shadows
var spotLight = new THREE.SpotLight(0xffffff);
spotLight.position.set(-40, 40, 50);
spotLight.castShadow = true;
scene.add(spotLight); // add geometries
addGeometries(scene); // add the output of the renderer to the html element
document.getElementById("WebGL-output").appendChild(renderer.domElement); // call the render function
var step = 0; render(); function addGeometries(scene) {
var geoms = []; geoms.push(new THREE.CylinderGeometry(1, 4, 4)); // basic cube
geoms.push(new THREE.BoxGeometry(2, 2, 2)); // basic spherer
geoms.push(new THREE.SphereGeometry(2)); geoms.push(new THREE.IcosahedronGeometry(4)); // create a convex shape (a shape without dents)
// using a couple of points
// for instance a cube
var points = [
new THREE.Vector3(2, 2, 2),
new THREE.Vector3(2, 2, -2),
new THREE.Vector3(-2, 2, -2),
new THREE.Vector3(-2, 2, 2),
new THREE.Vector3(2, -2, 2),
new THREE.Vector3(2, -2, -2),
new THREE.Vector3(-2, -2, -2),
new THREE.Vector3(-2, -2, 2)
];
geoms.push(new THREE.ConvexGeometry(points)); // create a lathgeometry
//http://en.wikipedia.org/wiki/Lathe_(graphics)
var pts = [];//points array - the path profile points will be stored here
var detail = .1;//half-circle detail - how many angle increments will be used to generate points
var radius = 3;//radius for half_sphere
for (var angle = 0.0; angle < Math.PI; angle += detail)//loop from 0.0 radians to PI (0 - 180 degrees)
pts.push(new THREE.Vector3(Math.cos(angle) * radius, 0, Math.sin(angle) * radius));//angle/radius to x,z
geoms.push(new THREE.LatheGeometry(pts, 12)); // create a OctahedronGeometry
geoms.push(new THREE.OctahedronGeometry(3)); // create a geometry based on a function
geoms.push(new THREE.ParametricGeometry(THREE.ParametricGeometries.mobius3d, 20, 10)); //
geoms.push(new THREE.TetrahedronGeometry(3)); geoms.push(new THREE.TorusGeometry(3, 1, 10, 10)); geoms.push(new THREE.TorusKnotGeometry(3, 0.5, 50, 20)); var j = 0;
for (var i = 0; i < geoms.length; i++) {
var cubeMaterial = new THREE.MeshLambertMaterial({wireframe: true, color: Math.random() * 0xffffff}); var materials = [ new THREE.MeshLambertMaterial({color: Math.random() * 0xffffff, shading: THREE.FlatShading}),
new THREE.MeshBasicMaterial({color: 0x000000, wireframe: true}) ]; var mesh = THREE.SceneUtils.createMultiMaterialObject(geoms[i], materials);
mesh.traverse(function (e) {
e.castShadow = true
}); //var mesh = new THREE.Mesh(geoms[i],materials[i]);
//mesh.castShadow=true;
mesh.position.x = -24 + ((i % 4) * 12);
mesh.position.y = 4;
mesh.position.z = -8 + (j * 12); if ((i + 1) % 4 == 0) j++;
scene.add(mesh);
} } function render() {
stats.update(); // render using requestAnimationFrame
requestAnimationFrame(render);
renderer.render(scene, camera);
} function initStats() { var stats = new Stats(); stats.setMode(0); // 0: fps, 1: ms // Align top-left
stats.domElement.style.position = 'absolute';
stats.domElement.style.left = '0px';
stats.domElement.style.top = '0px'; document.getElementById("Stats-output").appendChild(stats.domElement); return stats;
}
}
window.onload = init </script>
</body>
</html>
在Three.js中几何体基本上是三维空间中的点集(也被称为定点)和将这些点连接起来的面。以立方体为例:
一个立方体有8个顶点、6个面。在Three.js中每个面都是包含3个顶点的三角形,所以立方体的每个面都是由两个三角形组成的。
比如自定义几何体的方法如下:
var vertices = [
new THREE.Vector3(1, 3, 1),
new THREE.Vector3(1, 3, -1),
new THREE.Vector3(1, -1, 1),
new THREE.Vector3(1, -1, -1),
new THREE.Vector3(-1, 3, -1),
new THREE.Vector3(-1, 3, 1),
new THREE.Vector3(-1, -1, -1),
new THREE.Vector3(-1, -1, 1)
]; var faces = [
new THREE.Face3(0, 2, 1),
new THREE.Face3(2, 3, 1),
new THREE.Face3(4, 6, 5),
new THREE.Face3(6, 7, 5),
new THREE.Face3(4, 5, 1),
new THREE.Face3(5, 0, 1),
new THREE.Face3(7, 6, 2),
new THREE.Face3(6, 3, 2),
new THREE.Face3(5, 7, 0),
new THREE.Face3(7, 2, 0),
new THREE.Face3(1, 3, 4),
new THREE.Face3(3, 6, 4),
]; var geom = new THREE.Geometry();
geom.vertices = vertices;
geom.faces = faces;
geom.computeFaceNormals();
效果:
vertices数组中保存了几何体的顶点,faces数组保存了点连接起来的三角形面。如 new THREE.Face3(0, 2, 1), 就是使用vertices数组中的点0、2、1创建而成的三角形面。有了顶点和面然后创建 Geometry 对象并将点和面赋给上面对象,最后调用 geom.computeFaceNormals(); 渲染即可。
补充:Three.js可以用多种材质来创建网格
var clonedGeometry = mesh.children[0].geometry.clone();
var materials = [
new THREE.MeshLambertMaterial({opacity: 0.6, color: 0xff44ff, transparent: true}),
new THREE.MeshBasicMaterial({color: 0x000000, wireframe: true}) ]; var mesh2 = THREE.SceneUtils.createMultiMaterialObject(clonedGeometry, materials);
2. 网格对象(THREE.Mesh)的方法和属性
创建一个网格需要一个几何体,以及一个或多个材质。网格对象提供的属性和方法如下: (有通用的移动位置、缩放等功能)
例子如下:GUI控制其属性(scale>1为放大)
<!DOCTYPE html> <html> <head>
<title>Example 02.06 - Mesh Properties</title>
<script type="text/javascript" src="../libs/three.js"></script> <script type="text/javascript" src="../libs/stats.js"></script>
<script type="text/javascript" src="../libs/dat.gui.js"></script>
<style>
body {
/* set margin to 0 and overflow to hidden, to go fullscreen */
margin: 0;
overflow: hidden;
}
</style>
</head>
<body> <div id="Stats-output">
</div>
<!-- Div which will hold the Output -->
<div id="WebGL-output">
</div> <!-- Javascript code that runs our Three.js examples -->
<script type="text/javascript"> // once everything is loaded, we run our Three.js stuff.
function init() { var stats = initStats(); // create a scene, that will hold all our elements such as objects, cameras and lights.
var scene = new THREE.Scene(); // create a camera, which defines where we're looking at.
var camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 0.1, 1000); // create a render and set the size
var renderer = new THREE.WebGLRenderer(); renderer.setClearColor(new THREE.Color(0xEEEEEE, 1.0));
renderer.setSize(window.innerWidth, window.innerHeight);
renderer.shadowMapEnabled = true; // create the ground plane
var planeGeometry = new THREE.PlaneGeometry(60, 40, 1, 1);
var planeMaterial = new THREE.MeshLambertMaterial({color: 0xffffff});
var plane = new THREE.Mesh(planeGeometry, planeMaterial);
plane.receiveShadow = true; // rotate and position the plane
plane.rotation.x = -0.5 * Math.PI;
plane.position.x = 0;
plane.position.y = 0;
plane.position.z = 0; // add the plane to the scene
scene.add(plane); // position and point the camera to the center of the scene
camera.position.x = -30;
camera.position.y = 40;
camera.position.z = 30;
camera.lookAt(scene.position); // add subtle ambient lighting
var ambientLight = new THREE.AmbientLight(0x0c0c0c);
scene.add(ambientLight); // add spotlight for the shadows
var spotLight = new THREE.SpotLight(0xffffff);
spotLight.position.set(-40, 60, 020);
spotLight.castShadow = true;
scene.add(spotLight); // add the output of the renderer to the html element
document.getElementById("WebGL-output").appendChild(renderer.domElement); // call the render function
var step = 0; var controls = new function () {
this.scaleX = 1;
this.scaleY = 1;
this.scaleZ = 1; this.positionX = 0;
this.positionY = 4;
this.positionZ = 0; this.rotationX = 0;
this.rotationY = 0;
this.rotationZ = 0;
this.scale = 1; this.translateX = 0;
this.translateY = 0;
this.translateZ = 0; this.visible = true; this.translate = function () { cube.translateX(controls.translateX);
cube.translateY(controls.translateY);
cube.translateZ(controls.translateZ); controls.positionX = cube.position.x;
controls.positionY = cube.position.y;
controls.positionZ = cube.position.z;
}
}; var material = new THREE.MeshLambertMaterial({color: 0x44ff44});
var geom = new THREE.BoxGeometry(5, 8, 3);
var cube = new THREE.Mesh(geom, material);
cube.position.y = 4;
cube.castShadow = true;
scene.add(cube); var gui = new dat.GUI(); guiScale = gui.addFolder('scale');
guiScale.add(controls, 'scaleX', 0, 5);
guiScale.add(controls, 'scaleY', 0, 5);
guiScale.add(controls, 'scaleZ', 0, 5); guiPosition = gui.addFolder('position');
var contX = guiPosition.add(controls, 'positionX', -10, 10);
var contY = guiPosition.add(controls, 'positionY', -4, 20);
var contZ = guiPosition.add(controls, 'positionZ', -10, 10); contX.listen();
contX.onChange(function (value) {
cube.position.x = controls.positionX;
}); contY.listen();
contY.onChange(function (value) {
cube.position.y = controls.positionY;
}); contZ.listen();
contZ.onChange(function (value) {
cube.position.z = controls.positionZ;
}); guiRotation = gui.addFolder('rotation');
guiRotation.add(controls, 'rotationX', -4, 4);
guiRotation.add(controls, 'rotationY', -4, 4);
guiRotation.add(controls, 'rotationZ', -4, 4); guiTranslate = gui.addFolder('translate'); guiTranslate.add(controls, 'translateX', -10, 10);
guiTranslate.add(controls, 'translateY', -10, 10);
guiTranslate.add(controls, 'translateZ', -10, 10);
guiTranslate.add(controls, 'translate'); gui.add(controls, 'visible'); render(); function render() {
stats.update(); // render using requestAnimationFrame cube.visible = controls.visible; cube.rotation.x = controls.rotationX;
cube.rotation.y = controls.rotationY;
cube.rotation.z = controls.rotationZ; cube.scale.set(controls.scaleX, controls.scaleY, controls.scaleZ); requestAnimationFrame(render);
renderer.render(scene, camera);
} function initStats() { var stats = new Stats(); stats.setMode(0); // 0: fps, 1: ms // Align top-left
stats.domElement.style.position = 'absolute';
stats.domElement.style.left = '0px';
stats.domElement.style.top = '0px'; document.getElementById("Stats-output").appendChild(stats.domElement); return stats;
}
}
window.onload = init </script>
</body>
</html>
5.光源
Three.js有许多种不同种类的光源,每种光源都有特殊的行为和用法。如下:
1.THREE.SpotLight
最常用的光源(特别是想用阴影效果)。可以想象为手电筒或灯笼产生的光。THREE。PointLight与SpotLight非常相似,只是PointLight不能产生阴影(也就是没有castShadow属性)。
该光源具有产生光的方向和角度,如下:
创建聚光灯光源非常简单,如下:
var pointColor = "#ffffff";
var spotLight = new THREE.SpotLight(pointColor);
spotLight.position.set(-40, 60, -10);
spotLight.castShadow = true;
spotLight.shadowCameraNear = 2;
spotLight.shadowCameraFar = 200;
spotLight.shadowCameraFov = 30;
spotLight.target = plane;
spotLight.distance = 0;
spotLight.angle = 0.4; scene.add(spotLight);
注意: spotLight 的target属性比较重要,此属性可以指向某一个特定的对象。当然可以指向空间中任意一点,方法如下:
var target = new THREE.Object3D();
target.position = new THREE.Vector3(5, 0, 0); spotLight.target = target;
例如:
<!DOCTYPE html> <html> <head>
<title>Example 03.03 - Spot Light</title>
<script type="text/javascript" src="../libs/three.js"></script> <script type="text/javascript" src="../libs/stats.js"></script>
<script type="text/javascript" src="../libs/dat.gui.js"></script>
<style>
body {
/* set margin to 0 and overflow to hidden, to go fullscreen */
margin: 0;
overflow: hidden;
}
</style>
</head>
<body> <div id="Stats-output">
</div>
<!-- Div which will hold the Output -->
<div id="WebGL-output">
</div> <!-- Javascript code that runs our Three.js examples -->
<script type="text/javascript"> // once everything is loaded, we run our Three.js stuff.
function init() { var stopMovingLight = false; var stats = initStats(); // create a scene, that will hold all our elements such as objects, cameras and lights.
var scene = new THREE.Scene(); // create a camera, which defines where we're looking at.
var camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 0.1, 1000); // create a render and set the size
var renderer = new THREE.WebGLRenderer(); renderer.setClearColor(new THREE.Color(0xEEEEEE, 1.0));
renderer.setSize(window.innerWidth, window.innerHeight);
renderer.shadowMapEnabled = true;
renderer.shadowMapType = THREE.PCFShadowMap; // create the ground plane
var planeGeometry = new THREE.PlaneGeometry(60, 20, 1, 1);
var planeMaterial = new THREE.MeshLambertMaterial({color: 0xffffff});
var plane = new THREE.Mesh(planeGeometry, planeMaterial);
plane.receiveShadow = true; // rotate and position the plane
plane.rotation.x = -0.5 * Math.PI;
plane.position.x = 15;
plane.position.y = 0;
plane.position.z = 0; // add the plane to the scene
scene.add(plane); // create a cube
var cubeGeometry = new THREE.BoxGeometry(4, 4, 4);
var cubeMaterial = new THREE.MeshLambertMaterial({color: 0xff3333});
var cube = new THREE.Mesh(cubeGeometry, cubeMaterial);
cube.castShadow = true; // position the cube
cube.position.x = -4;
cube.position.y = 3;
cube.position.z = 0; // add the cube to the scene
scene.add(cube); var sphereGeometry = new THREE.SphereGeometry(4, 20, 20);
var sphereMaterial = new THREE.MeshLambertMaterial({color: 0x7777ff});
var sphere = new THREE.Mesh(sphereGeometry, sphereMaterial); // position the sphere
sphere.position.x = 20;
sphere.position.y = 0;
sphere.position.z = 2;
sphere.castShadow = true; // add the sphere to the scene
scene.add(sphere); // position and point the camera to the center of the scene
camera.position.x = -35;
camera.position.y = 30;
camera.position.z = 25;
camera.lookAt(new THREE.Vector3(10, 0, 0)); // add subtle ambient lighting
var ambiColor = "#1c1c1c";
var ambientLight = new THREE.AmbientLight(ambiColor);
scene.add(ambientLight); // add spotlight for a bit of light
var spotLight0 = new THREE.SpotLight(0xcccccc);
spotLight0.position.set(-40, 30, -10);
spotLight0.lookAt(plane);
scene.add(spotLight0); var target = new THREE.Object3D();
target.position = new THREE.Vector3(5, 0, 0); var pointColor = "#ffffff";
var spotLight = new THREE.SpotLight(pointColor);
spotLight.position.set(-40, 60, -10);
spotLight.castShadow = true;
spotLight.shadowCameraNear = 2;
spotLight.shadowCameraFar = 200;
spotLight.shadowCameraFov = 30;
spotLight.target = plane;
spotLight.distance = 0;
spotLight.angle = 0.4; scene.add(spotLight); // add a small sphere simulating the pointlight
var sphereLight = new THREE.SphereGeometry(0.2);
var sphereLightMaterial = new THREE.MeshBasicMaterial({color: 0xac6c25});
var sphereLightMesh = new THREE.Mesh(sphereLight, sphereLightMaterial);
sphereLightMesh.castShadow = true; sphereLightMesh.position = new THREE.Vector3(3, 20, 3);
scene.add(sphereLightMesh); // add the output of the renderer to the html element
document.getElementById("WebGL-output").appendChild(renderer.domElement); // call the render function
var step = 0; // used to determine the switch point for the light animation
var invert = 1;
var phase = 0; var controls = new function () {
this.rotationSpeed = 0.03;
this.bouncingSpeed = 0.03;
this.ambientColor = ambiColor;
this.pointColor = pointColor;
this.intensity = 1;
this.distance = 0;
this.exponent = 30;
this.angle = 0.1;
this.debug = false;
this.castShadow = true;
this.onlyShadow = false;
this.target = "Plane";
this.stopMovingLight = false; }; var gui = new dat.GUI();
gui.addColor(controls, 'ambientColor').onChange(function (e) {
ambientLight.color = new THREE.Color(e);
}); gui.addColor(controls, 'pointColor').onChange(function (e) {
spotLight.color = new THREE.Color(e);
}); gui.add(controls, 'angle', 0, Math.PI * 2).onChange(function (e) {
spotLight.angle = e;
}); gui.add(controls, 'intensity', 0, 5).onChange(function (e) {
spotLight.intensity = e;
}); gui.add(controls, 'distance', 0, 200).onChange(function (e) {
spotLight.distance = e;
}); gui.add(controls, 'exponent', 0, 100).onChange(function (e) {
spotLight.exponent = e;
}); gui.add(controls, 'debug').onChange(function (e) {
spotLight.shadowCameraVisible = e;
}); gui.add(controls, 'castShadow').onChange(function (e) {
spotLight.castShadow = e;
}); gui.add(controls, 'onlyShadow').onChange(function (e) {
spotLight.onlyShadow = e;
}); gui.add(controls, 'target', ['Plane', 'Sphere', 'Cube']).onChange(function (e) {
console.log(e);
switch (e) {
case "Plane":
spotLight.target = plane;
break;
case "Sphere":
spotLight.target = sphere;
break;
case "Cube":
spotLight.target = cube;
break;
} }); gui.add(controls, 'stopMovingLight').onChange(function (e) {
stopMovingLight = e;
}); render(); function render() {
stats.update();
// rotate the cube around its axes
cube.rotation.x += controls.rotationSpeed;
cube.rotation.y += controls.rotationSpeed;
cube.rotation.z += controls.rotationSpeed; // bounce the sphere up and down
step += controls.bouncingSpeed;
sphere.position.x = 20 + ( 10 * (Math.cos(step)));
sphere.position.y = 2 + ( 10 * Math.abs(Math.sin(step))); // move the light simulation
if (!stopMovingLight) {
if (phase > 2 * Math.PI) {
invert = invert * -1;
phase -= 2 * Math.PI;
} else {
phase += controls.rotationSpeed;
}
sphereLightMesh.position.z = +(7 * (Math.sin(phase)));
sphereLightMesh.position.x = +(14 * (Math.cos(phase)));
sphereLightMesh.position.y = 10; if (invert < 0) {
var pivot = 14;
sphereLightMesh.position.x = (invert * (sphereLightMesh.position.x - pivot)) + pivot;
} spotLight.position.copy(sphereLightMesh.position);
} // render using requestAnimationFrame
requestAnimationFrame(render); renderer.render(scene, camera);
} function initStats() { var stats = new Stats(); stats.setMode(0); // 0: fps, 1: ms // Align top-left
stats.domElement.style.position = 'absolute';
stats.domElement.style.left = '0px';
stats.domElement.style.top = '0px'; document.getElementById("Stats-output").appendChild(stats.domElement); return stats;
}
} window.onload = init; </script>
</body>
</html>
效果:
上面也演示了GUI中使用下拉列表、选择框、颜色选择器等控件。
Three.js场景的基本组件的更多相关文章
- 038——VUE中组件之WEB开发中组件使用场景与定义组件的方式
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...
- [js开源组件开发]js文本框计数组件
js文本框计数组件 先上效果图: 样式可以自行调整 ,它的功能提供文本框的实时计数,并作出对应的操作,比如现在超出了,点击下面的按钮后,文本框会闪动两下,阻止提交.具体例子可以点击demo:http: ...
- CocoStudio基础教程(5)使用CocoStudio场景编辑器关联组件
1.概述 我们有了UI交互.有了动画人物.有了物理模拟,还差最后一步——将这些元素融合起来.这就要用到cocoStudio中的场景编辑器了.这次我们要将先前我们做过的所有东西都放到一个场景中去.这项工 ...
- AmazeUI(妹子UI)中CSS组件、JS插件、Web组件的区别
AmazeUI(妹子UI)是非常优秀的国产前端UI,现在来介绍一下AmazeUI中CSS组件.JS插件与Web组件的区别. CSS组件顾名思义就是仅使用CSS渲染而成的组件,而JS插件也很容易理解,就 ...
- Vue main.js 文件中全局组件注册部分
在 \src\components\index.js 文件中export组件 import HeaderList from './HeaderList' import HeaderMenu from ...
- BootStrap fileinput.js文件上传组件实例代码
1.首先我们下载好fileinput插件引入插件 ? 1 2 3 <span style="font-size:14px;"><link type="t ...
- React.js 小书 Lesson7 - 组件的 render 方法
作者:胡子大哈 原文链接:http://huziketang.com/books/react/lesson7 转载请注明出处,保留原文链接和作者信息. React.js 中一切皆组件,用 React. ...
- 如何使用 js 实现一个树组件
如何使用 js 实现一个树组件 tree component const arr = [ { id: 1, value: 1, level: 1, parentId: 0, }, { id: 2, v ...
- 在Vue将第三方JS库封装为组件使用
第三方JS库地址:https://github.com/inorganik/CountUp.js 使用NPM进行安装: npm install --save countup 根据官方回答,CountU ...
随机推荐
- Anaconda与Python安装版本对应关系 --- 转载
转载自:https://blog.csdn.net/yuejisuo1948/article/details/81043823 首先解释一下上表. anaconda在每次发布新版本的时候都会给pyth ...
- cronicle 任务调度一主多从安装试用
cronicle 对于一主多从的安装还是很简单的,对于slave 就是少了setup一步,同时在master 界面,添加下slave 就可以了 就会加入集群中了 项目使用docker-compose ...
- Mac 无法安装安装psutil 报错 error: command '/usr/bin/clang' failed with exit status 1
psutil是一个特别好用来检查系统资源的一个包, 但是 在Mac安装却总是报错 查看监控系统脚本, 点这里 mac系统版本: Macos Mojave 10.14.3 报错信息如下: WARNING ...
- js操作表格、table、
js添加一行.删除一行 let str="<tr>" +"<td>"+a[1]+"</td>" +&qu ...
- RSA算法java实现(BigInteger类的各种应用)
一.RSA算法 1.密钥生成 随机生成两个大素数p.q 计算n=p*q 计算n的欧拉函数f=(p-1)*(q-1) 选取1<e<f,使e与f互素 计算d,ed=1modf 公钥为(e,n) ...
- 冰多多团队-第四次Scrum会议
冰多多团队-第四次Scrum会议 工作情况 团队成员 已完成任务 待完成任务 zpj 撰写团队任务拆解博客 完成部分Action的实现 牛雅哲 完成了词典单词,词典映射的代码实现,设计了初步的词典异常 ...
- js正则判断字符串中是否包含特殊字符和空格
字符串只能是数字.字母和中文组成,不能包含特殊符号和空格. /^[\u4e00-\u9fa5_a-zA-Z0-9]+$/
- java中过滤器(Filter)与拦截器(Interceptor )区别
过滤器(Filter) Servlet中的过滤器Filter是实现了javax.servlet.Filter接口的服务器端程序,主要的用途是设置字符集.控制权限.控制转向.做一些业务逻辑判断等.其工作 ...
- Spring 事务小结
@Override@Transactionalpublic void add() { this.in();} public void in(){ NyOrder nyOrder=new NyOrder ...
- docker run启动的容器挂掉了,数据怎么办
情景描述 在某个系统中,功能性的服务使用 docker stack deploy xxx 启动,某个国产数据库的服务单独使用 docker run xxx 启动,数据库服务没有将存储的位置挂载出来: ...