使用前端three.js加载3d模型过程中,往往会出现模型大小过大导致前端加载时间过长,降低用户体验。
本文所记录的是笔者在使用gltf-pipeline压缩3d模型中踩坑DRACOLoader与解决的一个过程。
所采用的three库版本为 ^0.138.2
通过gltf-pipeline可以大幅度压缩gltf/glb模型文件。
并且有如下的作用
npm install -g gltf-pipeline
或者
yarn global add gltf-pipeline
gltf-pipeline -i model.glb -o modelDraco.glb -d
使用 Draco 压缩网格 model.glb 文件,modelDraco.glb为压缩后输出文件名

gltf-pipeline -i model.glb -o modelDraco.glb -d -s
压缩并编写单独的缓冲区、着色器和纹理。

在多次百度之后写出的代码
let dracoLoader = new DRACOLoader();
dracoLoader.setDecoderPath("path");
dracoLoader.preload();
const loader = new GLTFLoader().setPath("path");
loader.setDRACOLoader(dracoLoader);
loader.load("modelName", (gltf) => {
scene.addObject(gltf.scene);
gltf = null;
});
在这里我遇到了一个大坑:
Uncaught SyntaxError: Unexpected token '<'

在问题过程排查中,发现网络请求是请求了模型数据的

后续发现bolb:xxx的请求不是写的应用层所发出的
之后通过阅读DRACOLoader.js的源码得



网络请求中bolb:xxx请求是由第250行URL.createObjectURL所创建的,创建该请求需要
并且请求的路径是使用setDecoderPath方法所设定
后续查阅资料得到
draco_decoder.js— Emscripten 编译的解码器,与任何现代浏览器兼容。draco_decoder.wasm— WebAssembly 解码器,与较新的浏览器和设备兼容。draco_wasm_wrapper.js— WASM 解码器的 JavaScript 包装器。在node_modules安装的包中获取three版本对应的draco路径为
node_modules\three\examples\js\libs

将改文件夹复制到public文件夹下并在DRACOLoader.setDecoderPath时候设置该对应路径即可
import { DRACOLoader } from "three/examples/jsm/loaders/DRACOLoader";
import { GLTFLoader } from "three/examples/jsm/loaders/GLTFLoader.js";
/**
*
* path:存放模型父路径
* modelName:模型名
* setCenter:是否居中
* scale:模型的缩放比设定
* position:模型的位置
* rotation:模型的局部旋转
*/
function loadModuleByDRACOLoader(
path,
modelName,
setCenter,
scale,
position,
rotation
) {
let scaleVec3, positionVec3;
if (typeof scale == "number") {
scaleVec3 = new THREE.Vector3(scale, scale, scale);
} else {
scaleVec3 = new THREE.Vector3(scale.x, scale.y, scale.z);
}
if (typeof position == "number") {
positionVec3 = new THREE.Vector3(position, position, position);
} else {
positionVec3 = new THREE.Vector3(position.x, position.y, position.z);
}
let dracoLoader = new DRACOLoader();
dracoLoader.setDecoderPath("./moduler/draco/"); // 设置public下的解码路径,注意最后面的/
dracoLoader.setDecoderConfig({ type: "js" }); //使用兼容性强的draco_decoder.js解码器
dracoLoader.preload();
const loader = new GLTFLoader().setPath(path);
loader.setDRACOLoader(dracoLoader);
return new Promise((res, rj) => {
loader.load(modelName, (gltf) => {
if (setCenter) {
gltf.scene.traverse(function(child) {
if (setCenter && child.isMesh) {
child.geometry.center();
}
});
}
gltf.scene.scale.copy(scaleVec3);
gltf.scene.position.copy(positionVec3);
if (rotation) {
gltf.scene.rotation.copy(rotation);
}
scene.add(gltf.scene);
res(gltf.scene);
gltf = null;
});
});
}
调用
loadModuleByDRACOLoader('./moduler/', "grow4-processed.glb", false, 1, 0)
因为遇到这个坑之后没有找到对应的解决方法,所以写了该文章作为记录也给遇到相同问题的开发者避坑。
还有🎇🎇大三求内推🎇🎇
我有一个Ruby程序,它使用rubyzip压缩XML文件的目录树。gem。我的问题是文件开始变得很重,我想提高压缩级别,因为压缩时间不是问题。我在rubyzipdocumentation中找不到一种为创建的ZIP文件指定压缩级别的方法。有人知道如何更改此设置吗?是否有另一个允许指定压缩级别的Ruby库? 最佳答案 这是我通过查看rubyzip内部创建的代码。level=Zlib::BEST_COMPRESSIONZip::ZipOutputStream.open(zip_file)do|zip|Dir.glob("**/*")d
我有一个模型:classItem项目有一个属性“商店”基于存储的值,我希望Item对象对特定方法具有不同的行为。Rails中是否有针对此的通用设计模式?如果方法中没有大的if-else语句,这是如何干净利落地完成的? 最佳答案 通常通过Single-TableInheritance. 关于ruby-on-rails-Rails-子类化模型的设计模式是什么?,我们在StackOverflow上找到一个类似的问题: https://stackoverflow.co
我需要从一个View访问多个模型。以前,我的links_controller仅用于提供以不同方式排序的链接资源。现在我想包括一个部分(我假设)显示按分数排序的顶级用户(@users=User.all.sort_by(&:score))我知道我可以将此代码插入每个链接操作并从View访问它,但这似乎不是“ruby方式”,我将需要在不久的将来访问更多模型。这可能会变得很脏,是否有针对这种情况的任何技术?注意事项:我认为我的应用程序正朝着单一格式和动态页面内容的方向发展,本质上是一个典型的网络应用程序。我知道before_filter但考虑到我希望应用程序进入的方向,这似乎很麻烦。最终从任何
我有一个包含模块的模型。我想在模块中覆盖模型的访问器方法。例如:classBlah这显然行不通。有什么想法可以实现吗? 最佳答案 您的代码看起来是正确的。我们正在毫无困难地使用这个确切的模式。如果我没记错的话,Rails使用#method_missing作为属性setter,因此您的模块将优先,阻止ActiveRecord的setter。如果您正在使用ActiveSupport::Concern(参见thisblogpost),那么您的实例方法需要进入一个特殊的模块:classBlah
我有一个表单,其中有很多字段取自数组(而不是模型或对象)。我如何验证这些字段的存在?solve_problem_pathdo|f|%>... 最佳答案 创建一个简单的类来包装请求参数并使用ActiveModel::Validations。#definedsomewhere,atthesimplest:require'ostruct'classSolvetrue#youcouldevencheckthesolutionwithavalidatorvalidatedoerrors.add(:base,"WRONG!!!")unlesss
我想向我的Controller传递一个参数,它是一个简单的复选框,但我不知道如何在模型的form_for中引入它,这是我的观点:{:id=>'go_finance'}do|f|%>Transferirde:para:Entrada:"input",:placeholder=>"Quantofoiganho?"%>Saída:"output",:placeholder=>"Quantofoigasto?"%>Nota:我想做一个额外的复选框,但我该怎么做,模型中没有一个对象,而是一个要检查的对象,以便在Controller中创建一个ifelse,如果没有检查,请帮助我,非常感谢,谢谢
让我们计算MRI范围内的类别:defcount_classesObjectSpace.count_objects[:T_CLASS]endk=count_classes用类方法定义类:classAdefself.foonilendend然后运行:putscount_classes-k#=>3请解释一下,为什么是三个? 最佳答案 查看MRI代码,每次你创建一个Class时,在Ruby中它是Class类型的对象,ruby会自动为这个新类创建“元类”类,这是另一个单例类型的Class对象。C函数调用(class.c)是:rb_define
我有一些非常大的模型,我必须将它们迁移到最新版本的Rails。这些模型有相当多的验证(User有大约50个验证)。是否可以将所有这些验证移动到另一个文件中?说app/models/validations/user_validations.rb。如果可以,有人可以提供示例吗? 最佳答案 您可以为此使用关注点:#app/models/validations/user_validations.rbrequire'active_support/concern'moduleUserValidationsextendActiveSupport:
对于Rails模型,是否可以/建议让一个类的成员不持久保存到数据库中?我想将用户最后选择的类型存储在session变量中。由于我无法从我的模型中设置session变量,我想将值存储在一个“虚拟”类成员中,该成员只是将值传递回Controller。你能有这样的类(class)成员吗? 最佳答案 将非持久属性添加到Rails模型就像任何其他Ruby类一样:classUser扩展解释:在Ruby中,所有实例变量都是私有(private)的,不需要在赋值前定义。attr_accessor创建一个setter和getter方法:classUs
我有一个正在构建的应用程序,我需要一个模型来创建另一个模型的实例。我希望每辆车都有4个轮胎。汽车模型classCar轮胎模型classTire但是,在make_tires内部有一个错误,如果我为Tire尝试它,则没有用于创建或新建的activerecord方法。当我检查轮胎时,它没有这些方法。我该如何补救?错误是这样的:未定义的方法'create'forActiveRecord::AttributeMethods::Serialization::Tire::Module我测试了两个环境:测试和开发,它们都因相同的错误而失败。 最佳答案