opengl--圆锥和圆柱光照和纹理

圆锥和圆柱光照和纹理

由于在圆锥的侧面中和底面圆中,重合的底面圆上的点的法向量是不同的,同时在纹理贴图时候,必有在同一个圆上位置,此处有两个顶点,其中一个的纹理索引是起始点,另一个是终点。
若将底面圆类在实现时,等同于被分为m个线段,则圆锥总的顶底需要一个底面圆心+底面圆周的点+侧面扇形上顶点+等同于m的圆锥顶点。即共需要顶点(m+1)*3+1个。

法向量和纹理:

在圆锥中:

顶点数组中,索引为1到m+1个的底面圆上的点、索引为0的底面圆心组成底面圆,法向量为垂直于圆平面单位向量。侧面上的法向量,例如对于索引为m+2个点,如下图,即侧面上扇形上的一个点P,和对应的圆锥顶点Q两个点的法向量,为垂直于两点的直线且与O、P、Q三点组成的平面,在同一个平面,我们可求出单位化后的法向量,其推导过程如下:
在这里插入图片描述

其纹理索引较为简单,相当于将整个纹理划分为不同的几个区域,然后映射到三角形上,即告诉opengl贴图时对应在图片上分割的位置。若纹理贴图重复一次,则位置为比例系数,若重复n此,则意味着总长度变为图片尺寸的n倍,即纹理索引需要乘以n。
具体实现代码:

void CMesh::CreateCone(float radius, int num_stacks, float height, float xz, float y)
{
	double angle = 2 * M_PI / num_stacks;
	//num_vertices = num_stacks + 2;//由于圆锥的底面圆上的顶点在底圆和侧面的法向量不一样,因此定点数要增加
	num_vertices = (num_stacks+1) * 3 + 1;
	num_indices = num_stacks * 2 * 3;//所画的三角形不变,因此索引不变

	CMeshVertex* vertices = new CMeshVertex[num_vertices];
	GLuint* indices = new GLuint[num_indices];

	vertices[0].pos = vec3{ 0,0,0 };
	vertices[0].normal = vec3{ 0,0,1 };
	vertices[0].color = { 1.0f,1.0f,1.0f,1.0f };// vec4{ 1.0f,0.0f,0.0f,1.0f };
	vertices[0].texcoord.x = xz / 2;
	vertices[0].texcoord.y = y;
	float nomalize_n = height * height / (height * height + radius * radius);


	for (int i = 0; i <=num_stacks; ++i) {
		vertices[i + 1].pos.x = cos(angle * i) * radius;
		vertices[i + 1].pos.y = -sin(angle * i) * radius;
		vertices[i + 1].pos.z = 0;
		vertices[i + 1].normal = vec3{ 0,0,1 };
		vertices[i + 1].color = { 1.0f,1.0f,1.0f,1.0f };// { 1.0f, 0.0f, 0.0f, 1.0f };
		vertices[i + 1].texcoord.x = (float)i / (float)num_stacks * xz;
		vertices[i + 1].texcoord.y = 0;
		
		vertices[i + 2 + num_stacks].pos = vertices[i + 1].pos;
		vertices[i + 2 + num_stacks].normal.x = cos(angle * i);
		vertices[i + 2 + num_stacks].normal.y = -sin(angle * i);
		vertices[i + 2 + num_stacks].normal.z = 0;
		vertices[i + 2 + num_stacks].color = { 1.0f,1.0f,1.0f,1.0f };// { 0.5f, 0.0f, 0.5f, 1.0f };
		vertices[i + 2 + num_stacks].texcoord = vertices[i + 1].texcoord;

		vertices[i + 1 + (num_stacks + 1)*2].pos = vec3(0.0f, 0.0f, height);
		vertices[i + 1 + (num_stacks +1)* 2].texcoord.x = (float)xz / 2;
		vertices[i + 1 + (num_stacks +1)* 2].texcoord.y = (float)y / 2;
		vertices[i + 1 + (num_stacks +1)* 2].color = vec4(1.0f, 1.0f, 1.0f, 1.0f);
		vertices[i + 1 + (num_stacks +1)* 2].normal.x = nomalize_n * cos(angle * i);
		vertices[i + 1 + (num_stacks +1)* 2].normal.y = -nomalize_n * sin(angle * i);
		vertices[i + 1 + (num_stacks +1)* 2].normal.z = radius *height/ (height*height + radius*radius);

		if (i != num_stacks) {
			indices[i * 6] = 0;
			indices[i * 6 + 1] = i + 1;
			indices[i * 6 + 2] = i + 2;
			indices[i * 6 + 3] = i+1+(num_stacks+1)*2;
			indices[i * 6 + 4] = i + 3 + num_stacks;
			indices[i * 6 + 5] = i + 2 + num_stacks;
		}	
	}

	//vertices[(num_stacks + 1) * 2 + 1].color = vec4(1.0f, 0.0f, 0.0f, 1.0f);
	CreateGLResources(vertices, indices);

	delete[] vertices;
	delete[] indices;
}

对于圆柱:

侧面与底面圆交点,在上下底面中的法向量是垂直与两个平面的单位向量,在侧面中为对应的圆心指向它们各自位置的归一化向量。其实现更为简单,但是需要的顶点数量改为4*(m+1)+2个。
具体实现代码:

void CMesh::CreateCylinder(float radius, int num_stacks, float height, float xz, float y)
{
	double angle = 2 * M_PI / num_stacks;
	num_vertices = (num_stacks + 1) * 4 + 2;
	num_indices = num_stacks * 3 * 4;

	CMeshVertex* vertices = new CMeshVertex[num_vertices];
	GLuint* indices = new GLuint[num_indices];

	vertices[0].pos = vec3{ 0,0,0 };
	vertices[0].normal = vec3{ 0,0,-1 };
	vertices[0].color = { 1.0f,1.0f,1.0f,1.0f };// vec4{ 1.0f,0.0f,0.0f,0.0f };
	vertices[0].texcoord.x = xz/2;
	vertices[0].texcoord.y = y;

	vertices[num_vertices - 1].pos = vec3{ 0,0,height };
	vertices[num_vertices - 1].normal = vec3{ 0,0,1 };
	vertices[num_vertices - 1].color = { 1.0f,1.0f,1.0f,1.0f };// { 0.0f, 0.5f, 0.5f, 0.0f };
	vertices[num_vertices - 1].texcoord.x = xz/2;
	vertices[num_vertices - 1].texcoord.y = y;

	for (int i = 0; i <= num_stacks; ++i) {
		vertices[i + 1].pos.x = cos(angle * i) * radius;
		vertices[i + 1].pos.y = -sin(angle * i) * radius;
		vertices[i + 1].pos.z = 0;
		vertices[i + 1].normal = vec3{ 0,0,-1 };
		vertices[i + 1].color = { 1.0f,1.0f,1.0f,1.0f };// { 1.0f,0.0f,0.0f,0.0f };
		vertices[i + 1].texcoord.x = (float)i / (float)num_stacks * xz;
		vertices[i + 1].texcoord.y = 0;

		//侧面下的圆上点
		vertices[i + 2 + num_stacks].pos = vertices[i + 1].pos;
		vertices[i + 2 + num_stacks].normal.x = cos(angle * i);
		vertices[i + 2 + num_stacks].normal.y = -sin(angle * i);
		vertices[i + 2 + num_stacks].normal.z = 0;
		vertices[i + 2 + num_stacks].color = { 1.0f,1.0f,1.0f,1.0f };// { 0.5f,0.0f,0.5f,0.0f };
		vertices[i + 2 + num_stacks].texcoord = vertices[i + 1].texcoord;


		//侧面上的圆上点
		vertices[i + 1 + 2 * (num_stacks + 1 )] = vertices[i + 2 + num_stacks];
		vertices[i + 1 + 2 * (num_stacks + 1)].pos.z = height;
		vertices[i + 1 + 2 * (num_stacks + 1)].texcoord.y = y;

		//最上边的一层圆上顶点
		vertices[i + 1 + 3 * (num_stacks + 1)] = vertices[i + 1];
		vertices[i + 1 + 3 * (num_stacks + 1)].pos.z = height;
		vertices[i + 1 + 3 * (num_stacks + 1)].color = { 1.0f,1.0f,1.0f,1.0f };//{ 0.0f,0.5f,0.5f,0.0f };
		vertices[i + 1 + 3 * (num_stacks + 1)].normal = vec3{ 0,0,1 };

		if (i != num_stacks) {
			indices[i * 12] = 0;
			indices[i * 12 + 1] = i+1;
			indices[i * 12 + 2] = i + 2;

			indices[i * 12 + 3] = num_vertices - 1;
			indices[i * 12 + 4] = i +2+ 3*(num_stacks+1);
			indices[i * 12 + 5] = i + 1 + 3*(num_stacks+1);

			indices[i * 12 + 6] = i + 2 +(num_stacks+1);
			indices[i * 12 + 7] = i + 1 +(num_stacks+1);
			indices[i * 12 + 8] = i +1+ 2*(num_stacks+1);

			indices[i * 12 + 9] = i + 2+num_stacks+1;
			indices[i * 12 + 10] = i+ 1+ 2*(num_stacks+1);
			indices[i * 12 + 11] = i + 2 + 2*(num_stacks+1);
		}

	}

	//vertices[num_stacks + 2].color = { 0.5f,0.0f,0.5f,0.0f };
	CreateGLResources(vertices, indices);

	delete[] vertices;
	delete[] indices;
}

实现效果

在这里插入图片描述
在这里插入图片描述

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值