diff --git a/LearnOpenGL/OpenGLWrapper.cpp b/LearnOpenGL/OpenGLWrapper.cpp
index 6744fa65b75c28ea18ac52aba435f0685de0ebe9..f000983b02ac4190aca1001539be6816fbde3754 100644
--- a/LearnOpenGL/OpenGLWrapper.cpp
+++ b/LearnOpenGL/OpenGLWrapper.cpp
@@ -175,6 +175,39 @@ void RenderObject::render(Camera &camera)
 	glUseProgram(0);
 }
 
+void RenderObject::projective_render(Camera &camera)
+{
+	const glm::mat4 bias = { 0.5, 0.0, 0.0, 0.5, 0.0, 0.5, 0.0, 0.5, 0.0, 0.0, 0.5, 0.5, 0.0, 0.0, 0.0, 1.0 };
+	glm::mat4 pp = glm::perspective(glm::radians(camera.Zoom), (float)_SCR_WIDTH / (float)_SCR_HEIGHT, 0.1f, 10.0f);
+	glm::mat4 pv = glm::lookAt(camera.Position, camera.Position + camera.Front, camera.Up);
+	glm::mat4 InvView = glm::inverse(camera.GetViewMatrix());
+	glm::mat4 result = bias * pp * pv;
+
+	auto prog = material->get_program();
+	glUseProgram(prog);
+
+	glm::mat4 projection = glm::perspective(glm::radians(camera.Zoom), (float)_SCR_WIDTH / (float)_SCR_HEIGHT, 0.1f, 500.0f);
+	glm::mat4 view = camera.GetViewMatrix();
+	set_uniform_value(prog, "TexGenMatCam0", result);
+	set_uniform_value(prog, "projection", projection);
+	set_uniform_value(prog, "view", view);
+	set_uniform_value(prog, "model", model);
+
+	{
+		glActiveTexture(GL_TEXTURE0);
+		glBindTexture(GL_TEXTURE_2D, material->get_diffuseMap());
+	}
+
+	{
+		glActiveTexture(GL_TEXTURE1);
+		glBindTexture(GL_TEXTURE_2D, material->get_specularMap());
+	}
+
+	draw_mesh(*mesh);
+
+	glUseProgram(0);
+}
+
 RenderObject *make_render_object(Mesh *mesh)
 {
 	RenderObject *ro = new RenderObject(mesh);
diff --git a/LearnOpenGL/OpenGLWrapper.h b/LearnOpenGL/OpenGLWrapper.h
index eb1a0b627f9f02beb867d77c1db8ddd534379c3b..f2722ffb594e16e080de95031ca56d33be6c3b63 100644
--- a/LearnOpenGL/OpenGLWrapper.h
+++ b/LearnOpenGL/OpenGLWrapper.h
@@ -77,6 +77,7 @@ public:
 	void set_material(Material *_material);
 
 	void render(Camera &camera);
+	void projective_render(Camera &camera);
 };
 
 RenderObject *make_render_object(Mesh *mesh);
diff --git a/LearnOpenGL/Source.cpp b/LearnOpenGL/Source.cpp
index da4f6a29dbb112122cb83df599ad30e9ea9a9a1a..146a05fd5f4ca37e399947fb6049814af5b40a45 100644
--- a/LearnOpenGL/Source.cpp
+++ b/LearnOpenGL/Source.cpp
@@ -57,6 +57,7 @@ int main()
 	auto lamp = build_program("Lighting_Lamp");
 	auto lightmap = build_program("Lighting_Maps");
 	auto texture_shader = build_program("Texture");
+	auto projector_shader = build_program("Projector");
 
 	auto cube = make_mesh("cube.obj");
 
@@ -66,12 +67,22 @@ int main()
 	auto white = load_image("white.png");
 	auto transparent = load_image("transparent.png");
 
+	auto wall = load_image("wall.jpg");
 	auto container_diffuse = load_image("container2.png");
 	auto container_specular = load_image("container2_specular.png");
 
 	auto defaultMaterial = new Material(lightmap, orange, transparent);
 	auto cubeMaterial = new Material(lightmap, container_diffuse, container_specular);
 	auto planeMaterial = new Material(lightmap, magenta, transparent);
+	auto projectorMaterial = new Material(projector_shader, transparent, transparent);
+
+	auto projector = make_render_object(make_mesh("cube.obj"));
+	{
+		projector->set_translate(glm::vec3(0.0f, 10.0f, 0.0f));
+	}
+	{
+		projector->set_material(projectorMaterial);
+	}
 
 	auto teapot = make_render_object(make_mesh("teapot.obj"));
 	{
@@ -79,7 +90,7 @@ int main()
 		teapot->set_rotate(glm::vec3(-90.0f, 0.0f, 0.0f));
 	}
 	{
-		teapot->set_material(defaultMaterial);
+		teapot->set_material(projectorMaterial);
 	}
 
 	auto cube1 = make_render_object(cube);
@@ -140,7 +151,7 @@ int main()
 		glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
 
 		{
-			teapot->render(camera);
+			teapot->projective_render(camera);
 			cube1->render(camera);
 			cube2->render(camera);
 			cube3->render(camera);