bool SimpleSkeletalAnimatedObject_cl::GetHeadRotation(const hkvVec3 &vTargetPos, hkvQuat &targetRot, float fMaxViewAngle)
{
  hkvMat4 objectMatrix;
  hkvMat4 parentObjectMatrix;

  // get the index of the parent bone
  int parentBoneIndex = GetMesh()->GetSkeleton()->GetBone(m_iHeadBoneIndex)->m_iParentIndex;

  // get the 4x4 matrix of the head bone and its parent in object space
  const VisSkeletalAnimResult_cl* pObjectSpaceResult = GetAnimConfig()->GetFinalResult()->GetCurrentObjectSpaceResult();
  pObjectSpaceResult->GetBoneTransformationMatrix(m_iHeadBoneIndex, objectMatrix);
  pObjectSpaceResult->GetBoneTransformationMatrix(parentBoneIndex, parentObjectMatrix);

  // get the current position of the target in object space
  hkvVec3 targetObjectspace = TransformToObjectSpace(vTargetPos);

  // get the current position of the bone in object space
  hkvVec3 boneObjectspace = objectMatrix.getTranslation();

  // calculate the look at direction in object space (just for the angle constraints)
  hkvVec3 vLookAtDir = targetObjectspace - boneObjectspace;

  // check if we are within the angle constraints
  vLookAtDir.normalizeIfNotZero();
  float fCosMax = hkvMath::cosDeg (180.f - fMaxViewAngle);
  bool bInsideFocusArea = vLookAtDir.y < fCosMax;
  if (!bInsideFocusArea)
  {
    // out of focus, so just look straight ahead
    targetRot.setIdentity();
    return false;
  }

  // create a LookAt-3x3 matrix from the bone position and the target position (both are in object space)
  // This orientation is later used to replace(!) the head bone in local space (VIS_REPLACE_BONE|VIS_LOCAL_SPACE flags)
  hkvMat3 lookatMatrix(hkvNoInitialization);
  lookatMatrix.setLookInDirectionMatrix(targetObjectspace - boneObjectspace);

  //  Apply our custom rotation matrix that tells the bone to focus with the eyes and not with the back of the head :-)
  lookatMatrix = lookatMatrix.multiply(m_RelativeHeadOrientation);

  // Invert the parents object matrix rotation to cancel out all parent bone orientations
  hkvMat3 parentObject = parentObjectMatrix.getRotationalPart();
  parentObject.invert();

  // put everything together
  hkvMat3 result = parentObject;
  result = result.multiply (lookatMatrix);

  // ...and make a quaternion from it
  targetRot.setFromMat3 (result);

  return true;
}
Ejemplo n.º 2
0
// Draw the scene to the screen
void draw() {
	// Update time
	time += 2.0f * timeStep;

	/////////////////////// PART 1: SIMULATION /////////////////////////////////

	// Grab buffers for OpenCL
	acquireGLBuffer(particles.particleBuffer[particles.currentBuffer]);
	acquireGLBuffer(particles.particleBuffer[1 - particles.currentBuffer]);

	// Prepare to run some kernels
	cl_int numParticles = NUM_PARTICLES;
	cl_int gridElements = GRID_SIZE * GRID_SIZE * GRID_SIZE;

	cl_uint workSize[3] = {numParticles, 0, 0};
	cl_uint gridWorkSize[3] = {gridElements, 0, 0};
	cl_uint workgroupSize[3] = {256, 0, 0};

	// Clear grid
	clSetKernelArg(openCLKernels.gridClearKernel, 0, sizeof(cl_mem), &particles.gridSizeBuffer);
	clSetKernelArg(openCLKernels.gridClearKernel, 1, sizeof(cl_int), &gridElements);
	clRunKernel(openCLKernels.gridClearKernel, gridWorkSize, workgroupSize);

	// Compute grid positions
	clSetKernelArg(openCLKernels.gridKernel, 0, sizeof(cl_mem), &particles.particleBuffer[particles.currentBuffer]);
	clSetKernelArg(openCLKernels.gridKernel, 1, sizeof(cl_mem), &particles.offsetBuffer);
	clSetKernelArg(openCLKernels.gridKernel, 2, sizeof(cl_mem), &particles.gridSizeBuffer);
	clSetKernelArg(openCLKernels.gridKernel, 3, sizeof(cl_int), &numParticles);
	clRunKernel(openCLKernels.gridKernel, workSize, workgroupSize);

	// Compute prefix sum for grid
	clSetKernelArg(openCLKernels.prefixSumKernel, 2, sizeof(cl_uint), (void*)&gridElements);

	int pingpong = 0;
	for(cl_int offset = 1; offset <= gridElements; offset *= 2) {
		if(offset == 1) {
			clSetKernelArg(openCLKernels.prefixSumKernel, 0, sizeof(cl_mem), (void*)&particles.gridSizeBuffer);
		}
		else {
			clSetKernelArg(openCLKernels.prefixSumKernel, 0, sizeof(cl_mem), (void*)&(pingpong == 0 ? particles.gridBuffer[0] : particles.gridBuffer[1]));
		}
		clSetKernelArg(openCLKernels.prefixSumKernel, 1, sizeof(cl_mem), (void*)&(pingpong == 0 ? particles.gridBuffer[1] : particles.gridBuffer[0]));
		clSetKernelArg(openCLKernels.prefixSumKernel, 3, sizeof(cl_int), (void*)&offset);
		clRunKernel(openCLKernels.prefixSumKernel, gridWorkSize, workgroupSize);
		pingpong = 1 - pingpong;
	}

	// Reorganize particles 
	clSetKernelArg(openCLKernels.gridReorderKernel, 0, sizeof(cl_mem), &particles.particleBuffer[particles.currentBuffer]);
	clSetKernelArg(openCLKernels.gridReorderKernel, 1, sizeof(cl_mem), &particles.particleBuffer[1 - particles.currentBuffer]);
	clSetKernelArg(openCLKernels.gridReorderKernel, 2, sizeof(cl_mem), &particles.velocityBuffer[particles.currentBuffer]);
	clSetKernelArg(openCLKernels.gridReorderKernel, 3, sizeof(cl_mem), &particles.velocityBuffer[1 - particles.currentBuffer]);
	clSetKernelArg(openCLKernels.gridReorderKernel, 4, sizeof(cl_mem), &particles.offsetBuffer);
	clSetKernelArg(openCLKernels.gridReorderKernel, 5, sizeof(cl_mem), (void*)&particles.gridSizeBuffer);
	clSetKernelArg(openCLKernels.gridReorderKernel, 6, sizeof(cl_mem), (void*)&(pingpong == 0 ? particles.gridBuffer[0] : particles.gridBuffer[1]));
	clSetKernelArg(openCLKernels.gridReorderKernel, 7, sizeof(cl_int), &numParticles);
	clRunKernel(openCLKernels.gridReorderKernel, workSize, workgroupSize);

	particle* testData = (particle*)malloc(sizeof(cl_float) * numParticles * 4);

	// Swap particle buffers
	particles.currentBuffer = 1 - particles.currentBuffer;

	// Send new cell select buffer
	int cellSelect[27];
	for(int i = 0; i < 27; i++) {
		cellSelect[i] = i;
	}
	shuffle(cellSelect, 27);
	clEnqueueWriteBuffer(clCommandQueue(), particles.cellSelectBuffer, true, 0, 27 * sizeof(cl_int), cellSelect, 0, 0, 0);
	clFinish(clCommandQueue());

	// Recalculate densities and normalized pressure derivatives
	clSetKernelArg(openCLKernels.dataKernel, 0, sizeof(cl_mem), &particles.particleBuffer[particles.currentBuffer]);
	clSetKernelArg(openCLKernels.dataKernel, 1, sizeof(cl_mem), &particles.dataBuffer);

	clSetKernelArg(openCLKernels.dataKernel, 2, sizeof(cl_mem), (void*)&particles.gridSizeBuffer);
	clSetKernelArg(openCLKernels.dataKernel, 3, sizeof(cl_mem), (void*)&(pingpong == 0 ? particles.gridBuffer[1] : particles.gridBuffer[0]));

	clSetKernelArg(openCLKernels.dataKernel, 4, sizeof(cl_mem), (void*)&particles.cellSelectBuffer);

	clSetKernelArg(openCLKernels.dataKernel, 5, sizeof(cl_int), &numParticles);
	clRunKernel(openCLKernels.dataKernel, workSize, workgroupSize);

	// Send new cell select buffer
	cellSelect[27];
	for(int i = 0; i < 27; i++) {
		cellSelect[i] = i;
	}
	shuffle(cellSelect, 27);
	clEnqueueWriteBuffer(clCommandQueue(), particles.cellSelectBuffer, true, 0, 27 * sizeof(cl_int), cellSelect, 0, 0, 0);
	clFinish(clCommandQueue());

	// Integrate position
	float dT = timeStep;
	clSetKernelArg(openCLKernels.simulationKernel, 0, sizeof(cl_mem), &particles.particleBuffer[particles.currentBuffer]);
	clSetKernelArg(openCLKernels.simulationKernel, 1, sizeof(cl_mem), &particles.particleBuffer[1 - particles.currentBuffer]);
	clSetKernelArg(openCLKernels.simulationKernel, 2, sizeof(cl_mem), &particles.velocityBuffer[particles.currentBuffer]);
	clSetKernelArg(openCLKernels.simulationKernel, 3, sizeof(cl_mem), &particles.velocityBuffer[1 - particles.currentBuffer]);
	clSetKernelArg(openCLKernels.simulationKernel, 4, sizeof(cl_mem), &particles.dataBuffer);
	
	clSetKernelArg(openCLKernels.simulationKernel, 5, sizeof(cl_mem), (void*)&particles.gridSizeBuffer);
	clSetKernelArg(openCLKernels.simulationKernel, 6, sizeof(cl_mem), (void*)&(pingpong == 0 ? particles.gridBuffer[1] : particles.gridBuffer[0]));

	clSetKernelArg(openCLKernels.simulationKernel, 7, sizeof(cl_mem), (void*)&particles.cellSelectBuffer);

	clSetKernelArg(openCLKernels.simulationKernel, 8, sizeof(cl_float), &dT);
	clSetKernelArg(openCLKernels.simulationKernel, 9, sizeof(cl_float), &time);
	clSetKernelArg(openCLKernels.simulationKernel, 10, sizeof(cl_int), &numParticles);

	clSetKernelArg(openCLKernels.simulationKernel, 11, sizeof(cl_mem), &particles.terrainBuffer);

	PaddedVector windDir = PadVector(
		TransformVector(YAxisRotationMatrix(particles.windAngle), MakeVector(1.0f, 0.0f, 0.0f))
	);
	clSetKernelArg(openCLKernels.simulationKernel, 12, sizeof(cl_float) * 4, &windDir);
	clSetKernelArg(openCLKernels.simulationKernel, 13, sizeof(cl_float), &particles.windPower);

	clRunKernel(openCLKernels.simulationKernel, workSize, workgroupSize);

	// Release buffers back to OpenGL
	releaseGLBuffer(particles.particleBuffer[particles.currentBuffer]);
	releaseGLBuffer(particles.particleBuffer[1 - particles.currentBuffer]);

	// Swap particle buffers
	particles.currentBuffer = 1 - particles.currentBuffer;

	//////////////////////// PART 2: RENDERIING ////////////////////////////////

	// Clear everything first thing.
	glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
	
	glBindFramebuffer(GL_FRAMEBUFFER, framebuffers.backgroundFBO);
	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
	
	// Activate shader.
	glUseProgram(objectShader.shaderProgram);

	// Set projection
	Matrix projection = PerspectiveMatrix(
		45.0f,
		(float)WINDOW_WIDTH/(float)WINDOW_HEIGHT,
		0.01f,
		100.0f
	);
	MatrixAsUniform(objectShader.projectionMatrix, projection);
	
	// Vertices
	glBindBuffer(GL_ARRAY_BUFFER, terrain.vertexBuffer);
	glVertexAttribPointer(
		objectShader.vertexPosition,
		4,
		GL_FLOAT,
		GL_FALSE,
		sizeof(GLfloat) * 4,
		(void*)0
	);
	glEnableVertexAttribArray(objectShader.vertexPosition);
	
	// Set modelview according to camera
	Matrix rot = lookatMatrix(camera.pos, VectorAdd(camera.pos, camera.front), camera.up);
	rot = MatrixMul(RotationMatrix(camera.elevation, MakeVector(1, 0, 0)), rot);
	Matrix trans = TranslationMatrix(-camera.pos.x, -camera.pos.y, -camera.pos.z);
	Matrix modelview =  MatrixMul(rot, trans);
	MatrixAsUniform(objectShader.modelviewMatrix, modelview);

	// Normal view matrix - inverse transpose of modelview.
	Matrix normalview = MatrixTranspose(FastMatrixInverse(modelview));
	MatrixAsUniform(objectShader.normalviewMatrix, normalview);

	// Set heightmap texture
	glActiveTexture(GL_TEXTURE0);
	glBindTexture(GL_TEXTURE_2D, terrain.heightTexture );
	glUniform1i(objectShader.terrainTexture, 0);

	// Set color textures
	glActiveTexture(GL_TEXTURE1);
	glBindTexture(GL_TEXTURE_2D, terrain.lowTexture);
	glUniform1i(objectShader.lowTexture, 1);

	glActiveTexture(GL_TEXTURE2);
	glBindTexture(GL_TEXTURE_2D, terrain.highTexture);
	glUniform1i(objectShader.highTexture, 2);

	// Turn off culling
	glDisable(GL_CULL_FACE);

	// Send element buffer to GPU and draw.
	glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, terrain.elementBuffer);

	glDrawElements(
		GL_TRIANGLES,
		512 * 512 * 6,
		GL_UNSIGNED_INT,
		(void*)0
	);
	
	// Turn culling back on
	glEnable(GL_CULL_FACE);

	// Switch to low-res viewport
	glViewport(0, 0, WINDOW_WIDTH / RESOLUTION_DIVIDER, WINDOW_HEIGHT / RESOLUTION_DIVIDER);

	// Low-res projection matrix
	Matrix projectionLowres = PerspectiveMatrix(
		45.0f,
		(float)(WINDOW_WIDTH / RESOLUTION_DIVIDER) / (float)(WINDOW_HEIGHT / RESOLUTION_DIVIDER),
		0.01f,
		100.0f
	);

	// Activate particle depth FBO
	glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
	glBindFramebuffer(GL_FRAMEBUFFER, framebuffers.particleFBO[0]);
	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

	// Activate shader
	glUseProgram(particleShader.shaderProgram);

	// Set textures
	glActiveTexture(GL_TEXTURE0);
	glBindTexture(GL_TEXTURE_2D, framebuffers.backgroundTexture);
	glUniform1i(particleShader.terrainTexture, 0);

	// Send uniforms
	MatrixAsUniform(particleShader.modelviewMatrix, modelview);
	MatrixAsUniform(particleShader.projectionMatrix, projectionLowres);
	glUniform2f(particleShader.screenSize, WINDOW_WIDTH / RESOLUTION_DIVIDER, WINDOW_HEIGHT / RESOLUTION_DIVIDER);

	// Bind new buffer and set up arrtibutes
	glBindBuffer(GL_ARRAY_BUFFER, particles.vertexBuffer[particles.currentBuffer]);
	glVertexAttribPointer(
		particleShader.vertexPosition,
		4,
		GL_FLOAT,
		GL_FALSE,
		sizeof(GLfloat) * 4,
		(void*)0
	);
	glEnableVertexAttribArray(particleShader.vertexPosition);

	// Bind element buffer and draw particles
	glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, particles.elementBuffer);
	glDrawElements(
		GL_POINTS,
		NUM_PARTICLES,
		GL_UNSIGNED_INT,
		(void*)0
	);

	// Activate particle thickness FBO
	glBindFramebuffer(GL_FRAMEBUFFER, framebuffers.particleThicknessFBO[0]);
	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

	// Activate shader
	glUseProgram(particleThicknessShader.shaderProgram);

	// Send uniforms
	MatrixAsUniform(particleThicknessShader.modelviewMatrix, modelview);
	MatrixAsUniform(particleThicknessShader.projectionMatrix, projectionLowres);
	glUniform2f(particleThicknessShader.screenSize, WINDOW_WIDTH / RESOLUTION_DIVIDER, WINDOW_HEIGHT / RESOLUTION_DIVIDER);

	// Set textures
	glActiveTexture(GL_TEXTURE0);
	glBindTexture(GL_TEXTURE_2D, framebuffers.backgroundTexture);
	glUniform1i(particleThicknessShader.terrainTexture, 0);

	// Bind new buffer and set up arrtibutes
	glBindBuffer(GL_ARRAY_BUFFER, particles.vertexBuffer[particles.currentBuffer]);
	glVertexAttribPointer(
		particleThicknessShader.vertexPosition,
		4,
		GL_FLOAT,
		GL_FALSE,
		sizeof(GLfloat) * 4,
		(void*)0
	);
	glEnableVertexAttribArray(particleThicknessShader.vertexPosition);

	// Enable additive blending and disable depth test
	glEnable(GL_BLEND);
	glBlendFunc(GL_ONE, GL_ONE);
	glDisable(GL_DEPTH_TEST);

	// Bind element buffer and draw particles, this time rendering thickness map
	glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, particles.elementBuffer);
	glDrawElements(
		GL_POINTS,
		NUM_PARTICLES,
		GL_UNSIGNED_INT,
		(void*)0
	);
	
	// Turn blending back off and depth test back on
	glDisable(GL_BLEND);
	glEnable(GL_DEPTH_TEST);

	// Activate particle velocity FBO
	glBindFramebuffer(GL_FRAMEBUFFER, framebuffers.velocityFBO);
	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

	// Activate shader
	glUseProgram(particleVelocityShader.shaderProgram);

	// Send uniforms
	MatrixAsUniform(particleVelocityShader.modelviewMatrix, modelview);
	MatrixAsUniform(particleVelocityShader.projectionMatrix, projectionLowres);
	glUniform2f(particleVelocityShader.screenSize, WINDOW_WIDTH / RESOLUTION_DIVIDER, WINDOW_HEIGHT / RESOLUTION_DIVIDER);

	// Bind new buffer and set up arrtibutes
	glBindBuffer(GL_ARRAY_BUFFER, particles.vertexBuffer[particles.currentBuffer]);
	glVertexAttribPointer(
		particleVelocityShader.vertexPosition,
		4,
		GL_FLOAT,
		GL_FALSE,
		sizeof(GLfloat) * 4,
		(void*)0
	);
	glEnableVertexAttribArray(particleVelocityShader.vertexPosition);

	// Bind element buffer and draw particles, this time rendering velocity map
	glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, particles.elementBuffer);
	glDrawElements(
		GL_POINTS,
		NUM_PARTICLES,
		GL_UNSIGNED_INT,
		(void*)0
	);

	// Curvature flow smoothing begins
	glUseProgram(curvatureFlowShader.shaderProgram);

	// Send uniforms
	glUniform1i(curvatureFlowShader.particleTexture, 0);

	glUniform2f(curvatureFlowShader.screenSize, WINDOW_WIDTH / RESOLUTION_DIVIDER, WINDOW_HEIGHT / RESOLUTION_DIVIDER);
	MatrixAsUniform(curvatureFlowShader.projectionMatrix, projectionLowres);

	// Prepare state
	glActiveTexture(GL_TEXTURE0);
	glBindBuffer(GL_ARRAY_BUFFER, screenQuad.vertexBuffer);
	glVertexAttribPointer(
		curvatureFlowShader.vertexPosition,
		3,
		GL_FLOAT,
		GL_FALSE,
		sizeof(GLfloat) * 3,
		(void*)0
	);
	glEnableVertexAttribArray(curvatureFlowShader.vertexPosition);
	glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, screenQuad.elementBuffer);

	// Smoothing loop
	glDisable(GL_DEPTH_TEST);
	pingpong = 0;
	for(int i = 0; i < smoothingIterations; i++) {
		// Bind no FBO
		glBindFramebuffer(GL_FRAMEBUFFER, 0);

		// Bind texture
		glBindTexture(GL_TEXTURE_2D, framebuffers.particleTexture[pingpong]);

		// Activate proper FBO and clear
		glBindFramebuffer(GL_FRAMEBUFFER, framebuffers.particleFBO[1 - pingpong]);

		// Draw a quad
		glDrawElements(
			GL_TRIANGLES,
			6,
			GL_UNSIGNED_INT,
			(void*)0
		);

		// Switch buffers
		pingpong = 1 - pingpong;
	}
	glEnable(GL_DEPTH_TEST);

	// Activate particle color FBO
	glBindFramebuffer(GL_FRAMEBUFFER, framebuffers.particleColorFBO);
	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

	// Liquid shading shader
	glUseProgram(liquidShadeShader.shaderProgram);

	// Bind and set textures
	glActiveTexture(GL_TEXTURE0);
	glBindTexture(GL_TEXTURE_2D, framebuffers.particleTexture[0]);
	glUniform1i(liquidShadeShader.particleTexture, 0);

	glActiveTexture(GL_TEXTURE1);
	glBindTexture(GL_TEXTURE_2D, framebuffers.particleThicknessTexture[0]);
	glUniform1i(liquidShadeShader.particleThicknessTexture, 1);

	glActiveTexture(GL_TEXTURE2);
	glBindTexture(GL_TEXTURE_2D, terrain.envTexture);
	glUniform1i(liquidShadeShader.environmentTexture, 2);

	glActiveTexture(GL_TEXTURE3);
	glBindTexture(GL_TEXTURE_2D, framebuffers.particleVelocityTexture);
	glUniform1i(liquidShadeShader.velocityTexture, 3);

	// Send uniforms
	glUniform2f(liquidShadeShader.screenSize, WINDOW_WIDTH, WINDOW_HEIGHT);
	MatrixAsUniform(liquidShadeShader.modelviewMatrix, modelview);
	MatrixAsUniform(liquidShadeShader.projectionMatrix, projection);
	glUniform1i(liquidShadeShader.useThickness, useThickness);

	// Draw a quad
    glDisable(GL_DEPTH_TEST);
	glBindBuffer(GL_ARRAY_BUFFER, screenQuad.vertexBuffer);
	glVertexAttribPointer(
		liquidShadeShader.vertexPosition,
		3,
		GL_FLOAT,
		GL_FALSE,
		sizeof(GLfloat) * 3,
		(void*)0
	);
	glEnableVertexAttribArray(liquidShadeShader.vertexPosition);
	glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, screenQuad.elementBuffer);
	glDrawElements(
		GL_TRIANGLES,
		6,
		GL_UNSIGNED_INT,
		(void*)0
	);
	glEnable(GL_DEPTH_TEST);

	// Switch back to full-res viewport
	glViewport(0, 0, WINDOW_WIDTH, WINDOW_HEIGHT);

	// Deactivate FBOs
	glBindFramebuffer(GL_FRAMEBUFFER, 0);
	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

	// Compose shader
	glUseProgram(compositionShader.shaderProgram);

	// Bind and set textures
	glActiveTexture(GL_TEXTURE0);
	glBindTexture(GL_TEXTURE_2D, terrain.envTexture);
	glUniform1i(compositionShader.backgroundTexture, 0);

	glActiveTexture(GL_TEXTURE1);
	glBindTexture(GL_TEXTURE_2D, framebuffers.particleColorTexture);
	glUniform1i(compositionShader.particleTexture, 1);

	glActiveTexture(GL_TEXTURE2);
	glBindTexture(GL_TEXTURE_2D, framebuffers.backgroundTexture);
	glUniform1i(compositionShader.terrainTexture, 2);

	// Send uniforms
	MatrixAsUniform(compositionShader.modelviewMatrix, modelview);
	
	// Draw a quad
    glDisable(GL_DEPTH_TEST);
	glBindBuffer(GL_ARRAY_BUFFER, screenQuad.vertexBuffer);
	glVertexAttribPointer(
		compositionShader.vertexPosition,
		3,
		GL_FLOAT,
		GL_FALSE,
		sizeof(GLfloat) * 3,
		(void*)0
	);
	glEnableVertexAttribArray(compositionShader.vertexPosition);
	glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, screenQuad.elementBuffer);
	glDrawElements(
		GL_TRIANGLES,
		6,
		GL_UNSIGNED_INT,
		(void*)0
	);
	glEnable(GL_DEPTH_TEST);

	// Switch drawing area and displayed area.
	glutSwapBuffers();
}