Commits

Jason McKesson committed 2bfc6e4

Lights now move based on constant velocity interpolators.

Comments (0)

Files changed (4)

Tut 12 Dynamic Range/Lights.cpp

 #include <stack>
 #include <math.h>
 #include "Lights.h"
+#include <glm/glm.hpp>
 
-static float g_fLightHeight = 5.5f;
+static float g_fLightHeight = 10.5f;
 static float g_fLightRadius = 70.0f;
 
 glm::vec4 CalcLightPosition(const Framework::Timer &timer, float alphaOffset)
 
 const float g_fLightAttenuation = 1.0f / (15.0f * 15.0f);
 
+float distance(const glm::vec3 &lhs, const glm::vec3 &rhs)
+{
+	return glm::length(rhs - lhs);
+}
+
 LightManager::LightManager()
-	: keyLightTimer(Framework::Timer::TT_LOOP, 5.0f)
-	, ambientInterpolator(false, 5)
+	: m_keyLightTimer(Framework::Timer::TT_LOOP, 5.0f)
+	, m_ambientInterpolator(true)
 {
-	ambientInterpolator.AppendValue(glm::vec4(0.2f, 0.2f, 0.2f, 1.0f));
-	ambientInterpolator.AppendValue(glm::vec4(0.0f, 0.0f, 0.0f, 1.0f));
-	ambientInterpolator.AppendValue(glm::vec4(0.7f, 0.7f, 0.7f, 1.0f));
-	ambientInterpolator.AppendValue(glm::vec4(0.0f, 0.5f, 0.0f, 1.0f));
-	ambientInterpolator.AppendValue(glm::vec4(0.2f, 0.2f, 0.2f, 1.0f));
+	std::vector<glm::vec4> ambientValues;
+	ambientValues.reserve(4);
+	
+	ambientValues.push_back(glm::vec4(0.1f, 0.1f, 0.1f, 1.0f));
+
+	m_ambientInterpolator.SetValues(ambientValues);
+
+	m_lightTimers.reserve(NUMBER_OF_LIGHTS - 1);
+	m_lightPos.reserve(NUMBER_OF_LIGHTS - 1);
+	m_lightPos.push_back(LightInterpolator(true));
+	m_lightPos.push_back(LightInterpolator(true));
+	m_lightPos.push_back(LightInterpolator(true));
+
+	std::vector<glm::vec3> posValues;
+	posValues.reserve(20);
+
+	posValues.push_back(glm::vec3(-50.0f, 30.0f, 70.0f));
+	posValues.push_back(glm::vec3(-70.0f, 30.0f, 50.0f));
+	posValues.push_back(glm::vec3(-70.0f, 30.0f, -50.0f));
+	posValues.push_back(glm::vec3(-50.0f, 30.0f, -70.0f));
+	posValues.push_back(glm::vec3(50.0f, 30.0f, -70.0f));
+	posValues.push_back(glm::vec3(70.0f, 30.0f, -50.0f));
+	posValues.push_back(glm::vec3(70.0f, 30.0f, 50.0f));
+	posValues.push_back(glm::vec3(50.0f, 30.0f, 70.0f));
+	m_lightPos[0].SetValues(posValues);
+	m_lightTimers.push_back(Framework::Timer(Framework::Timer::TT_LOOP, 15.0f));
+
+	posValues.clear();
+	posValues.push_back(glm::vec3(80.0f, 30.0f, -70.0f));
+	posValues.push_back(glm::vec3(70.0f, 25.0f, 70.0f));
+	m_lightPos[1].SetValues(posValues);
+	m_lightTimers.push_back(Framework::Timer(Framework::Timer::TT_LOOP, 15.0f));
+
+	posValues.clear();
+	posValues.push_back(glm::vec3(-70.0f, 25.0f, -75.0f));
+	posValues.push_back(glm::vec3(-70.0f, 5.0f, 0.0f));
+	posValues.push_back(glm::vec3(-70.0f, 25.0f, 70.0f));
+	posValues.push_back(glm::vec3(0.0f, 50.0f, 0.0f));
+	m_lightPos[2].SetValues(posValues);
+	m_lightTimers.push_back(Framework::Timer(Framework::Timer::TT_LOOP, 15.0f));
 }
 
 void LightManager::UpdateTime()
 {
-	keyLightTimer.Update();
+	m_keyLightTimer.Update();
+	for(size_t loop = 0; loop < m_lightTimers.size(); loop++)
+	{
+		m_lightTimers[loop].Update();
+	}
 }
 
 bool LightManager::TogglePause()
 {
-	return keyLightTimer.TogglePause();
+	for(size_t loop = 0; loop < m_lightTimers.size(); loop++)
+	{
+		m_lightTimers[loop].TogglePause();
+	}
+
+	return m_keyLightTimer.TogglePause();
 }
 
 LightBlock LightManager::GetLightPositions( const glm::mat4 &worldToCameraMat ) const
 {
 	LightBlock lightData;
 
-	lightData.ambientIntensity = ambientInterpolator.Interpolate(keyLightTimer.GetAlpha());
+	lightData.ambientIntensity = m_ambientInterpolator.Interpolate(m_keyLightTimer.GetAlpha());
 	lightData.lightAttenuation = g_fLightAttenuation;
 
 	lightData.lights[0].cameraSpaceLightPos =
 		worldToCameraMat * glm::vec4(0.0f, 1.0f, 0.0f, 0.0f);
 
-	lightData.lights[0].lightIntensity = glm::vec4(0.5f, 0.5f, 0.5f, 1.0f);
+	lightData.lights[0].lightIntensity = glm::vec4(0.1f, 0.1f, 0.1f, 1.0f);
 
 	for(int light = 1; light < NUMBER_OF_LIGHTS; light++)
 	{
-		glm::vec4 worldLightPos = CalcLightPosition(keyLightTimer,
-			light * (1.0f / (NUMBER_OF_LIGHTS - 1)));
+		int lightIx = light - 1;
+		glm::vec4 worldLightPos = glm::vec4(m_lightPos[lightIx].Interpolate(m_lightTimers[lightIx].GetAlpha()), 1.0f);
 		glm::vec4 lightPosCameraSpace = worldToCameraMat * worldLightPos;
 
 		lightData.lights[light].cameraSpaceLightPos = lightPosCameraSpace;
-		lightData.lights[light].lightIntensity = glm::vec4(0.1f, 0.1f, 0.0f, 1.0f);
+		lightData.lights[light].lightIntensity = glm::vec4(0.3f, 0.3f, 0.3f, 1.0f);
 	}
 
 	return lightData;
 
 int LightManager::GetNumberOfPointLights() const
 {
-	return NUMBER_OF_LIGHTS - 1;
+	return m_lightPos.size();
 }
 
-glm::vec3 LightManager::GetWorldLightPosition( int iLightIx ) const
+glm::vec3 LightManager::GetWorldLightPosition( int lightIx ) const
 {
-	glm::vec4 worldLightPos = CalcLightPosition(keyLightTimer,
-		iLightIx * (1.0f / (NUMBER_OF_LIGHTS - 1)));
-
-
-	return glm::vec3(worldLightPos);
+	return m_lightPos[lightIx].Interpolate(m_lightTimers[lightIx].GetAlpha());
 }

Tut 12 Dynamic Range/Lights.h

 	glm::vec3 GetWorldLightPosition(int iLightIx) const;
 
 private:
-	Framework::Timer keyLightTimer;
-	Framework::LinearInterpolator<glm::vec4> ambientInterpolator;
+	typedef Framework::ConstVelLinearInterpolator<glm::vec3> LightInterpolator;
+
+	Framework::Timer m_keyLightTimer;
+	Framework::LinearInterpolator<glm::vec4> m_ambientInterpolator;
+
+	std::vector<LightInterpolator> m_lightPos;
+	std::vector<Framework::Timer> m_lightTimers;
 
 };
 

Tut 12 Dynamic Range/Scene Lighting.cpp

 {
 	GLuint theProgram;
 
-	GLuint cameraToClipMatrixUnif;
 	GLuint modelToCameraMatrixUnif;
 
 	GLuint lightIntensityUnif;
 	GLuint lightAttenuationUnif;
 	GLuint shininessFactorUnif;
 	GLuint baseDiffuseColorUnif;
-
-	void SetWindowData(const glm::mat4 cameraToClip)
-	{
-		glUseProgram(theProgram);
-		glUniformMatrix4fv(cameraToClipMatrixUnif, 1, GL_FALSE,
-			glm::value_ptr(cameraToClip));
-		glUseProgram(0);
-	}
 };
 
 struct UnlitProgData
 	UnlitProgData data;
 	data.theProgram = Framework::CreateProgram(shaderList);
 	data.modelToCameraMatrixUnif = glGetUniformLocation(data.theProgram, "modelToCameraMatrix");
-	data.cameraToClipMatrixUnif = glGetUniformLocation(data.theProgram, "cameraToClipMatrix");
 	data.objectColorUnif = glGetUniformLocation(data.theProgram, "objectColor");
 
 	GLuint projectionBlock = glGetUniformBlockIndex(data.theProgram, "Projection");
 	ProgramData data;
 	data.theProgram = Framework::CreateProgram(shaderList);
 	data.modelToCameraMatrixUnif = glGetUniformLocation(data.theProgram, "modelToCameraMatrix");
-	data.cameraToClipMatrixUnif = glGetUniformLocation(data.theProgram, "cameraToClipMatrix");
 
 	data.normalModelToCameraMatrixUnif = glGetUniformLocation(data.theProgram, "normalModelToCameraMatrix");
 
 		0, sizeof(LightBlock));
 
 	glBindBufferRange(GL_UNIFORM_BUFFER, g_iProjectionBlockIndex, g_projectionUniformBuffer,
-		0, sizeof(LightBlock));
+		0, sizeof(ProjectionBlock));
 
 	glBindBuffer(GL_UNIFORM_BUFFER, 0);
 }

framework/Interpolators.h

 
 #include <math.h>
 #include <vector>
+#include <algorithm>
+#include <iterator>
 
 namespace Framework
 {
 	class LinearInterpolator
 	{
 	public:
+		typedef ValueType value_type;
+
 		explicit LinearInterpolator(bool isLoop)
 			: m_isLoop(isLoop)
-			, m_numSegments(0)
 		{}
 
-		LinearInterpolator(bool isLoop, int iNumReserve)
-			: m_isLoop(isLoop)
-			, m_numSegments(0)
+		template<typename BidirectionalRange>
+		void SetValues(const BidirectionalRange &data)
 		{
-			m_values.reserve(iNumReserve);
+			m_values.clear();
+			std::copy(data.begin(), data.end(), std::back_inserter(m_values));
+			if(m_isLoop)
+				m_values.push_back(*data.begin());
 		}
 
-		void AppendValue(const ValueType &data)
-		{
-			m_values.push_back(data);
-			m_numSegments = m_isLoop ? m_values.size() : (m_values.size() - 1);
-			if(m_values.size() < 2)
-				m_numSegments = 0;
-		}
+		size_t NumSegments() const {return m_values.empty() ? 0 : m_values.size() - 1;}
 
 		ValueType Interpolate(float fAlpha) const
 		{
-			if(m_numSegments == 0)
+			if(m_values.empty())
+				return ValueType();
+			if(m_values.size() == 1)
 				return m_values[0];
 
-			fAlpha *= m_numSegments;
+			fAlpha *= m_values.size() - 1;
 
 			float intPart = 0.0f;
 			float sectionAlpha = modf(fAlpha, &intPart);
 
-			int iStartIx = (int)intPart;
+			size_t iStartIx = (size_t)intPart;
 
-			int iNextIx = iStartIx + 1;
-			if(m_isLoop && (iNextIx == m_numSegments))
-			{
-				iNextIx = 0;
-			}
+			size_t iNextIx = iStartIx + 1;
 
-			if((size_t)iNextIx > m_numSegments)
+			if(iNextIx > NumSegments())
 				return m_values.back();
 
-
 			float invSecAlpha = 1.0f - sectionAlpha;
 
 			return m_values[iStartIx] * invSecAlpha + m_values[iNextIx] * sectionAlpha;
 
 	private:
 		std::vector<ValueType> m_values;
-		size_t m_numSegments;
 		bool m_isLoop;
 	};
 
-	template<typename ValueType, typename SplineBasis>
-	class CubicInterpolator
+	/**
+	\brief Interpolates with a constant velocity between positions.
+
+	This interpolator maps a range of [0, 1) onto a set of values. However, it takes the distance
+	between these values. There must be a free function called "distance" which takes two ValueType's and
+	returns a float distance between them.
+
+	The idea is that, if you add 0.1 to your alpha value, you will always get a movement of the same distance.
+	Not necessarily between the initial and final points, but the object will have moved at the same
+	speed along the path.
+	**/
+	template<typename ValueType>
+	class ConstVelLinearInterpolator
 	{
 	public:
-		CubicInterpolator(const SplineBasis &basis, bool isLoop)
-			: m_numSegments(0)
-			, m_basis(basis)
-			, m_isLoop(isLoop)
+		typedef ValueType value_type;
+
+		explicit ConstVelLinearInterpolator(bool isLoop)
+			: m_isLoop(isLoop)
+			, m_totalDist(0.0f)
 		{}
 
-		CubicInterpolator(const SplineBasis &basis, bool isLoop, int iNumReserve)
-			: m_numSegments(0)
-			, m_basis(basis)-
-			, m_isLoop(isLoop)
+		template<typename BidirectionalRange>
+		void SetValues(const BidirectionalRange &data)
 		{
-			m_values.reserve(iNumReserve);
+			m_values.clear();
+
+			typename BidirectionalRange::const_iterator curr = data.begin();
+			typename BidirectionalRange::const_iterator last = data.end();
+			for(; curr != last; ++curr)
+			{
+				Data currData;
+				currData.data = *curr;
+				currData.weight = 0.0f;
+				m_values.push_back(currData);
+			}
+
+			if(m_isLoop)
+			{
+				Data currData;
+				currData.data = *data.begin();
+				currData.weight = 0.0f;
+				m_values.push_back(currData);
+			}
+
+			//Compute the distances of each segment.
+			m_totalDist = 0.0f;
+			for(size_t iLoop = 1; iLoop < m_values.size(); ++iLoop)
+			{
+				m_totalDist += distance(m_values[iLoop - 1].data, m_values[iLoop].data);
+				m_values[iLoop].weight = m_totalDist;
+			}
+
+			//Compute the alpha value that represents when to use this segment.
+			for(size_t iLoop = 1; iLoop < m_values.size(); ++iLoop)
+			{
+				m_values[iLoop].weight /= m_totalDist;
+			}
 		}
 
-		void AppendValue(const ValueType &data)
-		{
-			m_values.push_back(data);
+		float Distance() const {return m_totalDist;}
 
-			size_t numValues = m_values.size();
-			if(numValues < 4)
-				m_numSegments = 0;
-			else
-				m_numSegments = SplineBasis::CountSegments(numValues, m_isLoop);
-		}
+		size_t NumSegments() const {return m_values.empty() ? 0 : m_values.size() - 1;}
 
 		ValueType Interpolate(float fAlpha) const
 		{
-			if(m_numSegments == 0)
-				return m_values[0];
+			if(m_values.empty())
+				return ValueType();
+			if(m_values.size() == 1)
+				return m_values[0].data;
 
-			fAlpha *= m_numSegments;
+			//Find which segment we are within.
+			size_t segment = 1;
+			for(; segment < m_values.size(); ++segment)
+			{
+				if(fAlpha < m_values[segment].weight)
+					break;
+			}
 
-			float intPart = 0.0f;
-			float sectionAlpha = modf(fAlpha, &intPart);
+			if(segment == m_values.size())
+				return m_values.back().data;
 
-			int iStartIx = (int)intPart;
+			float sectionAlpha = fAlpha - m_values[segment - 1].weight;
+			sectionAlpha /= m_values[segment].weight - m_values[segment - 1].weight;
 
-			m_basis.Interpolate(m_values, iStartIx, sectionAlpha);
+			float invSecAlpha = 1.0f - sectionAlpha;
+
+			return m_values[segment - 1].data * invSecAlpha + m_values[segment].data * sectionAlpha;
 		}
 
 	private:
-		std::vector<ValueType> m_values;
-		size_t m_numSegments;
-		SplineBasis m_basis;
+		struct Data
+		{
+			ValueType data;
+			float weight;
+		};
+
+		std::vector<Data> m_values;
 		bool m_isLoop;
+		float m_totalDist;
 	};
 }