Commits

Jason McKesson committed 53eb28f

Tut12: Basic frame in place. Camera movement and UBO-based lighting.

  • Participants
  • Parent commits 45c6ae6

Comments (0)

Files changed (13)

File Tut 12 Dynamic Range/Scene Lighting.cpp

 
 UnlitProgData g_Unlit;
 
+const int g_iMaterialBlockIndex = 0;
+const int g_iLightBlockIndex = 1;
+const int g_iProjectionBlockIndex = 2;
+
 UnlitProgData LoadUnlitProgram(const std::string &strVertexShader, const std::string &strFragmentShader)
 {
 	std::vector<GLuint> shaderList;
 	data.cameraToClipMatrixUnif = glGetUniformLocation(data.theProgram, "cameraToClipMatrix");
 	data.objectColorUnif = glGetUniformLocation(data.theProgram, "objectColor");
 
+	GLuint projectionBlock = glGetUniformBlockIndex(data.theProgram, "Projection");
+	glUniformBlockBinding(data.theProgram, projectionBlock, g_iProjectionBlockIndex);
+
 	return data;
 }
 
 	data.theProgram = Framework::CreateProgram(shaderList);
 	data.modelToCameraMatrixUnif = glGetUniformLocation(data.theProgram, "modelToCameraMatrix");
 	data.cameraToClipMatrixUnif = glGetUniformLocation(data.theProgram, "cameraToClipMatrix");
-	data.lightIntensityUnif = glGetUniformLocation(data.theProgram, "lightIntensity");
-	data.ambientIntensityUnif = glGetUniformLocation(data.theProgram, "ambientIntensity");
 
 	data.normalModelToCameraMatrixUnif = glGetUniformLocation(data.theProgram, "normalModelToCameraMatrix");
-	data.cameraSpaceLightPosUnif = glGetUniformLocation(data.theProgram, "cameraSpaceLightPos");
-	data.lightAttenuationUnif = glGetUniformLocation(data.theProgram, "lightAttenuation");
-	data.shininessFactorUnif = glGetUniformLocation(data.theProgram, "shininessFactor");
-	data.baseDiffuseColorUnif = glGetUniformLocation(data.theProgram, "baseDiffuseColor");
+
+	GLuint materialBlock = glGetUniformBlockIndex(data.theProgram, "Material");
+	GLuint lightBlock = glGetUniformBlockIndex(data.theProgram, "Light");
+	GLuint projectionBlock = glGetUniformBlockIndex(data.theProgram, "Projection");
+
+	glUniformBlockBinding(data.theProgram, materialBlock, g_iMaterialBlockIndex);
+	glUniformBlockBinding(data.theProgram, lightBlock, g_iLightBlockIndex);
+	glUniformBlockBinding(data.theProgram, projectionBlock, g_iProjectionBlockIndex);
 
 	return data;
 }
 	g_Unlit = LoadUnlitProgram("PosTransform.vert", "UniformColor.frag");
 }
 
-Framework::RadiusDef radiusDef = {150.0f, 3.0f, 500.0f, 6.0f, 2.0f};
-glm::vec3 objectCenter = glm::vec3(0.0f, 0.0f, 0.0f);
+class TimeKeeper
+{
+public:
+	TimeKeeper()
+		: keyLightTimer(Framework::Timer::TT_LOOP, 5.0f)
+	{}
+
+	void Update()
+	{
+		keyLightTimer.Update();
+	}
+
+	Framework::Timer keyLightTimer;
+};
+
+TimeKeeper g_time;
+
+Framework::RadiusDef radiusDef = {50.0f, 3.0f, 80.0f, 4.0f, 1.0f};
+glm::vec3 objectCenter = glm::vec3(-50.0f, 0.0f, 50.0f);
 
 Framework::MousePole g_mousePole(objectCenter, radiusDef);
 
 Framework::Mesh *g_pTerrainMesh = NULL;
 Framework::Mesh *g_pLightMesh = NULL;
 
+struct MaterialBlock
+{
+	glm::vec4 diffuseColor;
+	glm::vec4 specularColor;
+	float specularShininess;
+	float padding[3];
+};
+
+struct PerLight
+{
+	glm::vec3 cameraSpaceLightPos;
+	float padding;
+	glm::vec4 lightIntensity;
+};
+
+struct LightBlock
+{
+	glm::vec4 ambientIntensity;
+	float lightAttenuation;
+	float padding[3];
+	PerLight lights;
+};
+
+struct ProjectionBlock
+{
+	glm::mat4 cameraToClipMatrix;
+};
+
+LightBlock g_lightData;
+
+GLuint g_lightUniformBuffer;
+GLuint g_materialUniformBuffer;
+GLuint g_projectionUniformBuffer;
+
 //Called after the window and OpenGL are initialized. Called exactly once, before the main loop.
 void init()
 {
 	glDepthFunc(GL_LEQUAL);
 	glDepthRange(depthZNear, depthZFar);
 	glEnable(GL_DEPTH_CLAMP);
+
+
+	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);
+
+	MaterialBlock mtlData;
+	mtlData.diffuseColor = glm::vec4(1.0f);
+	mtlData.specularColor = glm::vec4(0.05f, 0.05f, 0.05f, 1.0f);
+	mtlData.specularShininess = 0.6f;
+
+	glGenBuffers(1, &g_materialUniformBuffer);
+	glBindBuffer(GL_UNIFORM_BUFFER, g_materialUniformBuffer);
+	glBufferData(GL_UNIFORM_BUFFER, sizeof(MaterialBlock), &mtlData, GL_STATIC_DRAW);
+
+	glBindBufferRange(GL_UNIFORM_BUFFER, g_iLightBlockIndex, g_lightUniformBuffer,
+		0, sizeof(LightBlock));
+
+	glBindBufferRange(GL_UNIFORM_BUFFER, g_iProjectionBlockIndex, g_projectionUniformBuffer,
+		0, sizeof(LightBlock));
+
+	glBindBuffer(GL_UNIFORM_BUFFER, 0);
 }
 
 static float g_fLightHeight = 1.5f;
 static float g_fLightRadius = 70.0f;
 
-Framework::Timer g_lightTimer(Framework::Timer::TT_LOOP, 5.0f);
-
 static float g_fRotateTime = 0.0f;
 static float g_fPrevTime = 0.0f;
 
+bool g_bDrawCameraPos = false;
+
 glm::vec4 CalcLightPosition()
 {
-	g_lightTimer.Update();
-
 	const float fLoopDuration = 5.0f;
 	const float fScale = 3.14159f * 2.0f;
 
-	float timeThroughLoop = g_lightTimer.GetAlpha();
+	float timeThroughLoop = g_time.keyLightTimer.GetAlpha();
 
 	glm::vec4 ret(0.0f, g_fLightHeight, 0.0f, 1.0f);
 
 
 void display()
 {
+	g_time.Update();
+
 	glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
 	glClearDepth(1.0f);
 	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
 		const glm::vec4 &worldLightPos = CalcLightPosition();
 		const glm::vec4 &lightPosCameraSpace = modelMatrix.Top() * worldLightPos;
 
-		ProgramData &prog = g_Programs[LM_VERT_COLOR_DIFFUSE];
+		ProgramData &prog = g_Programs[LM_VERT_COLOR_DIFFUSE_SPECULAR];
 
-		glUseProgram(prog.theProgram);
-		glUniform4f(prog.lightIntensityUnif, 0.8f, 0.8f, 0.8f, 1.0f);
-		glUniform4f(prog.ambientIntensityUnif, 0.2f, 0.2f, 0.2f, 1.0f);
-		glUniform3fv(prog.cameraSpaceLightPosUnif, 1, glm::value_ptr(lightPosCameraSpace));
-		glUniform1f(prog.lightAttenuationUnif, g_fLightAttenuation);
-		glUniform1f(prog.shininessFactorUnif, 0.5f);
-		glUseProgram(0);
+		LightBlock lightData;
+		lightData.ambientIntensity = glm::vec4(0.2f, 0.2f, 0.2f, 1.0f);
+		lightData.lightAttenuation = g_fLightAttenuation;
+		lightData.lights.cameraSpaceLightPos = glm::vec3(lightPosCameraSpace);
+		lightData.lights.lightIntensity = glm::vec4(0.8f, 0.8f, 0.8f, 1.0f);
+
+		glBindBuffer(GL_UNIFORM_BUFFER, g_lightUniformBuffer);
+		glBufferSubData(GL_UNIFORM_BUFFER, 0, sizeof(lightData), &lightData);
+		glBindBuffer(GL_UNIFORM_BUFFER, 0);
 
 		{
 			Framework::MatrixStackPusher push(modelMatrix);
 
 			//Render the ground plane.
 			{
+				glBindBufferRange(GL_UNIFORM_BUFFER, g_iMaterialBlockIndex, g_materialUniformBuffer,
+					0, sizeof(MaterialBlock));
+
 				Framework::MatrixStackPusher push(modelMatrix);
 				modelMatrix.RotateX(-90);
 
 					glm::value_ptr(normMatrix));
 				g_pTerrainMesh->Render();
 				glUseProgram(0);
+
+				glBindBufferRange(GL_UNIFORM_BUFFER, g_iMaterialBlockIndex, 0, 0, 0);
 			}
 
 			//Render the light
 				glUniform4f(g_Unlit.objectColorUnif, 0.8078f, 0.8706f, 0.9922f, 1.0f);
 				g_pLightMesh->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_pLightMesh->Render("flat");
+				glDepthMask(GL_TRUE);
+				glEnable(GL_DEPTH_TEST);
+				glUniform4f(g_Unlit.objectColorUnif, 1.0f, 1.0f, 1.0f, 1.0f);
+				g_pLightMesh->Render("flat");
+			}
 		}
 	}
 
 	Framework::MatrixStack persMatrix;
 	persMatrix.Perspective(45.0f, (h / (float)w), g_fzNear, g_fzFar);
 
-	for(int iProg = 0; iProg < LM_MAX_LIGHTING_MODEL; iProg++)
-	{
-		g_Programs[iProg].SetWindowData(persMatrix.Top());
-	}
+	ProjectionBlock projData;
+	projData.cameraToClipMatrix = persMatrix.Top();
 
-	g_Unlit.SetWindowData(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();
 	case 'L': g_fLightRadius += 0.5f; break;
 	case 'J': g_fLightRadius -= 0.5f; break;
 
-	case 'b': g_lightTimer.TogglePause(); break;
+	case 'b': g_time.keyLightTimer.TogglePause(); break;
+	case 't': g_bDrawCameraPos = !g_bDrawCameraPos; break;
+
+	case 'w': g_mousePole.OffsetTargetPos(Framework::MousePole::DIR_FORWARD, 5.0f); break;
+	case 's': g_mousePole.OffsetTargetPos(Framework::MousePole::DIR_BACKWARD, 5.0f); break;
+	case 'd': g_mousePole.OffsetTargetPos(Framework::MousePole::DIR_RIGHT, 5.0f); break;
+	case 'a': g_mousePole.OffsetTargetPos(Framework::MousePole::DIR_LEFT, 5.0f); break;
+	case 'e': g_mousePole.OffsetTargetPos(Framework::MousePole::DIR_UP, 5.0f); break;
+	case 'q': g_mousePole.OffsetTargetPos(Framework::MousePole::DIR_DOWN, 5.0f); break;
 	}
 
 	if(g_fLightRadius < 0.2f)

File Tut 12 Dynamic Range/data/DiffuseOnly.frag

 
 out vec4 outputColor;
 
-uniform vec3 modelSpaceLightPos;
+layout(std140) uniform;
 
-uniform vec4 lightIntensity;
-uniform vec4 ambientIntensity;
+uniform Material
+{
+	vec4 diffuseColor;
+	vec4 specularColor;
+	float specularShininess;
+} Mtl;
 
-uniform vec3 cameraSpaceLightPos;
+struct PerLight
+{
+	vec3 cameraSpaceLightPos;
+	vec4 lightIntensity;
+};
 
-uniform float lightAttenuation;
+uniform Light
+{
+	vec4 ambientIntensity;
+	float lightAttenuation;
+	PerLight lights;
+} Lgt;
 
-const vec4 specularColor = vec4(0.25, 0.25, 0.25, 1.0);
-uniform float shininessFactor;
 
-
-float CalcAttenuation(in vec3 cameraSpacePosition, out vec3 lightDirection)
+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 + lightAttenuation * sqrt(lightDistanceSqr)));
+	return (1 / ( 1.0 + Lgt.lightAttenuation * sqrt(lightDistanceSqr)));
 }
 
 void main()
 {
 	vec3 lightDir = vec3(0.0);
-	float atten = CalcAttenuation(cameraSpacePosition, lightDir);
-	vec4 attenIntensity = atten * lightIntensity;
+	float atten = CalcAttenuation(cameraSpacePosition,
+		Lgt.lights.cameraSpaceLightPos, lightDir);
+	vec4 attenIntensity = atten * Lgt.lights.lightIntensity;
 	
 	vec3 surfaceNormal = normalize(vertexNormal);
 	float cosAngIncidence = dot(surfaceNormal, lightDir);
 	cosAngIncidence = clamp(cosAngIncidence, 0, 1);
 	
 	outputColor = (diffuseColor * attenIntensity * cosAngIncidence) +
-		(diffuseColor * ambientIntensity);
+		(diffuseColor * Lgt.ambientIntensity);
 }

File Tut 12 Dynamic Range/data/DiffuseSpecular.frag

 
 out vec4 outputColor;
 
-uniform vec3 modelSpaceLightPos;
+layout(std140) uniform;
 
-uniform vec4 lightIntensity;
-uniform vec4 ambientIntensity;
+uniform Material
+{
+	vec4 diffuseColor;
+	vec4 specularColor;
+	float specularShininess;
+} Mtl;
 
-uniform vec3 cameraSpaceLightPos;
+struct PerLight
+{
+	vec3 cameraSpaceLightPos;
+	vec4 lightIntensity;
+};
 
-uniform float lightAttenuation;
+uniform Light
+{
+	vec4 ambientIntensity;
+	float lightAttenuation;
+	PerLight lights;
+} Lgt;
 
-const vec4 specularColor = vec4(0.25, 0.25, 0.25, 1.0);
-uniform float shininessFactor;
 
-
-float CalcAttenuation(in vec3 cameraSpacePosition, out vec3 lightDirection)
+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 + lightAttenuation * sqrt(lightDistanceSqr)));
+	return (1 / ( 1.0 + Lgt.lightAttenuation * sqrt(lightDistanceSqr)));
 }
 
 void main()
 {
-	vec3 lightDir = vec3(0.0);
-	float atten = CalcAttenuation(cameraSpacePosition, lightDir);
-	vec4 attenIntensity = atten * lightIntensity;
+	vec3 lightDir;
+	float atten = CalcAttenuation(cameraSpacePosition,
+		Lgt.lights.cameraSpaceLightPos, lightDir);
+	vec4 attenIntensity = atten * Lgt.lights.lightIntensity;
 	
 	vec3 surfaceNormal = normalize(vertexNormal);
 	float cosAngIncidence = dot(surfaceNormal, lightDir);
 	
 	vec3 halfAngle = normalize(lightDir + viewDirection);
 	float angleNormalHalf = acos(dot(halfAngle, surfaceNormal));
-	float exponent = angleNormalHalf / shininessFactor;
+	float exponent = angleNormalHalf / Mtl.specularShininess;
 	exponent = -(exponent * exponent);
 	float gaussianTerm = exp(exponent);
 
 	gaussianTerm = cosAngIncidence != 0.0 ? gaussianTerm : 0.0;
 
 	outputColor = (diffuseColor * attenIntensity * cosAngIncidence) +
-		(specularColor * attenIntensity * gaussianTerm) +
-		(diffuseColor * ambientIntensity);
+		(Mtl.specularColor * attenIntensity * gaussianTerm) +
+		(diffuseColor * Lgt.ambientIntensity);
 }

File Tut 12 Dynamic Range/data/PCN.vert

 out vec3 vertexNormal;
 out vec3 cameraSpacePosition;
 
-uniform mat4 cameraToClipMatrix;
+uniform Projection
+{
+	mat4 cameraToClipMatrix;
+};
+
 uniform mat4 modelToCameraMatrix;
-
 uniform mat3 normalModelToCameraMatrix;
 
 void main()

File Tut 12 Dynamic Range/data/PCNLighting.vert

-#version 330
-
-layout(location = 0) in vec3 position;
-layout(location = 1) in vec4 inDiffuseColor;
-layout(location = 2) in vec3 normal;
-
-out vec4 diffuseColor;
-out vec3 vertexNormal;
-out vec3 modelSpaceNormal;
-out vec3 cameraSpacePosition;
-
-smooth out vec4 passthrough;
-
-uniform mat4 cameraToClipMatrix;
-uniform mat4 modelToCameraMatrix;
-
-uniform mat3 normalModelToCameraMatrix;
-
-uniform vec3 cameraSpaceLightPos;
-
-void main()
-{
-	vec4 tempCamPosition = (modelToCameraMatrix * vec4(position, 1.0));
-	gl_Position = cameraToClipMatrix * tempCamPosition;
-
-	vec3 cameraNormal = normalize(normalModelToCameraMatrix * normal);
-	vertexNormal = cameraNormal;
-	modelSpaceNormal = normalize(normal);
-	diffuseColor = inDiffuseColor;
-	cameraSpacePosition = tempCamPosition.xyz;
-	
-	vec3 lightDir = normalize(cameraSpaceLightPos - tempCamPosition.xyz);
-	vec3 surfaceNormal = normalize(cameraNormal);
-	passthrough = vec4(dot(surfaceNormal, lightDir));
-
-}

File Tut 12 Dynamic Range/data/PN.vert

-#version 330
-
-layout(location = 0) in vec3 position;
-layout(location = 2) in vec3 normal;
-
-out vec4 diffuseColor;
-out vec3 vertexNormal;
-out vec3 cameraSpacePosition;
-
-uniform mat4 cameraToClipMatrix;
-uniform mat4 modelToCameraMatrix;
-uniform vec4 baseDiffuseColor;
-
-uniform mat3 normalModelToCameraMatrix;
-
-void main()
-{
-	vec4 tempCamPosition = (modelToCameraMatrix * vec4(position, 1.0));
-	gl_Position = cameraToClipMatrix * tempCamPosition;
-
-	vertexNormal = normalize(normalModelToCameraMatrix * normal);
-	diffuseColor = baseDiffuseColor;
-	cameraSpacePosition = vec3(tempCamPosition);
-}

File Tut 12 Dynamic Range/data/Passthrough.frag

-#version 330
-
-in vec4 diffuseColor;
-in vec3 vertexNormal;
-in vec3 modelSpaceNormal;
-in vec3 cameraSpacePosition;
-
-smooth in vec4 passthrough;
-
-out vec4 outputColor;
-
-uniform vec3 modelSpaceLightPos;
-
-uniform vec4 lightIntensity;
-uniform vec4 ambientIntensity;
-
-uniform vec3 cameraSpaceLightPos;
-
-uniform float lightAttenuation;
-
-const vec4 specularColor = vec4(0.25, 0.25, 0.25, 1.0);
-uniform float shininessFactor;
-
-
-void main()
-{
-	outputColor = passthrough;
-}

File Tut 12 Dynamic Range/data/PosTransform.vert

 
 layout(location = 0) in vec3 position;
 
-uniform mat4 cameraToClipMatrix;
+uniform Projection
+{
+	mat4 cameraToClipMatrix;
+};
+
 uniform mat4 modelToCameraMatrix;
 
 void main()

File Tut 12 Dynamic Range/data/ShowLighting.frag

-#version 330
-
-in vec4 diffuseColor;
-smooth in vec3 vertexNormal;
-in vec3 modelSpaceNormal;
-in vec3 cameraSpacePosition;
-
-out vec4 outputColor;
-
-uniform vec3 modelSpaceLightPos;
-
-uniform vec4 lightIntensity;
-uniform vec4 ambientIntensity;
-
-uniform vec3 cameraSpaceLightPos;
-
-uniform float lightAttenuation;
-
-const vec4 specularColor = vec4(0.25, 0.25, 0.25, 1.0);
-uniform float shininessFactor;
-
-
-void main()
-{
-	vec3 lightDir = normalize(cameraSpaceLightPos - cameraSpacePosition);
-	vec3 surfaceNormal = normalize(vertexNormal);
-	outputColor = vec4(dot(surfaceNormal, lightDir));
-}

File Tut 12 Dynamic Range/data/ShowNormals.frag

-#version 330
-
-in vec4 diffuseColor;
-smooth in vec3 vertexNormal;
-in vec3 modelSpaceNormal;
-in vec3 cameraSpacePosition;
-
-out vec4 outputColor;
-
-uniform vec3 modelSpaceLightPos;
-
-uniform vec4 lightIntensity;
-uniform vec4 ambientIntensity;
-
-uniform vec3 cameraSpaceLightPos;
-
-uniform float lightAttenuation;
-
-const vec4 specularColor = vec4(0.25, 0.25, 0.25, 1.0);
-uniform float shininessFactor;
-
-
-void main()
-{
-	outputColor = vec4(normalize(modelSpaceNormal), 1.0);
-}

File Tut 12 Dynamic Range/tutorials.lua

 
 SetupProject("Tut 12 Scene Lighting", "Scene Lighting.cpp",
-	"PNC.vert", "PN.vert", "DiffuseSpecular.frag", "DiffuseOnly.frag",
+	"PNC.vert", "PN.vert", "DiffuseSpecular.frag", "DiffuseOnly.frag"
 )
 

File framework/MousePole.cpp

 #include "MatrixStack.h"
 
 #include <math.h>
+#include <glm/gtx/quaternion.hpp>
 
 #ifndef M_PI
 #define M_PI 3.14159265f
 		else
 			this->MoveAway(!(glutGetModifiers() & GLUT_ACTIVE_SHIFT));
 	}
+
+	namespace
+	{
+		glm::vec3 g_offsets[] =
+		{
+			glm::vec3( 0.0f,  1.0f,  0.0f),
+			glm::vec3( 0.0f, -1.0f,  0.0f),
+			glm::vec3( 0.0f,  0.0f, -1.0f),
+			glm::vec3( 0.0f,  0.0f,  1.0f),
+			glm::vec3( 1.0f,  0.0f,  0.0f),
+			glm::vec3(-1.0f,  0.0f,  0.0f),
+		};
+	}
+
+	void MousePole::OffsetTargetPos( TargetOffsetDir eDir, float worldDistance )
+	{
+		glm::vec3 offsetDir = g_offsets[eDir];
+		OffsetTargetPos(offsetDir * worldDistance);
+	}
+
+	void MousePole::OffsetTargetPos( const glm::vec3 &cameraOffset )
+	{
+		glm::mat4 currMat = CalcMatrix();
+		glm::fquat orientation = glm::quat_cast(currMat);
+
+		glm::fquat invOrient = glm::conjugate(orientation);
+		glm::vec3 worldOffset = invOrient * cameraOffset;
+
+		m_lookAt += worldOffset;
+	}
 }
 

File framework/MousePole.h

 		void GetCurrVectors(glm::vec3 &pos, glm::vec3 &lookAt, glm::vec3 &upVec);
 		glm::mat4 CalcMatrix() const;
 
+		glm::vec3 GetLookAtPos() const {return m_lookAt;}
+		float GetLookAtDistance() const {return m_radius.fCurrRadius;}
+
+		void GLUTMouseMove(const glm::ivec2 &position);
+		void GLUTMouseButton(int button, int btnState, const glm::ivec2 &position);
+		void GLUTMouseWheel(int direction, const glm::ivec2 &position);
+
+		bool IsDragging() const {return m_bIsDragging;}
+
+		enum TargetOffsetDir
+		{
+			DIR_UP,
+			DIR_DOWN,
+			DIR_FORWARD,
+			DIR_BACKWARD,
+			DIR_RIGHT,
+			DIR_LEFT,
+		};
+
+		void OffsetTargetPos(TargetOffsetDir eDir, float worldDistance);
+		void OffsetTargetPos(const glm::vec3 &cameraOffset);
+
+	protected:
 		enum RotateMode
 		{
 			RM_DUAL_AXIS_ROTATE,
 			RM_SPIN_VIEW_AXIS,
 		};
 
-		void GLUTMouseMove(const glm::ivec2 &position);
-		void GLUTMouseButton(int button, int btnState, const glm::ivec2 &position);
-		void GLUTMouseWheel(int direction, const glm::ivec2 &position);
-
-		bool IsDragging() const {return m_bIsDragging;}
-
-	protected:
 		glm::vec3 m_lookAt;
 
 		float m_radCurrXZAngle;	//Angle around the y-axis. In radians