matplotlib如何绘制两点间连线_如何在任意两点间画个圆柱

77b40ec9a9173df97005a7704b4ce9b4.png

实现一遍在任意给定的两个点之间画个圆柱...

为啥不用OpenGL的实用库glu.h中方法

gluCylinder(GLUquadric*quad,GLdoublebase,GLdoubletop,GLdoubleheight,GLintslices,GLintstacks)

而要自己实现一遍哩?两个原因:

1)gluCylinder是生成从(0, 0, 0)沿着z轴方向生成圆柱,并不能依据给定的两点生成;

2)glu.h提供的方法多用于固定管线,不适太用于modern opengl管线;

思路很简单,先依据给定的两点生成所有顶点,然后生成三角面片索引,最后依索引渲染。这里只说生成顶点和索引的方法。

除了两点 a, b 的三维坐标,还需要有半径 radius,顶部圆形的细分slices,圆柱纵向的细分stacks.

注意哟:这里有一点要说明的是,我们先默认从(0, 0, 0)沿着z轴方向,按照给定的radius,slices, stacks以及两点间间距 生成需要的顶点,然后按照从 (0, 0, z)方向到(b.x-a.x, b.y-a.y, b.z-a.z)得到旋转和平移量,因为这一小段cylinder是刚性变换,所以直接给到所有顶点就行了。

直接贴代码和注释:

// 调用了glm库
// 该方法是我的一个类方法,可以生成由一系列圆柱连接而成的管道。几个成员变量说一下:
// [Input] std::vector<float> vertices_;    事先赋好值,是所有中点的 x, y, z 坐标
// [Input] subdivisions_;    环形细分,就是上文的slices
// [Input] stacks_;    纵向细分
// [Output] std::vector<glm::vec3> cylinder_vertices_;    依据 vertices_ 里的连续的两点之间填充一个圆柱的所有顶点
// [Output] std::vector<unsigned int> indices_;    依据 cylinder_vertices_ 绘制三角面片需要的顶点排列
void CylinderData::_gen_cylinder()
{
	cylinder_vertices_.clear();
	indices_.clear();
	// for setting indices
	unsigned int stack_step = subdivisions_ + 1;  // 用于每一stack的步进,由于加上了中心点,故而多加一个1
	unsigned int vertex_number_each_cylinder = stack_step * stacks_;  // 用于每一cylinder的步进
	
	// generate vertices and indices
	for (int i = 0; i < vertices_.size() / 3 - 1; i++)
	{
                // 获得连续的两个点,计算各分量差
		double hx = vertices_[i * 3 + 3] - vertices_[i * 3];
		double hy = vertices_[i * 3 + 4] - vertices_[i * 3 + 1];
		double hz = vertices_[i * 3 + 5] - vertices_[i * 3 + 2];
		if (hz == 0) hz = 0.00000001; 

		double length = std::sqrt(hx*hx + hy*hy + hz*hz);  // 该cylinder的高度
		// 下面几行是计算旋转角度和旋转轴 依据罗德里格公式描述旋转
                double ax = acos(hz / length);  // 旋转角度
                // 旋转轴由前后两向量叉乘得到
		if (hz < 0.0)
			ax = -ax;
		double rx = -hy * hz;
		double ry = hx * hz;

		glm::mat4 translate = glm::translate(glm::vec3(vertices_[i * 3], vertices_[i * 3 + 1], vertices_[i * 3 + 2]));
		glm::mat4 rotate = glm::rotate((float)ax, glm::vec3((float)rx, (float)ry, 0.0f));

                // 沿着 z 轴 按照给定的radius,slices, stacks以及两点间间距,生成顶点
		double z_step = length / (stacks_ - 1);  // 用于纵向细分步进
		double r_step = M_PI * 2 / subdivisions_;  // 用于环形细分步进
		for (int stack = 0; stack < stacks_; stack++)
		{
			double z = z_step * stack;
			for (int slice = 0; slice < subdivisions_; slice++)
			{
				double r = r_step * slice;
				double x = radius_ * std::cos(r);
				double y = radius_ * std::sin(r);
				glm::vec3 vertex = translate * rotate * glm::vec4(x, y, z, 1.0);  // 先旋转后平移
				cylinder_vertices_.push_back(vertex);
			}
			glm::vec3 center = translate * rotate * glm::vec4(0, 0, z, 1.0);  // 中心点,同样的 先旋转后平移
			cylinder_vertices_.push_back(center);
		}
		// 然后再便利一遍设置下索引号
		unsigned int cylinder_step = i * vertex_number_each_cylinder;
		for (int stack = 0; stack < stacks_ - 1; stack++)
		{
			for (int slice = 0; slice < subdivisions_; slice++)
			{
                                // i0, i1, i2, i3 对应画出两个三角面片绘制一个矩形面
                                // 绕一圈,以此来构成该stack层级的圆柱体侧面
				unsigned int i0 = slice;
				unsigned int i1 = (i0 + 1) % subdivisions_;  // 这里取模主要是为了最后一个点能与开始点连上形成闭环
				unsigned int i2 = i1 + stack_step;
				unsigned int i3 = i0 + stack_step;
                                // c0, c1 是上下两层stack的圆形中心点
				unsigned int c0 = subdivisions_;
				unsigned int c1 = c0 + stack_step;
				i0 += stack * stack_step + cylinder_step;
				i1 += stack * stack_step + cylinder_step;
				i2 += stack * stack_step + cylinder_step;
				i3 += stack * stack_step + cylinder_step;
				c0 += stack * stack_step + cylinder_step;
				c1 += stack * stack_step + cylinder_step;
				// sides
				indices_.push_back(i0);
				indices_.push_back(i1);
				indices_.push_back(i2);
				indices_.push_back(i2);
				indices_.push_back(i3);
				indices_.push_back(i0);
				// caps
                                // 那这里其实重复绘制了,更好的是判定最外层两侧画上盖就好
				indices_.push_back(i0);
				indices_.push_back(i1);
				indices_.push_back(c0);
				indices_.push_back(i3);
				indices_.push_back(i2);
				indices_.push_back(c1);
			}
		}
	}
}

特性:

其实有些重复绘制了,但是这样写看着比较清楚;

该function特性在于可以生成一串由多个小圆柱构成的管道,即可以实现依据给定的曲线来实现宽窄和细分可控的管道模型;

如果只需要实现一个圆柱,那么输入的 vertices_ 存两个点就好了,比较灵活。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值