Beispiel #1
0
void LightManager::init(GLuint program)
{
	numLights = 0;
	setUniformAttrib(uniLightPosition, "position", program);
	setUniformAttrib(uniLightIntensity, "intensity", program);
	uniNumLights = glGetUniformLocation(program, "numLights");
}
// Initialization code
void init()
{
	// Initializes the glew library
	glewInit();

	// Enables the depth test, which you will want in most cases. You can disable this in the render loop if you need to.
	glEnable(GL_DEPTH_TEST);

	// Create an std::vector and put our vertices into it. These are just hardcoded values here defined once.
	std::vector<VertexFormat> vertices;//our vertex positions
	vertices.push_back(VertexFormat(glm::vec3(-0.25, -0.25, -0.25),
		glm::vec4(1.0, 0.0, 0.0, 1.0), glm::vec3(0.0, 0.0, 1.0)));
	vertices.push_back(VertexFormat(glm::vec3(-0.25, 0.25, -0.25),
		glm::vec4(1.0, 0.0, 0.0, 1.0), glm::vec3(0.0, 0.0, 1.0)));
	vertices.push_back(VertexFormat(glm::vec3(0.25, 0.25, -0.25), // 3
		glm::vec4(1.0, 0.0, 0.0, 1.0), glm::vec3(0.0, 0.0, 1.0)));
	vertices.push_back(VertexFormat(glm::vec3(-0.25, -0.25, -0.25),
		glm::vec4(1.0, 0.0, 0.0, 1.0), glm::vec3(0.0, 0.0, 1.0)));
	vertices.push_back(VertexFormat(glm::vec3(0.25, 0.25, -0.25),
		glm::vec4(1.0, 0.0, 0.0, 1.0), glm::vec3(0.0, 0.0, 1.0)));
	vertices.push_back(VertexFormat(glm::vec3(0.25, -0.25, -0.25), // 6 end front face | NORMAL: (0.0, 0.0, 1.0)
		glm::vec4(1.0, 0.0, 0.0, 1.0), glm::vec3(0.0, 0.0, 1.0)));
	vertices.push_back(VertexFormat(glm::vec3(0.25, -0.25, -0.25),
		glm::vec4(1.0, 1.0, 0.0, 1.0), glm::vec3(1.0, 0.0, 0.0)));
	vertices.push_back(VertexFormat(glm::vec3(0.25, 0.25, -0.25),
		glm::vec4(1.0, 1.0, 0.0, 1.0), glm::vec3(1.0, 0.0, 0.0)));
	vertices.push_back(VertexFormat(glm::vec3(0.25, 0.25, -0.75), // 9
		glm::vec4(1.0, 1.0, 0.0, 1.0), glm::vec3(1.0, 0.0, 0.0)));
	vertices.push_back(VertexFormat(glm::vec3(0.25, -0.25, -0.25),
		glm::vec4(1.0, 1.0, 0.0, 1.0), glm::vec3(1.0, 0.0, 0.0)));
	vertices.push_back(VertexFormat(glm::vec3(0.25, 0.25, -0.75),
		glm::vec4(1.0, 1.0, 0.0, 1.0), glm::vec3(1.0, 0.0, 0.0)));
	vertices.push_back(VertexFormat(glm::vec3(0.25, -0.25, -0.75), // 12 end right face | NORMAL: (1.0, 0.0, 0.0)
		glm::vec4(1.0, 1.0, 0.0, 1.0), glm::vec3(1.0, 0.0, 0.0)));
	vertices.push_back(VertexFormat(glm::vec3(0.25, -0.25, -0.75),
		glm::vec4(1.0, 0.0, 1.0, 1.0), glm::vec3(0.0, 0.0, -1.0)));
	vertices.push_back(VertexFormat(glm::vec3(0.25, 0.25, -0.75),
		glm::vec4(1.0, 0.0, 1.0, 1.0), glm::vec3(0.0, 0.0, -1.0)));
	vertices.push_back(VertexFormat(glm::vec3(-0.25, 0.25, -0.75), // 15
		glm::vec4(1.0, 0.0, 1.0, 1.0), glm::vec3(0.0, 0.0, -1.0)));
	vertices.push_back(VertexFormat(glm::vec3(0.25, -0.25, -0.75),
		glm::vec4(1.0, 0.0, 1.0, 1.0), glm::vec3(0.0, 0.0, -1.0)));
	vertices.push_back(VertexFormat(glm::vec3(-0.25, 0.25, -0.75),
		glm::vec4(1.0, 0.0, 1.0, 1.0), glm::vec3(0.0, 0.0, -1.0)));
	vertices.push_back(VertexFormat(glm::vec3(-0.25, -0.25, -0.75), // 18 end back face | NORMAL: (0.0, 0.0, -1.0)
		glm::vec4(1.0, 0.0, 1.0, 1.0), glm::vec3(0.0, 0.0, -1.0)));
	vertices.push_back(VertexFormat(glm::vec3(-0.25, -0.25, -0.75),
		glm::vec4(0.0, 1.0, 0.0, 1.0), glm::vec3(-1.0, 0.0, 0.0)));
	vertices.push_back(VertexFormat(glm::vec3(-0.25, 0.25, -0.75),
		glm::vec4(0.0, 1.0, 0.0, 1.0), glm::vec3(-1.0, 0.0, 0.0)));
	vertices.push_back(VertexFormat(glm::vec3(-0.25, 0.25, -0.25), // 21
		glm::vec4(0.0, 1.0, 0.0, 1.0), glm::vec3(-1.0, 0.0, 0.0)));
	vertices.push_back(VertexFormat(glm::vec3(-0.25, -0.25, -0.75),
		glm::vec4(0.0, 1.0, 0.0, 1.0), glm::vec3(-1.0, 0.0, 0.0)));
	vertices.push_back(VertexFormat(glm::vec3(-0.25, 0.25, -0.25),
		glm::vec4(0.0, 1.0, 0.0, 1.0), glm::vec3(-1.0, 0.0, 0.0)));
	vertices.push_back(VertexFormat(glm::vec3(-0.25, -0.25, -0.25), // 24 end left face | NORMAL: (-1.0, 0.0, 0.0)
		glm::vec4(0.0, 1.0, 0.0, 1.0), glm::vec3(-1.0, 0.0, 0.0)));
	vertices.push_back(VertexFormat(glm::vec3(-0.25, 0.25, -0.25),
		glm::vec4(0.0, 0.0, 1.0, 1.0), glm::vec3(0.0, 1.0, 0.0)));
	vertices.push_back(VertexFormat(glm::vec3(-0.25, 0.25, -0.75),
		glm::vec4(0.0, 0.0, 1.0, 1.0), glm::vec3(0.0, 1.0, 0.0)));
	vertices.push_back(VertexFormat(glm::vec3(0.25, 0.25, -0.75), // 27
		glm::vec4(0.0, 0.0, 1.0, 1.0), glm::vec3(0.0, 1.0, 0.0)));
	vertices.push_back(VertexFormat(glm::vec3(-0.25, 0.25, -0.25),
		glm::vec4(0.0, 0.0, 1.0, 1.0), glm::vec3(0.0, 1.0, 0.0)));
	vertices.push_back(VertexFormat(glm::vec3(0.25, 0.25, -0.75),
		glm::vec4(0.0, 0.0, 1.0, 1.0), glm::vec3(0.0, 1.0, 0.0)));
	vertices.push_back(VertexFormat(glm::vec3(0.25, 0.25, -0.25), // 30 end top face | NORMAL: (0.0, 1.0, 0.0)
		glm::vec4(0.0, 0.0, 1.0, 1.0), glm::vec3(0.0, 1.0, 0.0)));
	vertices.push_back(VertexFormat(glm::vec3(-0.25, -0.25, -0.25),
		glm::vec4(0.0, 1.0, 1.0, 1.0), glm::vec3(0.0, -1.0, 0.0)));
	vertices.push_back(VertexFormat(glm::vec3(0.25, -0.25, -0.25),
		glm::vec4(0.0, 1.0, 1.0, 1.0), glm::vec3(0.0, -1.0, 0.0)));
	vertices.push_back(VertexFormat(glm::vec3(0.25, -0.25, -0.75), // 33
		glm::vec4(0.0, 1.0, 1.0, 1.0), glm::vec3(0.0, -1.0, 0.0)));
	vertices.push_back(VertexFormat(glm::vec3(-0.25, -0.25, -0.25),
		glm::vec4(0.0, 1.0, 1.0, 1.0), glm::vec3(0.0, -1.0, 0.0)));
	vertices.push_back(VertexFormat(glm::vec3(0.25, -0.25, -0.75),
		glm::vec4(0.0, 1.0, 1.0, 1.0), glm::vec3(0.0, -1.0, 0.0)));
	vertices.push_back(VertexFormat(glm::vec3(-0.25, -0.25, -0.75), // 36 end back face | NORMAL: (0.0, -1.0, 0.0)
		glm::vec4(0.0, 1.0, 1.0, 1.0), glm::vec3(0.0, -1.0, 0.0)));

	// This generates buffer object names
	// The first parameter is the number of buffer objects, and the second parameter is a pointer to an array of buffer objects (yes, before this call, vbo was an empty variable)
	// (In this example, there's only one buffer object.)
	glGenBuffers(1, &vbo);

	// Binds a named buffer object to the specified buffer binding point. Give it a target (GL_ARRAY_BUFFER) to determine where to bind the buffer.
	// There are several different target parameters, GL_ARRAY_BUFFER is for vertex attributes, feel free to Google the others to find out what else there is.
	// The second paramter is the buffer object reference. If no buffer object with the given name exists, it will create one.
	// Buffer object names are unsigned integers (like vbo). Zero is a reserved value, and there is no default buffer for each target (targets, like GL_ARRAY_BUFFER).
	// Passing in zero as the buffer name (second parameter) will result in unbinding any buffer bound to that target, and frees up the memory.
	glBindBuffer(GL_ARRAY_BUFFER, vbo);

	// Creates and initializes a buffer object's data.
	// First parameter is the target, second parameter is the size of the buffer, third parameter is a pointer to the data that will copied into the buffer, and fourth parameter is the 
	// expected usage pattern of the data. Possible usage patterns: GL_STREAM_DRAW, GL_STREAM_READ, GL_STREAM_COPY, GL_STATIC_DRAW, GL_STATIC_READ, GL_STATIC_COPY, GL_DYNAMIC_DRAW, 
	// GL_DYNAMIC_READ, or GL_DYNAMIC_COPY
	// Stream means that the data will be modified once, and used only a few times at most. Static means that the data will be modified once, and used a lot. Dynamic means that the data 
	// will be modified repeatedly, and used a lot. Draw means that the data is modified by the application, and used as a source for GL drawing. Read means the data is modified by 
	// reading data from GL, and used to return that data when queried by the application. Copy means that the data is modified by reading from the GL, and used as a source for drawing.
	glBufferData(GL_ARRAY_BUFFER, sizeof(VertexFormat) * 36, &vertices[0], GL_STATIC_DRAW);

	// By default, all client-side capabilities are disabled, including all generic vertex attribute arrays.
	// When enabled, the values in a generic vertex attribute array will be accessed and used for rendering when calls are made to vertex array commands (like glDrawArrays/glDrawElements)
	// A GL_INVALID_VALUE will be generated if the index parameter is greater than or equal to GL_MAX_VERTEX_ATTRIBS
	glEnableVertexAttribArray(0);

	// Defines an array of generic vertex attribute data. Takes an index, a size specifying the number of components (in this case, floats)(has a max of 4)
	// The third parameter, type, can be GL_BYTE, GL_UNSIGNED_BYTE, GL_SHORT, GL_UNSIGNED_SHORT, GL_FIXED, or GL_FLOAT
	// The fourth parameter specifies whether to normalize fixed-point data values, the fifth parameter is the stride which is the offset (in bytes) between generic vertex attributes
	// The fifth parameter is a pointer to the first component of the first generic vertex attribute in the array. If named buffer object is bound to GL_ARRAY_BUFFER (and it is, in this case) 
	// then the pointer parameter is treated as a byte offset into the buffer object's data.
	glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(VertexFormat), (void*)16);
	// You'll note sizeof(VertexFormat) is our stride, because each vertex contains data that adds up to that size.
	// You'll also notice we offset this parameter by 16 bytes, this is because the vec3 position attribute is after the vec4 color attribute. A vec4 has 4 floats, each being 4 bytes 
	// so we offset by 4*4=16 to make sure that our first attribute is actually the position. The reason we put position after color in the struct has to do with padding.
	// For more info on padding, Google it.

	// This is our color attribute, so the offset is 0, and the size is 4 since there are 4 floats for color.
	glEnableVertexAttribArray(1);
	glVertexAttribPointer(1, 4, GL_FLOAT, GL_FALSE, sizeof(VertexFormat), (void*)0);

	// This is our normal attribute, so the offset is 16(4*4) + 12(4*3) = 28
	glEnableVertexAttribArray(2);
	glVertexAttribPointer(2, 3, GL_FLOAT, GL_FALSE, sizeof(VertexFormat), (void*)28);

	// Read in the shader code from a file.
	std::string vertShader = readShader("VertexShader.glsl");
	std::string fragShader = readShader("FragmentShader.glsl");

	// createShader consolidates all of the shader compilation code
	vertex_shader = createShader(vertShader, GL_VERTEX_SHADER);
	fragment_shader = createShader(fragShader, GL_FRAGMENT_SHADER);

	// A shader is a program that runs on your GPU instead of your CPU. In this sense, OpenGL refers to your groups of shaders as "programs".
	// Using glCreateProgram creates a shader program and returns a GLuint reference to it.
	program = glCreateProgram();
	glAttachShader(program, vertex_shader);		// This attaches our vertex shader to our program.
	glAttachShader(program, fragment_shader);	// This attaches our fragment shader to our program.

	// This links the program, using the vertex and fragment shaders to create executables to run on the GPU.
	glLinkProgram(program);
	// End of shader and program creation

	// Tell OpenGL to use the shader program you've created.
	glUseProgram(program);

	// This gets us a reference to the uniform variable in the vertex shader, which is called "trans".
	// We're using this variable as a 4x4 transformation matrix
	// Only 2 parameters required: A reference to the shader program and the name of the uniform variable within the shader code.
	uniTrans = glGetUniformLocation(program, "trans");

	// We'll also need references to the rest of our uniforms too.
	uniNumLights = glGetUniformLocation(program, "numLights");

	// Because there are so many different uniforms for the Light struct, we'll want a function to make this easier.
	setUniformAttrib(uniLightPosition, "position");
	setUniformAttrib(uniLightColor, "diffuseColor");
	setUniformAttrib(uniLightConeDir, "coneDirection");
	setUniformAttrib(uniLightConeAng, "coneAngle");
	setUniformAttrib(uniLightAttenuation, "attenuation");
	setUniformAttrib(uniLightAmbient, "ambientCoefficient");

	// Set the number of lights in your shader.
	glUniform1i(uniNumLights, 3);

	// All the Z values passed into the shader are getting reversed somehow, so we will flip them in the shader code.
	// Alternatively, you can just remember to flip them beforehand. This example has it flipping them in the shader code, so don't flip them here too or you'll just 
	// end up leaving them in the wrong direction.

	Light dirLight;
	dirLight.ambientCoefficient = 0.15f;
	// Passing in 0 for the W value identifies this as a directional light, thus the only relevant values are the position (direction), color, and ambientCoefficient.
	dirLight.position = glm::vec4(-0.2f, -0.2f, 1.0f, 0.0f);
	dirLight.diffuseColor = glm::vec4(0.10f, 0.10f, 0.10f, 1.0f);

	Light pointLight;
	pointLight.ambientCoefficient = 0.0f;
	pointLight.position = glm::vec4(-1.0f, 0.0f, 0.0f, 1.0f); // The Z value appears to be flipped for some reason, we'll have to look into that.
	pointLight.coneAngle = 360.0f; // Setting a coneAngle of 180 (I set 360 to be extra safe) guarantees that this will not be a spotlight.
	pointLight.diffuseColor = glm::vec4(0.15f, 0.15f, 0.15f, 1.0f);
	pointLight.attenuation = 0.25f;
	pointLight.coneDirection = glm::vec4(1.0f, 1.0f, 1.0f, 1.0f); // Since coneAngle is 180+, this value is irreleavant.

	Light spotLight;
	spotLight.ambientCoefficient = 0.0f;
	spotLight.position = glm::vec4(0.0f, 0.0f, -1.0f, 1.0f); // The Z value appears to be flipped for some reason, we'll have to look into that.
	spotLight.coneAngle = 7.0f;
	spotLight.diffuseColor = glm::vec4(0.5f, 0.5f, 0.5f, 1.0f);
	spotLight.attenuation = 0.25f;
	spotLight.coneDirection = glm::vec4(0.0f, 0.0f, 1.0f, 1.0f);

	// A function to help setup a given light.
	setLight(0, &dirLight);
	setLight(1, &pointLight);
	setLight(2, &spotLight);
	
	// This is not necessary, but I prefer to handle my vertices in the clockwise order. glFrontFace defines which face of the triangles you're drawing is the front.
	// Essentially, if you draw your vertices in counter-clockwise order, by default (in OpenGL) the front face will be facing you/the screen. If you draw them clockwise, the front face 
	// will face away from you. By passing in GL_CW to this function, we are saying the opposite, and now the front face will face you if you draw in the clockwise order.
	// If you don't use this, just reverse the order of the vertices in your array when you define them so that you draw the points in a counter-clockwise order.
	glFrontFace(GL_CW);

	// This is also not necessary, but more efficient and is generally good practice. By default, OpenGL will render both sides of a triangle that you draw. By enabling GL_CULL_FACE, 
	// we are telling OpenGL to only render the front face. This means that if you rotated the triangle over the X-axis, you wouldn't see the other side of the triangle as it rotated.
	glEnable(GL_CULL_FACE);

	// Determines the interpretation of polygons for rasterization. The first parameter, face, determines which polygons the mode applies to.
	// The face can be either GL_FRONT, GL_BACK, or GL_FRONT_AND_BACK
	// The mode determines how the polygons will be rasterized. GL_POINT will draw points at each vertex, GL_LINE will draw lines between the vertices, and 
	// GL_FILL will fill the area inside those lines.
	glPolygonMode(GL_FRONT, GL_FILL);
}