threeJS创建mesh,创建平面,设置mesh的平移,旋转、缩放、自传、透明度、拉伸
这个小案例是当初我在学习的时候,小的一个小案例,代码还需要进一步优化;还请谅解~~;主要用到了threeJS创建mesh,创建平面,设置mesh的平移,旋转、缩放、自传、透明度、拉伸等这些小功能;
采用的是正交投影摄像机。可能初学者看到这个案例,想写其中的某一个小功能可能会有点蒙,不要着急,后面我会持续更新,把每个小功能的demo写出来分享给大家。和大家一起学习,共同进步。也希望大家可以给出一些建议!!非常感谢~~
1 需要加载这些相关的js文件
2 下面是实现的一些小功能
3 下面是相关代码,代码还没有优化,请谅解~~(具体的每一个小功能后面我都会进行一一讲解)
<!DOCTYPE html> <html lang="en" xmlns="http://www.w3.org/1999/xhtml"> <head> <meta charset="utf-8" /> <title></title> <style> body { margin: 0; overflow: hidden; /* 隐藏body窗口区域滚动条 */ } </style> <!--引入three.js三维引擎--> <script src="js/three.js"></script> <!-- 引入threejs扩展控件OrbitControls.js --> <script src="js/OrbitControls.js"></script> <script src="js/stats.min.js"></script> <script src="js/jquery-1.9.0.js"></script> <script src="js/dat.gui.js"></script> <script src="js/stats.js"></script> </head> <body> <div id="Stats-output"> </div> <div id="WebGL-output"> </div> <script type="text/javascript"> // once everything is loaded, we run our Three.js stuff. $(function () { 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.setClearColorHex(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: 0x777777 })); 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.CubeGeometry(15, 15, 15); var planeGeometry = new THREE.PlaneGeometry(14, 14, 4, 4); var meshMaterial = new THREE.MeshNormalMaterial({ 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; for (var f = 0, fl = sphere.geometry.faces.length; f < fl; f++) { var face = sphere.geometry.faces[f]; var arrow = new THREE.ArrowHelper( face.normal, face.centroid, 2, 0x3333FF); sphere.add(arrow); } 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(-40, 60, -10); spotLight.castShadow = true; scene.add(spotLight); // add the output of the renderer to the html element $("#WebGL-output").append(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 = meshMaterial.opacity; this.transparent = meshMaterial.transparent; this.visible = meshMaterial.visible; this.side = "front"; this.wireframe = meshMaterial.wireframe; this.wireframeLinewidth = meshMaterial.wireframeLinewidth; this.selectedMesh = "cube"; this.shadow = "flat"; } 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, 'wireframe').onChange(function (e) { meshMaterial.wireframe = e }); spGui.add(controls, 'wireframeLinewidth', 0, 20).onChange(function (e) { meshMaterial.wireframeLinewidth = e }); spGui.add(controls, 'visible').onChange(function (e) { meshMaterial.visible = 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.add(controls, 'shadow', ["flat", "smooth"]).onChange(function (e) { switch (e) { case "flat": // https://github.com/mrdoob/three.js/issues/1929 meshMaterial.shading = THREE.FlatShading; break; case "smooth": meshMaterial.shading = THREE.SmoothShading; break; } var oldPos = sphere.position.clone(); scene.remove(sphere); scene.remove(plane); scene.remove(cube); sphere = new THREE.Mesh(sphere.geometry.clone(), meshMaterial); cube = new THREE.Mesh(cube.geometry.clone(), meshMaterial); plane = new THREE.Mesh(plane.geometry.clone(), meshMaterial); sphere.position = oldPos; cube.position = oldPos; plane.position = oldPos; switch (controls.selectedMesh) { case "cube": scene.add(cube); break; case "sphere": scene.add(sphere); break; case "plane": scene.add(plane); break; } meshMaterial.needsUpdate = true; console.log(meshMaterial); }); 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); }); 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'; $("#Stats-output").append(stats.domElement); return stats; } }); </script> <script> /** * 创建场景对象Scene */ var scene = new THREE.Scene(); /** * 创建网格模型 */ //创建第一个方块 var geometry = new THREE.BoxGeometry(100, 100, 100); //创建一个立方体几何对象Geometry var material = new THREE.MeshLambertMaterial({ color: 0x0000ff }); //材质对象Material var mesh = new THREE.Mesh(geometry, material); //网格模型对象Mesh scene.add(mesh); //网格模型添加到场景中 // 设置产生投影的网格模型 mesh.castShadow = true; //创建第二个方块 var geometry2 = new THREE.BoxGeometry(100, 100, 100); //创建一个立方体几何对象Geometry var material2 = new THREE.MeshLambertMaterial({ color: 0x0000ff }); //材质对象Material var mesh2 = new THREE.Mesh(geometry2, material2); //网格模型对象Mesh mesh2.translateY(200);//方块二沿y轴正方向平移40 scene.add(mesh2); //网格模型添加到场景中 //创建第三个方块 var geometry3 = new THREE.BoxGeometry(100, 100, 100); //创建一个立方体几何对象Geometry var material3 = new THREE.MeshLambertMaterial({ color: 0x0000ff, transparent: true,//开启透明度 opacity: 0.5,//设置透明度具体值 }); //材质对象Material var mesh3 = new THREE.Mesh(geometry3, material3); //网格模型对象Mesh mesh3.translateY(400);//方块二沿y轴正方向平移80 scene.add(mesh3); //网格模型添加到场景中 //创建第四个方块 var geometry4 = new THREE.BoxGeometry(100, 100, 100); //创建一个立方体几何对象Geometry var material4 = new THREE.MeshLambertMaterial({ color: 0x0000ff, transparent: true,//开启透明度 opacity: 0.5,//设置透明度具体值 }); //材质对象Material var mesh4 = new THREE.Mesh(geometry4, material4); //网格模型对象Mesh mesh4.translateY(600);//方块二沿y轴正方向平移120 scene.add(mesh4); //网格模型添加到场景中 //创建第五个方块 var geometry5 = new THREE.BoxGeometry(100, 100, 100); //创建一个立方体几何对象Geometry var material5 = new THREE.MeshLambertMaterial({ color: 0x0000ff }); //材质对象Material var mesh5 = new THREE.Mesh(geometry5, material5); //网格模型对象Mesh mesh5.translateY(800);//方块二沿y轴正方向平移160 scene.add(mesh5); //网格模型添加到场景中 //创建第六个方块 var geometry6 = new THREE.BoxGeometry(100, 100, 100); //创建一个立方体几何对象Geometry var material6 = new THREE.MeshLambertMaterial({ color: 0x0000ff }); //材质对象Material var mesh6 = new THREE.Mesh(geometry6, material6); //网格模型对象Mesh mesh6.translateX(200);//方块二沿y轴正方向平移40 scene.add(mesh6); //网格模型添加到场景中 mesh6.castShadow = true; //创建第七个方块 var geometry7 = new THREE.BoxGeometry(100, 100, 100); //创建一个立方体几何对象Geometry var material7 = new THREE.MeshLambertMaterial({ color: 0x0000ff }); //材质对象Material var mesh7 = new THREE.Mesh(geometry7, material7); //网格模型对象Mesh mesh7.translateX(400);//方块二沿y轴正方向平移80 scene.add(mesh7); //网格模型添加到场景中 mesh7.castShadow = true; //创建第八个方块 var geometry8 = new THREE.BoxGeometry(100, 100, 100); //创建一个立方体几何对象Geometry var material8 = new THREE.MeshLambertMaterial({ color: 0x0000ff }); //材质对象Material var mesh8 = new THREE.Mesh(geometry8, material8); //网格模型对象Mesh mesh8.translateX(600);//方块二沿y轴正方向平移120 scene.add(mesh8); //网格模型添加到场景中 mesh8.castShadow = true; //创建第九个方块 var geometry9 = new THREE.BoxGeometry(100, 100, 100); //创建一个立方体几何对象Geometry var material9 = new THREE.MeshLambertMaterial({ color: 0x0000ff }); //材质对象Material var mesh9 = new THREE.Mesh(geometry9, material9); //网格模型对象Mesh mesh9.translateX(800);//方块二沿y轴正方向平移160 scene.add(mesh9); //网格模型添加到场景中 mesh9.castShadow = true; //创建第十个方块 var geometry10 = new THREE.BoxGeometry(200, 200, 200); //创建一个立方体几何对象Geometry var material10 = new THREE.MeshLambertMaterial({ color: 0x0000ff }); //材质对象Material var newMesh = new THREE.Mesh(geometry10, material10); //网格模型对象Mesh newMesh.copy(mesh); //相比mesh而言,在平移 newMesh.translateX(-500);//方块二沿y轴正方向平移300 scene.add(newMesh); //网格模型添加到场景中 // 通过Path类的线条绘制方法方法定义轮廓 var shape = new THREE.Shape(); shape.moveTo(0, 0); //起点 shape.lineTo(0, 100); //第2点 shape.lineTo(100, 100); //第3点 shape.lineTo(100, 0); //第4点 shape.lineTo(0, 0); //第5点 var geometry11 = new THREE.ExtrudeGeometry( //拉伸造型 shape, //二维轮廓 //拉伸参数 { amount: 300, //拉伸长度 } ); var material11 = new THREE.MeshPhongMaterial({ color: 0x0000ff, side: THREE.DoubleSide, //两面可见 // wireframe: true, }); //材质对象 var mesh11 = new THREE.Mesh(geometry11, material11); //网格模型对象 mesh11.translateY(-500);//方块二沿y轴正方向平移40 scene.add(mesh11); //网格模型添加到场景中 // 辅助坐标系 var axisHelper = new THREE.AxisHelper(250); scene.add(axisHelper); /** * 光源设置 */ //点光源 var point = new THREE.PointLight(0xffffff); point.position.set(40, 40, 30); //点光源位置 scene.add(point); //点光源添加到场景中 //环境光 var ambient = new THREE.AmbientLight(0x444444); scene.add(ambient); //创建一个平面几何体作为投影面 var planeGeometry = new THREE.PlaneGeometry(2000, 2000); var planeMaterial = new THREE.MeshLambertMaterial({ color: 0x999999 }); //材质对象Material // 平面网格模型作为投影面 var planeMesh = new THREE.Mesh(planeGeometry, planeMaterial); //网格模型对象Mesh scene.add(planeMesh); //网格模型添加到场景中 planeMesh.rotateX(-Math.PI / 2); //旋转网格模型 planeMesh.position.y = -50; //设置网格模型y坐标 // 设置接收阴影的投影面 planeMesh.receiveShadow = true; // 方向光 var directionalLight = new THREE.DirectionalLight(0xffffff, 1); // 设置光源位置 directionalLight.position.set(60, 60, 60); scene.add(directionalLight); // 设置用于计算阴影的光源对象 directionalLight.castShadow = true; // 设置计算阴影的区域,最好刚好紧密包围在对象周围 // 计算阴影的区域过大:模糊 过小:看不到或显示不完整 directionalLight.shadow.camera.near = 0.5; directionalLight.shadow.camera.far = 300; directionalLight.shadow.camera.left = -50; directionalLight.shadow.camera.right = 50; directionalLight.shadow.camera.top = 200; directionalLight.shadow.camera.bottom = -100; // 设置mapSize属性可以使阴影更清晰,不那么模糊 // directionalLight.shadow.mapSize.set(1024,1024) console.log(directionalLight.shadow.camera); /** * 相机设置 */ var width = window.innerWidth; //窗口宽度 var height = window.innerHeight; //窗口高度 var k = width / height; //窗口宽高比 var s = 1000; //三维场景显示范围控制系数,系数越大,显示的范围越大 //创建相机对象 var camera = new THREE.OrthographicCamera(-s * k, s * k, s, -s, 1, 2000); camera.position.set(200, 300, 200); //设置相机位置 camera.lookAt(scene.position); //设置相机方向(指向的场景对象) //实现相机切换 this.switchCamera = function () { if (camera instanceof THREE.PerspectiveCamera) { camera = new THREE.OrthographicCamera(window.innerWidth / -16, window.innerWidth / 16, window.innerHeight / 16, window.innerHeight / -16, -200, 500); camera.position.x = 120; camera.position.y = 60; camera.position.z = 180; camera.lookAt(scene.position); this.perspective = "Orthographic"; } else { camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 0.1, 1000); camera.position.x = 120; camera.position.y = 60; camera.position.z = 180; camera.lookAt(scene.position); this.perspective = "Perspective"; } };//代码放入GUI工具中,可以在页面上动态切换相机 //声明raycaster和mouse变量 var raycaster = new THREE.Raycaster(); console.log(raycaster); var mouse = new THREE.Vector2(); function onMouseClick(event) { //通过鼠标点击的位置计算出raycaster所需要的点的位置,以屏幕中心为原点,值的范围为-1到1. mouse.x = (event.clientX / window.innerWidth) * 2 - 1; mouse.y = - (event.clientY / window.innerHeight) * 2 + 1; // 通过鼠标点的位置和当前相机的矩阵计算出raycaster raycaster.setFromCamera(mouse, camera); // 获取raycaster直线和所有模型相交的数组集合 var intersects = raycaster.intersectObjects(scene.children); console.log(intersects[i].object); console.log(intersects); //将所有的相交的模型的颜色设置为红色,如果只需要将第一个触发事件,那就数组的第一个模型改变颜色即可 for (var i = 0; i < intersects.length; i++) { //ransparent: true;//开启透明度 //acity: 0.5//设置透明度具体值 intersects[i].object.material.color.set(0xff0000); // console.log(intersects[i].object); // 因为sphereMaterial.opacity和sphere.material.opacity值是相等的,所以只判断一个 // if (sphereMaterial.opacity > 0) { // sphereMaterial.opacity -= 0.05; // sphere.material.opacity -= 0.05; // } // else { // sphere.material.transparent = true; // clearInterval(timer); // } } } window.addEventListener('click', onMouseClick, false); //初始化dat.GUI简化试验流程 var gui; function initGui() { //声明一个保存需求修改的相关数据的对象 controls = { }; var gui = new dat.GUI(); } //初始化性能插件 var stats; function initStats() { stats = new Stats(); document.body.appendChild(stats.dom); } //用户交互插件 鼠标左键按住旋转,右键按住平移,滚轮缩放 var controls; function initControls() { controls = new THREE.OrbitControls(camera, renderer.domElement); // 如果使用animate方法时,将此函数删除 //controls.addEventListener( 'change', render ); // 使动画循环使用时阻尼或自转 意思是否有惯性 controls.enableDamping = true; //动态阻尼系数 就是鼠标拖拽旋转灵敏度 //controls.dampingFactor = 0.25; //是否可以缩放 controls.enableZoom = true; //是否自动旋转 controls.autoRotate = false; //设置相机距离原点的最远距离 controls.minDistance = 50; //设置相机距离原点的最远距离 controls.maxDistance = 1000; //是否开启右键拖拽 controls.enablePan = true; } //窗口变动触发的函数 function onWindowResize() { camera.aspect = window.innerWidth / window.innerHeight; camera.updateProjectionMatrix(); render(); renderer.setSize(window.innerWidth, window.innerHeight); } function animate() { //更新控制器 render(); //更新性能插件 stats.update(); //controls.update(); requestAnimationFrame(animate); } function draw() { initGui(); initControls(); initStats(); animate(); window.onresize = onWindowResize; } /** * 创建渲染器对象 */ var renderer = new THREE.WebGLRenderer({ antialias: true, alpha: true }); renderer.setSize(width, height);//设置渲染区域尺寸 renderer.setClearColor(0xb9d3ff, 1); //设置背景颜色 renderer.shadowMapEnabled = true; document.body.appendChild(renderer.domElement); //body元素中插入canvas对象 scene.add(ambient); //执行渲染操作 指定场景、相机作为参数 renderer.render(scene, camera); // 渲染函数 function render() { renderer.render(scene, camera); //执行渲染操作 mesh8.rotateY(0.01);//每次绕y轴旋转0.01弧度 requestAnimationFrame(render); //请求再次执行渲染函数render,渲染下一帧 } render(); //通过x,y,z指定旋转中心,obj是要旋转的对象 //function changePivot(x, y, z, obj) { // let wrapper = new THREE.Object3D(); //wrapper.position.set(250, 250, 250); //wrapper.add(mesh8); //mesh8.position.set(x, y, z); //return wrapper; //} //changePivot(); //创建控件对象 相机对象camera作为参数 控件可以监听鼠标的变化,改变相机对象的属性 var controls = new THREE.OrbitControls(camera); // onresize 事件会在窗口被调整大小时发生 window.onresize = function () { // 重置渲染器输出画布canvas尺寸 renderer.setSize(width, height); // 重置相机投影的相关参数 k = window.innerWidth / window.innerHeight;//窗口宽高比 camera.left = -s * k; camera.right = s * k; camera.top = s; camera.bottom = -s; // 渲染器执行render方法的时候会读取相机对象的投影矩阵属性projectionMatrix // 但是不会每渲染一帧,就通过相机的属性计算投影矩阵(节约计算资源) // 如果相机的一些属性发生了变化,需要执行updateProjectionMatrix ()方法更新相机的投影矩阵 camera.updateProjectionMatrix(); }; // onresize 事件会在窗口被调整大小时发生 window.onresize = function () { // 重置渲染器输出画布canvas尺寸 renderer.setSize(width, height); // 全屏情况下:设置观察范围长宽比aspect为窗口宽高比 camera.aspect = window.innerWidth / window.innerHeight; // 渲染器执行render方法的时候会读取相机对象的投影矩阵属性projectionMatrix // 但是不会每渲染一帧,就通过相机的属性计算投影矩阵(节约计算资源) // 如果相机的一些属性发生了变化,需要执行updateProjectionMatrix ()方法更新相机的投影矩阵 camera.updateProjectionMatrix(); }; //创建控件对象 相机对象camera作为参数 控件可以监听鼠标的变化,改变相机对象的属性 var control = new THREE.OrbitControls(camera); //监听鼠标事件,触发渲染函数,更新canvas画布渲染效果 control.addEventListener('change', render); </script> </body> </html>