OpenGL Project 1 - The Heart

Submitted by zach on Wed, 09/16/2020 - 08:39
Heart Image

The first project I did when learning OpenGL was a very simple project with one goal: create something pretty. We were challenged to create an object that would render on screen with a given OpenGL project sample and I decided I would create a heart. Check out this video for the rundown on the project:

Here's the code I used to render the heart:

//set up for all the different things needed to draw the heart

	float a1, a2;
	a1 = 2.0;
	a2 = -2.0;

	
	int steps = 10;
	int numSegments = 5;

	float xmod = 1;
	float ymod = 1;
	float xmod1 = 1;
	float ymod1 = 1;
	float shift = 0;
	float shift1 = 0;

	float segshift = 0;
	float segshiftNext = 0.35;


	//This first for loop draws the two halves of the heart
	//Later on I use i to modify the vertices to mirror the
	//half of the heart, skipping i == 0 to do some black magic
	for (int i = -1; i <= 1; ++i) {
		if (i == 0) continue;

		//reset the modifiers for each half of the heart
		xmod = 1;
		ymod = 1;
		xmod1 = 1;
		ymod1 = 1;
		shift = 0;
		shift1 = 0;

		segshift = 0;
		segshiftNext = 0.2;

		float color1 = 0.0;
		float color2 = 0.5;
		float color3 = 1;

		int color_inc = 0;
		float color_add = 2;

		//Draw each strip of the heart

		//Any more than six segments with the current
		//code makes some funky effects
		for (int j = 1; j <= numSegments; ++j) {

			//start the triangle strip topology
			glBegin(GL_TRIANGLE_STRIP);

			//Some math to modify how quickly each segment shrinks
			//modify xmod, ymod, and shift
			float modbase = (float)(j) / 10;
			float modbase1 = modbase * modbase;
			float modbase2 = modbase1 * modbase;

			xmod1 -= modbase1;
			ymod1 -= 0.1;
			shift1 +=modbase2;

			//Then walk around the edge of the cardioid
			//Special note here that 90 to 450 is 360 degrees,
			//but this loop goes one step further, this is to fully
			//complete the ring and avoid holes in the mesh
			for (int t = 90; t < 450 + steps; t += steps) {

				//Convert from degress to radians
				float rad = (3.14159 / 180.0)*t;

				//calculate the radius of the cardioid at the given angle in radians
				float r2 = a1 + a2 * sin(rad) + sin(rad)*(sqrt(fabs(cos(rad))) / (sin(rad) + 1.4));

				//a much less interesting cardioid that I didn't end up using
				float r = (a1 + a2 * sin(rad));

				//now convert from polar coordinates to rectangular
				float x = r2 * cos(rad);
				float y = r2 * sin(rad);

				//Set the color for the vertex, the colors increment every two vertices
				float rgb[3];
				float hsv[3] = { color1, color2, color3 };
				HsvRgb(hsv, rgb);
				glColor3f(rgb[0], rgb[1], rgb[2]);
				

				//Draw this current ring
				glVertex3f((float)(x * xmod), (float)(y*ymod - shift), (float)(i)*segshift);

				//Draw the next ring out with modified values
				//Don't need no stinkin transformation functions!
				glVertex3f((float)(x * xmod1), (float)(y*ymod1 - shift1), (float)(i)*(segshift + segshiftNext));
				

				//Update the colors in HSV
				//Original colors were named for RGB
				//So the names are kinda weird and I'm lazy


				if (color1 < 360) {
					color1 += color_add;
				}
				else {
					if (color2 < 1) {
						color2 += 0.1;
					}
					else {
							color1 = 0.0; //hue starts at 0	
							color2 = 0.5; //saturation starts at 0.5
							color3 = 1; //value is always 1
						
					}
				}

				


			}
			//End this part of the topology
			glEnd();
			
			//Change the modifiers for the next ring
			segshift = segshift + segshiftNext;
			xmod = xmod1;
			ymod = ymod1;
			shift = shift1;
			
			

		}
		//draw end caps
		//This is the same code for the very last ring
		//except using a polygon instead of a triangle strip
		for (int j = 1; j <= numSegments; ++j) {
			glBegin(GL_POLYGON);

			for (int t = 90; t < 450 + steps; t += steps) {
				float rad = (3.14159 / 180.0)*t;

				float r2 = a1 + a2 * sin(rad) + sin(rad)*(sqrt(fabs(cos(rad))) / (sin(rad) + 1.4));

				float r = (a1 + a2 * sin(rad));

				float x = r2 * cos(rad);
				float y = r2 * sin(rad);

				glVertex3f((float)(x * xmod), (float)(y*ymod - shift), (float)(i)*segshift);
			}
			glEnd();
		}
	}