材质就像物体的皮肤,决定了几何体的外表,例如是否像草地/金属,是否透明,是否显示线框等
一 材质
THREE.js的材质分为多种,Three.js提供了一个材质基类THREE.Material,
该基类拥有three.js所有材质的公有属性,分为三类:基础属性,融合属性,高级属性
基础属性:ID,name,透明度,是否可见,是否需要刷新等
融合属性:决定了物体如何与背景融合
高级属性:可以控制WEBGL上下文渲染物体的方法,大多数情况下,是不会用这些属性,我们这里不再讨论
1.1 基础属性
属性 | 描述 |
ID(描述符) | 用来标识材质,在创建时赋值 |
name(名称) | 通过该属性克赋予该材质名称 |
opacity(透明度) | 定义物体有多透明,与transparent属性一起使用 |
transparent(是否透明) | 设置为true时,会根据opacity的值来设置透明度,设置为false时,则只着色 |
overdraw(过度描绘) | 当使用THREE.CanvasRenderer画布渲染器绘制对象的时候,物体之间可能会有空隙,这时设置该值为true,多边形会被渲染的稍微大一点, |
visible(是否可见) | 定义该材质是否可见 |
side(侧面) |
决定了几何体的哪一面应用该材质, THREE.FrontSide应用到几何体的前(外)面; THREE.BackSide应用到几何体的后(内)面; THREE.DoubleSide应用到几何体的内外两侧 |
needUpdate(是否刷新) | 设置该值为true后,如果材质发生改变,就会使用新的材质刷新它的缓存 |
1.2 融合属性
属性 | 描述 | |
blending(融合) | 决定物体上的材质如何跟背景融合,一般是NormalBlending,这种模式一般只显示材质的上层 | |
blendsrc(融合源) |
通过指定融合源,融合目标来指定源如何跟目标融合以及融合时如何使用目标,以达到创建自定义的融合模式 融合源的默认值SrcAlphaFactor:使用alpha透明度通道进行融合 融合目标的默认值OneMinusSrcAlphaFactor:融合目标也使用融合源的alpha通道进行融合 blendingequation只读blendsrc和blenddst的值的叠加方式创建自定义的融合方式 |
|
blenddst(融合目标) | ||
blendingequation(融合公式) |
1.3 基础材质(MeshBasicMaterial)
MeshBasicMaterial是一种简单的材质,这种材质不考虑光照的影响。
使用这种材质的网格会被渲染成一些简单的平面多边形,而且可以通过设置wireframe的值会显示几何体的线框
属性 | 描述 |
color | 设置材质的颜色 |
wireframe | 是否将材质渲染成线框 |
wireframeLinewidth | 如果设置了wireframe的值,则该属性则设置了线框的宽度,即线框的宽度 |
wireframeLinecap(线框的端点) |
该属性定义了线框模式下端点的显示方式,有butt平,round圆,square方, 但是在实际的应用中,该值很难看出效果,而且webglrenderer不支持该属性 |
wireframeLinejoin(线框线段连接点) | 定义线段的连接点如何显示,webglrenderer不支持该属性 |
shading(着色方式) |
THREE.SmoothShading平滑着色,和THREE.FlatShading平面着色, 平面着色的话,每个面是什么颜色就会被渲染成什么颜色, 而平滑着色的话可以使物体的表面看起来变的更光滑一些 |
vertexColors(顶点颜色) | 可以通过该属性为每一个顶点定义不同的颜色,但是canvasRenderer不支持 |
fog(雾化) | 当前材质是否会受全局雾化效果的影响 |
side(面) |
该属性可以指定几何体的哪个面应用了材质, 由于材质多应用于物体前面的面上, 所以当旋转的时候,会有一部分时间是不可见的(其实是物体背面没有应用材质) side属性的值有front(只有物体的前面应用材质)和double(前后都应用材质) |
<!DOCTYPE html> <html> <head> <title>1</title> <script type="text/javascript" src="three.js"></script> <script type="text/javascript" src="dat.gui.js"></script> <script type="text/javascript" src="CanvasRenderer.js"></script> <script type="text/javascript" src="Projector.js"></script> <style> body { /* set margin to 0 and overflow to hidden, to go fullscreen */ margin: 0; overflow: hidden; } </style> </head> <body> <!-- Div which will hold the Output --> <div id="WebGL-output"> </div> <!-- Javascript code that runs our Three.js examples --> <script type="text/javascript"> //var scene function init() { //生成一个场景 var scene=new THREE.Scene(); //生成一个相机 //参数:视场,长宽比,近面,远面 var camera=new THREE.PerspectiveCamera(45,window.innerWidth/window.innerHeight,0.1,1000); camera.position.x=-20; camera.position.y=40; camera.position.z=30; camera.lookAt(scene.position); scene.add(camera); var render; //生成一个webgl的渲染器 var webGLrender=new THREE.WebGLRenderer(); webGLrender.setClearColor(0xEEEEEE); webGLrender.setSize(window.innerWidth,window.innerHeight); webGLrender.shadowMapEnabled=true; //允许阴影映射,渲染阴影需要大量的资源,因此我们需要告诉渲染器我们需要阴影 render=webGLrender; //生成一个canvas的渲染器,渲染器有什么不同? var canvasRender=new THREE.CanvasRenderer(); canvasRender.setSize(window.innerWidth,window.innerHeight); //允许阴影映射,渲染阴影需要大量的资源,因此我们需要告诉渲染器我们需要阴影 //scene.add(canvasRender); //生成基本材质,并将该材质应用于下面中的球体,方块或者平面 var material=new THREE.MeshBasicMaterial({color: 0x77777ff}); material.needsUpdate=true; //生成一个地面平面,并添加到场景中 //参数:长,宽,长分为多少份,宽分为多少份 var groundGeometry = new THREE.PlaneGeometry(100, 200, 20, 20); var groundMaterial = new THREE.MeshBasicMaterial({color: 0x777777}); var ground = new THREE.Mesh(groundGeometry, groundMaterial); ground.receiveShadow = true; ground.rotation.x = -0.5 * Math.PI; scene.add(ground); //生成一个方块,并添加到场景中 var cubeGeometry=new THREE.BoxGeometry(10,10,10); var cube=new THREE.Mesh(cubeGeometry,material); cube.castShadow=true; cube.position.set(0,3,2); scene.add(cube); //生成一个圆球,暂时不添加到场景,使用图形界面选择物体 var sphereGeometry=new THREE.SphereGeometry(10,10,10); var sphere=new THREE.Mesh(sphereGeometry,material); sphere.castShadow=true; sphere.position.set(0,3,2); //scene.add(sphere); //生成一个平面,暂时不添加到场景,使用图形界面选择物体 var planeGeometry=new THREE.PlaneGeometry(10,10,10); var plane=new THREE.Mesh(planeGeometry,material); plane.position.set(0,3,2); //生成环境光,弱化阴影 var ambientLight = new THREE.AmbientLight(0x0c0c0c); scene.add(ambientLight); //生成聚光灯 var spotLight0 = new THREE.SpotLight(0xffffff); spotLight0.position.set(-40, 60, -10); spotLight0.castShadow=true; scene.add(spotLight0); //增加图形控制界面 var controls=new function(){ this.rotationSpeed=0.02; this.opacity=material.opacity;//透明度 this.transparent=material.transparent; this.visible=material.visible; this.wireframe=material.wireframe; this.shading=material.shading; this.wireframeLineWidth=material.wireframeLineWidth; this.selectedMesh = "矩形"; this.switchRender=function(){ if(render instanceof THREE.WebGLRenderer){ render=canvasRender; }else{ render=webGLrender; } document.getElementById("WebGL-output").innerHTML=''; document.getElementById("WebGL-output").appendChild(render.domElement); } this.color=material.color.getStyle(); }; var gui=new dat.GUI(); //上面controls里面的opacity必须与下面的一致 var childGui=gui.addFolder("材质的共有属性"); childGui.add(controls,"opacity",0,1).onChange(function(e){ material.opacity=e; }); //注意,当opacity设置的值不为1时,以opacity为主 childGui.add(controls,"transparent").onChange(function(e){ material.transparent=e; }); childGui.add(controls,"wireframe").onChange(function(e){ material.wireframe=e; }); //如果visible的值为false,即不可见,不管opacity的值为多少,物体都是不可见的 childGui.add(controls,"visible").onChange(function(e){ material.visible=e; }); //addColor注意,增加颜色的图形控制,需要使用addColor方法 childGui.addColor(controls,"color").onChange(function(e){ material.color.setStyle(e); }); childGui.add(controls,"selectedMesh",["cube","sphere","plane"]).onChange(function(e){ scene.remove(plane); scene.remove(cube); scene.remove(sphere); switch(e){ case 'cube': scene.add(cube); break; case 'sphere': scene.add(sphere); break; case 'plane': scene.add(plane); break; } }); //gui的一个参数是一个对象,该对象控制的属性是add的函数的第二个参数 //即controls的this.switchRender必须与下面的属性一致,即上面代码的switchRender必须与下面语句的switchRender保持一致 gui.add(controls, 'switchRender'); document.getElementById("WebGL-output").append(render.domElement); function renderScene(){ requestAnimationFrame(renderScene); render.render(scene, camera); } //scene.fog=new THREE.Fog(0xffffff,0.015,100); renderScene(); } window.onload = init; </script> </body> </html>
1.4 基于深度着色的材质------MeshDepthMaterial
该种材质的外观不是由光照或者材质属性visible决定的,而是物体和相机的距离决定,
因此使用这种材质很容易创建出逐渐消失的效果
注意这个demo使用了场景的overrideMaterial属性
<!DOCTYPE html> <html> <head> <title>1</title> <script type="text/javascript" src="three.js"></script> <script type="text/javascript" src="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 which will hold the Output --> <div id="WebGL-output"> </div> <!-- Javascript code that runs our Three.js examples --> <script type="text/javascript"> //var scene function init() { //生成一个场景 var scene=new THREE.Scene(); //这里我们使用场景的overrideMaterial属性,即场景中的所有物体都应用这一种材质 scene.overrideMaterial = new THREE.MeshDepthMaterial(); //生成一个相机 //参数:视场,长宽比,近面,远面 var camera=new THREE.PerspectiveCamera(45,window.innerWidth/window.innerHeight,10,100); camera.position.x=-50; camera.position.y=40; camera.position.z=50; camera.lookAt(scene.position); scene.add(camera); var render; //生成一个webgl的渲染器 var webGLrender=new THREE.WebGLRenderer(); webGLrender.setClearColor(0xEEEEEE); webGLrender.setSize(window.innerWidth,window.innerHeight); webGLrender.shadowMapEnabled=true; //允许阴影映射,渲染阴影需要大量的资源,因此我们需要告诉渲染器我们需要阴影 render=webGLrender; //生成一个方块,并添加到场景中 var cubeGeometry=new THREE.BoxGeometry(10,10,10); var cube=new THREE.Mesh(cubeGeometry,new THREE.MeshLambertMaterial({"color":0xeeeeee})); cube.castShadow=true; cube.position.set(0,3,2); scene.add(cube); //增加图形控制界面 var controls=new function(){ this.cameraNear=camera.near; this.cameraFar=camera.far; this.rotationSpeed=0.02; this.addCube=function(){ var size=Math.random()*3+3; var cubeGeo=new THREE.BoxGeometry(4,4,10,10); var cube=new THREE.Mesh(cubeGeo,new THREE.MeshLambertMaterial({color:Math.random()*0xffffff})); cube.castShadow=true; cube.position.x = -60 + Math.round((Math.random() * 100)); cube.position.y = Math.round((Math.random() * 10)); cube.position.z = -100 + Math.round((Math.random() * 150)); scene.add(cube); } }; var gui=new dat.GUI(); gui.add(controls,"cameraNear",0,50).onChange(function(e){ camera.near=e; }); gui.add(controls,"cameraFar",0,50).onChange(function(e){ camera.far=e; }); gui.add(controls,"rotationSpeed",0,0.3); gui.add(controls, 'addCube'); for(var i=0;i<10;i++){ controls.addCube(); } //gui的一个参数是一个对象,该对象控制的属性是add的函数的第二个参数 //即controls的this.switchRender必须与下面的属性一致 document.getElementById("WebGL-output").append(render.domElement); function renderScene(){ scene.traverse(function(e){ if(e instanceof THREE.Mesh){ e.rotation.x+=controls.rotationSpeed; e.rotation.y+=controls.rotationSpeed; e.rotation.z+=controls.rotationSpeed; } }); requestAnimationFrame(renderScene); render.render(scene, camera); } //scene.fog=new THREE.Fog(0xffffff,0.015,100); renderScene(); } window.onload = init; </script> </body> </html>
1.5 联合材质
当一个几何体应用多种材质的时候,使用的就不是THREE.Mesh来创建网格了,
而是THREE.SceneUtil.createMultiMaterialObject方法
另外需要注意的细节,我们需要把MeshBasicMaterial材质的transparent值设置为true,
只有材质的transparent的值为true,three.js才会检查该材质的blending属性,进行融合操作
<!DOCTYPE html> <html> <head> <title>1</title> <script type="text/javascript" src="three.js"></script> <script type="text/javascript" src="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 which will hold the Output --> <div id="WebGL-output"> </div> <!-- Javascript code that runs our Three.js examples --> <script type="text/javascript"> //var scene function init() { //生成一个场景 var scene=new THREE.Scene(); //生成一个相机 //参数:视场,长宽比,近面,远面 var camera=new THREE.PerspectiveCamera(45,window.innerWidth/window.innerHeight,10,100); camera.position.x=-50; camera.position.y=40; camera.position.z=50; camera.lookAt(scene.position); scene.add(camera); var render; //生成一个webgl的渲染器 var webGLrender=new THREE.WebGLRenderer(); webGLrender.setClearColor(0xEEEEEE); webGLrender.setSize(window.innerWidth,window.innerHeight); webGLrender.shadowMapEnabled=true; //允许阴影映射,渲染阴影需要大量的资源,因此我们需要告诉渲染器我们需要阴影 render=webGLrender; //增加图形控制界面 var controls=new function(){ this.cameraNear=camera.near; this.cameraFar=camera.far; this.rotationSpeed=0.02; this.addCube=function(){ var size=Math.random()*3+3; var cubeGeo=new THREE.BoxGeometry(4,4,10,10); var basicMaterial=new THREE.MeshBasicMaterial({ color: 0x00ff00, transparent: true,//注意这里一定要设置基础材质的透明度为true blending: THREE.MultiplyBlending //这里的融合方式选择的是MultiplyBlending //即最终展示的颜色是前景颜色和背景的颜色相乘后得到的 }); var depthMaterial=new THREE.MeshDepthMaterial(); var cube=new THREE.SceneUtils.createMultiMaterialObject(cubeGeo,[basicMaterial,depthMaterial]); //cube.children[1].scale.set(0.99,0.99,0.99); cube.castShadow=true; cube.position.x = -60 + Math.round((Math.random() * 100)); cube.position.y = Math.round((Math.random() * 10)); cube.position.z = -100 + Math.round((Math.random() * 150)); scene.add(cube); } }; var gui=new dat.GUI(); gui.add(controls,"cameraNear",0,50).onChange(function(e){ camera.near=e; }); gui.add(controls,"cameraFar",0,50).onChange(function(e){ camera.far=e; }); gui.add(controls,"rotationSpeed",0,0.3); gui.add(controls, 'addCube'); for(var i=0;i<10;i++){ controls.addCube(); } document.getElementById("WebGL-output").append(render.domElement); function renderScene(){ scene.traverse(function(e){ if(e instanceof THREE.Mesh){ e.rotation.x+=controls.rotationSpeed; e.rotation.y+=controls.rotationSpeed; e.rotation.z+=controls.rotationSpeed; } }); requestAnimationFrame(renderScene); render.render(scene, camera); } //scene.fog=new THREE.Fog(0xffffff,0.015,100); renderScene(); } window.onload = init; </script> </body> </html>
1.6 计算法向量颜色的材质------MeshNormalMaterial
将该材质应用到几何体对象的时候,几何体对象的每一面的颜色都是从该面向外的法向量计算得到的
法向量决定了光反射的方向,在三维物体上映射材质时起辅助作用,还可以在计算光照,阴影时提供信息,为物体表面的像素上色
法向量所指的方向决定每个面从MeshNormalMaterial材质获取的颜色
//圆球每个面的法向量都不同我可以理解,但是法向量如何与颜色相联系在一起,没有搞明白
下面的demo,设置transparent为true,opacity为0.5,我们不仅可以看到计算法向颜色的材质,还可以看到材质共有的属性side的值front,back,both的效果
<!DOCTYPE html> <html> <head> <title>1</title> <script type="text/javascript" src="three.js"></script> <script type="text/javascript" src="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 which will hold the Output --> <div id="WebGL-output"> </div> <!-- Javascript code that runs our Three.js examples --> <script type="text/javascript"> //var scene function init() { //生成一个场景 var scene=new THREE.Scene(); //生成一个相机 //参数:视场,长宽比,近面,远面 var camera=new THREE.PerspectiveCamera(45,window.innerWidth/window.innerHeight,10,100); camera.position.x=-50; camera.position.y=40; camera.position.z=50; camera.lookAt(scene.position); scene.add(camera); var render; //生成一个webgl的渲染器 var webGLrender=new THREE.WebGLRenderer(); webGLrender.setClearColor(0xEEEEEE); webGLrender.setSize(window.innerWidth,window.innerHeight); webGLrender.shadowMapEnabled=true; //允许阴影映射,渲染阴影需要大量的资源,因此我们需要告诉渲染器我们需要阴影 render=webGLrender; 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); var sphereGeometry = new THREE.SphereGeometry(14, 20, 20); var meshMaterial = new THREE.MeshNormalMaterial({color: 0x7777ff}); var sphere = new THREE.Mesh(sphereGeometry, meshMaterial); sphere.position.x = 0; sphere.position.y = 3; sphere.position.z = 2; for (var f = 0, fl = sphere.geometry.faces.length; f < fl; f++) { var face = sphere.geometry.faces[f]; f==0?console.log(face)&&console.log(sphere.geometry.vertices[face.a]):""; var centroid = new THREE.Vector3(0, 0, 0); centroid.add(sphere.geometry.vertices[face.a]); centroid.add(sphere.geometry.vertices[face.b]); centroid.add(sphere.geometry.vertices[face.c]); centroid.divideScalar(3);//这个函数没有看明白是做什么的 var arrow = new THREE.ArrowHelper( face.normal,//面的法向量 centroid,//该面的质心 2, 0x3333FF,//颜色 0.5, 0.5); sphere.add(arrow); } scene.add(sphere); //增加图形控制界面 var controls=new function(){ this.opacity=1; this.transparent=false; this.rotationSpeed=0.02; this.side="front"; }; var gui=new dat.GUI(); gui.add(controls,"opacity",0,1).onChange(function(e){ meshMaterial.opacity=e; }); gui.add(controls,"transparent").onChange(function (e) { meshMaterial.transparent = e }); gui.add(controls,"rotationSpeed",0,0.3); gui.add(controls, 'side',["front","back","double"]).onChange(function(e){ switch(e){ case "front": meshMaterial.side=THREE.FrontSide; break; case "back": meshMaterial.side=THREE.BackSide; break; case "double": meshMaterial.side=THREE.DoubleSide; break; } }); //gui的一个参数是一个对象,该对象控制的属性是add的函数的第二个参数 //即controls的this.switchRender必须与下面的属性一致 document.getElementById("WebGL-output").append(render.domElement); function renderScene(){ scene.traverse(function(e){ if(e instanceof THREE.Mesh){ e.rotation.x+=controls.rotationSpeed; e.rotation.y+=controls.rotationSpeed; e.rotation.z+=controls.rotationSpeed; } }); requestAnimationFrame(renderScene); render.render(scene, camera); } //scene.fog=new THREE.Fog(0xffffff,0.015,100); renderScene(); } window.onload = init; </script> </body> </html>
1.7 为几何体的每一面都指定材质的材质----MeshFaceMaterial
这种并不是真正的材质,而更像一种材质容器,通过MeshFaceMaterial可以为几何体的每一个面都指定不同的材质
<!DOCTYPE html> <html> <head> <title>1</title> <script type="text/javascript" src="three.js"></script> <script type="text/javascript" src="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 which will hold the Output --> <div id="WebGL-output"> </div> <!-- Javascript code that runs our Three.js examples --> <script type="text/javascript"> //var scene function init() { //生成一个场景 var scene=new THREE.Scene(); //生成一个相机 //参数:视场,长宽比,近面,远面 var camera=new THREE.PerspectiveCamera(45,window.innerWidth/window.innerHeight,10,100); camera.position.x=-50; camera.position.y=40; camera.position.z=50; camera.lookAt(scene.position); scene.add(camera); var render; //生成一个webgl的渲染器 var webGLrender=new THREE.WebGLRenderer(); webGLrender.setClearColor(0xEEEEEE); webGLrender.setSize(window.innerWidth,window.innerHeight); webGLrender.shadowMapEnabled=true; //允许阴影映射,渲染阴影需要大量的资源,因此我们需要告诉渲染器我们需要阴影 render=webGLrender; 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); //生成一个有6个基础材质的数组 var materials=[]; materials.push(new THREE.MeshBasicMaterial({color:"red"})); materials.push(new THREE.MeshBasicMaterial({color:"blue"})); materials.push(new THREE.MeshBasicMaterial({color:"yellow"})); materials.push(new THREE.MeshBasicMaterial({color:"green"})); materials.push(new THREE.MeshBasicMaterial({color:"white"})); materials.push(new THREE.MeshBasicMaterial({color:"black"})); //这6个基础材质的数组作为参数传递给MeshFaceMaterial var faceMaterial=new THREE.MeshFaceMaterial(materials); //生成一个方块应用faceMaterial,即为每个面指定一种材质 var cubeGeom=new THREE.CubeGeometry(6,6,6); var cube=new THREE.Mesh(cubeGeom,faceMaterial); scene.add(cube); //增加图形控制界面 var controls=new function(){ this.rotationSpeed=0.02; }; var gui=new dat.GUI(); gui.add(controls,"rotationSpeed",0,0.3); //gui的一个参数是一个对象,该对象控制的属性是add的函数的第二个参数 //即controls的this.switchRender必须与下面的属性一致 document.getElementById("WebGL-output").append(render.domElement); function renderScene(){ scene.traverse(function(e){ if(e instanceof THREE.Mesh){ e.rotation.x+=controls.rotationSpeed; e.rotation.y+=controls.rotationSpeed; e.rotation.z+=controls.rotationSpeed; } }); requestAnimationFrame(renderScene); render.render(scene, camera); } //scene.fog=new THREE.Fog(0xffffff,0.015,100); renderScene(); } window.onload = init; </script> </body> </html>
这里的demo做了一个魔方
1 一共需要生成27个方块
2 每个方块的每个面都应用材质数组中材质,即每一个小方块的各个面颜色都不同
3 方块的长宽要比10小一些,留个空隙
4 注意一下每个方块的position
5 这些方块追加到一个网格中,然后再将网格追加到场景中
6 旋转的时候,是这个网格在旋转,而不是每个单独的旋转
<!DOCTYPE html> <html> <head> <title>1</title> <script type="text/javascript" src="three.js"></script> <script type="text/javascript" src="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 which will hold the Output --> <div id="WebGL-output"> </div> <!-- Javascript code that runs our Three.js examples --> <script type="text/javascript"> //var scene function init() { //生成一个场景 var scene=new THREE.Scene(); //生成一个相机 //参数:视场,长宽比,近面,远面 var camera=new THREE.PerspectiveCamera(45,window.innerWidth/window.innerHeight,10,100); camera.position.x=-50; camera.position.y=40; camera.position.z=50; camera.lookAt(scene.position); scene.add(camera); var render; //生成一个webgl的渲染器 var webGLrender=new THREE.WebGLRenderer(); webGLrender.setClearColor(0xEEEEEE); webGLrender.setSize(window.innerWidth,window.innerHeight); webGLrender.shadowMapEnabled=true; //允许阴影映射,渲染阴影需要大量的资源,因此我们需要告诉渲染器我们需要阴影 render=webGLrender; 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); //生成一个有6个基础材质的数组 var materials=[],group=new THREE.Mesh(); materials.push(new THREE.MeshBasicMaterial({color:"red"})); materials.push(new THREE.MeshBasicMaterial({color:"blue"})); materials.push(new THREE.MeshBasicMaterial({color:"yellow"})); materials.push(new THREE.MeshBasicMaterial({color:"green"})); materials.push(new THREE.MeshBasicMaterial({color:"white"})); materials.push(new THREE.MeshBasicMaterial({color:"black"})); //这6个基础材质的数组作为参数传递给MeshFaceMaterial var faceMaterial=new THREE.MeshFaceMaterial(materials); //生成27个方块,每三个应用一种材质,即为每个面指定一种材质 for(var x=0;x<3;x++){ for(var y=0;y<3;y++){ for(var z=0;z<3;z++){ var cubeGeom=new THREE.BoxGeometry(9,9,9,9); var cube=new THREE.Mesh(cubeGeom,faceMaterial); cube.position.set(x*10-10,y*10,z*10-10); group.add(cube); } } } scene.add(group); //增加图形控制界面 var controls=new function(){ this.rotationSpeed=0.02; }; var gui=new dat.GUI(); gui.add(controls,"rotationSpeed",0,0.3); //gui的一个参数是一个对象,该对象控制的属性是add的函数的第二个参数 //即controls的this.switchRender必须与下面的属性一致 document.getElementById("WebGL-output").append(render.domElement); function renderScene(){ group.rotation.x+=controls.rotationSpeed; group.rotation.y+=controls.rotationSpeed; group.rotation.z+=controls.rotationSpeed; requestAnimationFrame(renderScene); render.render(scene, camera); } //scene.fog=new THREE.Fog(0xffffff,0.015,100); renderScene(); } window.onload = init; </script> </body> </html>
1.8 高级材质
1 MeshLambertMaterial:会对光源做出反应,可以用来创建暗淡的材质
MeshLambertMaterial材质的ambient(环境色)属性:该材质的环境色,跟AmbientLight光源一起使用,这个颜色会与AmbientLight光源的颜色相乘,该属性的默认值是白色
MeshLambertMaterial材质的emissive(发射色)属性:该材质发射的颜色,它其实并不是光源,而是一种纯粹的,不受其他光照影响的颜色,该属性的默认值是黑色
<!DOCTYPE html> <html> <head> <title>1</title> <script type="text/javascript" src="three.js"></script> <script type="text/javascript" src="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 which will hold the Output --> <div id="WebGL-output"> </div> <!-- Javascript code that runs our Three.js examples --> <script type="text/javascript"> //var scene function init() { //生成一个场景 var scene=new THREE.Scene(); //生成一个相机 //参数:视场,长宽比,近面,远面 var camera=new THREE.PerspectiveCamera(45,window.innerWidth/window.innerHeight,10,100); camera.position.x=-20; camera.position.y=30; camera.position.z=40; camera.lookAt(scene.position); scene.add(camera); var render; //生成一个webgl的渲染器 var webGLrender=new THREE.WebGLRenderer(); webGLrender.setClearColor(0xEEEEEE); webGLrender.setSize(window.innerWidth,window.innerHeight); webGLrender.shadowMapEnabled=true; //允许阴影映射,渲染阴影需要大量的资源,因此我们需要告诉渲染器我们需要阴影 render=webGLrender; 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); var planeGeometry = new THREE.PlaneGeometry(1000, 1000, 4, 4); var plane = new THREE.Mesh(planeGeometry, new THREE.MeshBasicMaterial({color: 0x555555})); plane.rotation.x=-Math.PI/2; plane.position.y=0; scene.add(plane); //生成一个有6个基础材质的数组 var cubeGeom=new THREE.BoxGeometry(10,10,10); var material=new THREE.MeshLambertMaterial({ color:0x7777ff }); var cube=new THREE.Mesh(cubeGeom,material); cube.position.x=0; cube.position.y=13; cube.position.z=2; scene.add(cube); //增加图形控制界面 var controls=new function(){ this.ambient=material.ambient.getHex(); this.emissive=material.emissive.getHex(); this.rotationSpeed=0.02; this.opacity=material.opacity; this.transparent=material.transparent; this.side="front"; }; var gui=new dat.GUI(); gui.add(controls,"rotationSpeed",0,0.3); gui.add(controls,"opacity",0,1).onChange(function(e){ material.opacity=e; }); gui.add(controls,"transparent").onChange(function(e){ material.transparent=e; }); gui.add(controls,"side",["front","back","double"]).onChange(function(e){ switch(e){ case "front": material.side=THREE.FrontSide; break; case "back": material.side=THREE.BackSide; break; case "double": material.side=THREE.DoubleSide; break; } material.needsUpdate=true; }); //使用addColor方法,添加gui颜色选择器 gui.addColor(controls,"ambient").onChange(function(e){ //颜色选择器获取到的是gbs,需要转化THREE的color格式 material.ambient=new THREE.Color(e); }); gui.addColor(controls,"emissive").onChange(function(e){ material.emissive=new THREE.Color(e); }); //gui的一个参数是一个对象,该对象控制的属性是add的函数的第二个参数 //即controls的this.switchRender必须与下面的属性一致 document.getElementById("WebGL-output").append(render.domElement); function renderScene(){ cube.rotation.x+=controls.rotationSpeed; cube.rotation.y+=controls.rotationSpeed; cube.rotation.z+=controls.rotationSpeed; requestAnimationFrame(renderScene); render.render(scene, camera); } //scene.fog=new THREE.Fog(0xffffff,0.015,100); renderScene(); } window.onload = init; </script> </body> </html>
2 MeshPhongMaterial:会对光源做出反应,可以用来创建光亮的材质
名称 | 描述 |
specular(镜面) |
该属性指定该材质的光亮程度及其高光部分的颜色, 如果将它设置跟color的颜色相同,就会得到一种类似于金属的材质 如果设置成灰色,材质就会显得更像塑料 |
shininess | 该属性指定高光部分的亮度,默认值是30 |
<!DOCTYPE html> <html> <head> <title>Example 04.06 - Mesh Lambert material</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> <script type="text/javascript" src="../libs/CanvasRenderer.js"></script> <script type="text/javascript" src="../libs/Projector.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; var webGLRenderer = new THREE.WebGLRenderer(); webGLRenderer.setClearColor(new THREE.Color(0xEEEEEE, 1.0)); webGLRenderer.setSize(window.innerWidth, window.innerHeight); webGLRenderer.shadowMapEnabled = true; var canvasRenderer = new THREE.CanvasRenderer(); canvasRenderer.setSize(window.innerWidth, window.innerHeight); renderer = webGLRenderer; var groundGeom = new THREE.PlaneGeometry(100, 100, 4, 4); var groundMesh = new THREE.Mesh(groundGeom, new THREE.MeshBasicMaterial({color: 0x555555})); groundMesh.rotation.x = -Math.PI / 2; groundMesh.position.y = -20; scene.add(groundMesh); var sphereGeometry = new THREE.SphereGeometry(14, 20, 20); var cubeGeometry = new THREE.BoxGeometry(15, 15, 15); var planeGeometry = new THREE.PlaneGeometry(14, 14, 4, 4); var meshMaterial = new THREE.MeshLambertMaterial({color: 0x7777ff}); var sphere = new THREE.Mesh(sphereGeometry, meshMaterial); var cube = new THREE.Mesh(cubeGeometry, meshMaterial); var plane = new THREE.Mesh(planeGeometry, meshMaterial); // position the sphere sphere.position.x = 0; sphere.position.y = 3; sphere.position.z = 2; cube.position = sphere.position; plane.position = sphere.position; // add the sphere to the scene scene.add(cube); // position and point the camera to the center of the scene camera.position.x = -20; camera.position.y = 30; camera.position.z = 40; camera.lookAt(new THREE.Vector3(10, 0, 0)); // 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(-30, 60, 60); 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.bouncingSpeed = 0.03; this.opacity = meshMaterial.opacity; this.transparent = meshMaterial.transparent; this.overdraw = meshMaterial.overdraw; this.visible = meshMaterial.visible; this.emissive = meshMaterial.emissive.getHex(); this.ambient = meshMaterial.ambient.getHex(); this.side = "front"; this.color = meshMaterial.color.getStyle(); this.wrapAround = false; this.wrapR = 1; this.wrapG = 1; this.wrapB = 1; this.selectedMesh = "cube"; }; var gui = new dat.GUI(); var spGui = gui.addFolder("Mesh"); spGui.add(controls, 'opacity', 0, 1).onChange(function (e) { meshMaterial.opacity = e }); spGui.add(controls, 'transparent').onChange(function (e) { meshMaterial.transparent = e }); spGui.add(controls, 'visible').onChange(function (e) { meshMaterial.visible = e }); spGui.addColor(controls, 'ambient').onChange(function (e) { meshMaterial.ambient = new THREE.Color(e) }); spGui.addColor(controls, 'emissive').onChange(function (e) { meshMaterial.emissive = new THREE.Color(e) }); spGui.add(controls, 'side', ["front", "back", "double"]).onChange(function (e) { console.log(e); switch (e) { case "front": meshMaterial.side = THREE.FrontSide; break; case "back": meshMaterial.side = THREE.BackSide; break; case "double": meshMaterial.side = THREE.DoubleSide; break; } meshMaterial.needsUpdate = true; }); spGui.addColor(controls, 'color').onChange(function (e) { meshMaterial.color.setStyle(e) }); spGui.add(controls, 'selectedMesh', ["cube", "sphere", "plane"]).onChange(function (e) { scene.remove(plane); scene.remove(cube); scene.remove(sphere); switch (e) { case "cube": scene.add(cube); break; case "sphere": scene.add(sphere); break; case "plane": scene.add(plane); break; } scene.add(e); }); spGui.add(controls, 'wrapAround').onChange(function (e) { meshMaterial.wrapAround = e; meshMaterial.needsUpdate = true; }); spGui.add(controls, 'wrapR', 0, 1).step(0.01).onChange(function (e) { meshMaterial.wrapRGB.x = e; }); spGui.add(controls, 'wrapG', 0, 1).step(0.01).onChange(function (e) { meshMaterial.wrapRGB.y = e; }); spGui.add(controls, 'wrapB', 0, 1).step(0.01).onChange(function (e) { meshMaterial.wrapRGB.z = e; }); render(); function render() { stats.update(); cube.rotation.y = step += 0.01; plane.rotation.y = step; sphere.rotation.y = step; // 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>
3 ShaderMaterial:最通用也是最难用的材质,通过ShaderMaterial可以创建自己的着色程序,直接在webgl环境中运行,
着色器可以将three.js中的js对象转化为屏幕上的像素,
注意着色器不是js编写的,而是类似于c的GLSL语言,所以下面这个demo只是一个例子,并不做过多的解释
<!DOCTYPE html> <html> <head> <title>Example 04.08 - Shader material - http://glsl.heroku.com/</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> <script id="vertex-shader" type="x-shader/x-vertex"> uniform float time; varying vec2 vUv; void main() { vec3 posChanged = position; posChanged.x = posChanged.x*(abs(sin(time*1.0))); posChanged.y = posChanged.y*(abs(cos(time*1.0))); posChanged.z = posChanged.z*(abs(sin(time*1.0))); //gl_Position = projectionMatrix * modelViewMatrix * vec4(position*(abs(sin(time)/2.0)+0.5),1.0); gl_Position = projectionMatrix * modelViewMatrix * vec4(posChanged,1.0); } </script> <script id="fragment-shader-1" type="x-shader/x-fragment"> precision highp float; uniform float time; uniform float alpha; uniform vec2 resolution; varying vec2 vUv; void main2(void) { vec2 position = vUv; float red = 1.0; float green = 0.25 + sin(time) * 0.25; float blue = 0.0; vec3 rgb = vec3(red, green, blue); vec4 color = vec4(rgb, alpha); gl_FragColor = color; } #define PI 3.14159 #define TWO_PI (PI*2.0) #define N 68.5 void main(void) { vec2 center = (gl_FragCoord.xy); center.x=-10.12*sin(time/200.0); center.y=-10.12*cos(time/200.0); vec2 v = (gl_FragCoord.xy - resolution/20.0) / min(resolution.y,resolution.x) * 15.0; v.x=v.x-10.0; v.y=v.y-200.0; float col = 0.0; for(float i = 0.0; i < N; i++) { float a = i * (TWO_PI/N) * 61.95; col += cos(TWO_PI*(v.y * cos(a) + v.x * sin(a) + sin(time*0.004)*100.0 )); } col /= 5.0; gl_FragColor = vec4(col*1.0, -col*1.0,-col*4.0, 1.0); } </script> <script id="fragment-shader-2" type="x-shader/x-fragment"> // from http://glsl.heroku.com/e#7906.0 uniform float time; uniform vec2 resolution; // 2013-03-30 by @hintz #define CGFloat float #define M_PI 3.14159265359 vec3 hsvtorgb(float h, float s, float v) { float c = v * s; h = mod((h * 6.0), 6.0); float x = c * (1.0 - abs(mod(h, 2.0) - 1.0)); vec3 color; if (0.0 <= h && h < 1.0) { color = vec3(c, x, 0.0); } else if (1.0 <= h && h < 2.0) { color = vec3(x, c, 0.0); } else if (2.0 <= h && h < 3.0) { color = vec3(0.0, c, x); } else if (3.0 <= h && h < 4.0) { color = vec3(0.0, x, c); } else if (4.0 <= h && h < 5.0) { color = vec3(x, 0.0, c); } else if (5.0 <= h && h < 6.0) { color = vec3(c, 0.0, x); } else { color = vec3(0.0); } color += v - c; return color; } void main(void) { vec2 position = (gl_FragCoord.xy - 0.5 * resolution) / resolution.y; float x = position.x; float y = position.y; CGFloat a = atan(x, y); CGFloat d = sqrt(x*x+y*y); CGFloat d0 = 0.5*(sin(d-time)+1.5)*d; CGFloat d1 = 5.0; CGFloat u = mod(a*d1+sin(d*10.0+time), M_PI*2.0)/M_PI*0.5 - 0.5; CGFloat v = mod(pow(d0*4.0, 0.75),1.0) - 0.5; CGFloat dd = sqrt(u*u+v*v); CGFloat aa = atan(u, v); CGFloat uu = mod(aa*3.0+3.0*cos(dd*30.0-time), M_PI*2.0)/M_PI*0.5 - 0.5; // CGFloat vv = mod(dd*4.0,1.0) - 0.5; CGFloat d2 = sqrt(uu*uu+v*v)*1.5; gl_FragColor = vec4( hsvtorgb(dd+time*0.5/d1, sin(dd*time), d2), 1.0 ); } </script> <script id="fragment-shader-3" type="x-shader/x-fragment"> uniform vec2 resolution; uniform float time; vec2 rand(vec2 pos) { return fract( 0.00005 * (pow(pos+2.0, pos.yx + 1.0) * 22222.0)); } vec2 rand2(vec2 pos) { return rand(rand(pos)); } float softnoise(vec2 pos, float scale) { vec2 smplpos = pos * scale; float c0 = rand2((floor(smplpos) + vec2(0.0, 0.0)) / scale).x; float c1 = rand2((floor(smplpos) + vec2(1.0, 0.0)) / scale).x; float c2 = rand2((floor(smplpos) + vec2(0.0, 1.0)) / scale).x; float c3 = rand2((floor(smplpos) + vec2(1.0, 1.0)) / scale).x; vec2 a = fract(smplpos); return mix( mix(c0, c1, smoothstep(0.0, 1.0, a.x)), mix(c2, c3, smoothstep(0.0, 1.0, a.x)), smoothstep(0.0, 1.0, a.y)); } void main(void) { vec2 pos = gl_FragCoord.xy / resolution.y; pos.x += time * 0.1; float color = 0.0; float s = 1.0; for(int i = 0; i < 8; i++) { color += softnoise(pos+vec2(i)*0.02, s * 4.0) / s / 2.0; s *= 2.0; } gl_FragColor = vec4(color); } </script> <script id="fragment-shader-4" type="x-shader/x-fragment"> uniform float time; uniform vec2 resolution; vec2 rand(vec2 pos) { return fract( ( pow( pos+2.0, pos.yx+2.0 )*555555.0 ) ); } vec2 rand2(vec2 pos) { return rand(rand(pos)); } float softnoise(vec2 pos, float scale) { vec2 smplpos = pos * scale; float c0 = rand2((floor(smplpos) + vec2(0.0, 0.0)) / scale).x; float c1 = rand2((floor(smplpos) + vec2(1.0, 0.0)) / scale).x; float c2 = rand2((floor(smplpos) + vec2(0.0, 1.0)) / scale).x; float c3 = rand2((floor(smplpos) + vec2(1.0, 1.0)) / scale).x; vec2 a = fract(smplpos); return mix(mix(c0, c1, smoothstep(0.0, 1.0, a.x)), mix(c2, c3, smoothstep(0.0, 1.0, a.x)), smoothstep(0.0, 1.0, a.x)); } void main( void ) { vec2 pos = gl_FragCoord.xy / resolution.y - time * 0.4; float color = 0.0; float s = 1.0; for (int i = 0; i < 6; ++i) { color += softnoise(pos + vec2(0.01 * float(i)), s * 4.0) / s / 2.0; s *= 2.0; } gl_FragColor = vec4(color,mix(color,cos(color),sin(color)),color,1); } </script> <script id="fragment-shader-5" type="x-shader/x-fragment"> uniform float time; uniform vec2 resolution; // tie nd die by Snoep Games. void main( void ) { vec3 color = vec3(1.0, 0., 0.); vec2 pos = (( 1.4 * gl_FragCoord.xy - resolution.xy) / resolution.xx)*1.5; float r=sqrt(pos.x*pos.x+pos.y*pos.y)/15.0; float size1=2.0*cos(time/60.0); float size2=2.5*sin(time/12.1); float rot1=13.00; //82.0+16.0*sin(time/4.0); float rot2=-50.00; //82.0+16.0*sin(time/8.0); float t=sin(time); float a = (60.0)*sin(rot1*atan(pos.x-size1*pos.y/r,pos.y+size1*pos.x/r)+time); a += 200.0*acos(pos.x*2.0+cos(time/2.0))+asin(pos.y*5.0+sin(time/2.0)); a=a*(r/50.0); a=200.0*sin(a*5.0)*(r/30.0); if(a>5.0) a=a/200.0; if(a<0.5) a=a*22.5; gl_FragColor = vec4( cos(a/20.0),a*cos(a/200.0),sin(a/8.0), 1.0 ); } </script> <script id="fragment-shader-6" type="x-shader/x-fragment"> uniform float time; uniform vec2 resolution; void main( void ) { vec2 uPos = ( gl_FragCoord.xy / resolution.xy );//normalize wrt y axis //suPos -= vec2((resolution.x/resolution.y)/2.0, 0.0);//shift origin to center uPos.x -= 1.0; uPos.y -= 0.5; vec3 color = vec3(0.0); float vertColor = 2.0; for( float i = 0.0; i < 15.0; ++i ) { float t = time * (0.9); uPos.y += sin( uPos.x*i + t+i/2.0 ) * 0.1; float fTemp = abs(1.0 / uPos.y / 100.0); vertColor += fTemp; color += vec3( fTemp*(10.0-i)/10.0, fTemp*i/10.0, pow(fTemp,1.5)*1.5 ); } vec4 color_final = vec4(color, 1.0); gl_FragColor = color_final; } </script> <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(0x000000, 1.0)); renderer.setSize(window.innerWidth, window.innerHeight); renderer.shadowMapEnabled = true; var cubeGeometry = new THREE.BoxGeometry(20, 20, 20); var meshMaterial1 = createMaterial("vertex-shader", "fragment-shader-1"); var meshMaterial2 = createMaterial("vertex-shader", "fragment-shader-2"); var meshMaterial3 = createMaterial("vertex-shader", "fragment-shader-3"); var meshMaterial4 = createMaterial("vertex-shader", "fragment-shader-4"); var meshMaterial5 = createMaterial("vertex-shader", "fragment-shader-5"); var meshMaterial6 = createMaterial("vertex-shader", "fragment-shader-6"); var material = new THREE.MeshFaceMaterial( [meshMaterial1, meshMaterial2, meshMaterial3, meshMaterial4, meshMaterial5, meshMaterial6]); // var material = new THREE.MeshFaceMaterial([meshMaterial2, meshMaterial2, meshMaterial1, meshMaterial1, meshMaterial1, meshMaterial1]); var cube = new THREE.Mesh(cubeGeometry, material); // add the sphere to the scene scene.add(cube); // position and point the camera to the center of the scene camera.position.x = 30; camera.position.y = 30; camera.position.z = 30; camera.lookAt(new THREE.Vector3(0, 0, 0)); // 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 oldContext = null; var controls = new function () { this.rotationSpeed = 0.02; this.bouncingSpeed = 0.03; this.opacity = meshMaterial1.opacity; this.transparent = meshMaterial1.transparent; this.visible = meshMaterial1.visible; this.side = "front"; this.wireframe = meshMaterial1.wireframe; this.wireframeLinewidth = meshMaterial1.wireframeLinewidth; this.selectedMesh = "cube"; this.shadow = "flat"; }; render(); function render() { stats.update(); cube.rotation.y = step += 0.01; cube.rotation.x = step; cube.rotation.z = step; cube.material.materials.forEach(function (e) { e.uniforms.time.value += 0.01; }); // 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; } function createMaterial(vertexShader, fragmentShader) { var vertShader = document.getElementById(vertexShader).innerHTML; var fragShader = document.getElementById(fragmentShader).innerHTML; var attributes = {}; var uniforms = { time: {type: 'f', value: 0.2}, scale: {type: 'f', value: 0.2}, alpha: {type: 'f', value: 0.6}, resolution: {type: "v2", value: new THREE.Vector2()} }; uniforms.resolution.value.x = window.innerWidth; uniforms.resolution.value.y = window.innerHeight; var meshMaterial = new THREE.ShaderMaterial({ uniforms: uniforms, attributes: attributes, vertexShader: vertShader, fragmentShader: fragShader, transparent: true }); return meshMaterial; } } window.onload = init; </script> </body> </html>
1.9 线段几何体的材质
下面这两种材质只能应用于特定的几何体:THREE.Line(线段)
1.9.1 LineBaseMaterial:可以设置线段的颜色,宽度,端点,连接点等属性
1.9.2 LineDashedMaterial:与上面的LineBaseMaterial属性一样,但是可以通过指定短划线和空格的长度,创造出来虚线的效果
<!DOCTYPE html> <html> <head> <title>Example 04.09 - Linematerial</title> <script type="text/javascript" src="../libs/three.js"></script> <script type="text/javascript" src="../libs/stats.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(0x000000, 1.0)); renderer.setSize(window.innerWidth, window.innerHeight); renderer.shadowMapEnabled = true; // 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); // 环境光 没有特定的光源,该光源不会影响阴影的产生,使用该光源是为了弱化阴影或者添加一些颜色 var ambientLight = new THREE.AmbientLight(0x0c0c0c); scene.add(ambientLight); //聚光灯光源,最常使用的光源,锥形效果 var spotLight = new THREE.SpotLight(0xffffff); spotLight.position.set(-40, 60, -10); spotLight.castShadow = true; scene.add(spotLight); /*本处书中给出的例子是gosper曲线,涉及到数学曲线、,本人没有看懂,所以使用了随机生成的点,附带上Gosper函数, 能看懂的朋友,可以留言给我,谢谢了! function gosper(a, b) { var turtle = [0, 0, 0]; var points = []; var count = 0; rg(a, b, turtle); return points; //右走 function rt(x) { turtle[2] += x; } //左走 function lt(x) { turtle[2] -= x; } function fd(dist) { // ctx.beginPath(); points.push({x: turtle[0], y: turtle[1], z: Math.sin(count) * 5}); // ctx.moveTo(turtle[0], turtle[1]); var dir = turtle[2] * (Math.PI / 180); turtle[0] += Math.cos(dir) * dist; turtle[1] += Math.sin(dir) * dist; points.push({x: turtle[0], y: turtle[1], z: Math.sin(count) * 5}); // ctx.lineTo(turtle[0], turtle[1]); // ctx.stroke(); } function rg(st, ln, turtle) { st--; ln = ln / 2.6457; if (st > 0) { // ctx.strokeStyle = '#111'; rg(st, ln, turtle); rt(60); gl(st, ln, turtle); rt(120); gl(st, ln, turtle); lt(60); rg(st, ln, turtle); lt(120); rg(st, ln, turtle); rg(st, ln, turtle); lt(60); gl(st, ln, turtle); rt(60); } if (st == 0) { fd(ln); rt(60); fd(ln); rt(120); fd(ln); lt(60); fd(ln); lt(120); fd(ln); fd(ln); lt(60); fd(ln); rt(60) } } function gl(st, ln, turtle) { st--; ln = ln / 2.6457; if (st > 0) { // ctx.strokeStyle = '#555'; lt(60); rg(st, ln, turtle); rt(60); gl(st, ln, turtle); gl(st, ln, turtle); rt(120); gl(st, ln, turtle); rt(60); rg(st, ln, turtle); lt(120); rg(st, ln, turtle); lt(60); gl(st, ln, turtle); } if (st == 0) { lt(60); fd(ln); rt(60); fd(ln); fd(ln); rt(120); fd(ln); rt(60); fd(ln); lt(120); fd(ln); lt(60); fd(ln); } } } */ var points=[]; function getPoints(){ var rmd_x=Math.random()*50; var rmd_y=Math.random()*50; var rmd_z=Math.random()*50; points.push({x:rmd_x, y: rmd_y, z: rmd_z}); } for(var j=0;j<100;j++){ getPoints(); } //生成一个几何体 var lines = new THREE.Geometry(); var colors = []; var i = 0; //该几何体的顶点由getPoint函数生成的点组成 points.forEach(function (e) { lines.vertices.push(new THREE.Vector3(e.x, e.z, e.y)); colors[i] = new THREE.Color(0xffffff); colors[i].setHSL(e.x / 100 + 0.5, ( e.y * 20 ) / 300, 0.8); //色调,饱和度,亮度 i++; }); //该几何体的颜色就是上面得到的颜色 lines.colors = colors; /*这里有几个点不是很理解,linewidth是设置线段的宽度的,但是这里即使设置到50,也没有任何反应,不知道是哪里写错了 有能找到问题的欢迎留言给我,另外透明度的opacity属性也不起作用 */ var material = new THREE.LineBasicMaterial({ opacity: 1.0, linewidth: 4, vertexColors: THREE.VertexColors }); var line = new THREE.Line(lines, material); line.position.set(25, -30, -60); scene.add(line); // 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 render() { //stats.update(); line.rotation.z = step += 0.01; requestAnimationFrame(render); renderer.render(scene, camera); } }; window.onload = init; </script> </body> </html>
LineDashedMaterial与LineBasicMaterial相似,多了几个属性,dashSize:短划线的长度,gapSize间隔的长度
<!DOCTYPE html> <html> <head> <title>Example 04.09 - Linematerial</title> <script type="text/javascript" src="../libs/three.js"></script> <script type="text/javascript" src="../libs/stats.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(0x000000, 1.0)); renderer.setSize(window.innerWidth, window.innerHeight); renderer.shadowMapEnabled = true; // 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); // 环境光 没有特定的光源,该光源不会影响阴影的产生,使用该光源是为了弱化阴影或者添加一些颜色 var ambientLight = new THREE.AmbientLight(0x0c0c0c); scene.add(ambientLight); //聚光灯光源,最常使用的光源,锥形效果 var spotLight = new THREE.SpotLight(0xffffff); spotLight.position.set(-40, 60, -10); spotLight.castShadow = true; scene.add(spotLight); var points=[]; function getPoints(){ var rmd_x=Math.random()*50; var rmd_y=Math.random()*50; var rmd_z=Math.random()*50; points.push({x:rmd_x, y: rmd_y, z: rmd_z}); } for(var j=0;j<100;j++){ getPoints(); } //生成一个几何体 var lines = new THREE.Geometry(); var colors = []; var i = 0; //该几何体的顶点由getPoint函数生成的点组成 points.forEach(function (e) { lines.vertices.push(new THREE.Vector3(e.x, e.z, e.y)); colors[i] = new THREE.Color(0xffffff); colors[i].setHSL(e.x / 100 + 0.5, ( e.y * 20 ) / 300, 0.8); //色调,饱和度,亮度 i++; }); //该几何体的颜色就是上面得到的颜色 lines.colors = colors; //必须调用该方法,如果不调用,间隔就不能显示出来 lines.computeLineDistances(); var material = new THREE.LineDashedMaterial({ dashSize:10,//短划线的长度 gapSize:1,//间隔的长度 scale: 0.4,//缩放的比例 vertexColors:THREE.VertexColors//为每个顶点指定一个颜色 }); var line = new THREE.Line(lines, material); line.position.set(25, -30, -60); scene.add(line); // 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 render() { //stats.update(); line.rotation.z = step += 0.01; requestAnimationFrame(render); renderer.render(scene, camera); } }; window.onload = init; </script> </body> </html>