Jason McKesson avatar Jason McKesson committed 4aed14f

Tut12: Gamma correction implemented.

Comments (0)

Files changed (8)

Tut 12 Dynamic Range/Gamma Correction.cpp

+#include <algorithm>
+#include <string>
+#include <vector>
+#include <stack>
+#include <math.h>
+#include <glloader/gl_3_3_comp.h>
+#include <GL/freeglut.h>
+#include "../framework/framework.h"
+#include "../framework/Mesh.h"
+#include "../framework/MatrixStack.h"
+#include "../framework/MousePole.h"
+#include "../framework/ObjectPole.h"
+#include "../framework/Timer.h"
+#include <glm/glm.hpp>
+#include <glm/gtc/type_ptr.hpp>
+
+#include "Lights.h"
+#include "Scene.h"
+
+#define ARRAY_COUNT( array ) (sizeof( array ) / (sizeof( array[0] ) * (sizeof( array ) != sizeof(void*) || sizeof( array[0] ) <= sizeof(void*))))
+
+struct UnlitProgData
+{
+	GLuint theProgram;
+
+	GLuint objectColorUnif;
+	GLuint cameraToClipMatrixUnif;
+	GLuint modelToCameraMatrixUnif;
+
+	void SetWindowData(const glm::mat4 cameraToClip)
+	{
+		glUseProgram(theProgram);
+		glUniformMatrix4fv(cameraToClipMatrixUnif, 1, GL_FALSE,
+			glm::value_ptr(cameraToClip));
+		glUseProgram(0);
+	}
+};
+
+float g_fzNear = 1.0f;
+float g_fzFar = 1000.0f;
+
+struct Shaders
+{
+	const char *fileVertexShader;
+	const char *fileFragmentShader;
+};
+
+ProgramData g_Programs[LP_MAX_LIGHTING_PROGRAM_TYPES];
+Shaders g_ShaderFiles[LP_MAX_LIGHTING_PROGRAM_TYPES] =
+{
+	{"PCN.vert", "DiffuseSpecularGamma.frag"},
+	{"PCN.vert", "DiffuseOnlyGamma.frag"},
+
+	{"PN.vert", "DiffuseSpecularMtlGamma.frag"},
+	{"PN.vert", "DiffuseOnlyMtlGamma.frag"},
+};
+
+UnlitProgData g_Unlit;
+
+const int g_materialBlockIndex = 0;
+const int g_lightBlockIndex = 1;
+const int g_projectionBlockIndex = 2;
+
+UnlitProgData LoadUnlitProgram(const std::string &strVertexShader, const std::string &strFragmentShader)
+{
+	std::vector<GLuint> shaderList;
+
+	shaderList.push_back(Framework::LoadShader(GL_VERTEX_SHADER, strVertexShader));
+	shaderList.push_back(Framework::LoadShader(GL_FRAGMENT_SHADER, strFragmentShader));
+
+	UnlitProgData data;
+	data.theProgram = Framework::CreateProgram(shaderList);
+	data.modelToCameraMatrixUnif = glGetUniformLocation(data.theProgram, "modelToCameraMatrix");
+	data.objectColorUnif = glGetUniformLocation(data.theProgram, "objectColor");
+
+	GLuint projectionBlock = glGetUniformBlockIndex(data.theProgram, "Projection");
+	glUniformBlockBinding(data.theProgram, projectionBlock, g_projectionBlockIndex);
+
+	return data;
+}
+
+ProgramData LoadLitProgram(const std::string &strVertexShader, const std::string &strFragmentShader)
+{
+	std::vector<GLuint> shaderList;
+
+	shaderList.push_back(Framework::LoadShader(GL_VERTEX_SHADER, strVertexShader));
+	shaderList.push_back(Framework::LoadShader(GL_FRAGMENT_SHADER, strFragmentShader));
+
+	ProgramData data;
+	data.theProgram = Framework::CreateProgram(shaderList);
+	data.modelToCameraMatrixUnif = glGetUniformLocation(data.theProgram, "modelToCameraMatrix");
+
+	data.normalModelToCameraMatrixUnif = glGetUniformLocation(data.theProgram, "normalModelToCameraMatrix");
+
+	GLuint materialBlock = glGetUniformBlockIndex(data.theProgram, "Material");
+	GLuint lightBlock = glGetUniformBlockIndex(data.theProgram, "Light");
+	GLuint projectionBlock = glGetUniformBlockIndex(data.theProgram, "Projection");
+
+	glUniformBlockBinding(data.theProgram, materialBlock, g_materialBlockIndex);
+	glUniformBlockBinding(data.theProgram, lightBlock, g_lightBlockIndex);
+	glUniformBlockBinding(data.theProgram, projectionBlock, g_projectionBlockIndex);
+
+	return data;
+}
+
+void InitializePrograms()
+{
+	for(int iProg = 0; iProg < LP_MAX_LIGHTING_PROGRAM_TYPES; iProg++)
+	{
+		g_Programs[iProg] = LoadLitProgram(
+			g_ShaderFiles[iProg].fileVertexShader, g_ShaderFiles[iProg].fileFragmentShader);
+	}
+
+	g_Unlit = LoadUnlitProgram("PosTransform.vert", "UniformColor.frag");
+}
+
+const ProgramData &GetProgram(LightingProgramTypes eType)
+{
+	return g_Programs[eType];
+}
+
+
+LightManager g_lights;
+
+Framework::RadiusDef radiusDef = {50.0f, 3.0f, 80.0f, 4.0f, 1.0f};
+glm::vec3 objectCenter = glm::vec3(-59.5f, 4.0f, 65.0f);
+
+Framework::MousePole g_mousePole(objectCenter, radiusDef);
+
+namespace
+{
+	void MouseMotion(int x, int y)
+	{
+		g_mousePole.GLUTMouseMove(glm::ivec2(x, y));
+		glutPostRedisplay();
+	}
+
+	void MouseButton(int button, int state, int x, int y)
+	{
+		g_mousePole.GLUTMouseButton(button, state, glm::ivec2(x, y));
+		glutPostRedisplay();
+	}
+
+	void MouseWheel(int wheel, int direction, int x, int y)
+	{
+		g_mousePole.GLUTMouseWheel(direction, glm::ivec2(x, y));
+		glutPostRedisplay();
+	}
+}
+
+struct ProjectionBlock
+{
+	glm::mat4 cameraToClipMatrix;
+};
+
+GLuint g_lightUniformBuffer;
+GLuint g_materialUniformBuffer;
+GLuint g_projectionUniformBuffer;
+
+const glm::vec4 g_skyDaylightColor = glm::vec4(0.65f, 0.65f, 1.0f, 1.0f);
+
+void SetupHDRLighting()
+{
+	SunlightValueHDR values[] =
+	{
+		{ 0.0f/24.0f, glm::vec4(0.6f, 0.6f, 0.6f, 1.0f), glm::vec4(1.8f, 1.8f, 1.8f, 1.0f), g_skyDaylightColor, 3.0f},
+		{ 4.5f/24.0f, glm::vec4(0.6f, 0.6f, 0.6f, 1.0f), glm::vec4(1.8f, 1.8f, 1.8f, 1.0f), g_skyDaylightColor, 3.0f},
+		{ 6.5f/24.0f, glm::vec4(0.225f, 0.075f, 0.075f, 1.0f), glm::vec4(0.45f, 0.15f, 0.15f, 1.0f), glm::vec4(0.5f, 0.1f, 0.1f, 1.0f), 1.5f},
+		{ 8.0f/24.0f, glm::vec4(0.0f, 0.0f, 0.0f, 1.0f), glm::vec4(0.0f, 0.0f, 0.0f, 1.0f), glm::vec4(0.0f, 0.0f, 0.0f, 1.0f), 1.0f},
+		{18.0f/24.0f, glm::vec4(0.0f, 0.0f, 0.0f, 1.0f), glm::vec4(0.0f, 0.0f, 0.0f, 1.0f), glm::vec4(0.0f, 0.0f, 0.0f, 1.0f), 1.0f},
+		{19.5f/24.0f, glm::vec4(0.225f, 0.075f, 0.075f, 1.0f), glm::vec4(0.45f, 0.15f, 0.15f, 1.0f), glm::vec4(0.5f, 0.1f, 0.1f, 1.0f), 1.5f},
+		{20.5f/24.0f, glm::vec4(0.6f, 0.6f, 0.6f, 1.0f), glm::vec4(1.8f, 1.8f, 1.8f, 1.0f), g_skyDaylightColor, 3.0f},
+	};
+
+	g_lights.SetSunlightValues(values, 7);
+
+	g_lights.SetPointLightIntensity(0, glm::vec4(0.6f, 0.6f, 0.6f, 1.0f));
+	g_lights.SetPointLightIntensity(1, glm::vec4(0.0f, 0.0f, 0.7f, 1.0f));
+	g_lights.SetPointLightIntensity(2, glm::vec4(0.7f, 0.0f, 0.0f, 1.0f));
+}
+
+Scene *g_pScene = NULL;
+
+//Called after the window and OpenGL are initialized. Called exactly once, before the main loop.
+void init()
+{
+	InitializePrograms();
+
+	try
+	{
+		g_pScene = new Scene();
+	}
+	catch(std::exception &except)
+	{
+		printf(except.what());
+		throw;
+	}
+
+	SetupHDRLighting();
+
+	g_lights.CreateTimer("tetra", Framework::Timer::TT_LOOP, 2.5f);
+
+	glutMouseFunc(MouseButton);
+ 	glutMotionFunc(MouseMotion);
+	glutMouseWheelFunc(MouseWheel);
+
+	glEnable(GL_CULL_FACE);
+	glCullFace(GL_BACK);
+	glFrontFace(GL_CW);
+
+	const float depthZNear = 0.0f;
+	const float depthZFar = 1.0f;
+
+	glEnable(GL_DEPTH_TEST);
+	glDepthMask(GL_TRUE);
+	glDepthFunc(GL_LEQUAL);
+	glDepthRange(depthZNear, depthZFar);
+	glEnable(GL_DEPTH_CLAMP);
+
+	//Setup our Uniform Buffers
+	glGenBuffers(1, &g_lightUniformBuffer);
+	glBindBuffer(GL_UNIFORM_BUFFER, g_lightUniformBuffer);
+	glBufferData(GL_UNIFORM_BUFFER, sizeof(LightBlock), NULL, GL_DYNAMIC_DRAW);
+
+	glGenBuffers(1, &g_projectionUniformBuffer);
+	glBindBuffer(GL_UNIFORM_BUFFER, g_projectionUniformBuffer);
+	glBufferData(GL_UNIFORM_BUFFER, sizeof(ProjectionBlock), NULL, GL_DYNAMIC_DRAW);
+
+	//Bind the static buffers.
+	glBindBufferRange(GL_UNIFORM_BUFFER, g_lightBlockIndex, g_lightUniformBuffer,
+		0, sizeof(LightBlock));
+
+	glBindBufferRange(GL_UNIFORM_BUFFER, g_projectionBlockIndex, g_projectionUniformBuffer,
+		0, sizeof(ProjectionBlock));
+
+	glBindBuffer(GL_UNIFORM_BUFFER, 0);
+}
+
+bool g_bDrawCameraPos = false;
+bool g_bDrawLights = true;
+
+bool g_isGammaCorrect = false;
+float g_gammaValue = 2.2f;
+
+glm::vec4 GammaCorrect(const glm::vec4 &input, float gamma)
+{
+	glm::vec4 ret;
+	ret[0] = powf(input[0], 1.0f / gamma);
+	ret[1] = powf(input[1], 1.0f / gamma);
+	ret[2] = powf(input[2], 1.0f / gamma);
+	ret[3] = input[3];
+
+	return ret;
+}
+
+//Called to update the display.
+//You should call glutSwapBuffers after all of your rendering to display what you rendered.
+//If you need continuous updates of the screen, call glutPostRedisplay() at the end of the function.
+void display()
+{
+	g_lights.UpdateTime();
+
+	float gamma = g_isGammaCorrect ? g_gammaValue : 1.0f;
+
+	glm::vec4 bkg = GammaCorrect(g_lights.GetBackgroundColor(), gamma);
+
+	glClearColor(bkg[0], bkg[1], bkg[2], bkg[3]);
+	glClearDepth(1.0f);
+	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+
+	Framework::MatrixStack modelMatrix;
+	modelMatrix.SetMatrix(g_mousePole.CalcMatrix());
+
+	const glm::mat4 &worldToCamMat = modelMatrix.Top();
+	LightBlockGamma lightData = g_lights.GetLightInformationGamma(worldToCamMat);
+	lightData.gamma = gamma;
+
+	glBindBuffer(GL_UNIFORM_BUFFER, g_lightUniformBuffer);
+	glBufferSubData(GL_UNIFORM_BUFFER, 0, sizeof(lightData), &lightData);
+	glBindBuffer(GL_UNIFORM_BUFFER, 0);
+
+	if(g_pScene)
+	{
+		Framework::MatrixStackPusher push(modelMatrix);
+
+		g_pScene->Draw(modelMatrix, g_materialBlockIndex, g_lights.GetTimerValue("tetra"));
+	}
+
+	{
+		Framework::MatrixStackPusher push(modelMatrix);
+		//Render the sun
+		{
+			Framework::MatrixStackPusher push(modelMatrix);
+
+			glm::vec3 sunlightDir(g_lights.GetSunlightDirection());
+			modelMatrix.Translate(sunlightDir * 500.0f);
+			modelMatrix.Scale(30.0f, 30.0f, 30.0f);
+
+			glUseProgram(g_Unlit.theProgram);
+			glUniformMatrix4fv(g_Unlit.modelToCameraMatrixUnif, 1, GL_FALSE,
+				glm::value_ptr(modelMatrix.Top()));
+
+			glm::vec4 lightColor = GammaCorrect(g_lights.GetSunlightIntensity(), gamma);
+			glUniform4fv(g_Unlit.objectColorUnif, 1, glm::value_ptr(lightColor));
+			g_pScene->GetSphereMesh()->Render("flat");
+		}
+
+		//Render the lights
+		if(g_bDrawLights)
+		{
+			for(int light = 0; light < g_lights.GetNumberOfPointLights(); light++)
+			{
+				Framework::MatrixStackPusher push(modelMatrix);
+
+				modelMatrix.Translate(g_lights.GetWorldLightPosition(light));
+
+				glUseProgram(g_Unlit.theProgram);
+				glUniformMatrix4fv(g_Unlit.modelToCameraMatrixUnif, 1, GL_FALSE,
+					glm::value_ptr(modelMatrix.Top()));
+
+				glm::vec4 lightColor = GammaCorrect(g_lights.GetPointLightIntensity(light), gamma);
+				glUniform4fv(g_Unlit.objectColorUnif, 1, glm::value_ptr(lightColor));
+				g_pScene->GetCubeMesh()->Render("flat");
+			}
+		}
+
+		if(g_bDrawCameraPos)
+		{
+			Framework::MatrixStackPusher push(modelMatrix);
+
+			modelMatrix.SetIdentity();
+			modelMatrix.Translate(glm::vec3(0.0f, 0.0f, -g_mousePole.GetLookAtDistance()));
+
+			glDisable(GL_DEPTH_TEST);
+			glDepthMask(GL_FALSE);
+			glUseProgram(g_Unlit.theProgram);
+			glUniformMatrix4fv(g_Unlit.modelToCameraMatrixUnif, 1, GL_FALSE,
+				glm::value_ptr(modelMatrix.Top()));
+			glUniform4f(g_Unlit.objectColorUnif, 0.25f, 0.25f, 0.25f, 1.0f);
+			g_pScene->GetCubeMesh()->Render("flat");
+			glDepthMask(GL_TRUE);
+			glEnable(GL_DEPTH_TEST);
+			glUniform4f(g_Unlit.objectColorUnif, 1.0f, 1.0f, 1.0f, 1.0f);
+			g_pScene->GetCubeMesh()->Render("flat");
+		}
+	}
+
+	glutPostRedisplay();
+	glutSwapBuffers();
+}
+
+
+//Called whenever the window is resized. The new window size is given, in pixels.
+//This is an opportunity to call glViewport or glScissor to keep up with the change in size.
+void reshape (int w, int h)
+{
+	Framework::MatrixStack persMatrix;
+	persMatrix.Perspective(45.0f, (h / (float)w), g_fzNear, g_fzFar);
+
+	ProjectionBlock projData;
+	projData.cameraToClipMatrix = persMatrix.Top();
+
+	glBindBuffer(GL_UNIFORM_BUFFER, g_projectionUniformBuffer);
+	glBufferSubData(GL_UNIFORM_BUFFER, 0, sizeof(ProjectionBlock), &projData);
+	glBindBuffer(GL_UNIFORM_BUFFER, 0);
+
+	glViewport(0, 0, (GLsizei) w, (GLsizei) h);
+	glutPostRedisplay();
+}
+
+
+TimerTypes g_eTimerMode = TIMER_ALL;
+
+//Called whenever a key on the keyboard was pressed.
+//The key is given by the ''key'' parameter, which is in ASCII.
+//It's often a good idea to have the escape key (ASCII value 27) call glutLeaveMainLoop() to 
+//exit the program.
+void keyboard(unsigned char key, int x, int y)
+{
+	bool bChangedShininess = false;
+	bool bChangedLightModel = false;
+	switch (key)
+	{
+	case 27:
+		delete g_pScene;
+		g_pScene = NULL;
+		glutLeaveMainLoop();
+		break;
+		
+	case 'p': g_lights.TogglePause(g_eTimerMode); break;
+	case '-': g_lights.RewindTime(g_eTimerMode, 1.0f); break;
+	case '=': g_lights.FastForwardTime(g_eTimerMode, 1.0f); break;
+	case 't': g_bDrawCameraPos = !g_bDrawCameraPos; break;
+	case '1': g_eTimerMode = TIMER_ALL; printf("All\n"); break;
+	case '2': g_eTimerMode = TIMER_SUN; printf("Sun\n"); break;
+	case '3': g_eTimerMode = TIMER_LIGHTS; printf("Lights\n"); break;
+
+	case 'l':
+		g_isGammaCorrect = !g_isGammaCorrect;
+		if(g_isGammaCorrect)
+			printf("Gamma on!\n");
+		else
+			printf("Gamma off!\n");
+		break;
+
+	case 32:
+		{
+			float sunAlpha = g_lights.GetSunTime();
+			float sunTimeHours = sunAlpha * 24.0f + 12.0f;
+			sunTimeHours = sunTimeHours > 24.0f ? sunTimeHours - 24.0f : sunTimeHours;
+			int sunHours = int(sunTimeHours);
+			float sunTimeMinutes = (sunTimeHours - sunHours) * 60.0f;
+			int sunMinutes = int(sunTimeMinutes);
+			printf("%02i:%02i\n", sunHours, sunMinutes);
+		}
+		break;
+	}
+
+	g_mousePole.GLUTKeyOffset(key, 5.0f, 1.0f);
+}
+
+

Tut 12 Dynamic Range/Lights.cpp

 	return lightData;
 }
 
+LightBlockGamma LightManager::GetLightInformationGamma( const glm::mat4 &worldToCameraMat ) const
+{
+	LightBlockHDR lightDataHdr = GetLightInformationHDR(worldToCameraMat);
+	LightBlockGamma lightData;
+
+	memcpy(&lightData, &lightDataHdr, sizeof(LightBlockGamma));
+
+	return lightData;
+}
+
 glm::vec4 LightManager::GetSunlightDirection() const
 {
 	float angle = 2.0f * 3.14159f * m_sunTimer.GetAlpha();

Tut 12 Dynamic Range/Lights.h

 	PerLight lights[NUMBER_OF_LIGHTS];
 };
 
+struct LightBlockGamma
+{
+	glm::vec4 ambientIntensity;
+	float lightAttenuation;
+	float maxIntensity;
+	float gamma;
+	float padding;
+	PerLight lights[NUMBER_OF_LIGHTS];
+};
+
 struct SunlightValue
 {
 	float normTime;
 
 	LightBlock GetLightInformation(const glm::mat4 &worldToCameraMat) const;
 	LightBlockHDR GetLightInformationHDR(const glm::mat4 &worldToCameraMat) const;
+	LightBlockGamma GetLightInformationGamma(const glm::mat4 &worldToCameraMat) const;
 
 	glm::vec4 GetBackgroundColor() const;
 	float GetMaxIntensity() const;

Tut 12 Dynamic Range/data/DiffuseOnlyGamma.frag

+#version 330
+
+in vec4 diffuseColor;
+in vec3 vertexNormal;
+in vec3 cameraSpacePosition;
+
+out vec4 outputColor;
+
+layout(std140) uniform;
+
+uniform Material
+{
+	vec4 diffuseColor;
+	vec4 specularColor;
+	float specularShininess;
+} Mtl;
+
+struct PerLight
+{
+	vec4 cameraSpaceLightPos;
+	vec4 lightIntensity;
+};
+
+const int numberOfLights = 4;
+
+uniform Light
+{
+	vec4 ambientIntensity;
+	float lightAttenuation;
+	float maxIntensity;
+	float gamma;
+	PerLight lights[numberOfLights];
+} Lgt;
+
+
+float CalcAttenuation(in vec3 cameraSpacePosition,
+	in vec3 cameraSpaceLightPos,
+	out vec3 lightDirection)
+{
+	vec3 lightDifference =  cameraSpaceLightPos - cameraSpacePosition;
+	float lightDistanceSqr = dot(lightDifference, lightDifference);
+	lightDirection = lightDifference * inversesqrt(lightDistanceSqr);
+	
+	return (1 / ( 1.0 + Lgt.lightAttenuation * lightDistanceSqr));
+}
+
+vec4 ComputeLighting(in PerLight lightData)
+{
+	vec3 lightDir;
+	vec4 lightIntensity;
+	if(lightData.cameraSpaceLightPos.w == 0.0)
+	{
+		lightDir = vec3(lightData.cameraSpaceLightPos);
+		lightIntensity = lightData.lightIntensity;
+	}
+	else
+	{
+		float atten = CalcAttenuation(cameraSpacePosition,
+			lightData.cameraSpaceLightPos.xyz, lightDir);
+		lightIntensity = atten * lightData.lightIntensity;
+	}
+	
+	vec3 surfaceNormal = normalize(vertexNormal);
+	float cosAngIncidence = dot(surfaceNormal, lightDir);
+	cosAngIncidence = cosAngIncidence < 0.0001 ? 0.0 : cosAngIncidence;
+	
+	vec4 lighting = diffuseColor * lightIntensity * cosAngIncidence;
+	
+	return lighting;
+}
+
+void main()
+{
+	vec4 accumLighting = diffuseColor * Lgt.ambientIntensity;
+	for(int light = 0; light < numberOfLights; light++)
+	{
+		accumLighting += ComputeLighting(Lgt.lights[light]);
+	}
+	
+	accumLighting = accumLighting / Lgt.maxIntensity;
+	vec4 gamma = vec4(1.0 / Lgt.gamma);
+	gamma.w = 1.0;
+	outputColor = pow(accumLighting, gamma);
+}

Tut 12 Dynamic Range/data/DiffuseOnlyMtlGamma.frag

+#version 330
+
+in vec3 vertexNormal;
+in vec3 cameraSpacePosition;
+
+out vec4 outputColor;
+
+layout(std140) uniform;
+
+uniform Material
+{
+	vec4 diffuseColor;
+	vec4 specularColor;
+	float specularShininess;
+} Mtl;
+
+struct PerLight
+{
+	vec4 cameraSpaceLightPos;
+	vec4 lightIntensity;
+};
+
+const int numberOfLights = 4;
+
+uniform Light
+{
+	vec4 ambientIntensity;
+	float lightAttenuation;
+	float maxIntensity;
+	float gamma;
+	PerLight lights[numberOfLights];
+} Lgt;
+
+
+float CalcAttenuation(in vec3 cameraSpacePosition,
+	in vec3 cameraSpaceLightPos,
+	out vec3 lightDirection)
+{
+	vec3 lightDifference =  cameraSpaceLightPos - cameraSpacePosition;
+	float lightDistanceSqr = dot(lightDifference, lightDifference);
+	lightDirection = lightDifference * inversesqrt(lightDistanceSqr);
+	
+	return (1 / ( 1.0 + Lgt.lightAttenuation * lightDistanceSqr));
+}
+
+vec4 ComputeLighting(in PerLight lightData)
+{
+	vec3 lightDir;
+	vec4 lightIntensity;
+	if(lightData.cameraSpaceLightPos.w == 0.0)
+	{
+		lightDir = vec3(lightData.cameraSpaceLightPos);
+		lightIntensity = lightData.lightIntensity;
+	}
+	else
+	{
+		float atten = CalcAttenuation(cameraSpacePosition,
+			lightData.cameraSpaceLightPos.xyz, lightDir);
+		lightIntensity = atten * lightData.lightIntensity;
+	}
+	
+	vec3 surfaceNormal = normalize(vertexNormal);
+	float cosAngIncidence = dot(surfaceNormal, lightDir);
+	cosAngIncidence = cosAngIncidence < 0.0001 ? 0.0 : cosAngIncidence;
+	
+	vec4 lighting = Mtl.diffuseColor * lightIntensity * cosAngIncidence;
+	
+	return lighting;
+}
+
+void main()
+{
+	vec4 accumLighting = Mtl.diffuseColor * Lgt.ambientIntensity;
+	for(int light = 0; light < numberOfLights; light++)
+	{
+		accumLighting += ComputeLighting(Lgt.lights[light]);
+	}
+	
+	accumLighting = accumLighting / Lgt.maxIntensity;
+	vec4 gamma = vec4(1.0 / Lgt.gamma);
+	gamma.w = 1.0;
+	outputColor = pow(accumLighting, gamma);
+}

Tut 12 Dynamic Range/data/DiffuseSpecularGamma.frag

+#version 330
+
+in vec4 diffuseColor;
+in vec3 vertexNormal;
+in vec3 cameraSpacePosition;
+
+out vec4 outputColor;
+
+layout(std140) uniform;
+
+uniform Material
+{
+	vec4 diffuseColor;
+	vec4 specularColor;
+	float specularShininess;
+} Mtl;
+
+struct PerLight
+{
+	vec4 cameraSpaceLightPos;
+	vec4 lightIntensity;
+};
+
+const int numberOfLights = 4;
+
+uniform Light
+{
+	vec4 ambientIntensity;
+	float lightAttenuation;
+	float maxIntensity;
+	float gamma;
+	PerLight lights[numberOfLights];
+} Lgt;
+
+
+float CalcAttenuation(in vec3 cameraSpacePosition,
+	in vec3 cameraSpaceLightPos,
+	out vec3 lightDirection)
+{
+	vec3 lightDifference =  cameraSpaceLightPos - cameraSpacePosition;
+	float lightDistanceSqr = dot(lightDifference, lightDifference);
+	lightDirection = lightDifference * inversesqrt(lightDistanceSqr);
+	
+	return (1 / ( 1.0 + Lgt.lightAttenuation * lightDistanceSqr));
+}
+
+vec4 ComputeLighting(in PerLight lightData)
+{
+	vec3 lightDir;
+	vec4 lightIntensity;
+	if(lightData.cameraSpaceLightPos.w == 0.0)
+	{
+		lightDir = vec3(lightData.cameraSpaceLightPos);
+		lightIntensity = lightData.lightIntensity;
+	}
+	else
+	{
+		float atten = CalcAttenuation(cameraSpacePosition,
+			lightData.cameraSpaceLightPos.xyz, lightDir);
+		lightIntensity = atten * lightData.lightIntensity;
+	}
+	
+	vec3 surfaceNormal = normalize(vertexNormal);
+	float cosAngIncidence = dot(surfaceNormal, lightDir);
+	cosAngIncidence = cosAngIncidence < 0.0001 ? 0.0 : cosAngIncidence;
+	
+	vec3 viewDirection = normalize(-cameraSpacePosition);
+	
+	vec3 halfAngle = normalize(lightDir + viewDirection);
+	float angleNormalHalf = acos(dot(halfAngle, surfaceNormal));
+	float exponent = angleNormalHalf / Mtl.specularShininess;
+	exponent = -(exponent * exponent);
+	float gaussianTerm = exp(exponent);
+
+	gaussianTerm = cosAngIncidence != 0.0 ? gaussianTerm : 0.0;
+	
+	vec4 lighting = diffuseColor * lightIntensity * cosAngIncidence;
+	lighting += Mtl.specularColor * lightIntensity * gaussianTerm;
+	
+	return lighting;
+}
+
+void main()
+{
+	vec4 accumLighting = diffuseColor * Lgt.ambientIntensity;
+	for(int light = 0; light < numberOfLights; light++)
+	{
+		accumLighting += ComputeLighting(Lgt.lights[light]);
+	}
+	
+	accumLighting = accumLighting / Lgt.maxIntensity;
+	vec4 gamma = vec4(1.0 / Lgt.gamma);
+	gamma.w = 1.0;
+	outputColor = pow(accumLighting, gamma);
+}

Tut 12 Dynamic Range/data/DiffuseSpecularMtlGamma.frag

+#version 330
+
+in vec3 vertexNormal;
+in vec3 cameraSpacePosition;
+
+out vec4 outputColor;
+
+layout(std140) uniform;
+
+uniform Material
+{
+	vec4 diffuseColor;
+	vec4 specularColor;
+	float specularShininess;
+} Mtl;
+
+struct PerLight
+{
+	vec4 cameraSpaceLightPos;
+	vec4 lightIntensity;
+};
+
+const int numberOfLights = 4;
+
+uniform Light
+{
+	vec4 ambientIntensity;
+	float lightAttenuation;
+	float maxIntensity;
+	float gamma;
+	PerLight lights[numberOfLights];
+} Lgt;
+
+
+float CalcAttenuation(in vec3 cameraSpacePosition,
+	in vec3 cameraSpaceLightPos,
+	out vec3 lightDirection)
+{
+	vec3 lightDifference =  cameraSpaceLightPos - cameraSpacePosition;
+	float lightDistanceSqr = dot(lightDifference, lightDifference);
+	lightDirection = lightDifference * inversesqrt(lightDistanceSqr);
+	
+	return (1 / ( 1.0 + Lgt.lightAttenuation * lightDistanceSqr));
+}
+
+vec4 ComputeLighting(in PerLight lightData)
+{
+	vec3 lightDir;
+	vec4 lightIntensity;
+	if(lightData.cameraSpaceLightPos.w == 0.0)
+	{
+		lightDir = vec3(lightData.cameraSpaceLightPos);
+		lightIntensity = lightData.lightIntensity;
+	}
+	else
+	{
+		float atten = CalcAttenuation(cameraSpacePosition,
+			lightData.cameraSpaceLightPos.xyz, lightDir);
+		lightIntensity = atten * lightData.lightIntensity;
+	}
+	
+	vec3 surfaceNormal = normalize(vertexNormal);
+	float cosAngIncidence = dot(surfaceNormal, lightDir);
+	cosAngIncidence = cosAngIncidence < 0.0001 ? 0.0 : cosAngIncidence;
+	
+	vec3 viewDirection = normalize(-cameraSpacePosition);
+	
+	vec3 halfAngle = normalize(lightDir + viewDirection);
+	float angleNormalHalf = acos(dot(halfAngle, surfaceNormal));
+	float exponent = angleNormalHalf / Mtl.specularShininess;
+	exponent = -(exponent * exponent);
+	float gaussianTerm = exp(exponent);
+
+	gaussianTerm = cosAngIncidence != 0.0 ? gaussianTerm : 0.0;
+	
+	vec4 lighting = Mtl.diffuseColor * lightIntensity * cosAngIncidence;
+	lighting += Mtl.specularColor * lightIntensity * gaussianTerm;
+	
+	return lighting;
+}
+
+void main()
+{
+	vec4 accumLighting = Mtl.diffuseColor * Lgt.ambientIntensity;
+	for(int light = 0; light < numberOfLights; light++)
+	{
+		accumLighting += ComputeLighting(Lgt.lights[light]);
+	}
+	
+	accumLighting = accumLighting / Lgt.maxIntensity;
+	vec4 gamma = vec4(1.0 / Lgt.gamma);
+	gamma.w = 1.0;
+	outputColor = pow(accumLighting, gamma);
+}

Tut 12 Dynamic Range/tutorials.lua

 	"data/DiffuseSpecularMtl.frag", "data/DiffuseOnlyMtl.frag"
 )
 
+SetupProject("Tut 12 Gamma Correction", "Gamma Correction.cpp",
+	"Lights.h", "Lights.cpp", "Scene.h", "Scene.cpp",
+	"data/PNC.vert", "data/PN.vert",
+	"data/DiffuseSpecular.frag", "data/DiffuseOnly.frag",
+	"data/DiffuseSpecularMtl.frag", "data/DiffuseOnlyMtl.frag"
+)
+
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.