• draco编译及使用


    一、Draco简介

    谷歌开源的Draco库旨在大幅加速 3D 数据的编码、传输和解码。Draco不仅可以被用来压缩 mesh 和点云数据,它还支持压缩点( compressing points),连接信息,纹理协调,颜色信息,法线( normals)以及其他与几何相关的通用属性。另外Draco的算法既支持有损压缩模式,也支持无损压缩,还可以进行量化操作。目前3D模型支持stl、obj、glb、ply等格式。

    draco压缩算法对网格模型的压缩主要分为两个方面:

    • 利用网格边缘连接结构进行无损压缩( 参考Edgebreaker )
    • 利用更低的比特位数来近似表示原始浮点数据对顶点坐标、纹理等数据的有损量化压缩

    二、编译

    源码链接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
    • 新建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中某个文件链接错误
      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编译错误

    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;
    }
    
    
  • 相关阅读:
    python 发送邮件
    java 获取两个时间之前所有的日期
    java 子线程定时去更改主线程的变量
    post 两种方式 application/x-www-form-urlencoded和multipart/form-data
    aws 社交媒体技术大会 部分总结
    java操作Mongodb数据库
    实体类注解 @entity
    spring security 部分注解讲解
    @Column
    阿里云搭建服务器
  • 原文地址:https://www.cnblogs.com/xiaxuexiaoab/p/16399649.html
Copyright © 2020-2023  润新知