draco编译及使用
一、Draco简介
谷歌开源的Draco
库旨在大幅加速 3D 数据的编码、传输和解码。Draco不仅可以被用来压缩 mesh 和点云数据,它还支持压缩点( compressing points),连接信息,纹理协调,颜色信息,法线( normals)以及其他与几何相关的通用属性。另外Draco
的算法既支持有损压缩模式,也支持无损压缩,还可以进行量化操作。目前3D模型支持stl、obj、glb、ply等格式。
draco压缩算法对网格模型的压缩主要分为两个方面:
- 连接信息利用网格边缘连接结构进行无损压缩( 参考Edgebreaker )
- 几何信息利用更低的比特位数来近似表示原始浮点数据对顶点坐标、纹理等数据的有损量化压缩,以及预测压缩、熵编码(rANS算法)
二、编译
源码链接:https://github.com/google/draco , 文档:https://codelabs.developers.google.com/codelabs/draco-3d/index.html#0
目前最新的版本是1.5.2,stl在最新的master中支持,但1.5.2中暂不支持。如果需要支持glb格式编译时需要打开 -DDRACO_TRANSCODER_SUPPORTED=ON
编译步骤
- 切换到指定分支,也可以直接用master
- 下载依赖
git submodule sync git submodule update --init --recursive
- 新建build文件夹,然后进入到build目录
- 打开transcoder支持glb格式模型,设置安装目录以及版本
cmake -DDRACO_TRANSCODER_SUPPORTED=ON -DDRACO_JS_GLUE=OFF -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX="D:/Draco"..
- 编译安装
make -j4 make install
如果是windows系统可以借助CMake.gui
安装完成后,bin目录下会出现对应的可执行文件,对应得源码在tools目录下
三、常见问题
1、编译时注意在CMakeLists.txt中设置编译动态库,不然测试时读模型会报错
-
错误
不然读取模型会失败并出现以下错误,原因未知,可能是makefile中tiny_gltf文件未链接到静态库造成
TinyGLTF failed to load glb file: Failed to read file -
解决方法
设置编译动态库,即添加set(BUILD_SHARED_LIBS ON)
set(draco_root "${CMAKE_CURRENT_SOURCE_DIR}")
set(draco_src_root "${draco_root}/src/draco")
set(draco_build "${CMAKE_BINARY_DIR}")
set(BUILD_SHARED_LIBS ON)
2、编译时如果提示"M_PI"未定义(Windows下出现该问题)
-
问题
"M_PI"未定义 -
解决方法
可以将报错文件中#include修改为#include <math.h> 或者在报错文件头部添加
#ifndef M_PI
#define M_PI 3.14159265358979323846
#endif
3、自己更改asset中备注信息
在 io/gltf_encoder.cc==>GltfAsset::GltfAsset() 处修改成自己的字符
4、生成后头文件缺失
-
问题
头文件生成后缺失 -
解决方法
将draco\src\draco\compression\draco_compression_options.h手动复制到include对应的目录下
或者修改根目录下的CMakeLists.txt文件,
5、centos7编译错误
-
问题
-
解决方法
在错误抛出地方,将其用std::move()包裹,这是由于多个智能指针指向同一内存地址造成的,可参考 https://zhuanlan.zhihu.com/p/359964081
6、测试过程中如果提示缺少Eigen或者tiny_gltf.h文件
- 解决方法
将第三方库里面对应的文件赋值到include目录下,
四、测试
draco解析glb数据
点击展开CMakeLists.txt
cmake_minimum_required(VERSION 3.9.0)
project(testDraco VERSION 1.0)
# >>> build type
# set(CMAKE_BUILD_TYPE "Debug") # 指定生成的版本
# set(CMAKE_CXX_FLAGS_DEBUG "$ENV{CXXFLAGS} -O0 -Wall -g2 -ggdb")
# set(CMAKE_CXX_FLAGS_RELEASE "$ENV{CXXFLAGS} -O3 -Wall")
# <<<
# >>> CXX11
set(CMAKE_CXX_STANDARD 11) # C++ 11 编译器
SET(CMAKE_CXX_STANDARD_REQUIRED TRUE)
# <<< CXX11
# Draco
if(WIN32)
set(DRACO_ROOT "D:/googleDraco/dracoInstall/ReleaseDLL")
set(DRACO_ROOT_DEBUG "D:/googleDraco/dracoInstall/DebugDLL")
set(DRACO_LIBRARIES
"${DRACO_ROOT}/lib/draco.lib"
CACHE INTERNAL "")
set(DRACO_LIBRARIES_DEBUG
"${DRACO_ROOT_DEBUG}/lib/draco.lib"
CACHE INTERNAL "")
set(DRACO_RUNTIME_LIBRARIES
"${DRACO_ROOT}/lib/draco.dll"
CACHE INTERNAL "")
set(DRACO_RUNTIME_LIBRARIES_DEBUG
"${DRACO_ROOT_DEBUG}/lib/draco.dll"
CACHE INTERNAL "")
set(DRACO_INCLUDE_PATH "${DRACO_ROOT}/include" CACHE INTERNAL "")
elseif(UNIX)
endif()
set(EIGEN_INCLUDE_PATH "D:/googleDraco/draco/third_party/eigen" CACHE INTERNAL "")
set(TINYGLTF_INCLUDE_PATH "D:/googleDraco/draco/third_party/tinygltf" CACHE INTERNAL "")
add_executable(${PROJECT_NAME} testDraco.cpp)
target_include_directories(${PROJECT_NAME}
PRIVATE
${EIGEN_INCLUDE_PATH}
${TINYGLTF_INCLUDE_PATH}
${DRACO_INCLUDE_PATH}
)
target_link_libraries(${PROJECT_NAME}
PUBLIC
debug ${DRACO_LIBRARIES_DEBUG}
optimized ${DRACO_LIBRARIES}
)
if(WIN32)
set(DLL_FILES
${DRACO_RUNTIME_LIBRARIES}
)
set(DLL_FILES_DEBUG
${DRACO_RUNTIME_LIBRARIES_DEBUG}
)
add_custom_command(
TARGET ${PROJECT_NAME}
COMMAND ${CMAKE_COMMAND} -E copy_if_different "$<IF:$<CONFIG:Debug>,${DLL_FILES_DEBUG},${DLL_FILES}>" $<TARGET_FILE_DIR:${PROJECT_NAME}>
COMMAND_EXPAND_LISTS
)
endif()
点击展开源文件
#include <string>
#include <vector>
#include <iostream>
#include "draco/io/file_utils.h"
#include "draco/io/mesh_io.h"
#include "draco/io/gltf_decoder.h"
#include "draco/io/gltf_encoder.h"
// ref: https://github.com/google/draco/issues/770 https://github.com/google/draco/issues/750
int main(int argc, char* argv[])
{
// ---------- Import File -----------
const std::string glbPath = "E:/model/cube1.glb";
draco::GltfDecoder gltfDecoder;
auto glbMesh = gltfDecoder.DecodeFromFile(glbPath);
if (!glbMesh.ok()) {
std::cout << "Failed loading the input mesh: %s.\n" << glbMesh.status().error_msg() << std::endl;
return -1;
}
draco::Mesh *dmesh = glbMesh.value().get();
int tris = dmesh->num_faces();
int verts = dmesh->num_points();
std::vector<std::vector<float> > vertices;
std::vector<int> indices;
vertices.resize(verts);
indices.resize(tris * 3);
// laod vertex positions
auto attr = dmesh->GetNamedAttribute(draco::GeometryAttribute::POSITION);
if (attr == nullptr) {
return -1;
}
float vector[3];
switch (attr->data_type())
{
case draco::DataType::DT_FLOAT32:
if (attr->num_components() != 3)
{
std::cout << "Error: Invalid number of components in compressed mesh position attribute" << std::endl;
return -1;
}
if (attr->byte_stride() > 16)
{
std::cout << "Error: Attribute byte stride is too long" << std::endl;
return -1;
}
for (int v = 0; v < verts; v++)
{
attr->GetMappedValue(draco::PointIndex(v), &vector[0]);
vertices[v].push_back(vector[0]);
vertices[v].push_back(vector[1]);
vertices[v].push_back(vector[2]);
}
break;
default:
std:: cout << "Error: Invalid data type in compressed mesh position attribute" << std::endl;
return -1;
break;
}
//Load triangle indices
for (int t = 0; t < tris; ++t)
{
indices[3 * t] = dmesh->face(draco::FaceIndex(t))[0].value();
indices[3 * t + 1] = dmesh->face(draco::FaceIndex(t))[1].value();
indices[3 * t + 2] = dmesh->face(draco::FaceIndex(t))[2].value();
}
std::cout << "vertices size: " << vertices.size() << " first item: " << vertices[0][0] << " " << vertices[0][1] << " " << vertices[0][2] << std::endl;
std::cout << "indices size: " << indices.size() << " first face id: " << indices[0] << " " << indices[1] << " " << indices[2] << std::endl;
// ---------- Export File -----------
std::vector<std::vector<float> > cubeCoords;
cubeCoords.resize(8);
std::vector<int> cubeIndices;
cubeIndices.resize(36);
cubeCoords[0] = { 1.0f, -1.0f, 1.0f };
cubeCoords[1] = { -1.0f, -1.0f, 1.0f };
cubeCoords[2] = { -1.0f, 1.0f, 1.0f };
cubeCoords[3] = { 1.0f, 1.0f, 1.0f };
cubeCoords[4] = { 1.0f, 1.0f, -1.0f };
cubeCoords[5] = { -1.0f, 1.0f, -1.0f };
cubeCoords[6] = { -1.0f, -1.0f, -1.0f };
cubeCoords[7] = { 1.0f, -1.0f, -1.0f };
cubeIndices = { 2, 1, 0, 0, 3, 2, 2, 3, 4, 4, 5, 2, 5, 4, 7, 6, 5, 7, 1, 2, 5, 5, 6, 1, 1, 6, 7, 7, 0, 1, 0, 4, 3, 0, 7, 4 };
draco::Mesh::Face cubeFace;
// Define vertex layout
int numFace = cubeIndices.size() / 3;
draco::TriangleSoupMeshBuilder builder;
builder.Start(numFace);
int positionIndex = builder.AddAttribute(draco::GeometryAttribute::POSITION, 3, draco::DT_FLOAT32);
// Insert vertex data and faces into dracoMesh
for (int i = 0; i < numFace; ++i) {
const std::vector<float>& v0 = cubeCoords[cubeIndices[i * 3]];
const std::vector<float>& v1 = cubeCoords[cubeIndices[i * 3 + 1]];
const std::vector<float>& v2 = cubeCoords[cubeIndices[i * 3 + 2]];
builder.SetAttributeValuesForFace(positionIndex, draco::FaceIndex(i), (const void*)&v0[0], (const void*)&v1[0], (const void*)&v2[0]);
}
auto dracoMesh = builder.Finalize();
draco::GltfEncoder gltfEncoder;
std::string cubePath = "D:/cube.glb";
draco::DracoCompressionOptions compressOptions;
int compressionLevel = 6; // compression level [0-10], most=10, least=0.
int qbPosition = 16;
compressOptions.compression_level = compressionLevel;
compressOptions.quantization_bits_position = qbPosition;
dracoMesh->SetCompressionEnabled(true);
dracoMesh->SetCompressionOptions(compressOptions);
gltfEncoder.EncodeFile(*dracoMesh, cubePath);
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 全程不用写代码,我用AI程序员写了一个飞机大战
· DeepSeek 开源周回顾「GitHub 热点速览」
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 记一次.NET内存居高不下排查解决与启示
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
2017-06-26 MySQL数据库学习笔记----MySQL多表查询之外键、表连接、子查询、索引