关于cesium1.92以上版本无法加载draco压缩模型问题

1 篇文章 0 订阅
1 篇文章 0 订阅

        draco是谷歌发布的三维模型压缩库,可以用于压缩三维模型的顶点等数据,减小模型大小,使用c++版本的draco压缩后的模型在cesium1.89上可以正常加载显示,但是cesium1.92版本时,无法正常加载,会报Cannot read property '__destroy__' of undefined的错,下面是cesium报错信息:

        后来通过调试分析draco源码,发现我在使用draco压缩时只是对顶点纹理和面进行了操作,没有对材质进行绑定,所以cesium1.92以上版本无法加载,但是低版本的cesium是可以正常加载的,主要原因就是将其他数据格式组织成draco的mesh格式时存在问题,具体的mesh加载方式可以参考源码中ObjDecoder::DecodeInternal()方法。

        在进行压缩时,需要设置材质相关属性:

//设置材质相关,此项为必要操作,否则cesium1.92以上版本无法加载该b3dm
{
    draco::GeometryAttribute va;
    const auto geometry_attribute_type=draco::GeometryAttribute::GENERIC;
    va.Init(geometry_attribute_type,nullptr,1,draco::DT_UINT8,false,1,0);
    material_att_id=pointCloud->AddAttribute(va,false,1);
    int index=0;
    pointCloud->attribute(material_att_id)->SetAttributeValue(draco::AttributeValueIndex(0),&index);
}

        我的数据中只有一个纹理,所以index设置为0,如果有多个纹理材质,则需要遍历设置材质属性值:

{
    for(int i=0;i<count;++i)
        pointCloud->attribute(material_att_id)->SetAttributeValue(draco::AttrubuteValueIndex(i),&i);
}

        在设置三角面时,需要将面的每一个顶点都绑定一个材质id:

{
    for(int j=0;j<tri_indices.size();++j){
        //三角面的第一个点
        const draco::PointIndex vert_id1(3*j+0);
        pointCloud->attribute(material_att_id)->SetPointMapEntry(vert_id1,draco::AttributeValueIndex(0));
        //三角面的第二个点
        const draco::PointIndex vert_id2(3*j+1);
        pointCloud->attribute(material_att_id)->SetPointMapEntry(vert_id2,draco::AttributeValueIndex(0));
        //三角面的第三个点
        const draco::PointIndex vert_id3(3*j+2);
        pointCloud->attribute(material_att_id)->SetPointMapEntry(vert_id3,draco::AttributeValueIndex(0));
    }
}

        因为我的数据中只有一个纹理,所以每个面的每一个点对应的材质属性值都是0,即draco::AttributeValueIndex(0),如果有多个材质,需要注意设置成对应的材质属性值。

        下面附上部分代码:

{
    std::vector<osg::Vec3> tri_positions;//osg读取的顶点,自己实现
    std::vector<osg::Vec2> tri_texcoords0;//osg读取的纹理坐标,自己实现
    std::vector<osg::Vec3> tri_indices;//osg读取的三角面,自己实现
    
    //使用draco进行模型压缩代码
    int vertexCount = tri_positions.size(); // 顶点数量
	std::unique_ptr<draco::Mesh> dracoMesh(new draco::Mesh());
	draco::PointCloud* pointCloud = static_cast<draco::PointCloud*>(dracoMesh.get());
	dracoMesh->set_num_points(tri_indices.size() * 3);//设置要压缩的点个数
	dracoMesh->SetNumFaces(tri_indices.size());//设置要压缩的面个数

	int pos_att_id = 0;
	int tex_att_id = 0;
	int material_att_id = 0;
	//设置材质,此项为必须操作,否则cesium1.92以上版本无法加载该b3dm
	{
		draco::GeometryAttribute va;
		const auto geometry_attribute_type = draco::GeometryAttribute::GENERIC;
		va.Init(geometry_attribute_type, nullptr, 1, draco::DT_UINT8, false, 1, 0);
		material_att_id = pointCloud->AddAttribute(va, false, 1);
		int vvv = 0;
		pointCloud->attribute(material_att_id)->SetAttributeValue(draco::AttributeValueIndex(0), &vvv);
	}
	//设置顶点相关
	{
		draco::GeometryAttribute va;
		va.Init(draco::GeometryAttribute::POSITION, nullptr, 3, draco::DT_FLOAT32, false, sizeof(float) * 3, 0);
		pos_att_id = pointCloud->AddAttribute(va, false, vertexCount);//添加到dracoPointCloud中
		draco::PointAttribute* att_ptr = pointCloud->attribute(pos_att_id);//获取添加的对象
		//将顶点数据添加到压缩属性att中
		for (int j = 0; j < tri_positions.size(); j++) {
			att_ptr->SetAttributeValue(draco::AttributeValueIndex(j), &tri_positions[j][0]);//顶点数据添加到压缩属性att中
		}
	}
	//设置纹理坐标相关
	{
		draco::GeometryAttribute va;
		va.Init(draco::GeometryAttribute::TEX_COORD, nullptr, 2, draco::DT_FLOAT32, false, sizeof(float)*2, 0);
		tex_att_id = pointCloud->AddAttribute(va, false, vertexCount);//添加到dracoPointCloud中
		draco::PointAttribute* att_ptr = dracoMesh->attribute(tex_att_id);//获取添加的对象
		//将纹理数据添加到压缩属性att中
		for (int j = 0; j < tri_texcoords0.size(); j++) {
			att_ptr->SetAttributeValue(draco::AttributeValueIndex(j), &tri_texcoords0[j][0]);//纹理数据添加到压缩属性att中
		}
	}

	//遍历面,每一个三角面的三个点设置对应的材质、顶点和纹理坐标
	for (int j = 0; j < tri_indices.size(); ++j) {
        //三角面的第一个顶点
		const draco::PointIndex vert_id1(3 * j + 0);
		//设置对应的材质,此项为必须操作,否则cesium1.92以上版本无法加载该b3dm
		pointCloud->attribute(material_att_id)->SetPointMapEntry(vert_id1, draco::AttributeValueIndex(0));
		pointCloud->attribute(pos_att_id)->SetPointMapEntry(vert_id1, draco::AttributeValueIndex(tri_indices[j].x()));
		pointCloud->attribute(tex_att_id)->SetPointMapEntry(vert_id1, draco::AttributeValueIndex(tri_indices[j].x()));
        //三角面的第二个顶点
		const draco::PointIndex vert_id2(3 * j + 1);
		//设置对应材质,此项为必须操作,否则cesium1.92以上版本无法加载该b3dm
		pointCloud->attribute(material_att_id)->SetPointMapEntry(vert_id2, draco::AttributeValueIndex(0));
		pointCloud->attribute(pos_att_id)->SetPointMapEntry(vert_id2, draco::AttributeValueIndex(tri_indices[j].y()));
		pointCloud->attribute(tex_att_id)->SetPointMapEntry(vert_id2, draco::AttributeValueIndex(tri_indices[j].y()));
        //三角面的第三个顶点
		const draco::PointIndex vert_id3(3 * j + 2);
		//设置对应材质,此项为必须操作,否则cesium1.92以上版本无法加载该b3dm
		pointCloud->attribute(material_att_id)->SetPointMapEntry(vert_id3, draco::AttributeValueIndex(0));
		pointCloud->attribute(pos_att_id)->SetPointMapEntry(vert_id3, draco::AttributeValueIndex(tri_indices[j].z()));
		pointCloud->attribute(tex_att_id)->SetPointMapEntry(vert_id3, draco::AttributeValueIndex(tri_indices[j].z()));

		draco::Mesh::Face face;
		for (int c = 0; c < 3; ++c) {
			face[c] = 3 * j + c;
		}
		dracoMesh->SetFace(draco::FaceIndex(j), face);
	}

	//去除重复数据
	pointCloud->DeduplicateAttributeValues();
	pointCloud->DeduplicatePointIds();

	//设置压缩参数
	const int dracoCompressionSpeed = 5;
	const int dracoPositionBits = 14;

	draco::EncoderBuffer dracoBuffer;//压缩后的数据存储到draco的缓存区中
	draco::Encoder encoder;//压缩对象
	//设置压缩参数
	encoder.SetSpeedOptions(dracoCompressionSpeed, dracoCompressionSpeed);
	encoder.SetAttributeQuantization(draco::GeometryAttribute::POSITION,
			dracoPositionBits);

	//设置压缩方法
	encoder.SetEncodingMethod(draco::MeshEncoderMethod::MESH_EDGEBREAKER_ENCODING);
}

  • 6
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值