转载

《一起来学three.js构建WebGL应用》第二课

上一篇: 《一起来学three.js构建WebGL应用》第一课

继续来学习 WebGL 的 three.js 库。

今天做些不一样的东西(如 MeshBasicMaterial,MeshLambertMaterial 和 MeshPhongMaterial),尽量使用各种参数(color,opacity,ambient,emissive,specular),讲解如何制作纹理和凹凸映射的使用。

《一起来学three.js构建WebGL应用》第二课

Live Demo

HTML

如果你已经完成了第一课,那这里没什么新的内容。

这是要使用的 HTML 代码:

<!DOCTYPE html> <html lang="en" >  <head>   <meta charset="utf-8" />   <meta name="author" content="Script Tutorials" />   <title>WebGL With Three.js - Lesson 2 | Script Tutorials</title>   <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">   <link href="css/main.css" rel="stylesheet" type="text/css" />  </head>  <body>   <script src="js/three.min.js"></script>   <script src="js/THREEx.WindowResize.js"></script>   <script src="js/OrbitControls.js"></script>   <script src="js/stats.min.js"></script>   <script src="js/script.js"></script>  </body> </html>  

Javascript

主要场景

我们借用以前教程的主体代码

var particleLight; var lesson2 = {     scene: null,     camera: null,     renderer: null,     container: null,     controls: null,     clock: null,     stats: null,     init: function() { // Initialization  // 创建主场景  this.scene = new THREE.Scene();  var SCREEN_WIDTH = window.innerWidth,      SCREEN_HEIGHT = window.innerHeight;  // 准备照相机  var VIEW_ANGLE = 45, ASPECT = SCREEN_WIDTH / SCREEN_HEIGHT, NEAR = 1, FAR = 5000;  this.camera = new THREE.PerspectiveCamera( VIEW_ANGLE, ASPECT, NEAR, FAR);  this.scene.add(this.camera);  this.camera.position.set(100, 1000, 1000);  this.camera.lookAt(new THREE.Vector3(0,0,0));  // 准备渲染器  this.renderer = new THREE.WebGLRenderer({antialias:true, alpha: false});  this.renderer.setSize(SCREEN_WIDTH, SCREEN_HEIGHT);  this.renderer.setClearColor(0xffffff);  this.renderer.shadowMapEnabled = true;  this.renderer.shadowMapSoft = true;  // 容器  this.container = document.createElement('div');  document.body.appendChild(this.container);  this.container.appendChild(this.renderer.domElement);  // 事件  THREEx.WindowResize(this.renderer, this.camera);  // 轨道控制器 (OrbitControls)  this.controls = new THREE.OrbitControls(this.camera, this.renderer.domElement);  this.controls.target = new THREE.Vector3(0, 0, 0);  // 时钟  this.clock = new THREE.Clock();  // 统计  this.stats = new Stats();  this.stats.domElement.style.position = 'absolute';  this.stats.domElement.style.bottom = '0px';  this.stats.domElement.style.zIndex = 10;  this.container.appendChild( this.stats.domElement );  // 直线光照  var dLight = new THREE.DirectionalLight(0xffffff);  dLight.position.set(1, 300, 1);  dLight.castShadow = true;  // dLight.shadowCameraVisible = true;  dLight.shadowDarkness = 0.2;  dLight.shadowMapWidth = dLight.shadowMapHeight = 1000;  this.scene.add(dLight);  // 特定光照  particleLight = new THREE.Mesh( new THREE.SphereGeometry(10, 10, 10), new THREE.MeshBasicMaterial({ color: 0xffffaa }));  particleLight.position = dLight.position;  this.scene.add(particleLight);  // 背景  var groundGeometry = new THREE.PlaneGeometry(1200, 1200, 1, 1);  ground = new THREE.Mesh(groundGeometry, new THREE.MeshLambertMaterial({      color: 0xFF62B0  }));  ground.position.y = 0;  ground.rotation.x = - Math.PI / 2;  ground.receiveShadow = true;  this.scene.add(ground);     } }; // 给场景加动画 function animate() {     requestAnimationFrame(animate);     render();     update(); } // 更新控制器和统计 function update() {     lesson2.controls.update(lesson2.clock.getDelta());     lesson2.stats.update();     // smoothly move the particleLight     var timer = Date.now() * 0.000025;     particleLight.position.x = Math.sin(timer * 5) * 300;     particleLight.position.z = Math.cos(timer * 5) * 300; } // 渲染场景 function render() {     if (lesson2.renderer) {  lesson2.renderer.render(lesson2.scene, lesson2.camera);     } } // 初始化页面 function initializeLesson() {     lesson2.init();     animate(); } if (window.addEventListener)     window.addEventListener('load', initializeLesson, false); else if (window.attachEvent)     window.attachEvent('onload', initializeLesson); else window.onload = initializeLesson;  

颜色

和第一课一样,添加一个函数来生成一个随机的颜色(当然这个随机颜色是从预定义的颜色阵列里随机选择):

var colors = [  0xFF62B0,  0x9A03FE,  0x62D0FF,  0x48FB0D,  0xDFA800,  0xC27E3A,  0x990099,  0x9669FE,  0x23819C,  0x01F33E,  0xB6BA18,  0xFF800D,  0xB96F6F,  0x4A9586 ]; function getRandColor() {  return colors[Math.floor(Math.random() * colors.length)]; }  

创建并使用 SphereGeometry 网格来画一个球体:

drawSphere: function(x, z, material) {  var cube = new THREE.Mesh(new THREE.SphereGeometry(70, 70, 20), material);  cube.rotation.x = cube.rotation.z = Math.PI * Math.random();  cube.position.x = x;  cube.position.y = 100;  cube.position.z = z;  cube.castShadow = cube.receiveShadow = true;  this.scene.add(cube); }  

材料

如果你已经观看了 Demo ,很容易就会发现从简单到复杂整个被分成了好几个部分:

  • 从左到右开始结束的三个球是最简单的:使用了MeshBasicMaterial,MeshLambertMaterial 和MeshPhongMaterial,且仅使用了 color
  • 接下来的三个球几乎是相同的,但设置为半透明(透明度为0.5),第二行使用以下属性进行不同的组合:环境(ambient)、发射(emissive)、反射(specular)、光泽(shininess)
  • 最后的三排,使用纹理和凹凸组合:
var mlib = {   '1':   new THREE.MeshBasicMaterial({ color: getRandColor() }),   '2':   new THREE.MeshLambertMaterial({ color: getRandColor() }),   '3':   new THREE.MeshPhongMaterial({ color: getRandColor() }),    '4':   new THREE.MeshBasicMaterial({ color: getRandColor(), opacity: 0.5, transparent: true }),   '5':   new THREE.MeshLambertMaterial({ color: getRandColor(), opacity: 0.5, transparent: true }),   '6':   new THREE.MeshPhongMaterial({ color: getRandColor(), opacity: 0.5, transparent: true }),    '7':   new THREE.MeshLambertMaterial({ color: 0xff0000, ambient: 0xffffff }),   '8':   new THREE.MeshLambertMaterial({ color: 0xff0000, emissive: 0x000088 }),    '9':   new THREE.MeshPhongMaterial({ color: 0xff0000, ambient: 0x3ffc33 }),   '10':  new THREE.MeshPhongMaterial({ color: 0xff0000, emissive: 0x000088 }),   '11':  new THREE.MeshPhongMaterial({ color: 0xff0000, emissive: 0x004000, specular: 0x0022ff }),   '12':  new THREE.MeshPhongMaterial({ color: 0xff0000, specular: 0x0022ff, shininess: 3 }),    '13':  new THREE.MeshLambertMaterial({ map: texture, color: 0xff0000, ambient: 0x3ffc33 }),   '14':  new THREE.MeshLambertMaterial({ map: texture, color: 0xff0000, emissive: 0x000088 }),   '15':  new THREE.MeshLambertMaterial({ map: texture, color: 0xff0000, emissive: 0x004000, specular: 0x0022ff }),   '16':  new THREE.MeshLambertMaterial({ map: texture, color: 0xff0000, specular: 0x0022ff, shininess: 3 }),    '17':  new THREE.MeshPhongMaterial({ map: texture, color: 0xff0000, ambient: 0x3ffc33 }),   '18':  new THREE.MeshPhongMaterial({ map: texture, color: 0xff0000, emissive: 0x000088 }),   '19':  new THREE.MeshPhongMaterial({ map: texture, color: 0xff0000, emissive: 0x004000, specular: 0x0022ff }),   '20':  new THREE.MeshPhongMaterial({ map: texture, color: 0xff0000, specular: 0x0022ff, shininess: 3 }),    '21':  new THREE.MeshPhongMaterial({ map: texture, bumpMap: textureBump, color: 0xff0000, ambient: 0x3ffc33 }),   '22':  new THREE.MeshPhongMaterial({ map: texture, bumpMap: textureBump, color: 0xff0000, emissive: 0x000088 }),   '23':  new THREE.MeshPhongMaterial({ map: texture, bumpMap: textureBump, color: 0xff0000, emissive: 0x004000, specular: 0x0022ff }),   '24':  new THREE.MeshPhongMaterial({ map: texture, bumpMap: textureBump, color: 0xff0000, specular: 0x0022ff, shininess: 3 }), } 

把这些材料加入数组方便待会儿的使用。注意这里使用了两个纹理,一是“映射”,其次是“凹凸映射”。代码如下:

var texture = THREE.ImageUtils.loadTexture('texture.png'); texture.repeat.set(10, 10); texture.wrapS = texture.wrapT = THREE.RepeatWrapping; texture.anisotropy = 16; texture.needsUpdate = true;  var textureBump = THREE.ImageUtils.loadTexture('bump.png'); textureBump.repeat.set(10, 10); textureBump.wrapS = textureBump.wrapT = THREE.RepeatWrapping; textureBump.anisotropy = 16; textureBump.needsUpdate = true; 

现在只需要把不同位置的球用上不同的材料:

// add spheres with different materials this.drawSphere(-550, 400, mlib['1']); this.drawSphere(-350, 400, mlib['2']); this.drawSphere(-150, 400, mlib['3']);  this.drawSphere( 150, 400, mlib['4']); this.drawSphere( 350, 400, mlib['5']); this.drawSphere( 550, 400, mlib['6']);  this.drawSphere(-550, 200, mlib['7']); this.drawSphere(-350, 200, mlib['8']);  this.drawSphere( -50, 200, mlib['9']); this.drawSphere( 150, 200, mlib['10']); this.drawSphere( 350, 200, mlib['11']); this.drawSphere( 550, 200, mlib['12']);  this.drawSphere(-250, 0, mlib['13']); this.drawSphere( -90, 0, mlib['14']); this.drawSphere(  90, 0, mlib['15']); this.drawSphere( 250, 0, mlib['16']);  this.drawSphere(-250, -200, mlib['17']); this.drawSphere( -90, -200, mlib['18']); this.drawSphere(  90, -200, mlib['19']); this.drawSphere( 250, -200, mlib['20']);  this.drawSphere(-250, -400, mlib['21']); this.drawSphere( -90, -400, mlib['22']); this.drawSphere(  90, -400, mlib['23']); this.drawSphere( 250, -400, mlib['24']); 

Live Demo

好啦,今天的教程就到这里。

正文到此结束
Loading...