threejs使用外部模型

个人博客地址: https://cxx001.gitee.io

前面我们都是用Threejs提供的几何体来创建网格,对于简单几何体(如球体和方块)来说非常有效,但当你想要创建复杂的三维模型时,这不是最好的方法。通常情况下,你可以使用三维建模工具(如Blender和3D Studio Max)来创建复杂几何体。

本节就来学习如何加载和展示由这些三维建模工具所创建的模型。

网格对象组合与合并

在学习使用外部三维建模工具所创建的模型前,我们先了解两个基本操作:将对象组合在一起,以及将多个网格合并为一个网格。

1. 网格组合

这个不是什么新东西了,前面我们很多示例其实早就使用了。就是把多个网格对象添加到一个对象里(THREE.Group),对这1个对象移动、缩放、旋转变换操作其子对象会一起变换。

<!-- chapter-08-01.html -->
<!DOCTYPE html>
<html>
<head><title>Group</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 {margin: 0;overflow: hidden;}</style>
</head>
<body><div id="Stats-output">
</div>
<div id="WebGL-output">
</div><script type="text/javascript">function init() {var stats = initStats();var scene = new THREE.Scene();var camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 0.1, 1000);var webGLRenderer = new THREE.WebGLRenderer();webGLRenderer.setClearColor(new THREE.Color(0xEEEEEE, 1.0));webGLRenderer.setSize(window.innerWidth, window.innerHeight);webGLRenderer.shadowMapEnabled = true;camera.position.x = 30;camera.position.y = 30;camera.position.z = 30;camera.lookAt(new THREE.Vector3(0, 0, 0));var ground = new THREE.PlaneGeometry(100, 100, 50, 50);var groundMesh = THREE.SceneUtils.createMultiMaterialObject(ground,[new THREE.MeshBasicMaterial({wireframe: true, overdraw: true, color: 000000}),new THREE.MeshBasicMaterial({color: 0x00ff00, transparent: true, opacity: 0.5})]);groundMesh.rotation.x = -0.5 * Math.PI;scene.add(groundMesh);document.getElementById("WebGL-output").appendChild(webGLRenderer.domElement);var step = 0.03;var sphere;var cube;var group;var controls = new function () {this.cubePosX = 0;this.cubePosY = 3;this.cubePosZ = 10;this.spherePosX = 10;this.spherePosY = 5;this.spherePosZ = 0;this.groupPosX = 10;this.groupPosY = 5;this.groupPosZ = 0;this.grouping = false;this.rotate = false;this.groupScale = 1;this.cubeScale = 1;this.sphereScale = 1;this.redraw = function () {scene.remove(group);sphere = createMesh(new THREE.SphereGeometry(5, 10, 10));cube = createMesh(new THREE.BoxGeometry(6, 6, 6));sphere.position.set(controls.spherePosX, controls.spherePosY, controls.spherePosZ);cube.position.set(controls.cubePosX, controls.cubePosY, controls.cubePosZ);// 将球体和立方体网格添加到组合对象中group = new THREE.Group();group.add(sphere);group.add(cube);scene.add(group);// 在group组合对象中心位置标志一个箭头var arrow = new THREE.ArrowHelper(new THREE.Vector3(0, 1, 0), group.position, 10, 0x0000ff);scene.add(arrow);};};var gui = new dat.GUI();var sphereFolder = gui.addFolder("sphere");sphereFolder.add(controls, "spherePosX", -20, 20).onChange(function (e) {sphere.position.x = e;});sphereFolder.add(controls, "spherePosZ", -20, 20).onChange(function (e) {sphere.position.z = e;});sphereFolder.add(controls, "spherePosY", -20, 20).onChange(function (e) {sphere.position.y = e;});sphereFolder.add(controls, "sphereScale", 0, 3).onChange(function (e) {sphere.scale.set(e, e, e);});var cubeFolder = gui.addFolder("cube");cubeFolder.add(controls, "cubePosX", -20, 20).onChange(function (e) {cube.position.x = e;});cubeFolder.add(controls, "cubePosZ", -20, 20).onChange(function (e) {cube.position.z = e;});cubeFolder.add(controls, "cubePosY", -20, 20).onChange(function (e) {cube.position.y = e;});cubeFolder.add(controls, "cubeScale", 0, 3).onChange(function (e) {cube.scale.set(e, e, e);});var cubeFolder = gui.addFolder("group");cubeFolder.add(controls, "groupPosX", -20, 20).onChange(function (e) {group.position.x = e;});cubeFolder.add(controls, "groupPosZ", -20, 20).onChange(function (e) {group.position.z = e;});cubeFolder.add(controls, "groupPosY", -20, 20).onChange(function (e) {group.position.y = e;});cubeFolder.add(controls, "groupScale", 0, 3).onChange(function (e) {group.scale.set(e, e, e);});gui.add(controls, "grouping");gui.add(controls, "rotate");controls.redraw();render();function createMesh(geom) {var meshMaterial = new THREE.MeshNormalMaterial();meshMaterial.side = THREE.DoubleSide;var wireFrameMat = new THREE.MeshBasicMaterial();wireFrameMat.wireframe = true;var plane = THREE.SceneUtils.createMultiMaterialObject(geom, [meshMaterial, wireFrameMat]);return plane;}function render() {stats.update();if (controls.grouping && controls.rotate) {group.rotation.y += step;}if (controls.rotate && !controls.grouping) {sphere.rotation.y += step;cube.rotation.y += step;}requestAnimationFrame(render);webGLRenderer.render(scene, camera);}function initStats() {var stats = new Stats();stats.setMode(0); // 0: fps, 1: msstats.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>

在这里插入图片描述

2. 网格合并

通过THREE.Geometry.merge()函数可以将多个网格对象合并成一个。如果场景中网格太多是有性能瓶颈的,合并它们可以提升渲染效率。但是注意合并后你就不能再单独操作某个网格了。

<!-- chapter-08-02.html -->
<!DOCTYPE html>
<html>
<head><title>Merge objects</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 {margin: 0;overflow: hidden;}</style>
</head>
<body><div id="Stats-output">
</div>
<div id="WebGL-output">
</div><script type="text/javascript">function init() {var stats = initStats();var scene = new THREE.Scene();var camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 1, 500);var renderer = new THREE.WebGLRenderer();renderer.setClearColor(new THREE.Color(0x00000, 1.0));renderer.setSize(window.innerWidth, window.innerHeight);renderer.shadowMapEnabled = true;camera.position.x = 0;camera.position.y = 40;camera.position.z = 50;camera.lookAt(scene.position);document.getElementById("WebGL-output").appendChild(renderer.domElement);var step = 0;var cubeMaterial = new THREE.MeshNormalMaterial({color: 0x00ff00, transparent: true, opacity: 0.5});var controls = new function () {this.combined = false;this.numberOfObjects = 500;this.redraw = function () {var toRemove = [];// traverse遍历场景对象是不能增、删操作scene.traverse(function (e) {if (e instanceof THREE.Mesh) toRemove.push(e);});toRemove.forEach(function (e) {scene.remove(e)});if (controls.combined) {// 将所有网格对象合并到geometry一个对象中var geometry = new THREE.Geometry();for (var i = 0; i < controls.numberOfObjects; i++) {var cubeMesh = addCube();cubeMesh.updateMatrix(); // 变换矩阵,保证合并后正确定位和旋转geometry.merge(cubeMesh.geometry, cubeMesh.matrix); // 添加合并网格}scene.add(new THREE.Mesh(geometry, cubeMaterial));} else {// 不合并,网格对象一个个添加到场景中for (var i = 0; i < controls.numberOfObjects; i++) {scene.add(addCube());}}};};var gui = new dat.GUI();gui.add(controls, 'numberOfObjects', 0, 20000);gui.add(controls, 'combined').onChange(controls.redraw);gui.add(controls, 'redraw');controls.redraw();render();// 添加立方体function addCube() {var cubeSize = 1.0;var cubeGeometry = new THREE.BoxGeometry(cubeSize, cubeSize, cubeSize);var cube = new THREE.Mesh(cubeGeometry, cubeMaterial);cube.position.x = -60 + Math.round((Math.random() * 100));cube.position.y = Math.round((Math.random() * 10));cube.position.z = -150 + Math.round((Math.random() * 175));return cube;}var rotation = 0;function render() {rotation += 0.005;stats.update();camera.position.x = Math.sin(rotation) * 50;camera.position.z = Math.cos(rotation) * 50;camera.lookAt(scene.position);requestAnimationFrame(render);renderer.render(scene, camera);}function initStats() {var stats = new Stats();stats.setMode(0); // 0: fps, 1: msstats.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>

创建2W个网格直接添加进场景,看帧率降到14了。

同样2W个,合并后,帧率正常了。


从外部资源加载网格

threejs支持多种三维文件格式,可以读取并从中导入几何体和网格。下面是threejs支持的文件格式:

下面依次介绍这些三维文件格式在Threejs中怎么导入/导出的。

1. 以Threejs的JSON格式保存和加载

你可以在两种情形下使用Threejs的JSON文件格式:用它来保存和加载单个THREE.Mesh(网格),或者用它来保存和加载整个场景。

  1. 保存和加载THREE.Mesh

保存:通过mesh.toJSON()可以将网格转换为json对象,后面就是js的常规保存了。

加载:Threejs提供了一个叫THREE.ObjectLoader的辅助对象,使用它可以将JSON转换成THREE.Mesh对象。

<!-- chapter-08-03.html -->
<!DOCTYPE html>
<html>
<head><title>Save & Load Mesh</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 {margin: 0;overflow: hidden;}</style>
</head>
<body><div id="Stats-output">
</div>
<div id="WebGL-output">
</div><script type="text/javascript">function init() {var stats = initStats();var scene = new THREE.Scene();var camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 0.1, 1000);var webGLRenderer = new THREE.WebGLRenderer();webGLRenderer.setClearColor(new THREE.Color(0xEEEEEE, 1.0));webGLRenderer.setSize(window.innerWidth, window.innerHeight);webGLRenderer.shadowMapEnabled = true;var knot = createMesh(new THREE.TorusKnotGeometry(10, 1, 64, 8, 2, 3, 1));scene.add(knot);camera.position.x = -30;camera.position.y = 40;camera.position.z = 50;camera.lookAt(new THREE.Vector3(-20, 0, 0));document.getElementById("WebGL-output").appendChild(webGLRenderer.domElement);var loadedMesh;var controls = new function () {this.radius = knot.geometry.parameters.radius;this.tube = 0.3;this.radialSegments = knot.geometry.parameters.radialSegments;this.tubularSegments = knot.geometry.parameters.tubularSegments;this.p = knot.geometry.parameters.p;this.q = knot.geometry.parameters.q;this.heightScale = knot.geometry.parameters.heightScale;this.redraw = function () {scene.remove(knot);knot = createMesh(new THREE.TorusKnotGeometry(controls.radius, controls.tube, Math.round(controls.radialSegments), Math.round(controls.tubularSegments), Math.round(controls.p), Math.round(controls.q), controls.heightScale));scene.add(knot);};// 保存this.save = function () {// 网格对象转换为JSON对象var result = knot.toJSON();// 调用HTML5本地保存数据接口localStorage.setItem("json", JSON.stringify(result));};// 加载this.load = function () {scene.remove(loadedMesh);// 调用HTML5本地读取数据接口var json = localStorage.getItem("json");if (json) {// JSON字符串转换为json对象var loadedGeometry = JSON.parse(json);// JSON对象转换为网格对象var loader = new THREE.ObjectLoader();loadedMesh = loader.parse(loadedGeometry);loadedMesh.position.x -= 50;scene.add(loadedMesh);}}};var gui = new dat.GUI();var ioGui = gui.addFolder('Save & Load');ioGui.add(controls, 'save').onChange(controls.save);ioGui.add(controls, 'load').onChange(controls.load);var meshGui = gui.addFolder('mesh');meshGui.add(controls, 'radius', 0, 40).onChange(controls.redraw);meshGui.add(controls, 'tube', 0, 40).onChange(controls.redraw);meshGui.add(controls, 'radialSegments', 0, 400).step(1).onChange(controls.redraw);meshGui.add(controls, 'tubularSegments', 1, 20).step(1).onChange(controls.redraw);meshGui.add(controls, 'p', 1, 10).step(1).onChange(controls.redraw);meshGui.add(controls, 'q', 1, 15).step(1).onChange(controls.redraw);meshGui.add(controls, 'heightScale', 0, 5).onChange(controls.redraw);render();function createMesh(geom) {var meshMaterial = new THREE.MeshBasicMaterial({vertexColors: THREE.VertexColors,wireframe: true,wireframeLinewidth: 2,color: 0xaaaaaa});meshMaterial.side = THREE.DoubleSide;var mesh = new THREE.Mesh(geom, meshMaterial);return mesh;}function render() {stats.update();knot.rotation.y += 0.01;requestAnimationFrame(render);webGLRenderer.render(scene, camera);}function initStats() {var stats = new Stats();stats.setMode(0); // 0: fps, 1: msstats.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>

  1. 保存和加载场景

使用Threejs提供的导出器和加载器: THREE.SceneExporterTHREE.SceneLoader。也支持从URL地址加载。

<!-- chapter-08-04.html -->
<!DOCTYPE html>
<html>
<head><title>Load and save scene</title><script type="text/javascript" src="../libs/three.js"></script><script type="text/javascript" src="../libs/SceneLoader.js"></script><script type="text/javascript" src="../libs/SceneExporter.js"></script><script type="text/javascript" src="../libs/stats.js"></script><script type="text/javascript" src="../libs/dat.gui.js"></script><style>body {margin: 0;overflow: hidden;}</style>
</head>
<body><div id="Stats-output">
</div>
<div id="WebGL-output">
</div><script type="text/javascript">function init() {var stats = initStats();var scene = new THREE.Scene();var camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 0.1, 1000);var renderer = new THREE.WebGLRenderer();renderer.setClearColor(new THREE.Color(0xEEEEEE, 1.0));renderer.setSize(window.innerWidth, window.innerHeight);var planeGeometry = new THREE.PlaneGeometry(60, 20, 1, 1);var planeMaterial = new THREE.MeshLambertMaterial({color: 0xffffff});var plane = new THREE.Mesh(planeGeometry, planeMaterial);plane.rotation.x = -0.5 * Math.PI;plane.position.x = 15;plane.position.y = 0;plane.position.z = 0;scene.add(plane);var cubeGeometry = new THREE.BoxGeometry(4, 4, 4);var cubeMaterial = new THREE.MeshLambertMaterial({color: 0xff0000});var cube = new THREE.Mesh(cubeGeometry, cubeMaterial);cube.position.x = -4;cube.position.y = 3;cube.position.z = 0;scene.add(cube);var sphereGeometry = new THREE.SphereGeometry(4, 20, 20);var sphereMaterial = new THREE.MeshLambertMaterial({color: 0x7777ff});var sphere = new THREE.Mesh(sphereGeometry, sphereMaterial);sphere.position.x = 20;sphere.position.y = 0;sphere.position.z = 2;scene.add(sphere);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.PointLight(0xffffff);spotLight.position.set(-40, 60, -10);scene.add(spotLight);document.getElementById("WebGL-output").appendChild(renderer.domElement);var controls = new function () {// 导出场景this.exportScene = function () {var exporter = new THREE.SceneExporter();var sceneJson = JSON.stringify(exporter.parse(scene));localStorage.setItem('scene', sceneJson);};// 清理场景this.clearScene = function () {scene = new THREE.Scene();};// 导入场景this.importScene = function () {var json = (localStorage.getItem('scene'));var sceneLoader = new THREE.SceneLoader();sceneLoader.parse(JSON.parse(json), function (e) {scene = e.scene;}, '.'); // 最后参数是外部纹理资源路径,这个示例没有使用外部资源,所以传入当前目录即可。}};var gui = new dat.GUI();gui.add(controls, "exportScene");gui.add(controls, "clearScene");gui.add(controls, "importScene");render();function render() {stats.update();requestAnimationFrame(render);renderer.render(scene, camera);}function initStats() {var stats = new Stats();stats.setMode(0); // 0: fps, 1: msstats.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>

2. 使用Blender导出JSON格式加载

有很多三维软件可以用来创建复杂的网格。其中一个流行的开源的软件叫作Blender(www.blender.org)。

Threejs库目前已经提供了支持Blender以及Maya和3D Studio Max的导出器(插件扩展的形式),可以直接将文件导出为Threejs的JSON格式。

注:怎么安装和使用Blender支持导出json格式的插件这里不详细介绍了,详情参考《Three.js开发指南-第八章》。

<!-- chapter-08-05.html -->
<!DOCTYPE html>
<html>
<head><title>Load blender model </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 {margin: 0;overflow: hidden;}</style>
</head>
<body><div id="Stats-output">
</div>
<div id="WebGL-output">
</div><script type="text/javascript">function init() {var stats = initStats();var scene = new THREE.Scene();var camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 0.1, 1000);var webGLRenderer = new THREE.WebGLRenderer();webGLRenderer.setClearColor(new THREE.Color(0xEEEEEE, 1.0));webGLRenderer.setSize(window.innerWidth, window.innerHeight);webGLRenderer.shadowMapEnabled = true;camera.position.x = -30;camera.position.y = 40;camera.position.z = 50;camera.lookAt(new THREE.Vector3(0, 10, 0));var spotLight = new THREE.SpotLight(0xffffff);spotLight.position.set(0, 50, 30);spotLight.intensity = 2;scene.add(spotLight);document.getElementById("WebGL-output").appendChild(webGLRenderer.domElement);var mesh;// 加载Blender导出的JSON模型文件var loader = new THREE.JSONLoader();/* 参数:* JSON模型文件* 回调函数,返回几何体和材质数组* 材质所在路径,即JSON中mapDiffuse字段图片路径*/loader.load('../assets/models/misc_chair01.js', function (geometry, mat) {mesh = new THREE.Mesh(geometry, mat[0]);mesh.scale.x = 15;mesh.scale.y = 15;mesh.scale.z = 15;scene.add(mesh);}, '../assets/models/');render();function render() {stats.update();if (mesh) {mesh.rotation.y += 0.02;}requestAnimationFrame(render);webGLRenderer.render(scene, camera);}function initStats() {var stats = new Stats();stats.setMode(0); // 0: fps, 1: msstats.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. 加载OBJ/MTL格式模型

OBJ和MTL是相互配合的两种格式,经常一起使用。OBJ文件定义几何体,MTL文件定义所用材质。

<!-- chapter-08-06.html -->
<!DOCTYPE html>
<html>
<head><title>Load OBJ and MTL </title><script type="text/javascript" src="../libs/three.js"></script><script type="text/javascript" src="../libs/OBJLoader.js"></script><script type="text/javascript" src="../libs/MTLLoader.js"></script><script type="text/javascript" src="../libs/OBJMTLLoader.js"></script><script type="text/javascript" src="../libs/stats.js"></script><script type="text/javascript" src="../libs/dat.gui.js"></script><style>body {margin: 0;overflow: hidden;}</style>
</head>
<body><div id="Stats-output">
</div>
<div id="WebGL-output">
</div><script type="text/javascript">function init() {var stats = initStats();var scene = new THREE.Scene();var camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 0.1, 1000);var webGLRenderer = new THREE.WebGLRenderer();webGLRenderer.setClearColor(new THREE.Color(0xaaaaff, 1.0));webGLRenderer.setSize(window.innerWidth, window.innerHeight);webGLRenderer.shadowMapEnabled = true;camera.position.x = -30;camera.position.y = 40;camera.position.z = 50;camera.lookAt(new THREE.Vector3(0, 10, 0));var spotLight = new THREE.SpotLight(0xffffff);spotLight.position.set(0, 40, 30);spotLight.intensity = 2;scene.add(spotLight);document.getElementById("WebGL-output").appendChild(webGLRenderer.domElement);var mesh;// 加载OBJ/MTL格式var loader = new THREE.OBJMTLLoader();loader.load('../assets/models/butterfly.obj', '../assets/models/butterfly.mtl', function (object) {// 对加载的网格模型材质属性微调var wing1 = object.children[4].children[0];var wing2 = object.children[5].children[0];wing1.material.opacity = 0.6;wing1.material.transparent = true;wing1.material.depthTest = false;wing1.material.side = THREE.DoubleSide;wing2.material.opacity = 0.6;wing2.material.depthTest = false;wing2.material.transparent = true;wing2.material.side = THREE.DoubleSide;object.scale.set(140, 140, 140);mesh = object;scene.add(mesh);object.rotation.x = 0.2;object.rotation.y = -1.3;});render();function render() {stats.update();if (mesh) {mesh.rotation.y += 0.006;}requestAnimationFrame(render);webGLRenderer.render(scene, camera);}function initStats() {var stats = new Stats();stats.setMode(0); // 0: fps, 1: msstats.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>

在这里插入图片描述

4. 加载Collada模型(.dae)

这是另一种非常通用的格式,不仅可以定义模型(网格和材质),还可以定义场景以及动画。

加载这种格式,使用上和加载OBJ/MTL模型步骤基本一样。主要区别是回调函数的返回结构不同:

var result = {...scene: scene,morphs: morphs,skins: skins,animations: animData,dae: {...}...
}

还一个需要注意的点是,导出.dae格式模型,如果描述文件中纹理是用的.tga格式,那么需要把它转换为.png,并对应修改.dae模型文件的XML元素,指向转换后的.png文件。因为WebGL不支持.tga格式的纹理。

<!-- chapter-08-07.html -->
<!DOCTYPE html>
<html>
<head><title>Load collada model </title><script type="text/javascript" src="../libs/three.js"></script><script type="text/javascript" src="../libs/ColladaLoader.js"></script><script type="text/javascript" src="../libs/stats.js"></script><script type="text/javascript" src="../libs/dat.gui.js"></script><style>body {margin: 0;overflow: hidden;}</style>
</head>
<body><div id="Stats-output">
</div>
<div id="WebGL-output">
</div><script type="text/javascript">function init() {var stats = initStats();var scene = new THREE.Scene();var camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 0.1, 1000);var webGLRenderer = new THREE.WebGLRenderer();webGLRenderer.setClearColor(new THREE.Color(0xcccccc, 1.0));webGLRenderer.setSize(window.innerWidth, window.innerHeight);webGLRenderer.shadowMapEnabled = true;camera.position.x = 150;camera.position.y = 150;camera.position.z = 150;camera.lookAt(new THREE.Vector3(0, 20, 0));var spotLight = new THREE.SpotLight(0xffffff);spotLight.position.set(150, 150, 150);spotLight.intensity = 2;scene.add(spotLight);document.getElementById("WebGL-output").appendChild(webGLRenderer.domElement);var mesh;// 加载.dae模型文件var loader = new THREE.ColladaLoader();loader.load("../assets/models/dae/Truck_dae.dae", function (result) {// 模型中找到我们需要的网格对象mesh = result.scene.children[0].children[0].clone();mesh.scale.set(4, 4, 4);scene.add(mesh);});render();function render() {stats.update();requestAnimationFrame(render);webGLRenderer.render(scene, camera);}function initStats() {var stats = new Stats();stats.setMode(0); // 0: fps, 1: msstats.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. 加载STL、CTM、VTK、AWD、Assimp、VRML和Babylon模型

这些使用都基本相同,就不一一列完整示例了,下面是它们的加载方式:

// STL
var loader = new THREE.STLLoader();
loader.load("../assets/models/SolidHead_2_lowPoly_42k.stl", function (geometry) {console.log(geometry);var mat = new THREE.MeshLambertMaterial({color: 0x7777ff});var mesh = new THREE.Mesh(geometry, mat);mesh.rotation.x = -0.5 * Math.PI;mesh.scale.set(0.6, 0.6, 0.6);scene.add(mesh);
});// CTM
var loader = new THREE.CTMLoader();
loader.load("../assets/models/auditt_wheel.ctm", function (geometry) {var mat = new THREE.MeshLambertMaterial({color: 0xff8888});var group = new THREE.Mesh(geometry, mat);group.scale.set(20, 20, 20);scene.add(group);
}, {});// VTK
var loader = new THREE.VTKLoader();
loader.load("../assets/models/moai_fixed.vtk", function (geometry) {var mat = new THREE.MeshLambertMaterial({color: 0xaaffaa});var group = new THREE.Mesh(geometry, mat);group.scale.set(9, 9, 9);scene.add(group);
});// AWD
var loader = new THREE.AWDLoader();
loader.load("../assets/models/awd/PolarBear.awd", function (model) {console.log(model);model.traverse(function (child) {if (child instanceof THREE.Mesh) {child.material = new THREE.MeshLambertMaterial({color: 0xaaaaaa});console.log(child.geometry);}});model.scale.set(0.1, 0.1, 0.1);scene.add(model);
});// Assimp
var loader = new THREE.AssimpJSONLoader();
loader.load("../assets/models/assimp/spider.obj.assimp.json", function (model) {console.log(model);model.traverse(function (child) {if (child instanceof THREE.Mesh) {// child.material = new THREE.MeshLambertMaterial({color:0xaaaaaa});console.log(child.geometry);}});model.scale.set(0.1, 0.1, 0.1);scene.add(model);
});// VRML
var loader = new THREE.VRMLLoader();
loader.load("../assets/models/vrml/tree.wrl", function (model) {console.log(model);model.traverse(function (child) {if (child instanceof THREE.Mesh) {// child.material = new THREE.MeshLambertMaterial({color:0xaaaaaa});console.log(child.geometry);}});model.scale.set(10, 10, 10);scene.add(model);
});// Babylon
var loader = new THREE.BabylonLoader();
loader.load("../assets/models/babylon/skull.babylon", function (loadedScene) {console.log(loadedScene.children[1].material = new THREE.MeshLambertMaterial());scene = loadedScene;
});

6. 加载PDB模型(分子结构)

这是一种特殊的模型,用于显示分子结构。

<!-- chapter-08-08.html -->
<!DOCTYPE html>
<html>
<head><title>Load pdb model </title><script type="text/javascript" src="../libs/three.js"></script><script type="text/javascript" src="../libs/PDBLoader.js"></script><script type="text/javascript" src="../libs/stats.js"></script><script type="text/javascript" src="../libs/dat.gui.js"></script><style>body {margin: 0;overflow: hidden;}</style>
</head>
<body><div id="Stats-output">
</div>
<div id="WebGL-output">
</div><script type="text/javascript">function init() {var stats = initStats();var scene = new THREE.Scene();var camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 0.1, 1000);var webGLRenderer = new THREE.WebGLRenderer();webGLRenderer.setClearColor(new THREE.Color(0x000, 1.0));webGLRenderer.setSize(window.innerWidth, window.innerHeight);webGLRenderer.shadowMapEnabled = true;camera.position.x = 6;camera.position.y = 6;camera.position.z = 6;camera.lookAt(new THREE.Vector3(0, 0, 0));var dir1 = new THREE.DirectionalLight(0.4);dir1.position.set(-30, 30, -30);scene.add(dir1);var dir2 = new THREE.DirectionalLight(0.4);dir2.position.set(-30, 30, 30);scene.add(dir2);var dir3 = new THREE.DirectionalLight(0.4);dir3.position.set(30, 30, -30);scene.add(dir3);var spotLight = new THREE.SpotLight(0xffffff);spotLight.position.set(30, 30, 30);scene.add(spotLight);document.getElementById("WebGL-output").appendChild(webGLRenderer.domElement);var mesh;var loader = new THREE.PDBLoader();var group = new THREE.Object3D();loader.load("../assets/models/aspirin.pdb", function (geometry, geometryBonds) {//loader.load("../assets/models/diamond.pdb", function (geometry, geometryBonds) {			// 在分子结构顶点处创建圆点var i = 0;geometry.vertices.forEach(function (position) {var sphere = new THREE.SphereGeometry(0.2);var material = new THREE.MeshPhongMaterial({color: geometry.colors[i++]});var mesh = new THREE.Mesh(sphere, material);mesh.position.copy(position);group.add(mesh);});// 分子圆点之间的键创建连接管for (var j = 0; j < geometryBonds.vertices.length; j += 2) {var path = new THREE.SplineCurve3([geometryBonds.vertices[j], geometryBonds.vertices[j + 1]]);var tube = new THREE.TubeGeometry(path, 1, 0.04);var material = new THREE.MeshPhongMaterial({color: 0xcccccc});var mesh = new THREE.Mesh(tube, material);group.add(mesh);}scene.add(group);});render();function render() {stats.update();if (group) {group.rotation.y += 0.006;group.rotation.x += 0.006;}requestAnimationFrame(render);webGLRenderer.render(scene, camera);}function initStats() {var stats = new Stats();stats.setMode(0); // 0: fps, 1: msstats.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>

7. 把加载的外部模型创建为粒子系统

这里用PLY格式模型举例,其加载流程都差不多,没什么要说的。我们做一些不一样的操作,将使用加载的模型信息来创建一个粒子系统。

<!-- chapter-08-09.html -->
<!DOCTYPE html>
<html>
<head><title>Load ply model </title><script type="text/javascript" src="../libs/three.js"></script><script type="text/javascript" src="../libs/PLYLoader.js"></script><script type="text/javascript" src="../libs/stats.js"></script><script type="text/javascript" src="../libs/dat.gui.js"></script><style>body {margin: 0;overflow: hidden;}</style>
</head>
<body><div id="Stats-output">
</div>
<div id="WebGL-output">
</div><script type="text/javascript">function init() {var stats = initStats();var scene = new THREE.Scene();var camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 0.1, 1000);var webGLRenderer = new THREE.WebGLRenderer();webGLRenderer.setClearColor(new THREE.Color(0x000, 1.0));webGLRenderer.setSize(window.innerWidth, window.innerHeight);webGLRenderer.shadowMapEnabled = true;camera.position.x = 10;camera.position.y = 10;camera.position.z = 10;camera.lookAt(new THREE.Vector3(0, -2, 0));var spotLight = new THREE.SpotLight(0xffffff);spotLight.position.set(20, 20, 20);scene.add(spotLight);document.getElementById("WebGL-output").appendChild(webGLRenderer.domElement);var loader = new THREE.PLYLoader();var group = new THREE.Object3D();loader.load("../assets/models/test.ply", function (geometry) {// 粒子系统的点云材质var material = new THREE.PointCloudMaterial({color: 0xffffff,size: 0.4,opacity: 0.6,transparent: true,blending: THREE.AdditiveBlending,map: generateSprite()  // 外部纹理信息});group = new THREE.PointCloud(geometry, material);group.sortParticles = true;scene.add(group);});render();// 获取画布的纹理信息function generateSprite() {var canvas = document.createElement('canvas');canvas.width = 16;canvas.height = 16;var context = canvas.getContext('2d');var gradient = context.createRadialGradient(canvas.width / 2, canvas.height / 2, 0, canvas.width / 2, canvas.height / 2, canvas.width / 2);gradient.addColorStop(0, 'rgba(255,255,255,1)');gradient.addColorStop(0.2, 'rgba(0,255,255,1)');gradient.addColorStop(0.4, 'rgba(0,0,64,1)');gradient.addColorStop(1, 'rgba(0,0,0,1)');context.fillStyle = gradient;context.fillRect(0, 0, canvas.width, canvas.height);var texture = new THREE.Texture(canvas);texture.needsUpdate = true;return texture;}function render() {stats.update();if (group) {group.rotation.y += 0.006;}requestAnimationFrame(render);webGLRenderer.render(scene, camera);}function initStats() {var stats = new Stats();stats.setMode(0); // 0: fps, 1: msstats.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>

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/4855.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Kafka详解

文章目录 1、kafka简单介绍2、kafka使用场景3、kafka基本概念4、kafka集群1、数据冗余2、分区的写入1、使用 Partition Key 写入特定 Partition2、由 kafka 决定3、自定义规则 3、读取分区数据 5、提交策略6、kafka如何保证高并发 1、kafka简单介绍 kafka是一款分布式、支持分…

IDEA远程DeBug调试

1. 介绍 当我们在开发过程中遇到一些复杂的问题或需要对代码进行调试时&#xff0c;远程调试是一种非常有用的工具。使用 IntelliJ IDEA 进行远程调试可以让你在远程服务器上的应用程序中设置断点、查看变量和执行调试操作。 远程调试的好处如下&#xff1a; 提供更方便的调试…

《Opencv3编程入门》学习笔记—第十一章

《Opencv3编程入门》学习笔记 记录一下在学习《Opencv3编程入门》这本书时遇到的问题或重要的知识点。 第十一章 特征检测与匹配 一、SURF特征点检测 太复杂了&#xff01;全是公式&#xff01; &#xff08;一&#xff09;SURF算法概览 SURF&#xff0c;SpeededUp Rebus…

无广告 齐全 简洁 免费的音乐开源软件(支持 电脑max win linux 手机 )——lxMusic

无广告 齐全 简洁 免费的音乐开源软件&#xff08;支持 电脑max win linux 手机 &#xff09;——lxMusic 话不多说先上效果 &#xff08;真香&#xff09; 下载地址&#xff08;官方&#xff09; https://www.lanzoui.com/b0bf2cfa/ 密码&#xff1a;glqw 软件安装包说明 文…

对 tcp out-of-window 的安全建议

TCP 收到一个 out of window 报文后会立即回复一个 ack&#xff0c;这是 RFC793 中 SEGMENT ARRIVES 段的要求。但这是为什么&#xff1f;难道不是默默丢弃才对吗&#xff1f; 对 oow 报文回复 ack&#xff0c;岂不是把正确的 ack 号回过去了吗&#xff0c;这样攻击者盲打一番…

Qt在Ubuntu下如何进行桌面软件开发?

文章目录 0.引言1.新建项目2.编写第一个程序3.在Qt外部启动程序 0.引言 笔者研究的方向涉及在ubuntu中运行代码&#xff0c;早先是直接利用控制台运行代码文件&#xff0c;在控制台中虽然设法将代码精简到一个三个文件中&#xff0c;只需要在控制台运行这三个文件即可&#xff…

MySQL数据库增删改查及聚合查询SQL语句学习汇总

目录 数据库增删改查SQL语句 MySQL数据库指令 1.查询数据库 2.创建数据库 3.删除数据库 4.选择数据库 创建表table 查看所有表 创建表 查看指定表的结构 删除表 数据库命令进行注释 增删改查&#xff08;CRUD&#xff09;详细说明 增加 SQL库提供了关于时间的…

搞芯片怎么能不懂perl?

各位ICer在工作的过程中&#xff0c;无论是前端还是后端&#xff0c;都会使用各种常见的脚本语言&#xff0c;比如&#xff1a;shell&#xff0c;python&#xff0c;perl&#xff0c;tcl等等用于文件的处理&#xff0c;case测试&#xff0c;工具环境的调用和搭建&#xff0c;虽…

【压缩空气储能】非补燃压缩空气储能系统集成的零碳排放综合能源优化调度(Matlab代码实现)

&#x1f4a5;&#x1f4a5;&#x1f49e;&#x1f49e;欢迎来到本博客❤️❤️&#x1f4a5;&#x1f4a5; &#x1f3c6;博主优势&#xff1a;&#x1f31e;&#x1f31e;&#x1f31e;博客内容尽量做到思维缜密&#xff0c;逻辑清晰&#xff0c;为了方便读者。 ⛳️座右铭&a…

MySQL环境搭建(Windows电脑)

MySQL环境搭建-Windows电脑篇 软件获取&#xff1a; 搜索gzh【李桥桉】&#xff0c;需要win电脑安装包&#xff0c;回复【win-MS】。 搜索gzh【李桥桉】&#xff0c;需要mac电脑安装包&#xff0c;回复【mac-MS】。 注意&#xff1a;确保电脑为64位系统&#xff08;不是的话需要…

SpringSecurity(五):前后端分离认证总结案例。

前后端分离认证总结案例 前言难点分析Controller层eneity层RoleUser dao层service层config层LoginFilterSecurityConfig resourcesmapper propertiespom.xml结尾 前言 和上一篇一样&#xff0c;从上倒下复制粘贴&#xff0c;所有代码贴完再运行&#xff0c;代码没有问题&#…

Qt QLineEdit篇

QLineEdit篇 【1】QLineEdit简介【2】QLineEdit常用方法【3】QLineEdit使用举例UI设计界面效果头文件源文件 PC饱和了&#xff0c;跟我学Qt比较实在&#xff0c;哈哈哈 【1】QLineEdit简介 QLineEdit是Qt框架中的一个类&#xff0c;用于创建一个文本输入框&#xff0c;允许用…