天天看點

opengl--圓錐和圓柱光照和紋理圓錐和圓柱光照和紋理

圓錐和圓柱光照和紋理

由于在圓錐的側面中和底面圓中,重合的底面圓上的點的法向量是不同的,同時在紋理貼圖時候,必有在同一個圓上位置,此處有兩個頂點,其中一個的紋理索引是起始點,另一個是終點。

若将底面圓類在實作時,等同于被分為m個線段,則圓錐總的頂底需要一個底面圓心+底面圓周的點+側面扇形上頂點+等同于m的圓錐頂點。即共需要頂點(m+1)*3+1個。

法向量和紋理:

在圓錐中:

頂點數組中,索引為1到m+1個的底面圓上的點、索引為0的底面圓心組成底面圓,法向量為垂直于圓平面機關向量。側面上的法向量,例如對于索引為m+2個點,如下圖,即側面上扇形上的一個點P,和對應的圓錐頂點Q兩個點的法向量,為垂直于兩點的直線且與O、P、Q三點組成的平面,在同一個平面,我們可求出機關化後的法向量,其推導過程如下:

opengl--圓錐和圓柱光照和紋理圓錐和圓柱光照和紋理

其紋理索引較為簡單,相當于将整個紋理劃分為不同的幾個區域,然後映射到三角形上,即告訴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;
}
           

實作效果

opengl--圓錐和圓柱光照和紋理圓錐和圓柱光照和紋理
opengl--圓錐和圓柱光照和紋理圓錐和圓柱光照和紋理

繼續閱讀