CloudCompare点云颜色显示代码解析

关键代码:

数据的加载过程

CC_FILE_ERROR PlyFilter::loadFile(const QString& filename, const QString& inputTextureFilename, ccHObject& container, LoadParameters& parameters)
{
	//设置点云读取函数,对不同的属性类型会有不同的读取方式
	ply_set_read_cb(ply, pointElements[pp.elemIndex].elementName, pp.propName, scalar_cb, sf, 1);
	...
	//通过下面函数调用PointCloudTpl::addPoint,为成员变量m_points添加数据
	success = ply_read(ply);
}

CloudCompare点云颜色的设置主要有三种设置方式(阶段):

  • 初始化打开的时候,例如数据带rgb或者intensity属性的时候 在这里插入图片描述
    使用这种方式,点云的颜色在读取点property的时候就决定了,看关键代码调用:
static int ply_read_list_property(p_ply ply, p_ply_element element, p_ply_property property, p_ply_argument argument){
    //使用函数指针调用,传入argument->value通过调用对应类型的函数(跳转1或者跳转2等)赋值
    if (!handler(ply, &argument->value)) {
        ply_ferror(ply, "Error reading '%s' of '%s' number %d",
                property->name, element->name, argument->instance_index);
        return 0;
    }
    //一样是函数指针,对应ply_set_read_cb设置的方法(跳转3或者跳转4等)
    if (read_cb && !read_cb(argument)) {
        ply_ferror(ply, "Aborted by user");
        return 0;
    }
    return 1;
}
//跳转1
static int ibinary_float32(p_ply ply, double *value) {
    float float32;
    if (!ply->idriver->ichunk(ply, &float32, sizeof(float32))) return 0;
    *value = float32;
    return 1;
}
//跳转2
static int ibinary_uint8(p_ply ply, double *value) {
    t_ply_uint8 uint8;
    if (!ply->idriver->ichunk(ply, &uint8, 1)) return 0;
    *value = uint8;
    return 1;
}
//无论是否跳转3或者4,都必须设置点坐标
static int vertex_cb(p_ply_argument argument){
	//ccPointCloud* cloud 调用方法为m_points添加所有点云坐标
	cloud->addPoint((s_Point + s_Pshift).toPC());
}
//跳转3 存在可供rgb映射的数值,设置rgb映射
static int rgb_cb(p_ply_argument argument)
//跳转4 对应上图设置intensity打开,因为intensity只有一个数值,所以cc让其映射到rgb全为intensity的grep_cb
static int grey_cb(p_ply_argument argument)
//无论跳转3还是4,只要设置颜色就需要到跳转到下面函数上
void ccPointCloud::addColor(const ccColor::Rgba& C){	
	//关键成员变量m_rgbaColors登场,后期将作为glcolorpoint参数
	m_rgbaColors->emplace_back(C);
}

数据做好准备后,在函数ccPointCloud::drawMeOnly中调用ccPointCloud::updateVBOs

void ccPointCloud::drawMeOnly(CC_DRAW_CONTEXT& context)
{
	//updateVBOs跳转
	bool useVBOs = context.useVBOs && !toDisplay.indexMap ? updateVBOs(context, glParams) : false;
	glChunkColorPointer(context, k, toDisplay.decimStep, useVBOs);
	glFunc->glDrawArrays(GL_POINTS, 0, static_cast<GLsizei>(chunkSize));
}

bool ccPointCloud::updateVBOs(const CC_DRAW_CONTEXT& context, const glDrawParams& glParams)
{
	//m_rgbaColors在此被送到缓存VBO中
 	m_vboManager.vbos[chunkIndex]->write(m_vboManager.vbos[chunkIndex]->rgbShift, ccChunk::Start(*m_rgbaColors, chunkIndex), sizeof(ColorCompType) * chunkSize * 4);
}

需要注意地是,如果除了xyz选择了,但其他都不选地情况下关键代码*glChunkColorPointer(context, k, toDisplay.decimStep, useVBOs);*是不走的,也就是说不启用顶点数组的颜色数据,OpenGL会使用默认颜色(通常是白色)渲染所有点。

  • 使用Scala Filed(SF),数据初始化配置时候添加Scalar,将某类属性作为标量,也就是颜色的标尺。在这里插入图片描述
    和ply_read_list_property很类似,通过函数指针调用
static int scalar_cb(p_ply_argument argument)
{
	//根据Scale指定的属性,比如本次的intensity,经过转换直接变为 
	ScalarType scal = static_cast<ScalarType>(ply_get_argument_value(argument));
	sf->setValue(instance_index,scal);


	return 1;
}

剩下的点云颜色设置和数据传入vbos中相关的代码都在函数ccPointCloud::drawMeOnly
其中chunkSize的大小就是根据前面读取的点云多少获取的。所有点云的颜色数据最终传入vbos中

bool ccPointCloud::updateVBOs(const CC_DRAW_CONTEXT& context, const glDrawParams& glParams)
{
 	//s_rgbBuffer4ub当前所有点的颜色组成的数组,每个点都包含rgba,每个元素8位,刚好可代表255
 	//m_vboManager.sourceSF 记录当前scalar Fields中顶点某类属性数据,xyz或者intensity
 	//_sf 一个顶点的一个属性,double类型
 	//关键函数getColor,通过属性值在预设好的ccColorScale中查到对应的颜色
 	ColorCompType* _sfColors = s_rgbBuffer4ub;
	ScalarType* _sf = ccChunk::Start(*m_vboManager.sourceSF, chunkIndex);
	for (int j = 0; j < chunkSize; j++, _sf++)
	{
		//we need to convert scalar value to color into a temporary structure
		const ccColor::Rgb* col = _sf ? m_vboManager.sourceSF->getColor(*_sf) : nullptr;
		if (!col)
		{
			col = &ccColor::lightGreyRGB;
			*_sfColors++ = col->r;
			*_sfColors++ = col->g;
			*_sfColors++ = col->b;
			*_sfColors++ = ccColor::MAX;
		}
		//then send them in VRAM
		//通过vboManager管理器把颜色数据传入VRAM
		m_vboManager.vbos[chunkIndex]->write(m_vboManager.vbos[chunkIndex]->rgbShift, s_rgbBuffer4ub, sizeof(ColorCompType) * chunkSize * 4);

}

在函数drawMeOnly中,更新vbo后需要进一步告知如何处理顶点数据和颜色数据,这和官网介绍的OpneGL使用可编程shader处理数据有区别。

void ccPointCloud::drawMeOnly(CC_DRAW_CONTEXT& context)
{
	glFunc->glEnableClientState(GL_VERTEX_ARRAY);
	glFunc->glEnableClientState(GL_COLOR_ARRAY);
	//points 函数内部调用glVertexPointer
	glChunkVertexPointer(context, k, toDisplay.decimStep, useVBOs);
	//SF colors 函数内部调用glColorPointer
	glChunkSFPointer(context, k, toDisplay.decimStep, useVBOs);
	glFunc->glDrawArrays(GL_POINTS, 0, static_cast<GLsizei>(chunkSize));
	
}

现在重点手撕下函数ccPointCloud::updateVBOs中通过Scale Field获取颜色。
查看调用

//传入的value首先需要经过正则化
getColorByRelativePos(normalize(value), m_colorRampSteps, m_showNaNValuesInGrey ? &ccColor::lightGreyRGB : nullptr);

//normalize(value)函数相对简单,除了指定指数log变化以外,大部分都走非对称或者对称逻辑。在normalize函数中根据色彩饱和度进行调整。
//需要注意的是

//在函数getColorByRelativePos中调用getColorByIndex
inline const ccColor::Rgb& getColorByIndex(unsigned index) const
{
	assert(m_updated && index < MAX_STEPS);
	return m_rgbaScale[index];
}
//m_rgbaScale是一个在打开cc时,通过ccColorScalesManager::Create创建的不同类型的ccColorScale的成员变量,该成员共有1024位的
//在ccColorScalesManager::Create中主要


总结

提示:这里对文章进行总结:

例如:以上就是今天要讲的内容,本文仅仅简单介绍了pandas的使用,而pandas提供了大量能使我们快速便捷地处理数据的函数和方法。

  • 5
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值