├── DeferredRenderer ├── empty.frag ├── skybox │ ├── back.jpg │ ├── left.jpg │ ├── top.jpg │ ├── bottom.jpg │ ├── front.jpg │ ├── right.jpg │ └── v1 │ │ ├── top.jpg │ │ ├── back.jpg │ │ ├── bottom.jpg │ │ ├── front.jpg │ │ ├── left.jpg │ │ └── right.jpg ├── shadow.vert ├── SceneObject.cpp ├── blur.vert ├── skybox.frag ├── ssao.vert ├── ubershader.vert ├── plShadow.vert ├── PointLight.h ├── plShadow.frag ├── skybox.vert ├── light.vert ├── PointLightShadowMap.h ├── common.h ├── VBO.h ├── SceneObject.h ├── ShadowMap.h ├── gbuffer.vert ├── gbuffer.frag ├── Octree.h ├── FullscreenQuad.h ├── Mesh.h ├── GBuffer.h ├── AABB.h ├── VBO.cpp ├── OctreeNode.h ├── PointLightShadowMap.cpp ├── blur.frag ├── Octree.cpp ├── ssao.frag ├── light.frag ├── FullscreenQuad.cpp ├── ShadowMap.cpp ├── Scene.h ├── OctreeNode.cpp ├── Camera.hpp ├── Mesh.cpp ├── ubershader.frag ├── AABB.cpp ├── Shader.h ├── tiny_obj_loader.h ├── MeshHelper.h ├── main.cpp ├── GBuffer.cpp ├── DeferredRenderer.vcxproj.filters ├── Shader.cpp ├── DeferredRenderer.vcxproj ├── Scene.cpp └── tiny_obj_loader.cc ├── README.md ├── DeferredRenderer.sln ├── .gitattributes └── .gitignore /DeferredRenderer/empty.frag: -------------------------------------------------------------------------------- 1 | #version 420 core 2 | 3 | void main() {} -------------------------------------------------------------------------------- /DeferredRenderer/skybox/back.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JAGJ10/DeferredRenderer/HEAD/DeferredRenderer/skybox/back.jpg -------------------------------------------------------------------------------- /DeferredRenderer/skybox/left.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JAGJ10/DeferredRenderer/HEAD/DeferredRenderer/skybox/left.jpg -------------------------------------------------------------------------------- /DeferredRenderer/skybox/top.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JAGJ10/DeferredRenderer/HEAD/DeferredRenderer/skybox/top.jpg -------------------------------------------------------------------------------- /DeferredRenderer/skybox/bottom.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JAGJ10/DeferredRenderer/HEAD/DeferredRenderer/skybox/bottom.jpg -------------------------------------------------------------------------------- /DeferredRenderer/skybox/front.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JAGJ10/DeferredRenderer/HEAD/DeferredRenderer/skybox/front.jpg -------------------------------------------------------------------------------- /DeferredRenderer/skybox/right.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JAGJ10/DeferredRenderer/HEAD/DeferredRenderer/skybox/right.jpg -------------------------------------------------------------------------------- /DeferredRenderer/skybox/v1/top.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JAGJ10/DeferredRenderer/HEAD/DeferredRenderer/skybox/v1/top.jpg -------------------------------------------------------------------------------- /DeferredRenderer/skybox/v1/back.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JAGJ10/DeferredRenderer/HEAD/DeferredRenderer/skybox/v1/back.jpg -------------------------------------------------------------------------------- /DeferredRenderer/skybox/v1/bottom.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JAGJ10/DeferredRenderer/HEAD/DeferredRenderer/skybox/v1/bottom.jpg -------------------------------------------------------------------------------- /DeferredRenderer/skybox/v1/front.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JAGJ10/DeferredRenderer/HEAD/DeferredRenderer/skybox/v1/front.jpg -------------------------------------------------------------------------------- /DeferredRenderer/skybox/v1/left.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JAGJ10/DeferredRenderer/HEAD/DeferredRenderer/skybox/v1/left.jpg -------------------------------------------------------------------------------- /DeferredRenderer/skybox/v1/right.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JAGJ10/DeferredRenderer/HEAD/DeferredRenderer/skybox/v1/right.jpg -------------------------------------------------------------------------------- /DeferredRenderer/shadow.vert: -------------------------------------------------------------------------------- 1 | #version 420 core 2 | 3 | layout(location = 0) in vec3 position; 4 | 5 | uniform mat4 mvp; 6 | 7 | void main() { 8 | gl_Position = mvp * vec4(position, 1.0); 9 | } -------------------------------------------------------------------------------- /DeferredRenderer/SceneObject.cpp: -------------------------------------------------------------------------------- 1 | #include "SceneObject.h" 2 | 3 | SceneObject::SceneObject() : bb(glm::vec3(0), glm::vec3(1)), toBeDestroyed(false) {} 4 | 5 | AABB SceneObject::getAABB() const { 6 | return bb; 7 | } -------------------------------------------------------------------------------- /DeferredRenderer/blur.vert: -------------------------------------------------------------------------------- 1 | #version 420 core 2 | 3 | in vec2 vertexPos; 4 | 5 | out vec2 coord; 6 | 7 | void main() { 8 | coord = vertexPos * 0.5f + 0.5f; 9 | gl_Position = vec4(vertexPos, 0.0, 1.0); 10 | } -------------------------------------------------------------------------------- /DeferredRenderer/skybox.frag: -------------------------------------------------------------------------------- 1 | #version 420 core 2 | 3 | in vec3 fragPos; 4 | 5 | uniform samplerCube skybox; 6 | 7 | out vec4 fragColor; 8 | 9 | void main() { 10 | fragColor = texture(skybox, fragPos); 11 | } 12 | -------------------------------------------------------------------------------- /DeferredRenderer/ssao.vert: -------------------------------------------------------------------------------- 1 | #version 420 core 2 | 3 | in vec2 vertexPos; 4 | 5 | out vec2 coord; 6 | 7 | void main() { 8 | coord = vertexPos * 0.5f + 0.5f; 9 | gl_Position = vec4(vertexPos, 0.0, 1.0); 10 | } -------------------------------------------------------------------------------- /DeferredRenderer/ubershader.vert: -------------------------------------------------------------------------------- 1 | #version 420 core 2 | 3 | in vec2 vertexPos; 4 | 5 | out vec2 coord; 6 | 7 | void main() { 8 | coord = vertexPos * 0.5f + 0.5f; 9 | gl_Position = vec4(vertexPos, 0.0, 1.0); 10 | } -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Deferred Renderer 2 | A Deferred Renderer with support for point lights, shadow maps, SSAO, and skybox 3 | 4 | 5 | Required dependencies: 6 | - GLFW 7 | - GLEW 8 | - GLM 9 | 10 | Built with Visual Studio 2013 11 | -------------------------------------------------------------------------------- /DeferredRenderer/plShadow.vert: -------------------------------------------------------------------------------- 1 | #version 420 core 2 | 3 | layout(location = 0) in vec3 position; 4 | 5 | uniform mat4 mvp; 6 | 7 | out vec3 fragPos; 8 | 9 | void main() { 10 | gl_Position = mvp * vec4(position, 1.0); 11 | fragPos = position; 12 | } -------------------------------------------------------------------------------- /DeferredRenderer/PointLight.h: -------------------------------------------------------------------------------- 1 | #ifndef POINT_LIGHT_H 2 | #define POINT_LIGHT_H 3 | 4 | #include "common.h" 5 | 6 | struct PointLight { 7 | glm::vec3 position; 8 | glm::vec3 color; 9 | glm::vec3 attenuation; 10 | float radius; 11 | }; 12 | 13 | #endif -------------------------------------------------------------------------------- /DeferredRenderer/plShadow.frag: -------------------------------------------------------------------------------- 1 | #version 420 core 2 | 3 | in vec3 fragPos; 4 | 5 | uniform mat4 inverseMView; 6 | uniform vec3 worldPos; 7 | 8 | out float squaredDist; 9 | 10 | void main(void) { 11 | vec3 dist = worldPos - fragPos; 12 | squaredDist = dot(dist, dist); 13 | } -------------------------------------------------------------------------------- /DeferredRenderer/skybox.vert: -------------------------------------------------------------------------------- 1 | #version 420 core 2 | 3 | in vec2 position; 4 | 5 | uniform mat4 inverseVP; 6 | 7 | out vec3 fragPos; 8 | 9 | void main() { 10 | fragPos = normalize((inverseVP * vec4(position, 1.0, 1.0)).xyz); 11 | gl_Position = vec4(position, 1.0, 1.0); 12 | } 13 | -------------------------------------------------------------------------------- /DeferredRenderer/light.vert: -------------------------------------------------------------------------------- 1 | #version 420 core 2 | 3 | in vec3 position; 4 | 5 | uniform mat4 mView; 6 | uniform mat4 projection; 7 | 8 | uniform vec3 worldPos; 9 | uniform float radius; 10 | 11 | void main() { 12 | vec3 wPos = (position * radius) + worldPos; 13 | gl_Position = projection * mView * vec4(wPos, 1.0); 14 | } -------------------------------------------------------------------------------- /DeferredRenderer/PointLightShadowMap.h: -------------------------------------------------------------------------------- 1 | #ifndef POINT_LIGHT_SHADOW_MAP_H 2 | #define POINT_LIGHT_SHADOW_MAP_H 3 | 4 | #include "common.h" 5 | #include "ShadowMap.h" 6 | 7 | class PointLightShadowMap : public ShadowMap { 8 | public: 9 | GLuint cubeMap; 10 | 11 | PointLightShadowMap(int width, int height); 12 | ~PointLightShadowMap(); 13 | }; 14 | 15 | #endif -------------------------------------------------------------------------------- /DeferredRenderer/common.h: -------------------------------------------------------------------------------- 1 | #ifndef COMMON_H 2 | #define COMMON_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | #endif 16 | -------------------------------------------------------------------------------- /DeferredRenderer/VBO.h: -------------------------------------------------------------------------------- 1 | #ifndef VBO_H 2 | #define VBO_H 3 | 4 | #include "common.h" 5 | 6 | class VBO { 7 | public: 8 | VBO(); 9 | ~VBO(); 10 | 11 | void create(); 12 | void destroy(); 13 | void bind(GLuint type); 14 | GLuint getID() const; 15 | GLuint getBufferType() const; 16 | bool created() const; 17 | 18 | private: 19 | GLuint id; 20 | GLuint bufferType; 21 | }; 22 | 23 | #endif -------------------------------------------------------------------------------- /DeferredRenderer/SceneObject.h: -------------------------------------------------------------------------------- 1 | #ifndef SCENE_OBJECT_H 2 | #define SCENE_OBJECT_H 3 | 4 | #include "AABB.h" 5 | 6 | class SceneObject { 7 | public: 8 | SceneObject(); 9 | virtual ~SceneObject() = 0; 10 | 11 | virtual void update(float deltaT) = 0; 12 | virtual void destroy() = 0; 13 | 14 | AABB getAABB() const; 15 | 16 | protected: 17 | AABB bb; 18 | 19 | private: 20 | bool toBeDestroyed; 21 | }; 22 | 23 | #endif -------------------------------------------------------------------------------- /DeferredRenderer/ShadowMap.h: -------------------------------------------------------------------------------- 1 | #ifndef SHADOW_MAP_H 2 | #define SHADOW_MAP_H 3 | 4 | #include "common.h" 5 | 6 | class ShadowMap { 7 | public: 8 | GLuint depth; 9 | 10 | ShadowMap(int width, int height); 11 | ~ShadowMap(); 12 | void bind(); 13 | void bindDraw(); 14 | void bindRead(); 15 | void unbind(); 16 | void unbindDraw(); 17 | void unbindRead(); 18 | 19 | protected: 20 | GLuint fbo; 21 | 22 | int width, height; 23 | }; 24 | 25 | #endif -------------------------------------------------------------------------------- /DeferredRenderer/gbuffer.vert: -------------------------------------------------------------------------------- 1 | #version 420 core 2 | 3 | layout(location = 0) in vec3 position; 4 | layout(location = 1) in vec3 normal; 5 | 6 | uniform mat4 mView; 7 | uniform mat4 projection; 8 | uniform mat3 mNormal; 9 | 10 | out vec3 fragPos; 11 | out vec3 fragNormal; 12 | 13 | void main() { 14 | gl_Position = projection * mView * vec4(position, 1.0); 15 | fragPos = (mView * vec4(position, 1.0)).xyz; 16 | fragNormal = normalize(mNormal * normal); 17 | } -------------------------------------------------------------------------------- /DeferredRenderer/gbuffer.frag: -------------------------------------------------------------------------------- 1 | #version 420 core 2 | 3 | in vec3 fragPos; 4 | in vec3 fragNormal; 5 | 6 | uniform vec3 diffuse; 7 | uniform float specular; 8 | 9 | layout(location = 0) out vec4 position; 10 | layout(location = 1) out vec4 normal; 11 | layout(location = 2) out vec4 color; 12 | 13 | void main() { 14 | position = vec4(fragPos, 1.0); 15 | normal = vec4(fragNormal, specular); 16 | //normal = vec4(fragNormal * 0.5 + 0.5, specular); 17 | color = vec4(diffuse, 1.0); 18 | } -------------------------------------------------------------------------------- /DeferredRenderer/Octree.h: -------------------------------------------------------------------------------- 1 | #ifndef OCTREE_H 2 | #define OCTREE_H 3 | 4 | #include "common.h" 5 | #include "OctreeNode.h" 6 | 7 | #include 8 | 9 | class Octree { 10 | public: 11 | int maxObjects; 12 | int maxLevels; 13 | 14 | Octree(AABB rootBB); 15 | bool add(SceneObject &so); 16 | AABB getRootBB() const; 17 | std::vector findObjects(AABB bb); 18 | 19 | private: 20 | std::unique_ptr root; 21 | std::vector objectsOutsideRoot; 22 | }; 23 | 24 | #endif -------------------------------------------------------------------------------- /DeferredRenderer/FullscreenQuad.h: -------------------------------------------------------------------------------- 1 | #ifndef FULLSCREEN_QUAD_H 2 | #define FULLSCREEN_QUAD_H 3 | 4 | #include "common.h" 5 | #include "VBO.h" 6 | 7 | class FullscreenQuad { 8 | public: 9 | int numIndices; 10 | FullscreenQuad(); 11 | ~FullscreenQuad(); 12 | 13 | void clear(); 14 | void updateBuffers(std::vector& positions, std::vector& indices); 15 | void render(); 16 | 17 | private: 18 | GLuint vao; 19 | VBO positionBuffer; 20 | VBO indexBuffer; 21 | 22 | void setAttributes(); 23 | }; 24 | 25 | #endif -------------------------------------------------------------------------------- /DeferredRenderer/Mesh.h: -------------------------------------------------------------------------------- 1 | #ifndef MESH_H 2 | #define MESH_H 3 | 4 | #include "common.h" 5 | #include "VBO.h" 6 | 7 | class Mesh { 8 | public: 9 | int numIndices; 10 | glm::vec3 ambient; 11 | glm::vec3 diffuse; 12 | float specular; 13 | 14 | Mesh(); 15 | ~Mesh(); 16 | 17 | void create(); 18 | void updateBuffers(std::vector& positions, std::vector& indices, std::vector& normals); 19 | void updateBuffers(std::vector& positions, std::vector& indices); 20 | void clear(); 21 | void render(); 22 | bool hasBuffer() const; 23 | 24 | private: 25 | GLuint vao; 26 | VBO positionBuffer; 27 | VBO indexBuffer; 28 | VBO normalBuffer; 29 | 30 | void setAttributes(); 31 | }; 32 | 33 | #endif -------------------------------------------------------------------------------- /DeferredRenderer/GBuffer.h: -------------------------------------------------------------------------------- 1 | #ifndef GBUFFER_H 2 | #define GBUFFER_H 3 | 4 | #include "Shader.h" 5 | 6 | class GBuffer { 7 | public: 8 | GLuint position, normal, color, depth, light, effect1, effect2; 9 | 10 | GBuffer(int widthIn, int heightIn); 11 | ~GBuffer(); 12 | 13 | GLuint getFBO() const; 14 | int getWidth() const; 15 | int getHeight() const; 16 | void setDrawBuffers(); 17 | void setDrawLight(); 18 | void setDrawEffect(); 19 | void setDrawNone(); 20 | //void setReadBuffer(); 21 | void setReadEffect(); 22 | void bind(); 23 | void bindDraw(); 24 | void bindRead(); 25 | void unbind(); 26 | void unbindDraw(); 27 | void unbindRead(); 28 | void setGeomTextures(); 29 | 30 | private: 31 | GLenum drawBuffers[3]; 32 | 33 | GLuint fbo; 34 | 35 | int width, height; 36 | }; 37 | 38 | #endif -------------------------------------------------------------------------------- /DeferredRenderer/AABB.h: -------------------------------------------------------------------------------- 1 | #ifndef AABB_H 2 | #define AABB_H 3 | 4 | #include "common.h" 5 | 6 | class AABB { 7 | public: 8 | glm::vec3 upper; 9 | glm::vec3 lower; 10 | 11 | AABB(glm::vec3 lower, glm::vec3 upper); 12 | 13 | bool operator==(const AABB &bb); 14 | bool operator!=(const AABB &bb); 15 | 16 | glm::vec3 getCenter() const; 17 | void setCenter(glm::vec3 center); 18 | glm::vec3 getLower() const; 19 | void setLower(glm::vec3 lower); 20 | glm::vec3 getUpper() const; 21 | void setUpper(glm::vec3 upper); 22 | glm::vec3 getHalfDims() const; 23 | 24 | bool intersects(AABB bb) const; 25 | bool intersects(glm::vec3 p1, glm::vec3 p2) const; 26 | bool contains(AABB bb) const; 27 | bool contains(glm::vec3 p) const; 28 | 29 | private: 30 | glm::vec3 center; 31 | glm::vec3 halfDims; 32 | 33 | void calcCenter(); 34 | void calcHalfDims(); 35 | }; 36 | 37 | #endif -------------------------------------------------------------------------------- /DeferredRenderer/VBO.cpp: -------------------------------------------------------------------------------- 1 | #include "VBO.h" 2 | 3 | VBO::VBO() : id(0), bufferType(0) {} 4 | 5 | VBO::~VBO() { 6 | if (id != 0) glDeleteBuffers(1, &id); 7 | } 8 | 9 | void VBO::create() { 10 | glGenBuffers(1, &id); 11 | } 12 | 13 | void VBO::destroy() { 14 | if (bufferType != 0) { 15 | switch (bufferType) { 16 | case GL_ARRAY_BUFFER: 17 | glBindBuffer(bufferType, 0); 18 | break; 19 | case GL_ELEMENT_ARRAY_BUFFER: 20 | glBindBuffer(bufferType, 0); 21 | break; 22 | } 23 | } 24 | 25 | if (id != 0) glDeleteBuffers(1, &id); 26 | 27 | id = 0; 28 | } 29 | 30 | void VBO::bind(GLuint type) { 31 | bufferType = type; 32 | glBindBuffer(bufferType, id); 33 | } 34 | 35 | GLuint VBO::getID() const { 36 | return id; 37 | } 38 | 39 | GLuint VBO::getBufferType() const { 40 | return bufferType; 41 | } 42 | 43 | bool VBO::created() const { 44 | return id != 0; 45 | } -------------------------------------------------------------------------------- /DeferredRenderer/OctreeNode.h: -------------------------------------------------------------------------------- 1 | #ifndef OCTREE_NODE_H 2 | #define OCTREE_NODE_H 3 | 4 | #include "common.h" 5 | #include "SceneObject.h" 6 | #include 7 | 8 | class OctreeNode { 9 | public: 10 | OctreeNode(AABB bb, int level, OctreeNode *parent, int maxObjects); 11 | 12 | std::vector getObjects(); 13 | bool add(SceneObject &so); 14 | AABB getAABB() const; 15 | bool leafNode() const; 16 | std::vector> &getChildren(); 17 | 18 | private: 19 | OctreeNode *parent; 20 | int level; 21 | int maxObjects; 22 | bool isLeaf; 23 | std::vector> children; 24 | std::vector objects; 25 | AABB bb; 26 | 27 | //void mergeChildren(); //Unnecessary if rebuilding octree each frame 28 | //void destroyChildren(); //Unnecessary if rebuilding octree each frame 29 | bool partition(); 30 | }; 31 | 32 | #endif -------------------------------------------------------------------------------- /DeferredRenderer/PointLightShadowMap.cpp: -------------------------------------------------------------------------------- 1 | #include "PointLightShadowMap.h" 2 | 3 | PointLightShadowMap::PointLightShadowMap(int width, int height) : ShadowMap(width, height) { 4 | //Create cubemap texture for 6 sided depth map 5 | glGenTextures(1, &cubeMap); 6 | glBindTexture(GL_TEXTURE_CUBE_MAP, cubeMap); 7 | glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR); 8 | glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_LINEAR); 9 | glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); 10 | glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); 11 | glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE); 12 | 13 | for (int i = 0; i < 6; i++) { 14 | glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, GL_RGBA16F, width, height, 0, GL_RGBA, GL_FLOAT, NULL); 15 | } 16 | } 17 | 18 | PointLightShadowMap::~PointLightShadowMap() { 19 | if (fbo != 0) { 20 | glDeleteTextures(1, &cubeMap); 21 | } 22 | } -------------------------------------------------------------------------------- /DeferredRenderer/blur.frag: -------------------------------------------------------------------------------- 1 | #version 420 core 2 | 3 | in vec2 coord; 4 | 5 | uniform sampler2D ssaoMap; 6 | 7 | out vec4 fragColor; 8 | 9 | const int blurSize = 1; 10 | 11 | void main() { 12 | vec4 result = vec4(0.0); 13 | vec2 hlim = vec2(float(-blurSize) * 0.5 + 0.5); 14 | for (int x = -blurSize; x < blurSize; x++) { 15 | for (int y = -blurSize; y < blurSize; y++) { 16 | vec2 offset = (hlim + vec2(float(x), float(y))) * vec2(1.0 / 1280, 1.0 / 720); //TODO: pass in; 17 | result += texture(ssaoMap, coord + offset); 18 | } 19 | } 20 | 21 | fragColor = result / float(blurSize * 4 * blurSize); 22 | } 23 | 24 | /*vec4 bilateralFilter() { 25 | vec4 color = vec4(0.0); 26 | vec2 center = gl_TexCoord[0].xy; 27 | vec2 sample; 28 | float sum = 0.0; 29 | float coefG,coefZ,finalCoef; 30 | float Zp = getDepth(center); 31 | 32 | const float epsilon = 0.01; 33 | 34 | for(int i = -(kernelSize-1)/2; i <= (kernelSize-1)/2; i++) { 35 | for(int j = -(kernelSize-1)/2; j <= (kernelSize-1)/2; j++) { 36 | sample = center + vec2(i,j) / texSize; 37 | coefG = gaussianCoef(i,j); 38 | float zTmp = getDepth(sample); 39 | coefZ = 1.0 / (epsilon + abs(Zp - zTmp)); 40 | finalCoef = coefG * coefZ; 41 | sum += finalCoef; 42 | color += finalCoef * texture2D(AOTex,sample); 43 | } 44 | } 45 | 46 | return color / sum; 47 | }*/ -------------------------------------------------------------------------------- /DeferredRenderer.sln: -------------------------------------------------------------------------------- 1 | 2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 2013 4 | VisualStudioVersion = 12.0.21005.1 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "DeferredRenderer", "DeferredRenderer\DeferredRenderer.vcxproj", "{8DA95418-9394-491A-ADFF-3AB3A1D3CF36}" 7 | EndProject 8 | Global 9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 10 | Debug|Win32 = Debug|Win32 11 | Debug|x64 = Debug|x64 12 | Release|Win32 = Release|Win32 13 | Release|x64 = Release|x64 14 | EndGlobalSection 15 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 16 | {8DA95418-9394-491A-ADFF-3AB3A1D3CF36}.Debug|Win32.ActiveCfg = Debug|Win32 17 | {8DA95418-9394-491A-ADFF-3AB3A1D3CF36}.Debug|Win32.Build.0 = Debug|Win32 18 | {8DA95418-9394-491A-ADFF-3AB3A1D3CF36}.Debug|x64.ActiveCfg = Debug|x64 19 | {8DA95418-9394-491A-ADFF-3AB3A1D3CF36}.Debug|x64.Build.0 = Debug|x64 20 | {8DA95418-9394-491A-ADFF-3AB3A1D3CF36}.Release|Win32.ActiveCfg = Release|Win32 21 | {8DA95418-9394-491A-ADFF-3AB3A1D3CF36}.Release|Win32.Build.0 = Release|Win32 22 | {8DA95418-9394-491A-ADFF-3AB3A1D3CF36}.Release|x64.ActiveCfg = Release|x64 23 | {8DA95418-9394-491A-ADFF-3AB3A1D3CF36}.Release|x64.Build.0 = Release|x64 24 | EndGlobalSection 25 | GlobalSection(SolutionProperties) = preSolution 26 | HideSolutionNode = FALSE 27 | EndGlobalSection 28 | EndGlobal 29 | -------------------------------------------------------------------------------- /DeferredRenderer/Octree.cpp: -------------------------------------------------------------------------------- 1 | #include "Octree.h" 2 | 3 | using namespace std; 4 | 5 | Octree::Octree(AABB rootBB) : maxObjects(6), maxLevels(20) { 6 | this->root.reset(new OctreeNode(rootBB, 0, nullptr, maxObjects)); 7 | } 8 | 9 | /** 10 | * Adds object to the octree 11 | * Returns true if object is within the bounds of the tree 12 | * False otherwise 13 | */ 14 | bool Octree::add(SceneObject &so) { 15 | if (root->getAABB().contains(so.getAABB())) { 16 | root->add(so); 17 | return true; 18 | } else { 19 | objectsOutsideRoot.push_back(&so); 20 | return false; 21 | } 22 | } 23 | 24 | AABB Octree::getRootBB() const { 25 | return root->getAABB(); 26 | } 27 | 28 | /** 29 | * Returns a vector of all sceneobjects that intersect the specified AABB region 30 | */ 31 | vector Octree::findObjects(AABB bb) { 32 | vector objs; 33 | for (auto &o : objectsOutsideRoot) { 34 | if (bb.intersects(o->getAABB())) { 35 | objs.push_back(o); 36 | } 37 | } 38 | 39 | vector octree; 40 | octree.push_back(root.get()); 41 | while (!octree.empty()) { 42 | OctreeNode *cur = octree.back(); 43 | octree.pop_back(); 44 | 45 | if (bb.intersects(cur->getAABB())) { 46 | for (auto &o : cur->getObjects()) { 47 | if (bb.intersects(o->getAABB())) { 48 | objs.push_back(o); 49 | } 50 | } 51 | } 52 | 53 | if (!cur->leafNode()) { 54 | for (auto &c : cur->getChildren()) { 55 | octree.push_back(c.get()); 56 | } 57 | } 58 | } 59 | 60 | return objs; 61 | } -------------------------------------------------------------------------------- /DeferredRenderer/ssao.frag: -------------------------------------------------------------------------------- 1 | #version 420 core 2 | 3 | in vec2 coord; 4 | 5 | uniform mat4 projection; 6 | 7 | uniform int kernelSize; 8 | uniform vec2 noiseScale; 9 | uniform vec3 kernel[500]; 10 | 11 | uniform sampler2D positionMap; 12 | uniform sampler2D normalMap; 13 | uniform sampler2D noiseMap; 14 | 15 | out vec4 fragColor; 16 | 17 | const float radius = 10; 18 | const int occlPower = 1; 19 | 20 | void main() { 21 | vec3 normal = normalize(texture(normalMap, coord).xyz); 22 | vec3 pos = texture(positionMap, coord).xyz; 23 | 24 | vec3 origin = pos; 25 | 26 | vec3 rVec = texture(noiseMap, coord * noiseScale).xyz * 2.0 - 1.0; 27 | vec3 tangent = normalize(rVec - normal * dot(rVec, normal)); 28 | vec3 bitangent = cross(normal, tangent); 29 | mat3 tbn = mat3(tangent, bitangent, normal); 30 | 31 | float occlusion = 0.0f; 32 | for (int i = 0; i < kernelSize; i++) { 33 | //Get sample position 34 | vec3 s = tbn * kernel[i]; 35 | s = s * radius + origin; 36 | 37 | //Project sample position 38 | vec4 offset = vec4(s, 1.0); 39 | offset = projection * offset; 40 | offset.xy /= offset.w; 41 | offset.xy = offset.xy * 0.5 + 0.5; 42 | 43 | //Get sample depth 44 | float sampleDepth = texture(positionMap, offset.xy).z; 45 | 46 | //Range check and accumulate 47 | float rangeCheck = abs(origin.z - sampleDepth) < radius ? 1.0 : 0.0; 48 | occlusion += (sampleDepth >= s.z ? 1.0 : 0.0) * rangeCheck; 49 | } 50 | 51 | occlusion = 1.0 - (occlusion / float(kernelSize)); 52 | 53 | fragColor = vec4(vec3(pow(occlusion, occlPower)), 1); 54 | } -------------------------------------------------------------------------------- /DeferredRenderer/light.frag: -------------------------------------------------------------------------------- 1 | #version 420 core 2 | 3 | uniform sampler2D positionMap; 4 | uniform sampler2D normalMap; 5 | uniform sampler2D colorMap; 6 | uniform samplerCube shadowMap; 7 | 8 | uniform mat4 inverseMView; 9 | uniform vec3 lPos; 10 | uniform vec3 worldPos; 11 | uniform float radius; 12 | uniform vec3 lightColor; 13 | uniform vec3 lightAttenuation; 14 | uniform vec2 screenSize; 15 | 16 | out vec4 fragColor; 17 | 18 | const float specularPower = 16.0f; 19 | 20 | float getShadowFactor(vec3 position) { 21 | float sDist = texture(shadowMap, normalize(position - worldPos)).x; 22 | float fDist = dot(worldPos - position, worldPos - position); 23 | 24 | if (fDist * 0.95 < sDist) return 1.0; 25 | else return 0.5; 26 | } 27 | 28 | void main() { 29 | vec2 coord = gl_FragCoord.xy / screenSize; 30 | vec3 n = normalize(texture(normalMap, coord).xyz); 31 | float s = texture(normalMap, coord).w; 32 | vec3 pos = texture(positionMap, coord).xyz; 33 | vec3 color = texture(colorMap, coord).xyz; 34 | 35 | float shadowFactor = getShadowFactor((inverseMView * vec4(pos, 1.0)).xyz); 36 | 37 | float r = length(lPos - pos); 38 | float attenuation = dot(lightAttenuation, vec3(1, r, 0)); 39 | vec3 l = (lPos - pos) / r; 40 | vec3 v = -normalize(pos); 41 | vec3 h = normalize(v + l); 42 | 43 | float ndotl = dot(n, l); 44 | vec3 diffuse = max(0.0f, ndotl) * color; 45 | 46 | vec3 specular = vec3(0); 47 | if (ndotl >= 0) specular = pow(max(0.0f, dot(n, h)), specularPower) * vec3(s); 48 | 49 | fragColor = vec4(shadowFactor * lightColor * (diffuse + specular), 1); 50 | //fragColor = vec4(vec3(shadowFactor), 1); 51 | } -------------------------------------------------------------------------------- /DeferredRenderer/FullscreenQuad.cpp: -------------------------------------------------------------------------------- 1 | #include "FullscreenQuad.h" 2 | 3 | using namespace std; 4 | 5 | FullscreenQuad::FullscreenQuad() : numIndices(0), vao(0), positionBuffer(VBO()), indexBuffer(VBO()) { 6 | vector positions = { 7 | 1.0f, 1.0f, //Top Right 8 | 1.0f, -1.0f, //Bottom Right 9 | -1.0f, -1.0f, //Bottom Left 10 | -1.0f, 1.0f //Top Left 11 | }; 12 | vector indices = { 13 | 0, 1, 3, //First Triangle 14 | 1, 2, 3 //Second Triangle 15 | }; 16 | 17 | glGenVertexArrays(1, &vao); 18 | positionBuffer.create(); 19 | indexBuffer.create(); 20 | updateBuffers(positions, indices); 21 | } 22 | 23 | FullscreenQuad::~FullscreenQuad() { 24 | glDeleteVertexArrays(1, &vao); 25 | } 26 | 27 | void FullscreenQuad::clear() { 28 | numIndices = 0; 29 | } 30 | 31 | void FullscreenQuad::updateBuffers(vector& positions, vector& indices) { 32 | numIndices = int(indices.size()); 33 | glBindVertexArray(vao); 34 | 35 | positionBuffer.bind(GL_ARRAY_BUFFER); 36 | glBufferData(GL_ARRAY_BUFFER, sizeof(float)* positions.size(), &positions[0], GL_STATIC_DRAW); 37 | 38 | indexBuffer.bind(GL_ELEMENT_ARRAY_BUFFER); 39 | glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(GLuint)* indices.size(), &indices[0], GL_STATIC_DRAW); 40 | 41 | setAttributes(); 42 | glBindVertexArray(0); 43 | } 44 | 45 | void FullscreenQuad::setAttributes() { 46 | positionBuffer.bind(GL_ARRAY_BUFFER); 47 | glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, 0); 48 | glEnableVertexAttribArray(0); 49 | } 50 | 51 | void FullscreenQuad::render() { 52 | glBindVertexArray(vao); 53 | glDrawElements(GL_TRIANGLES, numIndices, GL_UNSIGNED_INT, 0); 54 | } -------------------------------------------------------------------------------- /DeferredRenderer/ShadowMap.cpp: -------------------------------------------------------------------------------- 1 | #include "ShadowMap.h" 2 | 3 | ShadowMap::ShadowMap(int width, int height) : width(width), height(height) { 4 | //Create FBO 5 | glGenFramebuffers(1, &fbo); 6 | glBindFramebuffer(GL_FRAMEBUFFER, fbo); 7 | 8 | //Create depth texture 9 | glGenTextures(1, &depth); 10 | glBindTexture(GL_TEXTURE_2D, depth); 11 | glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT16, width, height, 0, GL_DEPTH_COMPONENT, GL_FLOAT, nullptr); 12 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); 13 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); 14 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); 15 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); 16 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE, GL_COMPARE_REF_TO_TEXTURE); 17 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_FUNC, GL_LEQUAL); 18 | 19 | glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, depth, 0); 20 | 21 | glDrawBuffer(GL_NONE); 22 | glReadBuffer(GL_NONE); 23 | 24 | //Unbind 25 | glBindFramebuffer(GL_FRAMEBUFFER, 0); 26 | } 27 | 28 | ShadowMap::~ShadowMap() { 29 | if (fbo != 0) { 30 | glDeleteFramebuffers(1, &fbo); 31 | glDeleteTextures(1, &depth); 32 | } 33 | } 34 | 35 | void ShadowMap::bind() { 36 | glBindFramebuffer(GL_FRAMEBUFFER, fbo); 37 | } 38 | 39 | void ShadowMap::bindDraw() { 40 | glBindFramebuffer(GL_DRAW_FRAMEBUFFER, fbo); 41 | } 42 | 43 | void ShadowMap::bindRead() { 44 | glBindFramebuffer(GL_READ_FRAMEBUFFER, fbo); 45 | } 46 | 47 | void ShadowMap::unbind() { 48 | glBindFramebuffer(GL_FRAMEBUFFER, 0); 49 | } 50 | 51 | void ShadowMap::unbindDraw() { 52 | glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0); 53 | } 54 | 55 | void ShadowMap::unbindRead() { 56 | glBindFramebuffer(GL_READ_FRAMEBUFFER, 0); 57 | } -------------------------------------------------------------------------------- /DeferredRenderer/Scene.h: -------------------------------------------------------------------------------- 1 | #ifndef SCENE_H 2 | #define SCENE_H 3 | 4 | #include "common.h" 5 | #include "SceneObject.h" 6 | #include "Octree.h" 7 | #include "GBuffer.h" 8 | #include "AABB.h" 9 | #include "Mesh.h" 10 | #include "FullscreenQuad.h" 11 | #include "Camera.hpp" 12 | #include "Shader.h" 13 | #include "PointLight.h" 14 | #include "MeshHelper.h" 15 | #include "ShadowMap.h" 16 | #include "PointLightShadowMap.h" 17 | #include "tiny_obj_loader.h" 18 | #include 19 | #include 20 | 21 | class Scene { 22 | public: 23 | Scene(int width, int height, Camera& cam); 24 | ~Scene(); 25 | 26 | void loadMeshes(); 27 | void renderScene(Camera &cam); 28 | void setType(int type); 29 | 30 | private: 31 | int type; 32 | int width, height; 33 | float aspectRatio; 34 | 35 | glm::mat4 mView, projection, dLightMView, dLightProjection; 36 | glm::mat3 normalMatrix; 37 | 38 | CameraDireciton directions[6]; 39 | 40 | GLuint noiseTex, skyboxTexture; 41 | glm::vec2 noiseScale; 42 | 43 | GBuffer gBuffer; 44 | ShadowMap dLightShadow; 45 | PointLightShadowMap pLightShadow; 46 | Shader geometry; 47 | Shader shadow; 48 | Shader plShadow; 49 | Shader stencil; 50 | Shader lightPass; 51 | Shader ssao; 52 | Shader blur; 53 | Shader finalPass; 54 | Shader skybox; 55 | FullscreenQuad fsQuad; 56 | //Octree octree; 57 | //std::vector visibleObjects; 58 | Mesh sphere; 59 | std::vector lights; 60 | std::vector meshes; 61 | std::vector kernel; 62 | 63 | void loadCubemap(); 64 | void initKernel(); 65 | void geometryPass(); 66 | void shadowPass(); 67 | void plShadowPass(PointLight pl); 68 | void stencilPass(PointLight pl); 69 | void pointLightPass(PointLight pl); 70 | void ssaoPass(); 71 | void blurPass(); 72 | void compositePass(); 73 | void skyboxPass(); 74 | }; 75 | 76 | #endif -------------------------------------------------------------------------------- /DeferredRenderer/OctreeNode.cpp: -------------------------------------------------------------------------------- 1 | #include "OctreeNode.h" 2 | 3 | using namespace std; 4 | 5 | OctreeNode::OctreeNode(AABB bb, int level, OctreeNode *parent, int maxObjects) : isLeaf(true), bb(bb), level(level), parent(parent), maxObjects(maxObjects) {} 6 | 7 | vector OctreeNode::getObjects() { 8 | return objects; 9 | } 10 | 11 | bool OctreeNode::add(SceneObject &so) { 12 | bool inserted = false; 13 | if (bb.contains(so.getAABB())) { 14 | if (isLeaf) { 15 | if (objects.size() < maxObjects) objects.push_back(&so); 16 | else { 17 | partition(); 18 | for (auto &c : children) { 19 | inserted = c->add(so); 20 | } 21 | 22 | if (!inserted) objects.push_back(&so); //Over maxObject limit 23 | } 24 | return true; 25 | } else { 26 | for (auto &c : children) { 27 | c->add(so); 28 | } 29 | return true; 30 | } 31 | } else { 32 | return false; 33 | } 34 | } 35 | 36 | /** 37 | * Returns true if the Node is successfully partitioned 38 | * Returns false if the Node is not a leaf 39 | */ 40 | bool OctreeNode::partition() { 41 | if (!isLeaf) return false; 42 | 43 | glm::vec3 halfDims = bb.getHalfDims(); 44 | for (int x = 0; x < 2; x++) { 45 | for (int y = 0; y < 2; y++) { 46 | for (int z = 0; z < 2; z++) { 47 | glm::vec3 offset = glm::vec3(x * halfDims.x, y * halfDims.y, z * halfDims.z); 48 | AABB childBB(bb.getLower() + offset, bb.getCenter() + offset); 49 | 50 | children[x + y * 2 + z * 4].reset(new OctreeNode(childBB, level + 1, this, maxObjects)); 51 | } 52 | } 53 | } 54 | 55 | isLeaf = false; 56 | return true; 57 | } 58 | 59 | AABB OctreeNode::getAABB() const { 60 | return bb; 61 | } 62 | 63 | bool OctreeNode::leafNode() const { 64 | return isLeaf; 65 | } 66 | 67 | vector> &OctreeNode::getChildren() { 68 | return children; 69 | } -------------------------------------------------------------------------------- /DeferredRenderer/Camera.hpp: -------------------------------------------------------------------------------- 1 | #ifndef CAMERA_H 2 | #define CAMERA_H 3 | 4 | #include "common.h" 5 | #include 6 | 7 | enum Movement { 8 | FORWARD, 9 | BACKWARD, 10 | LEFT, 11 | RIGHT, 12 | UP, 13 | DOWN 14 | }; 15 | 16 | struct CameraDireciton { 17 | GLenum face; 18 | glm::vec3 target; 19 | glm::vec3 up; 20 | }; 21 | 22 | class Camera { 23 | public: 24 | glm::vec3 eye; 25 | glm::vec3 front; 26 | glm::vec3 up; 27 | glm::vec3 right; 28 | 29 | GLfloat yaw; 30 | GLfloat pitch; 31 | 32 | float speed; 33 | float mouseSens; 34 | GLfloat zoom; 35 | 36 | Camera() : eye(glm::vec3(300.0f, 300.0f, 300.0f)), 37 | front(glm::normalize(glm::vec3(cos(glm::radians(-90.0f)), 0.0f, sin(glm::radians(-90.0f))))), 38 | up(glm::vec3(0.0f, 1.0f, 0.0f)), 39 | right(glm::cross(up, (eye - front))), 40 | yaw(-90.0f), 41 | pitch(0.0f), 42 | speed(50.0f), 43 | mouseSens(4.0f), 44 | zoom(45.0f) 45 | {} 46 | 47 | glm::mat4 getMView() { 48 | return glm::lookAt(eye, glm::vec3(0.0f, 0.0f, 0.0f), up); 49 | //return glm::lookAt(eye, eye + front, up); 50 | } 51 | 52 | void wasdMovement(Movement dir, float deltaTime) { 53 | float velocity = speed * deltaTime; 54 | switch (dir) { 55 | case FORWARD: 56 | eye += front * velocity; 57 | break; 58 | case BACKWARD: 59 | eye -= front * velocity; 60 | break; 61 | case LEFT: 62 | eye -= glm::normalize(glm::cross(front, up)) * velocity; 63 | break; 64 | case RIGHT: 65 | eye += glm::normalize(glm::cross(front, up)) * velocity; 66 | break; 67 | case UP: 68 | eye.y += 2 * (float)velocity; 69 | break; 70 | case DOWN: 71 | eye.y -= 2 * (float)velocity; 72 | break; 73 | } 74 | } 75 | 76 | void mouseMovement(float xoffset, float yoffset, float deltaTime) { 77 | yaw += (GLfloat)(mouseSens * deltaTime * xoffset); 78 | pitch += (GLfloat)(mouseSens * deltaTime * yoffset); 79 | 80 | if (pitch > 89.0f) pitch = 89.0f; 81 | if (pitch < -89.0f) pitch = -89.0f; 82 | 83 | front.x = cos(glm::radians(yaw)) * cos(glm::radians(pitch)); 84 | front.y = sin(glm::radians(pitch)); 85 | front.z = sin(glm::radians(yaw)) * cos(glm::radians(pitch)); 86 | front = glm::normalize(front); 87 | } 88 | }; 89 | 90 | #endif -------------------------------------------------------------------------------- /DeferredRenderer/Mesh.cpp: -------------------------------------------------------------------------------- 1 | #include "Mesh.h" 2 | 3 | using namespace std; 4 | 5 | Mesh::Mesh() : numIndices(0), vao(0), positionBuffer(VBO()), indexBuffer(VBO()), normalBuffer(VBO()) {} 6 | 7 | Mesh::~Mesh() { 8 | glDeleteVertexArrays(1, &vao); 9 | } 10 | 11 | void Mesh::create() { 12 | glGenVertexArrays(1, &vao); 13 | positionBuffer.create(); 14 | indexBuffer.create(); 15 | normalBuffer.create(); 16 | } 17 | 18 | void Mesh::updateBuffers(vector& positions, vector& indices, vector& normals) { 19 | numIndices = int(indices.size()); 20 | glBindVertexArray(vao); 21 | 22 | positionBuffer.bind(GL_ARRAY_BUFFER); 23 | glBufferData(GL_ARRAY_BUFFER, sizeof(float) * positions.size(), &positions[0], GL_STATIC_DRAW); 24 | 25 | if (normals.size() != 0) { 26 | normalBuffer.bind(GL_ARRAY_BUFFER); 27 | glBufferData(GL_ARRAY_BUFFER, sizeof(float) * normals.size(), &normals[0], GL_STATIC_DRAW); 28 | } 29 | 30 | indexBuffer.bind(GL_ELEMENT_ARRAY_BUFFER); 31 | glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(GLuint) * indices.size(), &indices[0], GL_STATIC_DRAW); 32 | 33 | setAttributes(); 34 | glBindVertexArray(0); 35 | } 36 | 37 | void Mesh::updateBuffers(vector& positions, vector& indices) { 38 | numIndices = int(indices.size()); 39 | glBindVertexArray(vao); 40 | 41 | positionBuffer.bind(GL_ARRAY_BUFFER); 42 | glBufferData(GL_ARRAY_BUFFER, sizeof(glm::vec3) * positions.size(), &positions[0], GL_STATIC_DRAW); 43 | 44 | indexBuffer.bind(GL_ELEMENT_ARRAY_BUFFER); 45 | glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(GLuint) * indices.size(), &indices[0], GL_STATIC_DRAW); 46 | 47 | setAttributes(); 48 | glBindVertexArray(0); 49 | } 50 | 51 | void Mesh::clear() { 52 | numIndices = 0; 53 | } 54 | 55 | void Mesh::render() { 56 | glBindVertexArray(vao); 57 | glDrawElements(GL_TRIANGLES, numIndices, GL_UNSIGNED_INT, 0); 58 | } 59 | 60 | void Mesh::setAttributes() { 61 | if (hasBuffer()) { 62 | positionBuffer.bind(GL_ARRAY_BUFFER); 63 | glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, 0); 64 | glEnableVertexAttribArray(0); 65 | 66 | normalBuffer.bind(GL_ARRAY_BUFFER); 67 | glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 0, 0); 68 | glEnableVertexAttribArray(1); 69 | } else { 70 | //glBindBuffer(GL_ARRAY_BUFFER, 0); 71 | //glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); 72 | //glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(float), &positions[0]); 73 | //glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, sizeof(float), &normals[0]); 74 | } 75 | } 76 | 77 | bool Mesh::hasBuffer() const { 78 | return positionBuffer.created(); 79 | } -------------------------------------------------------------------------------- /DeferredRenderer/ubershader.frag: -------------------------------------------------------------------------------- 1 | #version 420 core 2 | 3 | in vec2 coord; 4 | 5 | uniform mat4 inverseMView; 6 | 7 | uniform sampler2D positionMap; 8 | uniform sampler2D normalMap; 9 | uniform sampler2D colorMap; 10 | uniform sampler2D lightMap; 11 | uniform sampler2D ssaoMap; 12 | uniform sampler2DShadow shadowMap; 13 | 14 | uniform vec3 l; 15 | uniform mat4 shadowMapMVP; 16 | uniform int shadowMapWidth; 17 | uniform int shadowMapHeight; 18 | 19 | uniform int type; 20 | 21 | out vec4 fragColor; 22 | 23 | const float specularPower = 16.0f; 24 | const vec3 lightColor = vec3(0.5); 25 | 26 | float linearizeDepth(float depth) { 27 | float f = 2000.0; 28 | float n = 10.0; 29 | return (2 * n) / (f + n - depth * (f - n)); 30 | } 31 | 32 | float getShadowFactor(vec3 position) { 33 | vec4 p = inverseMView * vec4(position, 1.0); 34 | p = shadowMapMVP * p; 35 | p /= p.w; 36 | p.xyz = p.xyz * 0.5 + 0.5; 37 | 38 | float factor = 0; 39 | 40 | vec2 offset = vec2(1.0 / float(shadowMapWidth), 1.0 / float(shadowMapHeight)); 41 | 42 | for (int y = -1; y <= 1; y++) { 43 | for (int x = -1; x <= 1; x++) { 44 | vec3 uvc = vec3(p.xy + (vec2(x,y) * offset), p.z - 0.005); 45 | factor += texture(shadowMap, uvc); 46 | } 47 | } 48 | 49 | return (0.5 + (factor / 18)); 50 | } 51 | 52 | void main() { 53 | vec3 n = normalize(texture(normalMap, coord).xyz); 54 | float s = texture(normalMap, coord).w; 55 | vec3 pos = texture(positionMap, coord).xyz; 56 | vec3 color = texture(colorMap, coord).xyz; 57 | vec3 light = texture(lightMap, coord).xyz; 58 | float ssao = texture(ssaoMap, coord).x; 59 | 60 | float shadowFactor = getShadowFactor(pos); 61 | 62 | vec3 ambient = color * 0.1; 63 | 64 | vec3 v = -normalize(pos); 65 | vec3 h = normalize(v + l); 66 | 67 | float ndotl = dot(n, l); 68 | vec3 diffuse = max(0.0f, ndotl) * color; 69 | 70 | vec3 specular = vec3(0); 71 | if (ndotl >= 0) specular = pow(max(0.0f, dot(n, h)), specularPower) * vec3(s); 72 | 73 | vec3 finalColor = lightColor * (diffuse + specular); 74 | 75 | if (type == 0) { 76 | fragColor = vec4(color, 1); 77 | } else if (type == 1) { 78 | fragColor = vec4(n, 1); 79 | } else if (type == 2) { 80 | fragColor = vec4(ssao); 81 | } else if (type == 3) { 82 | fragColor = vec4(finalColor, 1); 83 | } else if (type == 4) { 84 | fragColor = vec4(light * ssao, 1); 85 | } else if (type == 5) { 86 | fragColor = vec4((ambient + finalColor) * ssao, 1); 87 | } else if (type == 6) { 88 | fragColor = vec4((ambient + (finalColor * shadowFactor)) * ssao, 1); 89 | } else if (type == 7) { 90 | fragColor = vec4((ambient + light + (finalColor * shadowFactor)) * ssao, 1); 91 | } 92 | } -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | ############################################################################### 2 | # Set default behavior to automatically normalize line endings. 3 | ############################################################################### 4 | * text=auto 5 | 6 | ############################################################################### 7 | # Set default behavior for command prompt diff. 8 | # 9 | # This is need for earlier builds of msysgit that does not have it on by 10 | # default for csharp files. 11 | # Note: This is only used by command line 12 | ############################################################################### 13 | #*.cs diff=csharp 14 | 15 | ############################################################################### 16 | # Set the merge driver for project and solution files 17 | # 18 | # Merging from the command prompt will add diff markers to the files if there 19 | # are conflicts (Merging from VS is not affected by the settings below, in VS 20 | # the diff markers are never inserted). Diff markers may cause the following 21 | # file extensions to fail to load in VS. An alternative would be to treat 22 | # these files as binary and thus will always conflict and require user 23 | # intervention with every merge. To do so, just uncomment the entries below 24 | ############################################################################### 25 | #*.sln merge=binary 26 | #*.csproj merge=binary 27 | #*.vbproj merge=binary 28 | #*.vcxproj merge=binary 29 | #*.vcproj merge=binary 30 | #*.dbproj merge=binary 31 | #*.fsproj merge=binary 32 | #*.lsproj merge=binary 33 | #*.wixproj merge=binary 34 | #*.modelproj merge=binary 35 | #*.sqlproj merge=binary 36 | #*.wwaproj merge=binary 37 | 38 | ############################################################################### 39 | # behavior for image files 40 | # 41 | # image files are treated as binary by default. 42 | ############################################################################### 43 | #*.jpg binary 44 | #*.png binary 45 | #*.gif binary 46 | 47 | ############################################################################### 48 | # diff behavior for common document formats 49 | # 50 | # Convert binary document formats to text before diffing them. This feature 51 | # is only available from the command line. Turn it on by uncommenting the 52 | # entries below. 53 | ############################################################################### 54 | #*.doc diff=astextplain 55 | #*.DOC diff=astextplain 56 | #*.docx diff=astextplain 57 | #*.DOCX diff=astextplain 58 | #*.dot diff=astextplain 59 | #*.DOT diff=astextplain 60 | #*.pdf diff=astextplain 61 | #*.PDF diff=astextplain 62 | #*.rtf diff=astextplain 63 | #*.RTF diff=astextplain 64 | -------------------------------------------------------------------------------- /DeferredRenderer/AABB.cpp: -------------------------------------------------------------------------------- 1 | #include "AABB.h" 2 | 3 | using namespace std; 4 | 5 | AABB::AABB(glm::vec3 lower, glm::vec3 upper) : lower(lower), upper(upper) { 6 | calcCenter(); 7 | calcHalfDims(); 8 | } 9 | 10 | bool AABB::operator==(const AABB &bb) { 11 | return lower == bb.lower && upper == bb.upper; 12 | } 13 | 14 | bool AABB::operator!=(const AABB &bb) { 15 | return lower != bb.lower || upper != bb.upper; 16 | } 17 | 18 | glm::vec3 AABB::getCenter() const { 19 | return center; 20 | } 21 | 22 | void AABB::setCenter(glm::vec3 center) { 23 | this->center = center; 24 | } 25 | 26 | glm::vec3 AABB::getLower() const { 27 | return lower; 28 | } 29 | 30 | void AABB::setLower(glm::vec3 lower) { 31 | this->lower = lower; 32 | } 33 | 34 | glm::vec3 AABB::getUpper() const { 35 | return upper; 36 | } 37 | 38 | void AABB::setUpper(glm::vec3 upper) { 39 | this->upper = upper; 40 | } 41 | 42 | glm::vec3 AABB::getHalfDims() const { 43 | return halfDims; 44 | } 45 | 46 | bool AABB::intersects(AABB bb) const { 47 | if (upper.x < bb.lower.x) 48 | return false; 49 | if (upper.y < bb.lower.y) 50 | return false; 51 | if (upper.z < bb.lower.z) 52 | return false; 53 | if (lower.x > bb.upper.x) 54 | return false; 55 | if (lower.y > bb.upper.y) 56 | return false; 57 | if (lower.z > bb.upper.z) 58 | return false; 59 | 60 | return true; 61 | } 62 | 63 | bool AABB::intersects(glm::vec3 p1, glm::vec3 p2) const { 64 | glm::vec3 d = (p2 - p1) * 0.5f; 65 | glm::vec3 e = (upper - lower) * 0.5f; 66 | glm::vec3 c = p1 + d - (lower + upper) * 0.5f; 67 | glm::vec3 ad = glm::vec3(fabs(d.x), fabs(d.y), fabs(d.z)); 68 | 69 | if (fabs(c.x) > e.x + ad.x) 70 | return false; 71 | if (fabs(c.y) > e.y + ad.y) 72 | return false; 73 | if (fabs(c.z) > e.z + ad.z) 74 | return false; 75 | 76 | float epsilon = numeric_limits::epsilon(); 77 | 78 | if (fabs(d.y * c.z - d.z * c.y) > e.y * ad.z + e.z * ad.y + epsilon) 79 | return false; 80 | if (fabs(d.z * c.x - d.x * c.z) > e.z * ad.x + e.x * ad.z + epsilon) 81 | return false; 82 | if (fabs(d.x * c.y - d.y * c.x) > e.x * ad.y + e.y * ad.x + epsilon) 83 | return false; 84 | 85 | return true; 86 | } 87 | 88 | bool AABB::contains(AABB bb) const { 89 | if (bb.lower.x >= lower.x && bb.upper.x <= upper.x && bb.lower.y >= lower.y && 90 | bb.upper.y <= upper.y && bb.lower.z >= lower.z && bb.upper.z <= upper.z) 91 | return true; 92 | 93 | return false; 94 | } 95 | 96 | bool AABB::contains(glm::vec3 p) const { 97 | if (p.x >= lower.x && p.x <= upper.x && p.y >= lower.y && 98 | p.y <= upper.y && p.z >= lower.z && p.z <= upper.z) 99 | return true; 100 | 101 | return false; 102 | } 103 | 104 | void AABB::calcCenter() { 105 | center = ((upper - lower) * 0.5f) + lower; 106 | } 107 | 108 | void AABB::calcHalfDims() { 109 | halfDims = (upper - lower) * 0.5f; 110 | } -------------------------------------------------------------------------------- /DeferredRenderer/Shader.h: -------------------------------------------------------------------------------- 1 | #ifndef SHADER_H 2 | #define SHADER_H 3 | 4 | #include "common.h" 5 | #include 6 | #include 7 | #include 8 | 9 | class Shader { 10 | public: 11 | GLuint program; 12 | 13 | Shader(const GLchar* vertexPath, const GLchar* fragmentPath); 14 | ~Shader(); 15 | 16 | int setUniformf(const GLchar* name, float param); 17 | int setUniformv2f(const GLchar* name, float param1, float param2); 18 | int setUniformv2f(const GLchar* name, const glm::vec2 ¶m); 19 | int setUniformv3f(const GLchar* name, float param1, float param2, float param3); 20 | int setUniformv3f(const GLchar* name, const glm::vec3 ¶m); 21 | int setUniformv4f(const GLchar* name, float param1, float param2, float param3, float param4); 22 | int setUniformv4f(const GLchar* name, const glm::vec4 ¶m); 23 | int setUniformi(const GLchar* name, int param); 24 | int setUniformv2i(const GLchar* name, int param1, int param2); 25 | int setUniformmat3(const GLchar* name, const glm::mat3 ¶m); 26 | int setUniformmat4(const GLchar* name, const glm::mat4 ¶m); 27 | 28 | //Array uniforms 29 | int setUniform1iv(const GLchar* name, GLuint numParams, const int* params); 30 | int setUniform2iv(const GLchar* name, GLuint numParams, const int* params); 31 | int setUniform3iv(const GLchar* name, GLuint numParams, const int* params); 32 | int setUniform4iv(const GLchar* name, GLuint numParams, const int* params); 33 | int setUniform1fv(const GLchar* name, GLuint numParams, const float* params); 34 | int setUniform2fv(const GLchar* name, GLuint numParams, const float* params); 35 | int setUniform3fv(const GLchar* name, GLuint numParams, const float* params); 36 | int setUniform4fv(const GLchar* name, GLuint numParams, const float* params); 37 | 38 | //---------------------------- Using Attribute Location ---------------------------- 39 | 40 | void setUniformf(int paramLoc, float param); 41 | void setUniformv2f(int paramLoc, float param1, float param2); 42 | void setUniformv2f(int paramLoc, const glm::vec2 ¶m); 43 | void setUniformv3f(int paramLoc, float param1, float param2, float param3); 44 | void setUniformv3f(int paramLoc, const glm::vec3 ¶m); 45 | void setUniformv4f(int paramLoc, float param1, float param2, float param3, float param4); 46 | void setUniformv4f(int paramLoc, const glm::vec4 ¶m); 47 | void setUniformi(int paramLoc, int param); 48 | void setUniformv2i(int paramLoc, int param1, int param2); 49 | void setUniformmat3(int paramLoc, const glm::mat3 ¶m); 50 | void setUniformmat4(int paramLoc, const glm::mat4 ¶m); 51 | 52 | //Array uniforms 53 | void setUniform1iv(int paramLoc, GLuint numParams, const int* params); 54 | void setUniform2iv(int paramLoc, GLuint numParams, const int* params); 55 | void setUniform3iv(int paramLoc, GLuint numParams, const int* params); 56 | void setUniform4iv(int paramLoc, GLuint numParams, const int* params); 57 | void setUniform1fv(int paramLoc, GLuint numParams, const float* params); 58 | void setUniform2fv(int paramLoc, GLuint numParams, const float* params); 59 | void setUniform3fv(int paramLoc, GLuint numParams, const float* params); 60 | void setUniform4fv(int paramLoc, GLuint numParams, const float* params); 61 | }; 62 | 63 | #endif -------------------------------------------------------------------------------- /DeferredRenderer/tiny_obj_loader.h: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright 2012-2015, Syoyo Fujita. 3 | // 4 | // Licensed under 2-clause BSD liecense. 5 | // 6 | #ifndef _TINY_OBJ_LOADER_H 7 | #define _TINY_OBJ_LOADER_H 8 | 9 | #include 10 | #include 11 | #include 12 | 13 | namespace tinyobj { 14 | 15 | typedef struct { 16 | std::string name; 17 | 18 | float ambient[3]; 19 | float diffuse[3]; 20 | float specular[3]; 21 | float transmittance[3]; 22 | float emission[3]; 23 | float shininess; 24 | float ior; // index of refraction 25 | float dissolve; // 1 == opaque; 0 == fully transparent 26 | // illumination model (see http://www.fileformat.info/format/material/) 27 | int illum; 28 | 29 | std::string ambient_texname; 30 | std::string diffuse_texname; 31 | std::string specular_texname; 32 | std::string normal_texname; 33 | std::map unknown_parameter; 34 | } material_t; 35 | 36 | typedef struct { 37 | std::vector positions; 38 | std::vector normals; 39 | std::vector texcoords; 40 | std::vector indices; 41 | std::vector material_ids; // per-mesh material ID 42 | } mesh_t; 43 | 44 | typedef struct { 45 | std::string name; 46 | mesh_t mesh; 47 | } shape_t; 48 | 49 | class MaterialReader { 50 | public: 51 | MaterialReader() {} 52 | virtual ~MaterialReader() {} 53 | 54 | virtual std::string operator()(const std::string &matId, 55 | std::vector &materials, 56 | std::map &matMap) = 0; 57 | }; 58 | 59 | class MaterialFileReader : public MaterialReader { 60 | public: 61 | MaterialFileReader(const std::string &mtl_basepath) 62 | : m_mtlBasePath(mtl_basepath) {} 63 | virtual ~MaterialFileReader() {} 64 | virtual std::string operator()(const std::string &matId, 65 | std::vector &materials, 66 | std::map &matMap); 67 | 68 | private: 69 | std::string m_mtlBasePath; 70 | }; 71 | 72 | /// Loads .obj from a file. 73 | /// 'shapes' will be filled with parsed shape data 74 | /// The function returns error string. 75 | /// Returns empty string when loading .obj success. 76 | /// 'mtl_basepath' is optional, and used for base path for .mtl file. 77 | std::string LoadObj(std::vector &shapes, // [output] 78 | std::vector &materials, // [output] 79 | const char *filename, const char *mtl_basepath = NULL); 80 | 81 | /// Loads object from a std::istream, uses GetMtlIStreamFn to retrieve 82 | /// std::istream for materials. 83 | /// Returns empty string when loading .obj success. 84 | std::string LoadObj(std::vector &shapes, // [output] 85 | std::vector &materials, // [output] 86 | std::istream &inStream, MaterialReader &readMatFn); 87 | 88 | /// Loads materials into std::map 89 | /// Returns an empty string if successful 90 | std::string LoadMtl(std::map &material_map, 91 | std::vector &materials, std::istream &inStream); 92 | } 93 | 94 | #endif // _TINY_OBJ_LOADER_H 95 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ## Ignore Visual Studio temporary files, build results, and 2 | ## files generated by popular Visual Studio add-ons. 3 | 4 | # User-specific files 5 | *.suo 6 | *.user 7 | *.sln.docstates 8 | 9 | # Build results 10 | [Dd]ebug/ 11 | [Dd]ebugPublic/ 12 | [Rr]elease/ 13 | x64/ 14 | build/ 15 | bld/ 16 | [Bb]in/ 17 | [Oo]bj/ 18 | 19 | # Roslyn cache directories 20 | *.ide/ 21 | 22 | # MSTest test Results 23 | [Tt]est[Rr]esult*/ 24 | [Bb]uild[Ll]og.* 25 | 26 | #NUNIT 27 | *.VisualState.xml 28 | TestResult.xml 29 | 30 | # Build Results of an ATL Project 31 | [Dd]ebugPS/ 32 | [Rr]eleasePS/ 33 | dlldata.c 34 | 35 | *_i.c 36 | *_p.c 37 | *_i.h 38 | *.ilk 39 | *.meta 40 | *.obj 41 | *.pch 42 | *.pdb 43 | *.pgc 44 | *.pgd 45 | *.rsp 46 | *.sbr 47 | *.tlb 48 | *.tli 49 | *.tlh 50 | *.tmp 51 | *.tmp_proj 52 | *.log 53 | *.vspscc 54 | *.vssscc 55 | .builds 56 | *.pidb 57 | *.svclog 58 | *.scc 59 | 60 | # Chutzpah Test files 61 | _Chutzpah* 62 | 63 | # Visual C++ cache files 64 | ipch/ 65 | *.aps 66 | *.ncb 67 | *.opensdf 68 | *.sdf 69 | *.cachefile 70 | 71 | # Visual Studio profiler 72 | *.psess 73 | *.vsp 74 | *.vspx 75 | 76 | # TFS 2012 Local Workspace 77 | $tf/ 78 | 79 | # Guidance Automation Toolkit 80 | *.gpState 81 | 82 | # ReSharper is a .NET coding add-in 83 | _ReSharper*/ 84 | *.[Rr]e[Ss]harper 85 | *.DotSettings.user 86 | 87 | # JustCode is a .NET coding addin-in 88 | .JustCode 89 | 90 | # TeamCity is a build add-in 91 | _TeamCity* 92 | 93 | # DotCover is a Code Coverage Tool 94 | *.dotCover 95 | 96 | # NCrunch 97 | _NCrunch_* 98 | .*crunch*.local.xml 99 | 100 | # MightyMoose 101 | *.mm.* 102 | AutoTest.Net/ 103 | 104 | # Web workbench (sass) 105 | .sass-cache/ 106 | 107 | # Installshield output folder 108 | [Ee]xpress/ 109 | 110 | # DocProject is a documentation generator add-in 111 | DocProject/buildhelp/ 112 | DocProject/Help/*.HxT 113 | DocProject/Help/*.HxC 114 | DocProject/Help/*.hhc 115 | DocProject/Help/*.hhk 116 | DocProject/Help/*.hhp 117 | DocProject/Help/Html2 118 | DocProject/Help/html 119 | 120 | # Click-Once directory 121 | publish/ 122 | 123 | # Publish Web Output 124 | *.[Pp]ublish.xml 125 | *.azurePubxml 126 | ## TODO: Comment the next line if you want to checkin your 127 | ## web deploy settings but do note that will include unencrypted 128 | ## passwords 129 | #*.pubxml 130 | 131 | # NuGet Packages Directory 132 | packages/* 133 | ## TODO: If the tool you use requires repositories.config 134 | ## uncomment the next line 135 | #!packages/repositories.config 136 | 137 | # Enable "build/" folder in the NuGet Packages folder since 138 | # NuGet packages use it for MSBuild targets. 139 | # This line needs to be after the ignore of the build folder 140 | # (and the packages folder if the line above has been uncommented) 141 | !packages/build/ 142 | 143 | # Windows Azure Build Output 144 | csx/ 145 | *.build.csdef 146 | 147 | # Windows Store app package directory 148 | AppPackages/ 149 | 150 | # Others 151 | sql/ 152 | *.Cache 153 | ClientBin/ 154 | [Ss]tyle[Cc]op.* 155 | ~$* 156 | *~ 157 | *.dbmdl 158 | *.dbproj.schemaview 159 | *.pfx 160 | *.publishsettings 161 | node_modules/ 162 | 163 | # RIA/Silverlight projects 164 | Generated_Code/ 165 | 166 | # Backup & report files from converting an old project file 167 | # to a newer Visual Studio version. Backup files are not needed, 168 | # because we have git ;-) 169 | _UpgradeReport_Files/ 170 | Backup*/ 171 | UpgradeLog*.XML 172 | UpgradeLog*.htm 173 | 174 | # SQL Server files 175 | *.mdf 176 | *.ldf 177 | 178 | # Business Intelligence projects 179 | *.rdl.data 180 | *.bim.layout 181 | *.bim_*.settings 182 | 183 | # Microsoft Fakes 184 | FakesAssemblies/ 185 | 186 | # LightSwitch generated files 187 | GeneratedArtifacts/ 188 | _Pvt_Extensions/ 189 | ModelManifest.xml 190 | *.mtl 191 | *.cobj 192 | -------------------------------------------------------------------------------- /DeferredRenderer/MeshHelper.h: -------------------------------------------------------------------------------- 1 | #ifndef MESH_HELPER_H 2 | #define MESH_HELPER_H 3 | 4 | #include "common.h" 5 | #include "tiny_obj_loader.h" 6 | 7 | inline void generatePatchedSphere(std::vector &positions, std::vector &indices) { 8 | float m = 5; //squares per face 9 | for (int i = 0; i <= m - 1; i += 1) { 10 | for (int j = 0; j <= m - 1; j += 1) { 11 | float sa = -1.0f + 2.0f * (i / m); 12 | float sb = -1.0f + 2.0f * ((i + 1) / m); 13 | float ta = -1.0f + 2.0f * (j / m); 14 | float tb = -1.0f + 2.0f * ((j + 1) / m); 15 | GLuint i = GLuint(positions.size()); 16 | positions.push_back(glm::normalize(glm::vec3(sa, tb, 1.0f))); 17 | positions.push_back(glm::normalize(glm::vec3(sb, tb, 1.0f))); 18 | positions.push_back(glm::normalize(glm::vec3(sb, ta, 1.0f))); 19 | positions.push_back(glm::normalize(glm::vec3(sa, ta, 1.0f))); 20 | indices.push_back(i + 0); indices.push_back(i + 1); indices.push_back(i + 2); 21 | indices.push_back(i + 2); indices.push_back(i + 3); indices.push_back(i + 0); 22 | i += 4; 23 | positions.push_back(glm::normalize(glm::vec3(sa, ta, -1.0f))); 24 | positions.push_back(glm::normalize(glm::vec3(sb, ta, -1.0f))); 25 | positions.push_back(glm::normalize(glm::vec3(sb, tb, -1.0f))); 26 | positions.push_back(glm::normalize(glm::vec3(sa, tb, -1.0f))); 27 | indices.push_back(i + 0); indices.push_back(i + 1); indices.push_back(i + 2); 28 | indices.push_back(i + 2); indices.push_back(i + 3); indices.push_back(i + 0); 29 | i += 4; 30 | positions.push_back(glm::normalize(glm::vec3(sa, 1.0f, ta))); 31 | positions.push_back(glm::normalize(glm::vec3(sb, 1.0f, ta))); 32 | positions.push_back(glm::normalize(glm::vec3(sb, 1.0f, tb))); 33 | positions.push_back(glm::normalize(glm::vec3(sa, 1.0f, tb))); 34 | indices.push_back(i + 0); indices.push_back(i + 1); indices.push_back(i + 2); 35 | indices.push_back(i + 2); indices.push_back(i + 3); indices.push_back(i + 0); 36 | i += 4; 37 | positions.push_back(glm::normalize(glm::vec3(sa, -1.0f, tb))); 38 | positions.push_back(glm::normalize(glm::vec3(sb, -1.0f, tb))); 39 | positions.push_back(glm::normalize(glm::vec3(sb, -1.0f, ta))); 40 | positions.push_back(glm::normalize(glm::vec3(sa, -1.0f, ta))); 41 | indices.push_back(i + 0); indices.push_back(i + 1); indices.push_back(i + 2); 42 | indices.push_back(i + 2); indices.push_back(i + 3); indices.push_back(i + 0); 43 | i += 4; 44 | positions.push_back(glm::normalize(glm::vec3(-1.0f, sa, ta))); 45 | positions.push_back(glm::normalize(glm::vec3(-1.0f, sb, ta))); 46 | positions.push_back(glm::normalize(glm::vec3(-1.0f, sb, tb))); 47 | positions.push_back(glm::normalize(glm::vec3(-1.0f, sa, tb))); 48 | indices.push_back(i + 0); indices.push_back(i + 1); indices.push_back(i + 2); 49 | indices.push_back(i + 2); indices.push_back(i + 3); indices.push_back(i + 0); 50 | i += 4; 51 | positions.push_back(glm::normalize(glm::vec3(1.0f, sa, tb))); 52 | positions.push_back(glm::normalize(glm::vec3(1.0f, sb, tb))); 53 | positions.push_back(glm::normalize(glm::vec3(1.0f, sb, ta))); 54 | positions.push_back(glm::normalize(glm::vec3(1.0f, sa, ta))); 55 | indices.push_back(i + 0); indices.push_back(i + 1); indices.push_back(i + 2); 56 | indices.push_back(i + 2); indices.push_back(i + 3); indices.push_back(i + 0); 57 | i += 4; 58 | } 59 | } 60 | } 61 | 62 | inline std::pair, std::vector> read(std::istream& stream) { 63 | assert(sizeof(float) == sizeof(int)); 64 | const auto sz = sizeof(int); 65 | 66 | std::vector shapes; 67 | std::vector materials; 68 | 69 | int nMeshes = 0; 70 | int nMatProperties = 0; 71 | stream.read((char*)&nMeshes, sz); 72 | stream.read((char*)&nMatProperties, sz); 73 | shapes.resize(nMeshes); 74 | materials.resize(nMeshes); 75 | 76 | for (size_t i = 0; i < nMeshes; ++i) { 77 | int nVertices = 0, nNormals = 0, nTexcoords = 0, nIndices = 0; 78 | stream.read((char*)&nVertices, sz); 79 | stream.read((char*)&nNormals, sz); 80 | stream.read((char*)&nTexcoords, sz); 81 | stream.read((char*)&nIndices, sz); 82 | 83 | shapes[i].mesh.positions.resize(nVertices); 84 | shapes[i].mesh.normals.resize(nNormals); 85 | shapes[i].mesh.texcoords.resize(nTexcoords); 86 | shapes[i].mesh.indices.resize(nIndices); 87 | 88 | stream.read((char*)&shapes[i].mesh.positions[0], nVertices * sz); 89 | stream.read((char*)&shapes[i].mesh.normals[0], nNormals * sz); 90 | stream.read((char*)&shapes[i].mesh.texcoords[0], nTexcoords * sz); 91 | stream.read((char*)&shapes[i].mesh.indices[0], nIndices * sz); 92 | stream.read((char*)&materials[i].ambient[0], 3 * sz); 93 | stream.read((char*)&materials[i].diffuse[0], 3 * sz); 94 | stream.read((char*)&materials[i].specular[0], 3 * sz); 95 | } 96 | 97 | std::pair, std::vector> ret(shapes, materials); 98 | 99 | return ret; 100 | } 101 | 102 | #endif -------------------------------------------------------------------------------- /DeferredRenderer/main.cpp: -------------------------------------------------------------------------------- 1 | #define GLEW_DYNAMIC 2 | #include "common.h" 3 | #include 4 | #include "tiny_obj_loader.h" 5 | #include 6 | #include "Camera.hpp" 7 | #include "Scene.h" 8 | 9 | #define _CRTDBG_MAP_ALLOC 10 | #include 11 | #include 12 | 13 | void write(std::ostream& stream, const std::vector& shapes, const std::vector& materials); 14 | 15 | static const int width = 1280; 16 | static const int height = 720; 17 | static const GLfloat lastX = (width / 2); 18 | static const GLfloat lastY = (height / 2); 19 | float deltaTime = 0.0f; 20 | float lastFrame = 0.0f; 21 | 22 | void handleInput(GLFWwindow* window, Camera& cam, Scene& scene); 23 | 24 | int main() { 25 | //Checks for memory leaks in debug mode 26 | _CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF); 27 | 28 | glfwInit(); 29 | glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 4); 30 | glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 4); 31 | glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); 32 | glfwWindowHint(GLFW_RESIZABLE, GL_FALSE); 33 | 34 | GLFWwindow* window = glfwCreateWindow(width, height, "Deferred Renderer", nullptr, nullptr); 35 | glfwMakeContextCurrent(window); 36 | 37 | //Set callbacks for keyboard and mouse 38 | glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_DISABLED); 39 | 40 | glewExperimental = GL_TRUE; 41 | glewInit(); 42 | glGetError(); 43 | 44 | // Define the viewport dimensions 45 | glViewport(0, 0, width, height); 46 | glEnable(GL_TEXTURE_CUBE_MAP_SEAMLESS); 47 | 48 | Camera cam = Camera(); 49 | Scene scene(width, height, cam); 50 | 51 | /*std::string inputfile = "scenes/rungholt.obj"; 52 | std::vector shapes; 53 | std::vector materials; 54 | 55 | std::string err = tinyobj::LoadObj(shapes, materials, inputfile.c_str()); 56 | 57 | if (!err.empty()) { 58 | std::cerr << err << std::endl; 59 | exit(1); 60 | } 61 | 62 | std::cout << "shapes: " << shapes.size() << std::endl; 63 | std::cout << "materials: " << materials.size() << std::endl; 64 | 65 | std::ofstream outfile("scenes/rungholt2.cobj", std::ifstream::binary); 66 | write(outfile, shapes, materials); 67 | return 1;*/ 68 | scene.loadMeshes(); 69 | 70 | while (!glfwWindowShouldClose(window)) { 71 | //Set frame times 72 | float currentFrame = float(glfwGetTime()); 73 | deltaTime = currentFrame - lastFrame; 74 | lastFrame = currentFrame; 75 | 76 | // Check and call events 77 | glfwPollEvents(); 78 | handleInput(window, cam, scene); 79 | 80 | scene.renderScene(cam); 81 | 82 | // Swap the buffers 83 | glfwSwapBuffers(window); 84 | 85 | glfwSetCursorPos(window, lastX, lastY); 86 | } 87 | 88 | glfwTerminate(); 89 | 90 | return 0; 91 | } 92 | 93 | void handleInput(GLFWwindow* window, Camera& cam, Scene& scene) { 94 | if (glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS) 95 | glfwSetWindowShouldClose(window, GL_TRUE); 96 | 97 | if (glfwGetKey(window, GLFW_KEY_W) == GLFW_PRESS) 98 | cam.wasdMovement(FORWARD, deltaTime); 99 | 100 | if (glfwGetKey(window, GLFW_KEY_S) == GLFW_PRESS) 101 | cam.wasdMovement(BACKWARD, deltaTime); 102 | 103 | if (glfwGetKey(window, GLFW_KEY_D) == GLFW_PRESS) 104 | cam.wasdMovement(RIGHT, deltaTime); 105 | 106 | if (glfwGetKey(window, GLFW_KEY_A) == GLFW_PRESS) 107 | cam.wasdMovement(LEFT, deltaTime); 108 | 109 | if (glfwGetKey(window, GLFW_KEY_LEFT_SHIFT) == GLFW_PRESS) 110 | cam.wasdMovement(UP, deltaTime); 111 | 112 | if (glfwGetKey(window, GLFW_KEY_LEFT_CONTROL) == GLFW_PRESS) 113 | cam.wasdMovement(DOWN, deltaTime); 114 | 115 | if (glfwGetKey(window, GLFW_KEY_KP_0) == GLFW_PRESS) 116 | scene.setType(0); 117 | 118 | if (glfwGetKey(window, GLFW_KEY_KP_1) == GLFW_PRESS) 119 | scene.setType(1); 120 | 121 | if (glfwGetKey(window, GLFW_KEY_KP_2) == GLFW_PRESS) 122 | scene.setType(2); 123 | 124 | if (glfwGetKey(window, GLFW_KEY_KP_3) == GLFW_PRESS) 125 | scene.setType(3); 126 | 127 | if (glfwGetKey(window, GLFW_KEY_KP_4) == GLFW_PRESS) 128 | scene.setType(4); 129 | 130 | if (glfwGetKey(window, GLFW_KEY_KP_5) == GLFW_PRESS) 131 | scene.setType(5); 132 | 133 | if (glfwGetKey(window, GLFW_KEY_KP_6) == GLFW_PRESS) 134 | scene.setType(6); 135 | 136 | if (glfwGetKey(window, GLFW_KEY_KP_7) == GLFW_PRESS) 137 | scene.setType(7); 138 | 139 | double xpos, ypos; 140 | glfwGetCursorPos(window, &xpos, &ypos); 141 | if (glfwGetMouseButton(window, GLFW_MOUSE_BUTTON_LEFT) == GLFW_PRESS) 142 | cam.mouseMovement((float(xpos) - lastX), (lastY - float(ypos)), deltaTime); 143 | } 144 | 145 | void write(std::ostream& stream, const std::vector& shapes, const std::vector& materials) { 146 | assert(sizeof(float) == sizeof(int)); 147 | const auto sz = sizeof(int); 148 | const int nMeshes = static_cast(shapes.size()); 149 | const int nMatProperties = 3; 150 | 151 | stream.write((const char*)&nMeshes, sz); //nMeshes 152 | stream.write((const char*)&nMatProperties, sz); //nMatProperties 153 | 154 | for (size_t i = 0; i < nMeshes; ++i) { 155 | const int nVertices = (int)shapes[i].mesh.positions.size(); 156 | const int nNormals = (int)shapes[i].mesh.normals.size(); 157 | const int nTexcoords = (int)shapes[i].mesh.texcoords.size(); 158 | const int nIndices = (int)shapes[i].mesh.indices.size(); 159 | 160 | //Write nVertices, nNormals,, nTexcoords, nIndices 161 | //Write #nVertices positions 162 | //Write #nVertices normals 163 | //Write #nVertices texcoord 164 | //Write #nIndices indices 165 | //Write #nMatProperties material properties 166 | stream.write((const char*)&nVertices, sz); 167 | stream.write((const char*)&nNormals, sz); 168 | stream.write((const char*)&nTexcoords, sz); 169 | stream.write((const char*)&nIndices, sz); 170 | 171 | stream.write((const char*)&shapes[i].mesh.positions[0], nVertices * sz); 172 | stream.write((const char*)&shapes[i].mesh.normals[0], nNormals * sz); 173 | stream.write((const char*)&shapes[i].mesh.texcoords[0], nTexcoords * sz); 174 | stream.write((const char*)&shapes[i].mesh.indices[0], nIndices * sz); 175 | stream.write((const char*)&materials[i].ambient[0], 3 * sz); 176 | stream.write((const char*)&materials[i].diffuse[0], 3 * sz); 177 | stream.write((const char*)&materials[i].specular[0], 3 * sz); 178 | } 179 | } -------------------------------------------------------------------------------- /DeferredRenderer/GBuffer.cpp: -------------------------------------------------------------------------------- 1 | #include "GBuffer.h" 2 | 3 | GBuffer::GBuffer(int width, int height) : width(width), height(height) { 4 | //Create FBO 5 | glGenFramebuffers(1, &fbo); 6 | glBindFramebuffer(GL_FRAMEBUFFER, fbo); 7 | 8 | //Create GBuffer textures 9 | glGenTextures(1, &position); 10 | glGenTextures(1, &normal); 11 | glGenTextures(1, &color); 12 | glGenTextures(1, &light); 13 | glGenTextures(1, &depth); 14 | glGenTextures(1, &effect1); 15 | glGenTextures(1, &effect2); 16 | 17 | //Position 18 | glBindTexture(GL_TEXTURE_2D, position); 19 | glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA32F, width, height, 0, GL_RGBA, GL_FLOAT, nullptr); 20 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); 21 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); 22 | glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); 23 | glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); 24 | 25 | //Normal 26 | glBindTexture(GL_TEXTURE_2D, normal); 27 | glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA16F, width, height, 0, GL_RGBA, GL_FLOAT, nullptr); 28 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); 29 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); 30 | glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); 31 | glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); 32 | 33 | //Color 34 | glBindTexture(GL_TEXTURE_2D, color); 35 | glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, width, height, 0, GL_RGBA, GL_FLOAT, nullptr); 36 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); 37 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); 38 | glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); 39 | glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); 40 | 41 | //Light buffer 42 | glBindTexture(GL_TEXTURE_2D, light); 43 | glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA16F, width, height, 0, GL_RGBA, GL_FLOAT, nullptr); 44 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); 45 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); 46 | glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); 47 | glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); 48 | 49 | //Create first post process effect buffer 50 | glBindTexture(GL_TEXTURE_2D, effect1); 51 | glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA16F, width, height, 0, GL_RGBA, GL_FLOAT, nullptr); 52 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); 53 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); 54 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); 55 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); 56 | 57 | //Create second post process effect buffer 58 | glBindTexture(GL_TEXTURE_2D, effect2); 59 | glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA16F, width, height, 0, GL_RGBA, GL_FLOAT, nullptr); 60 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); 61 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); 62 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); 63 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); 64 | 65 | //Create depth texture 66 | glBindTexture(GL_TEXTURE_2D, depth); 67 | glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH24_STENCIL8, width, height, 0, GL_DEPTH_STENCIL, GL_UNSIGNED_INT_24_8, nullptr); 68 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); 69 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); 70 | glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); 71 | glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); 72 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE, GL_NONE); 73 | 74 | //Attach textures to FBO 75 | glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, position, 0); 76 | glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, GL_TEXTURE_2D, normal, 0); 77 | glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT2, GL_TEXTURE_2D, color, 0); 78 | glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT3, GL_TEXTURE_2D, light, 0); 79 | glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT4, GL_TEXTURE_2D, effect1, 0); 80 | glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT5, GL_TEXTURE_2D, effect2, 0); 81 | glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_TEXTURE_2D, depth, 0); 82 | 83 | for (int i = 0; i < 3; i++) { 84 | drawBuffers[i] = GL_COLOR_ATTACHMENT0 + i; 85 | } 86 | 87 | glDrawBuffers(3, drawBuffers); 88 | 89 | //Unbind 90 | glBindFramebuffer(GL_FRAMEBUFFER, 0); 91 | } 92 | 93 | GBuffer::~GBuffer() { 94 | if (fbo != 0) { 95 | glDeleteFramebuffers(1, &fbo); 96 | glDeleteTextures(1, &position); 97 | glDeleteTextures(1, &normal); 98 | glDeleteTextures(1, &color); 99 | glDeleteTextures(1, &light); 100 | glDeleteTextures(1, &depth); 101 | glDeleteTextures(1, &effect1); 102 | glDeleteTextures(1, &effect2); 103 | } 104 | } 105 | 106 | GLuint GBuffer::getFBO() const { 107 | return fbo; 108 | } 109 | 110 | int GBuffer::getWidth() const { 111 | return width; 112 | } 113 | 114 | int GBuffer::getHeight() const { 115 | return height; 116 | } 117 | 118 | void GBuffer::setDrawBuffers() { 119 | glDrawBuffers(3, drawBuffers); 120 | } 121 | 122 | void GBuffer::setDrawLight() { 123 | glDrawBuffer(GL_COLOR_ATTACHMENT3); 124 | } 125 | 126 | void GBuffer::setDrawEffect() { 127 | glDrawBuffer(GL_COLOR_ATTACHMENT4); 128 | } 129 | 130 | void GBuffer::setDrawNone() { 131 | glDrawBuffer(GL_NONE); 132 | } 133 | 134 | void GBuffer::setReadEffect() { 135 | glReadBuffer(GL_COLOR_ATTACHMENT4); 136 | } 137 | 138 | void GBuffer::bind() { 139 | glBindFramebuffer(GL_FRAMEBUFFER, fbo); 140 | } 141 | 142 | void GBuffer::bindDraw() { 143 | glBindFramebuffer(GL_DRAW_FRAMEBUFFER, fbo); 144 | } 145 | 146 | void GBuffer::bindRead() { 147 | glBindFramebuffer(GL_READ_FRAMEBUFFER, fbo); 148 | } 149 | 150 | void GBuffer::unbind() { 151 | glBindFramebuffer(GL_FRAMEBUFFER, 0); 152 | } 153 | 154 | void GBuffer::unbindDraw() { 155 | glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0); 156 | } 157 | 158 | void GBuffer::unbindRead() { 159 | glBindFramebuffer(GL_READ_FRAMEBUFFER, 0); 160 | } 161 | 162 | void GBuffer::setGeomTextures() { 163 | glActiveTexture(GL_TEXTURE0); 164 | glBindTexture(GL_TEXTURE_2D, position); 165 | 166 | glActiveTexture(GL_TEXTURE1); 167 | glBindTexture(GL_TEXTURE_2D, normal); 168 | 169 | glActiveTexture(GL_TEXTURE2); 170 | glBindTexture(GL_TEXTURE_2D, color); 171 | 172 | glActiveTexture(GL_TEXTURE3); 173 | glBindTexture(GL_TEXTURE_2D, depth); 174 | } -------------------------------------------------------------------------------- /DeferredRenderer/DeferredRenderer.vcxproj.filters: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} 6 | rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms 7 | 8 | 9 | {1a32c216-094c-4ced-9edb-a6e44c91a8e4} 10 | 11 | 12 | {e95164eb-c675-4c60-afbb-e7386a427c9b} 13 | 14 | 15 | {3e1054ed-a5aa-40ec-934f-b1dc1868ecaa} 16 | 17 | 18 | {a0ee73bd-e212-4d7c-b7ea-6ab324cf56f5} 19 | 20 | 21 | {6c7ad6e3-3b2b-4358-8f67-40a0d73fadf5} 22 | 23 | 24 | {987cbef0-1235-4eb8-b13e-189b6d7ce2b5} 25 | 26 | 27 | {746c42fa-fe6e-4b40-91af-663bf90b30ae} 28 | 29 | 30 | {028550e7-1bc1-4acc-b517-dcfc308f9418} 31 | 32 | 33 | {fba6576a-21fc-4d41-887a-809a649f9ca3} 34 | 35 | 36 | {71632cb6-b673-4623-aff3-f6b7c5c9e700} 37 | 38 | 39 | {2c16a48a-e0df-4cbe-a05a-2aec43bdd7eb} 40 | 41 | 42 | {6089f568-abfa-4a6f-9285-590dbcbf1a32} 43 | 44 | 45 | {397e1aff-0b37-46bc-902d-16825d0d7dd0} 46 | 47 | 48 | {057a38ba-275a-4d48-9787-fbe7e153a2d9} 49 | 50 | 51 | {b4cc671f-4630-4d6f-b1cd-55d6aa055e63} 52 | 53 | 54 | {272437f8-8008-4cdd-adaa-6acd236f30d3} 55 | 56 | 57 | {94a7df28-72da-4238-b7d2-84f5f41cecda} 58 | 59 | 60 | {beab3113-4de1-4423-a482-a87d4247c9c5} 61 | 62 | 63 | 64 | 65 | src\Mesh 66 | 67 | 68 | src\Octree 69 | 70 | 71 | src\Octree 72 | 73 | 74 | src\SceneObjects 75 | 76 | 77 | src\SceneObjects 78 | 79 | 80 | src\Shader 81 | 82 | 83 | src\Shader 84 | 85 | 86 | tinyobj 87 | 88 | 89 | src\Shader 90 | 91 | 92 | src\Scene 93 | 94 | 95 | src\Shader 96 | 97 | 98 | src 99 | 100 | 101 | src\Lighting 102 | 103 | 104 | src\Lighting 105 | 106 | 107 | src\Lighting 108 | 109 | 110 | 111 | 112 | tinyobj 113 | 114 | 115 | src\Scene 116 | 117 | 118 | src\Shader 119 | 120 | 121 | src\Shader 122 | 123 | 124 | src\Shader 125 | 126 | 127 | src\Shader 128 | 129 | 130 | src 131 | 132 | 133 | src\SceneObjects 134 | 135 | 136 | src\SceneObjects 137 | 138 | 139 | src\Scene 140 | 141 | 142 | src\Mesh 143 | 144 | 145 | src\Octree 146 | 147 | 148 | src\Octree 149 | 150 | 151 | src\Lighting 152 | 153 | 154 | src\Lighting 155 | 156 | 157 | src\Lighting 158 | 159 | 160 | 161 | 162 | shaders\gbuffer 163 | 164 | 165 | shaders\gbuffer 166 | 167 | 168 | shaders\ssao 169 | 170 | 171 | shaders\ssao 172 | 173 | 174 | shaders\blur 175 | 176 | 177 | shaders\blur 178 | 179 | 180 | shaders\fsquad 181 | 182 | 183 | shaders\fsquad 184 | 185 | 186 | shaders\lighting 187 | 188 | 189 | shaders\lighting 190 | 191 | 192 | shaders\stencil 193 | 194 | 195 | shaders\shadow 196 | 197 | 198 | shaders\shadow 199 | 200 | 201 | shaders\skybox 202 | 203 | 204 | shaders\skybox 205 | 206 | 207 | shaders\shadow 208 | 209 | 210 | -------------------------------------------------------------------------------- /DeferredRenderer/Shader.cpp: -------------------------------------------------------------------------------- 1 | #include "Shader.h" 2 | 3 | using namespace std; 4 | 5 | Shader::Shader(const GLchar* vertexPath, const GLchar* fragmentPath) { 6 | string vertexCode; 7 | string fragmentCode; 8 | try { 9 | //Open files 10 | ifstream vShaderFile(vertexPath); 11 | ifstream fShaderFile(fragmentPath); 12 | stringstream vShaderStream, fShaderStream; 13 | // Read file's buffer contents into streams 14 | vShaderStream << vShaderFile.rdbuf(); 15 | fShaderStream << fShaderFile.rdbuf(); 16 | //close file handlers 17 | vShaderFile.close(); 18 | fShaderFile.close(); 19 | //Convert stream into string 20 | vertexCode = vShaderStream.str(); 21 | fragmentCode = fShaderStream.str(); 22 | } 23 | catch (exception e) { 24 | cout << "ERROR::SHADER::FILE_NOT_SUCCESFULLY_READ" << endl; 25 | } 26 | 27 | const GLchar* vShaderCode = vertexCode.c_str(); 28 | const GLchar * fShaderCode = fragmentCode.c_str(); 29 | //Compile shaders 30 | GLuint vertex, fragment; 31 | GLint success; 32 | GLchar infoLog[512]; 33 | //Vertex Shader 34 | vertex = glCreateShader(GL_VERTEX_SHADER); 35 | glShaderSource(vertex, 1, &vShaderCode, NULL); 36 | glCompileShader(vertex); 37 | //Print compile errors if any 38 | glGetShaderiv(vertex, GL_COMPILE_STATUS, &success); 39 | 40 | if (!success) { 41 | glGetShaderInfoLog(vertex, 512, NULL, infoLog); 42 | cout << "ERROR::SHADER::VERTEX::COMPILATION_FAILED\n" << infoLog << endl; 43 | } 44 | 45 | //Fragment Shader 46 | fragment = glCreateShader(GL_FRAGMENT_SHADER); 47 | glShaderSource(fragment, 1, &fShaderCode, NULL); 48 | glCompileShader(fragment); 49 | //Print compile errors if any 50 | glGetShaderiv(fragment, GL_COMPILE_STATUS, &success); 51 | 52 | if (!success) { 53 | glGetShaderInfoLog(fragment, 512, NULL, infoLog); 54 | cout << "ERROR::SHADER::FRAGMENT::COMPILATION_FAILED\n" << infoLog << endl; 55 | } 56 | 57 | //Shader Program 58 | this->program = glCreateProgram(); 59 | glAttachShader(this->program, vertex); 60 | glAttachShader(this->program, fragment); 61 | glLinkProgram(this->program); 62 | //Print linking errors if any 63 | glGetProgramiv(this->program, GL_LINK_STATUS, &success); 64 | 65 | if (!success) { 66 | glGetProgramInfoLog(this->program, 512, NULL, infoLog); 67 | cout << "ERROR::SHADER::PROGRAM::LINKING_FAILED\n" << infoLog << endl; 68 | std::cout << vertexPath << std::endl; 69 | std::cout << fragmentPath << std::endl; 70 | } 71 | 72 | //Delete the shaders as they're linked into our program now and no longer necessery 73 | glDeleteShader(vertex); 74 | glDeleteShader(fragment); 75 | } 76 | 77 | Shader::~Shader() { 78 | if (program) glDeleteProgram(program); 79 | } 80 | 81 | int Shader::setUniformf(const GLchar* name, float param) { 82 | GLint loc = glGetUniformLocation(program, name); 83 | 84 | if (loc != -1) 85 | glUniform1f(loc, param); 86 | 87 | return loc; 88 | } 89 | 90 | int Shader::setUniformv2f(const GLchar* name, float param1, float param2) { 91 | GLint loc = glGetUniformLocation(program, name); 92 | 93 | if (loc != -1) 94 | glUniform2f(loc, param1, param2); 95 | 96 | return loc; 97 | } 98 | 99 | int Shader::setUniformv2f(const GLchar* name, const glm::vec2 ¶m) { 100 | return setUniformv2f(name, param.x, param.y); 101 | } 102 | 103 | int Shader::setUniformv3f(const GLchar* name, float param1, float param2, float param3) { 104 | GLint loc = glGetUniformLocation(program, name); 105 | 106 | if (loc != -1) 107 | glUniform3f(loc, param1, param2, param3); 108 | 109 | return loc; 110 | } 111 | 112 | int Shader::setUniformv3f(const GLchar* name, const glm::vec3 ¶m) { 113 | return setUniformv3f(name, param.x, param.y, param.z); 114 | } 115 | 116 | int Shader::setUniformv4f(const GLchar* name, float param1, float param2, float param3, float param4) { 117 | GLint loc = glGetUniformLocation(program, name); 118 | 119 | if (loc != -1) 120 | glUniform4f(loc, param1, param2, param3, param4); 121 | 122 | return loc; 123 | } 124 | 125 | int Shader::setUniformv4f(const GLchar* name, const glm::vec4 ¶m) { 126 | return setUniformv4f(name, param.x, param.y, param.z, param.w); 127 | } 128 | 129 | int Shader::setUniformi(const GLchar* name, int param) { 130 | GLint loc = glGetUniformLocation(program, name); 131 | 132 | if (loc != -1) 133 | glUniform1i(loc, param); 134 | 135 | return loc; 136 | } 137 | 138 | int Shader::setUniformv2i(const GLchar* name, int param1, int param2) { 139 | GLint loc = glGetUniformLocation(program, name); 140 | 141 | if (loc != -1) 142 | glUniform2i(loc, param1, param2); 143 | 144 | return loc; 145 | } 146 | 147 | int Shader::setUniformmat3(const GLchar* name, const glm::mat3& param) { 148 | GLint loc = glGetUniformLocation(program, name); 149 | 150 | if (loc != -1) 151 | glUniformMatrix3fv(loc, 1, GL_FALSE, glm::value_ptr(param)); 152 | 153 | return loc; 154 | } 155 | 156 | int Shader::setUniformmat4(const GLchar* name, const glm::mat4& param) { 157 | GLint loc = glGetUniformLocation(program, name); 158 | 159 | if (loc != -1) 160 | glUniformMatrix4fv(loc, 1, GL_FALSE, glm::value_ptr(param)); 161 | 162 | return loc; 163 | } 164 | 165 | int Shader::setUniform1iv(const GLchar* name, GLuint numParams, const int* params) { 166 | GLint loc = glGetUniformLocation(program, name); 167 | 168 | if (loc != -1) 169 | glUniform1iv(loc, numParams, params); 170 | 171 | return loc; 172 | } 173 | 174 | int Shader::setUniform2iv(const GLchar* name, GLuint numParams, const int* params) { 175 | GLint loc = glGetUniformLocation(program, name); 176 | 177 | if (loc != -1) 178 | glUniform2iv(loc, numParams, params); 179 | 180 | return loc; 181 | } 182 | 183 | int Shader::setUniform3iv(const GLchar* name, GLuint numParams, const int* params) { 184 | GLint loc = glGetUniformLocation(program, name); 185 | 186 | if (loc != -1) 187 | glUniform3iv(loc, numParams, params); 188 | 189 | return loc; 190 | } 191 | 192 | int Shader::setUniform4iv(const GLchar* name, GLuint numParams, const int* params) { 193 | GLint loc = glGetUniformLocation(program, name); 194 | 195 | if (loc != -1) 196 | glUniform4iv(loc, numParams, params); 197 | 198 | return loc; 199 | } 200 | 201 | int Shader::setUniform1fv(const GLchar* name, GLuint numParams, const float* params) { 202 | GLint loc = glGetUniformLocation(program, name); 203 | 204 | if (loc != -1) 205 | glUniform1fv(loc, numParams, params); 206 | 207 | return loc; 208 | } 209 | 210 | int Shader::setUniform2fv(const GLchar* name, GLuint numParams, const float* params) { 211 | GLint loc = glGetUniformLocation(program, name); 212 | 213 | if (loc != -1) 214 | glUniform2fv(loc, numParams, params); 215 | 216 | return loc; 217 | } 218 | 219 | int Shader::setUniform3fv(const GLchar* name, GLuint numParams, const float* params) { 220 | GLint loc = glGetUniformLocation(program, name); 221 | 222 | if (loc != -1) 223 | glUniform3fv(loc, numParams, params); 224 | 225 | return loc; 226 | } 227 | 228 | int Shader::setUniform4fv(const GLchar* name, GLuint numParams, const float* params) { 229 | GLint loc = glGetUniformLocation(program, name); 230 | 231 | if (loc != -1) 232 | glUniform4fv(loc, numParams, params); 233 | 234 | return loc; 235 | } 236 | 237 | //-------------------- Attribute Location Versions ---------------------- 238 | 239 | void Shader::setUniformf(int loc, float param) { 240 | if (loc != -1) 241 | glUniform1f(loc, param); 242 | } 243 | 244 | void Shader::setUniformv2f(int loc, float param1, float param2) { 245 | if (loc != -1) 246 | glUniform2f(loc, param1, param2); 247 | } 248 | 249 | void Shader::setUniformv2f(int loc, const glm::vec2 ¶m) { 250 | setUniformv2f(loc, param.x, param.y); 251 | } 252 | 253 | void Shader::setUniformv3f(int loc, float param1, float param2, float param3) { 254 | if (loc != -1) 255 | glUniform3f(loc, param1, param2, param3); 256 | } 257 | 258 | void Shader::setUniformv3f(int loc, const glm::vec3 ¶m) { 259 | setUniformv3f(loc, param.x, param.y, param.z); 260 | } 261 | 262 | void Shader::setUniformv4f(int loc, float param1, float param2, float param3, float param4) { 263 | if (loc != -1) 264 | glUniform4f(loc, param1, param2, param3, param4); 265 | } 266 | 267 | void Shader::setUniformv4f(int loc, const glm::vec4 ¶m) { 268 | setUniformv4f(loc, param.x, param.y, param.z, param.w); 269 | } 270 | 271 | void Shader::setUniformi(int loc, int param) { 272 | if (loc != -1) 273 | glUniform1i(loc, param); 274 | } 275 | 276 | void Shader::setUniformv2i(int loc, int param1, int param2) { 277 | if (loc != -1) 278 | glUniform2i(loc, param1, param2); 279 | } 280 | 281 | void Shader::setUniformmat3(int loc, const glm::mat3 ¶m) { 282 | if (loc != -1) 283 | glUniformMatrix3fv(loc, 1, false, glm::value_ptr(param)); 284 | } 285 | 286 | void Shader::setUniformmat4(int loc, const glm::mat4 ¶m) { 287 | if (loc != -1) 288 | glUniformMatrix4fv(loc, 1, false, glm::value_ptr(param)); 289 | } 290 | 291 | void Shader::setUniform1iv(int loc, GLuint numParams, const int* params) { 292 | if (loc != -1) 293 | glUniform1iv(loc, numParams, params); 294 | } 295 | 296 | void Shader::setUniform2iv(int loc, GLuint numParams, const int* params) { 297 | if (loc != -1) 298 | glUniform2iv(loc, numParams, params); 299 | } 300 | 301 | void Shader::setUniform3iv(int loc, GLuint numParams, const int* params) { 302 | if (loc != -1) 303 | glUniform3iv(loc, numParams, params); 304 | } 305 | 306 | void Shader::setUniform4iv(int loc, GLuint numParams, const int* params) { 307 | if (loc != -1) 308 | glUniform4iv(loc, numParams, params); 309 | } 310 | 311 | void Shader::setUniform1fv(int loc, GLuint numParams, const float* params) { 312 | if (loc != -1) 313 | glUniform1fv(loc, numParams, params); 314 | } 315 | 316 | void Shader::setUniform2fv(int loc, GLuint numParams, const float* params) { 317 | if (loc != -1) 318 | glUniform2fv(loc, numParams, params); 319 | } 320 | 321 | void Shader::setUniform3fv(int loc, GLuint numParams, const float* params) { 322 | if (loc != -1) 323 | glUniform3fv(loc, numParams, params); 324 | } 325 | 326 | void Shader::setUniform4fv(int loc, GLuint numParams, const float* params) { 327 | if (loc != -1) 328 | glUniform4fv(loc, numParams, params); 329 | } -------------------------------------------------------------------------------- /DeferredRenderer/DeferredRenderer.vcxproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Debug 6 | Win32 7 | 8 | 9 | Debug 10 | x64 11 | 12 | 13 | Release 14 | Win32 15 | 16 | 17 | Release 18 | x64 19 | 20 | 21 | 22 | {8DA95418-9394-491A-ADFF-3AB3A1D3CF36} 23 | Win32Proj 24 | DeferredRenderer 25 | 26 | 27 | 28 | Application 29 | true 30 | v120 31 | Unicode 32 | 33 | 34 | Application 35 | true 36 | v120 37 | Unicode 38 | 39 | 40 | Application 41 | false 42 | v120 43 | true 44 | Unicode 45 | 46 | 47 | Application 48 | false 49 | v120 50 | true 51 | Unicode 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | true 71 | 72 | 73 | true 74 | 75 | 76 | false 77 | 78 | 79 | false 80 | 81 | 82 | 83 | 84 | 85 | Level3 86 | Disabled 87 | WIN32;_DEBUG;_WINDOWS;%(PreprocessorDefinitions) 88 | C:\OpenGL\SOIL\src;C:\OpenGL\devil\include;C:\OpenGL\GLEW\include;C:\OpenGL\GLM;C:\OpenGL\GLFW\include\;%(AdditionalIncludeDirectories) 89 | 90 | 91 | Console 92 | true 93 | C:\OpenGL\SOIL\lib;C:\OpenGL\devil;C:\OpenGL\GLEW\lib\Release\x64;C:\OpenGL\GLFW\lib-vc2013;%(AdditionalLibraryDirectories) 94 | SOIL.lib;glfw3.lib;opengl32.lib;glew32.lib;%(AdditionalDependencies) 95 | 96 | 97 | 98 | 99 | 100 | 101 | Level3 102 | Disabled 103 | WIN32;_DEBUG;_WINDOWS;%(PreprocessorDefinitions) 104 | C:\OpenGL\SOIL\src;C:\OpenGL\devil\include;C:\OpenGL\GLEW\include;C:\OpenGL\GLM;C:\OpenGL\GLFW\include\;%(AdditionalIncludeDirectories) 105 | 106 | 107 | Console 108 | true 109 | C:\OpenGL\SOIL\lib;C:\OpenGL\devil;C:\OpenGL\GLEW\lib\Release\x64;C:\OpenGL\GLFW\lib-vc2013;%(AdditionalLibraryDirectories) 110 | SOIL.lib;glfw3.lib;opengl32.lib;glew32.lib;%(AdditionalDependencies) 111 | 112 | 113 | 114 | 115 | Level3 116 | 117 | 118 | MaxSpeed 119 | true 120 | true 121 | WIN32;NDEBUG;_WINDOWS;%(PreprocessorDefinitions) 122 | C:\OpenGL\SOIL\src;C:\OpenGL\devil\include;C:\OpenGL\GLEW\include;C:\OpenGL\GLM;C:\OpenGL\GLFW\include\;%(AdditionalIncludeDirectories) 123 | 124 | 125 | Console 126 | true 127 | true 128 | true 129 | C:\OpenGL\SOIL\lib;C:\OpenGL\devil;C:\OpenGL\GLEW\lib\Release\x64;C:\OpenGL\GLFW\lib-vc2013;%(AdditionalLibraryDirectories) 130 | SOIL.lib;glfw3.lib;opengl32.lib;glew32.lib;%(AdditionalDependencies) 131 | 132 | 133 | 134 | 135 | Level3 136 | 137 | 138 | MaxSpeed 139 | true 140 | true 141 | WIN32;NDEBUG;_WINDOWS;%(PreprocessorDefinitions) 142 | C:\OpenGL\SOIL\src;C:\OpenGL\devil\include;C:\OpenGL\GLEW\include;C:\OpenGL\GLM;C:\OpenGL\GLFW\include\;%(AdditionalIncludeDirectories) 143 | 144 | 145 | Console 146 | true 147 | true 148 | true 149 | C:\OpenGL\SOIL\lib;C:\OpenGL\devil;C:\OpenGL\GLEW\lib\Release\x64;C:\OpenGL\GLFW\lib-vc2013;%(AdditionalLibraryDirectories) 150 | SOIL.lib;glfw3.lib;opengl32.lib;glew32.lib;%(AdditionalDependencies) 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | 176 | 177 | 178 | CppCode 179 | 180 | 181 | 182 | 183 | 184 | 185 | 186 | 187 | 188 | 189 | 190 | 191 | 192 | 193 | 194 | 195 | 196 | 197 | 198 | 199 | 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 209 | 210 | 211 | -------------------------------------------------------------------------------- /DeferredRenderer/Scene.cpp: -------------------------------------------------------------------------------- 1 | #include "Scene.h" 2 | 3 | using namespace std; 4 | 5 | static const int kernelSize = 64; 6 | static const int noiseSize = 4; 7 | static const int blurSize = 2; 8 | static const glm::vec4 lightDir = glm::vec4(1, 1, 1, 0); 9 | 10 | Scene::Scene(int width, int height, Camera& cam) : 11 | width(width), height(height), 12 | gBuffer(GBuffer(width, height)), 13 | dLightShadow(ShadowMap(2048, 2048)), 14 | pLightShadow(PointLightShadowMap(1024, 1024)), 15 | geometry(Shader("gbuffer.vert", "gbuffer.frag")), 16 | shadow(Shader("shadow.vert", "empty.frag")), 17 | plShadow(Shader("plShadow.vert", "plShadow.frag")), 18 | stencil(Shader("light.vert", "empty.frag")), 19 | ssao(Shader("ssao.vert", "ssao.frag")), 20 | blur(Shader("blur.vert", "blur.frag")), 21 | lightPass(Shader("light.vert", "light.frag")), 22 | finalPass(Shader("ubershader.vert", "ubershader.frag")), 23 | skybox(Shader("skybox.vert", "skybox.frag")), 24 | fsQuad(FullscreenQuad()), 25 | sphere(Mesh()) 26 | { 27 | type = 0; 28 | aspectRatio = float(width) / float(height); 29 | projection = glm::infinitePerspective(cam.zoom, aspectRatio, 0.1f); 30 | dLightMView = glm::lookAt(glm::vec3(500.0f, 500.0f, 500.0f), glm::vec3(0), glm::vec3(0, 1, 0)); 31 | dLightProjection = glm::ortho(-450.0f, 450.0f, -450.0f, 450.0f, 0.1f, 2000.0f); 32 | 33 | directions[0] = { GL_TEXTURE_CUBE_MAP_POSITIVE_X, glm::vec3(1.0f, 0.0f, 0.0f), glm::vec3(0.0f, -1.0f, 0.0f) }; 34 | directions[1] = { GL_TEXTURE_CUBE_MAP_NEGATIVE_X, glm::vec3(-1.0f, 0.0f, 0.0f), glm::vec3(0.0f, -1.0f, 0.0f) }; 35 | directions[2] = { GL_TEXTURE_CUBE_MAP_POSITIVE_Y, glm::vec3(0.0f, 1.0f, 0.0f), glm::vec3(0.0f, 0.0f, -1.0f) }; 36 | directions[3] = { GL_TEXTURE_CUBE_MAP_NEGATIVE_Y, glm::vec3(0.0f, -1.0f, 0.0f), glm::vec3(0.0f, 0.0f, 1.0f) }; 37 | directions[4] = { GL_TEXTURE_CUBE_MAP_POSITIVE_Z, glm::vec3(0.0f, 0.0f, 1.0f), glm::vec3(0.0f, -1.0f, 0.0f) }; 38 | directions[5] = { GL_TEXTURE_CUBE_MAP_NEGATIVE_Z, glm::vec3(0.0f, 0.0f, -1.0f), glm::vec3(0.0f, -1.0f, 0.0f) }; 39 | 40 | srand(int(time(NULL))); 41 | 42 | for (int i = 0; i < 1; i++) { 43 | float r1 = static_cast (rand()) / static_cast (RAND_MAX); 44 | float r2 = static_cast (rand()) / static_cast (RAND_MAX); 45 | float r3 = static_cast (rand()) / static_cast (RAND_MAX); 46 | PointLight pl; 47 | //pl.color = glm::vec3(r1, r2, r3); 48 | pl.color = glm::vec3(1); 49 | //pl.position = glm::vec3(500 * (r1 * 2 - 1), 50 * r2, 500 * (r3 * 2 - 1)); 50 | pl.position = glm::vec3(100, 20, 280); 51 | pl.attenuation = glm::vec3(1, 0.01f, 0.001f); //radius, 0.001 = 500, 0.01 = 159 52 | pl.radius = (-pl.attenuation.y + sqrtf(pow(pl.attenuation.y, 2) - (4 * pl.attenuation.z*(pl.attenuation.x - 256)))) / (2 * pl.attenuation.z); 53 | lights.push_back(pl); 54 | } 55 | 56 | loadCubemap(); 57 | } 58 | 59 | Scene::~Scene() { 60 | if (noiseTex != 0) glDeleteTextures(1, &noiseTex); 61 | if (skyboxTexture != 0) glDeleteTextures(1, &skyboxTexture); 62 | } 63 | 64 | void Scene::setType(int type) { 65 | this->type = type; 66 | } 67 | 68 | void Scene::loadCubemap() { 69 | vector faces{ "skybox/v1/right.jpg", "skybox/v1/left.jpg", "skybox/v1/top.jpg", "skybox/v1/bottom.jpg", "skybox/v1/back.jpg", "skybox/v1/front.jpg" }; 70 | //vector faces{ "skybox/right.jpg", "skybox/left.jpg", "skybox/top.jpg", "skybox/bottom.jpg", "skybox/back.jpg", "skybox/front.jpg" }; 71 | int width, height; 72 | unsigned char* image; 73 | 74 | glGenTextures(1, &skyboxTexture); 75 | glBindTexture(GL_TEXTURE_CUBE_MAP, skyboxTexture); 76 | for (GLuint i = 0; i < faces.size(); i++) { 77 | image = SOIL_load_image(faces[i], &width, &height, 0, SOIL_LOAD_RGB); 78 | glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, image); 79 | } 80 | 81 | glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_LINEAR); 82 | glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR); 83 | glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); 84 | glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); 85 | glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE); 86 | glBindTexture(GL_TEXTURE_CUBE_MAP, 0); 87 | 88 | free(image); 89 | } 90 | 91 | void Scene::loadMeshes() { 92 | ifstream infile("scenes/rungholt.cobj", std::ifstream::binary); 93 | pair, vector> sm = read(infile); 94 | 95 | meshes.clear(); 96 | meshes.resize(sm.first.size()); 97 | 98 | for (int i = 0; i < sm.first.size(); i++) { 99 | meshes[i].create(); 100 | meshes[i].updateBuffers(sm.first[i].mesh.positions, sm.first[i].mesh.indices, sm.first[i].mesh.normals); 101 | meshes[i].ambient = glm::vec3(sm.second[i].ambient[0], sm.second[i].ambient[1], sm.second[i].ambient[2]); 102 | meshes[i].diffuse = glm::vec3(sm.second[i].diffuse[0], sm.second[i].diffuse[1], sm.second[i].diffuse[2]); 103 | meshes[i].specular = sm.second[i].specular[0]; 104 | } 105 | 106 | vector positions; 107 | vector indices; 108 | generatePatchedSphere(positions, indices); 109 | sphere.create(); 110 | sphere.updateBuffers(positions, indices); 111 | 112 | initKernel(); 113 | } 114 | 115 | void Scene::initKernel() { 116 | for (int i = 0; i < kernelSize; i++) { 117 | float r1 = static_cast (rand()) / static_cast (RAND_MAX); 118 | float r2 = static_cast (rand()) / static_cast (RAND_MAX); 119 | float r3 = static_cast (rand()) / static_cast (RAND_MAX); 120 | glm::vec3 k(r1 * 2.0f - 1.0f, r2 * 2.0f - 1.0f, r3); 121 | k = glm::normalize(k); 122 | float scale = float(i) / float(kernelSize); 123 | scale = glm::lerp(0.1f, 1.0f, scale * scale); 124 | k *= scale; 125 | 126 | kernel.push_back(k.x); 127 | kernel.push_back(k.y); 128 | kernel.push_back(k.z); 129 | } 130 | 131 | vector noise; 132 | for (int i = 0; i < kernelSize; i++) { 133 | float r1 = static_cast (rand()) / static_cast (RAND_MAX); 134 | float r2 = static_cast (rand()) / static_cast (RAND_MAX); 135 | float r3 = static_cast (rand()) / static_cast (RAND_MAX); 136 | glm::vec3 n(r1 * 2.0f - 1.0f, r2 * 2.0f - 1.0f, 0); 137 | n = glm::normalize(n); 138 | noise.push_back(n); 139 | } 140 | 141 | glGenTextures(1, &noiseTex); 142 | glBindTexture(GL_TEXTURE_2D, noiseTex); 143 | glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA16F, noiseSize, noiseSize, 0, GL_RGBA, GL_FLOAT, &noise[0]); 144 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); 145 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); 146 | glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); 147 | glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); 148 | glBindTexture(GL_TEXTURE_2D, 0); 149 | 150 | noiseScale = glm::vec2(width / noiseSize, height / noiseSize); 151 | } 152 | 153 | void Scene::renderScene(Camera &cam) { 154 | //Set camera 155 | mView = cam.getMView(); 156 | normalMatrix = glm::mat3(glm::inverseTranspose(mView)); 157 | 158 | //Clear buffer 159 | glClearColor(0.0f, 0.0f, 0.0f, 1.0f); 160 | 161 | //Render geometry to gBuffer 162 | geometryPass(); 163 | 164 | //Render shadowmap 165 | shadowPass(); 166 | 167 | //Render point light shadow maps 168 | 169 | //Need to clear light buffer 170 | gBuffer.bindDraw(); 171 | gBuffer.setDrawLight(); 172 | glClear(GL_COLOR_BUFFER_BIT); 173 | gBuffer.unbindDraw(); 174 | 175 | //Compute stencil and then render lights 176 | for (auto &pl : lights) { 177 | glViewport(0, 0, 1024, 1024); 178 | plShadowPass(pl); 179 | glViewport(0, 0, width, height); 180 | glEnable(GL_STENCIL_TEST); 181 | stencilPass(pl); 182 | pointLightPass(pl); 183 | glDisable(GL_STENCIL_TEST); 184 | } 185 | 186 | //SSAO to gBuffer's effect1 texture 187 | ssaoPass(); 188 | 189 | //Blur over SSAO to filter out noise (TODO: use better blur) 190 | 191 | //Render directional light and compute final color with light buffer 192 | compositePass(); 193 | 194 | //Render skybox last 195 | skyboxPass(); 196 | 197 | GLenum err = glGetError(); 198 | if (err != 0) cout << err << endl; 199 | } 200 | 201 | void Scene::geometryPass() { 202 | glUseProgram(geometry.program); 203 | gBuffer.bindDraw(); 204 | gBuffer.setDrawBuffers(); 205 | 206 | geometry.setUniformmat4("mView", mView); 207 | geometry.setUniformmat4("projection", projection); 208 | geometry.setUniformmat3("mNormal", normalMatrix); 209 | 210 | glDepthMask(GL_TRUE); 211 | glEnable(GL_DEPTH_TEST); 212 | 213 | glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); 214 | 215 | for (auto &i : meshes) { 216 | geometry.setUniformv3f("diffuse", i.diffuse); 217 | geometry.setUniformf("specular", i.specular); 218 | i.render(); 219 | } 220 | 221 | glDisable(GL_DEPTH_TEST); 222 | glDepthMask(GL_FALSE); 223 | } 224 | 225 | void Scene::shadowPass() { 226 | glViewport(0, 0, 2048, 2048); 227 | glUseProgram(shadow.program); 228 | dLightShadow.bindDraw(); 229 | 230 | shadow.setUniformmat4("mvp", dLightProjection * dLightMView); 231 | 232 | glDepthMask(GL_TRUE); 233 | glEnable(GL_DEPTH_TEST); 234 | 235 | glClear(GL_DEPTH_BUFFER_BIT); 236 | 237 | for (auto &i : meshes) { 238 | i.render(); 239 | } 240 | 241 | glDisable(GL_DEPTH_TEST); 242 | glDepthMask(GL_FALSE); 243 | 244 | dLightShadow.unbindDraw(); 245 | glViewport(0, 0, width, height); 246 | } 247 | 248 | void Scene::plShadowPass(PointLight pl) { 249 | //Render out depth for depth testing 250 | glUseProgram(stencil.program); 251 | pLightShadow.bindDraw(); 252 | glDrawBuffer(GL_NONE); 253 | 254 | stencil.setUniformmat4("mView", mView); 255 | stencil.setUniformmat4("projection", projection); 256 | stencil.setUniformv3f("worldPos", pl.position); 257 | stencil.setUniformf("radius", pl.radius); 258 | 259 | glDepthMask(GL_TRUE); 260 | glEnable(GL_DEPTH_TEST); 261 | 262 | glClear(GL_DEPTH_BUFFER_BIT); 263 | sphere.render(); 264 | 265 | glDisable(GL_DEPTH_TEST); 266 | glDepthMask(GL_FALSE); 267 | 268 | pLightShadow.unbindDraw(); 269 | 270 | //Render shadow map to cube 271 | glUseProgram(plShadow.program); 272 | pLightShadow.bindDraw(); 273 | glDrawBuffer(GL_COLOR_ATTACHMENT0); 274 | 275 | plShadow.setUniformv3f("worldPos", pl.position); 276 | 277 | //glEnable(GL_DEPTH_TEST); 278 | 279 | for (int i = 0; i < 6; i++) { 280 | glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, directions[i].face, pLightShadow.cubeMap, 0); 281 | glClear(GL_COLOR_BUFFER_BIT); 282 | plShadow.setUniformmat4("mvp", projection * glm::lookAt(pl.position, pl.position + directions[i].target, directions[i].up)); 283 | for (auto &i : meshes) { 284 | i.render(); 285 | } 286 | } 287 | 288 | //glDisable(GL_DEPTH_TEST); 289 | 290 | pLightShadow.unbindDraw(); 291 | } 292 | 293 | void Scene::stencilPass(PointLight pl) { 294 | glUseProgram(stencil.program); 295 | gBuffer.bindDraw(); 296 | gBuffer.setDrawNone(); 297 | 298 | stencil.setUniformmat4("mView", mView); 299 | stencil.setUniformmat4("projection", projection); 300 | stencil.setUniformv3f("worldPos", pl.position); 301 | stencil.setUniformf("radius", pl.radius); 302 | 303 | glEnable(GL_DEPTH_TEST); 304 | glStencilFunc(GL_ALWAYS, 0, 0); 305 | glStencilOpSeparate(GL_BACK, GL_KEEP, GL_INCR_WRAP, GL_KEEP); 306 | glStencilOpSeparate(GL_FRONT, GL_KEEP, GL_DECR_WRAP, GL_KEEP); 307 | 308 | glClear(GL_STENCIL_BUFFER_BIT); 309 | 310 | sphere.render(); 311 | 312 | glDisable(GL_DEPTH_TEST); 313 | 314 | gBuffer.unbindDraw(); 315 | } 316 | 317 | void Scene::pointLightPass(PointLight pl) { 318 | glUseProgram(lightPass.program); 319 | gBuffer.bindDraw(); 320 | gBuffer.setDrawLight(); 321 | 322 | glActiveTexture(GL_TEXTURE0); 323 | glBindTexture(GL_TEXTURE_2D, gBuffer.position); 324 | glActiveTexture(GL_TEXTURE1); 325 | glBindTexture(GL_TEXTURE_2D, gBuffer.normal); 326 | glActiveTexture(GL_TEXTURE2); 327 | glBindTexture(GL_TEXTURE_2D, gBuffer.color); 328 | glActiveTexture(GL_TEXTURE3); 329 | glBindTexture(GL_TEXTURE_CUBE_MAP, pLightShadow.cubeMap); 330 | 331 | lightPass.setUniformi("positionMap", 0); 332 | lightPass.setUniformi("normalMap", 1); 333 | lightPass.setUniformi("colorMap", 2); 334 | lightPass.setUniformi("shadowMap", 3); 335 | 336 | lightPass.setUniformmat4("inverseMView", glm::inverse(mView)); 337 | lightPass.setUniformmat4("mView", mView); 338 | lightPass.setUniformmat4("projection", projection); 339 | lightPass.setUniformv3f("worldPos", pl.position); 340 | lightPass.setUniformf("radius", pl.radius); 341 | lightPass.setUniformv3f("lPos", glm::vec3(mView * glm::vec4(pl.position, 1.0))); 342 | lightPass.setUniformv3f("lightColor", pl.color); 343 | lightPass.setUniformv3f("lightAttenuation", pl.attenuation); 344 | lightPass.setUniformv2f("screenSize", glm::vec2(width, height)); 345 | 346 | glStencilFunc(GL_NOTEQUAL, 0, 0xFF); 347 | glEnable(GL_BLEND); 348 | glBlendEquation(GL_FUNC_ADD); 349 | glBlendFunc(GL_ONE, GL_ONE); 350 | glEnable(GL_CULL_FACE); 351 | 352 | sphere.render(); 353 | 354 | glDisable(GL_CULL_FACE); 355 | glDisable(GL_BLEND); 356 | 357 | gBuffer.unbindDraw(); 358 | } 359 | 360 | void Scene::ssaoPass() { 361 | glUseProgram(ssao.program); 362 | gBuffer.bindDraw(); 363 | gBuffer.setDrawEffect(); 364 | 365 | ssao.setUniformmat4("projection", projection); 366 | ssao.setUniformi("kernelSize", kernelSize); 367 | ssao.setUniformv2f("noiseScale", noiseScale); 368 | ssao.setUniform3fv("kernel", kernelSize, &kernel[0]); 369 | 370 | glActiveTexture(GL_TEXTURE0); 371 | glBindTexture(GL_TEXTURE_2D, gBuffer.position); 372 | glActiveTexture(GL_TEXTURE1); 373 | glBindTexture(GL_TEXTURE_2D, gBuffer.normal); 374 | glActiveTexture(GL_TEXTURE2); 375 | glBindTexture(GL_TEXTURE_2D, noiseTex); 376 | 377 | ssao.setUniformi("positionMap", 0); 378 | ssao.setUniformi("normalMap", 1); 379 | ssao.setUniformi("noiseMap", 2); 380 | 381 | fsQuad.render(); 382 | 383 | gBuffer.unbindDraw(); 384 | } 385 | 386 | void Scene::blurPass() { 387 | 388 | } 389 | 390 | void Scene::compositePass() { 391 | //Composition pass (directional light + light buffer) 392 | glUseProgram(finalPass.program); 393 | glBindFramebuffer(GL_FRAMEBUFFER, 0); 394 | 395 | finalPass.setUniformmat4("inverseMView", glm::inverse(mView)); 396 | 397 | glActiveTexture(GL_TEXTURE0); 398 | glBindTexture(GL_TEXTURE_2D, gBuffer.position); 399 | glActiveTexture(GL_TEXTURE1); 400 | glBindTexture(GL_TEXTURE_2D, gBuffer.normal); 401 | glActiveTexture(GL_TEXTURE2); 402 | glBindTexture(GL_TEXTURE_2D, gBuffer.color); 403 | glActiveTexture(GL_TEXTURE3); 404 | glBindTexture(GL_TEXTURE_2D, gBuffer.light); 405 | glActiveTexture(GL_TEXTURE4); 406 | glBindTexture(GL_TEXTURE_2D, gBuffer.effect1); 407 | glActiveTexture(GL_TEXTURE5); 408 | glBindTexture(GL_TEXTURE_2D, dLightShadow.depth); 409 | 410 | finalPass.setUniformi("positionMap", 0); 411 | finalPass.setUniformi("normalMap", 1); 412 | finalPass.setUniformi("colorMap", 2); 413 | finalPass.setUniformi("lightMap", 3); 414 | finalPass.setUniformi("ssaoMap", 4); 415 | finalPass.setUniformi("shadowMap", 5); 416 | 417 | finalPass.setUniformv3f("l", glm::vec3(mView * lightDir)); 418 | finalPass.setUniformmat4("shadowMapMVP", dLightProjection * dLightMView); 419 | finalPass.setUniformi("shadowMapWidth", 2048); 420 | finalPass.setUniformi("shadowMapHeight", 2048); 421 | 422 | finalPass.setUniformi("type", type); 423 | 424 | //glEnable(GL_FRAMEBUFFER_SRGB); 425 | 426 | glClear(GL_COLOR_BUFFER_BIT); 427 | 428 | fsQuad.render(); 429 | 430 | //glDisable(GL_FRAMEBUFFER_SRGB); 431 | } 432 | 433 | void Scene::skyboxPass() { 434 | //Blit gbuffer's depth to main FBO for testing 435 | glBindFramebuffer(GL_READ_FRAMEBUFFER, gBuffer.getFBO()); 436 | glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0); 437 | glBlitFramebuffer(0, 0, width, height, 0, 0, width, height, GL_DEPTH_BUFFER_BIT, GL_NEAREST); 438 | 439 | glUseProgram(skybox.program); 440 | glBindFramebuffer(GL_FRAMEBUFFER, 0); 441 | 442 | glActiveTexture(GL_TEXTURE0); 443 | glBindTexture(GL_TEXTURE_CUBE_MAP, skyboxTexture); 444 | 445 | skybox.setUniformi("skybox", 0); 446 | 447 | skybox.setUniformmat4("inverseVP", glm::inverse(projection * glm::mat4(glm::mat3(mView)))); 448 | 449 | glEnable(GL_DEPTH_TEST); 450 | glDepthFunc(GL_LEQUAL); 451 | 452 | fsQuad.render(); 453 | 454 | glDisable(GL_DEPTH_TEST); 455 | } -------------------------------------------------------------------------------- /DeferredRenderer/tiny_obj_loader.cc: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright 2012-2015, Syoyo Fujita. 3 | // 4 | // Licensed under 2-clause BSD liecense. 5 | // 6 | 7 | // 8 | // version 0.9.9: Replace atof() with custom parser. 9 | // version 0.9.8: Fix multi-materials(per-face material ID). 10 | // version 0.9.7: Support multi-materials(per-face material ID) per 11 | // object/group. 12 | // version 0.9.6: Support Ni(index of refraction) mtl parameter. 13 | // Parse transmittance material parameter correctly. 14 | // version 0.9.5: Parse multiple group name. 15 | // Add support of specifying the base path to load material file. 16 | // version 0.9.4: Initial suupport of group tag(g) 17 | // version 0.9.3: Fix parsing triple 'x/y/z' 18 | // version 0.9.2: Add more .mtl load support 19 | // version 0.9.1: Add initial .mtl load support 20 | // version 0.9.0: Initial 21 | // 22 | 23 | #include 24 | #include 25 | #include 26 | #include 27 | 28 | #include 29 | #include 30 | #include 31 | #include 32 | #include 33 | 34 | #include "tiny_obj_loader.h" 35 | 36 | namespace tinyobj { 37 | 38 | struct vertex_index { 39 | int v_idx, vt_idx, vn_idx; 40 | vertex_index(){}; 41 | vertex_index(int idx) : v_idx(idx), vt_idx(idx), vn_idx(idx){}; 42 | vertex_index(int vidx, int vtidx, int vnidx) 43 | : v_idx(vidx), vt_idx(vtidx), vn_idx(vnidx){}; 44 | }; 45 | // for std::map 46 | static inline bool operator<(const vertex_index &a, const vertex_index &b) { 47 | if (a.v_idx != b.v_idx) 48 | return (a.v_idx < b.v_idx); 49 | if (a.vn_idx != b.vn_idx) 50 | return (a.vn_idx < b.vn_idx); 51 | if (a.vt_idx != b.vt_idx) 52 | return (a.vt_idx < b.vt_idx); 53 | 54 | return false; 55 | } 56 | 57 | struct obj_shape { 58 | std::vector v; 59 | std::vector vn; 60 | std::vector vt; 61 | }; 62 | 63 | static inline bool isSpace(const char c) { return (c == ' ') || (c == '\t'); } 64 | 65 | static inline bool isNewLine(const char c) { 66 | return (c == '\r') || (c == '\n') || (c == '\0'); 67 | } 68 | 69 | // Make index zero-base, and also support relative index. 70 | static inline int fixIndex(int idx, int n) { 71 | if (idx > 0) return idx - 1; 72 | if (idx == 0) return 0; 73 | return n + idx; // negative value = relative 74 | } 75 | 76 | static inline std::string parseString(const char *&token) { 77 | std::string s; 78 | token += strspn(token, " \t"); 79 | int e = strcspn(token, " \t\r"); 80 | s = std::string(token, &token[e]); 81 | token += e; 82 | return s; 83 | } 84 | 85 | static inline int parseInt(const char *&token) { 86 | token += strspn(token, " \t"); 87 | int i = atoi(token); 88 | token += strcspn(token, " \t\r"); 89 | return i; 90 | } 91 | 92 | 93 | // Tries to parse a floating point number located at s. 94 | // 95 | // s_end should be a location in the string where reading should absolutely 96 | // stop. For example at the end of the string, to prevent buffer overflows. 97 | // 98 | // Parses the following EBNF grammar: 99 | // sign = "+" | "-" ; 100 | // END = ? anything not in digit ? 101 | // digit = "0" | "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9" ; 102 | // integer = [sign] , digit , {digit} ; 103 | // decimal = integer , ["." , integer] ; 104 | // float = ( decimal , END ) | ( decimal , ("E" | "e") , integer , END ) ; 105 | // 106 | // Valid strings are for example: 107 | // -0 +3.1417e+2 -0.0E-3 1.0324 -1.41 11e2 108 | // 109 | // If the parsing is a success, result is set to the parsed value and true 110 | // is returned. 111 | // 112 | // The function is greedy and will parse until any of the following happens: 113 | // - a non-conforming character is encountered. 114 | // - s_end is reached. 115 | // 116 | // The following situations triggers a failure: 117 | // - s >= s_end. 118 | // - parse failure. 119 | // 120 | static bool tryParseDouble(const char *s, const char *s_end, double *result) 121 | { 122 | if (s >= s_end) 123 | { 124 | return false; 125 | } 126 | 127 | double mantissa = 0.0; 128 | // This exponent is base 2 rather than 10. 129 | // However the exponent we parse is supposed to be one of ten, 130 | // thus we must take care to convert the exponent/and or the 131 | // mantissa to a * 2^E, where a is the mantissa and E is the 132 | // exponent. 133 | // To get the final double we will use ldexp, it requires the 134 | // exponent to be in base 2. 135 | int exponent = 0; 136 | 137 | // NOTE: THESE MUST BE DECLARED HERE SINCE WE ARE NOT ALLOWED 138 | // TO JUMP OVER DEFINITIONS. 139 | char sign = '+'; 140 | char exp_sign = '+'; 141 | char const *curr = s; 142 | 143 | // How many characters were read in a loop. 144 | int read = 0; 145 | // Tells whether a loop terminated due to reaching s_end. 146 | bool end_not_reached = false; 147 | 148 | /* 149 | BEGIN PARSING. 150 | */ 151 | 152 | // Find out what sign we've got. 153 | if (*curr == '+' || *curr == '-') 154 | { 155 | sign = *curr; 156 | curr++; 157 | } 158 | else if (isdigit(*curr)) { /* Pass through. */ } 159 | else 160 | { 161 | goto fail; 162 | } 163 | 164 | // Read the integer part. 165 | while ((end_not_reached = (curr != s_end)) && isdigit(*curr)) 166 | { 167 | mantissa *= 10; 168 | mantissa += static_cast(*curr - 0x30); 169 | curr++; read++; 170 | } 171 | 172 | // We must make sure we actually got something. 173 | if (read == 0) 174 | goto fail; 175 | // We allow numbers of form "#", "###" etc. 176 | if (!end_not_reached) 177 | goto assemble; 178 | 179 | // Read the decimal part. 180 | if (*curr == '.') 181 | { 182 | curr++; 183 | read = 1; 184 | while ((end_not_reached = (curr != s_end)) && isdigit(*curr)) 185 | { 186 | // NOTE: Don't use powf here, it will absolutely murder precision. 187 | mantissa += static_cast(*curr - 0x30) * pow(10, -read); 188 | read++; curr++; 189 | } 190 | } 191 | else if (*curr == 'e' || *curr == 'E') {} 192 | else 193 | { 194 | goto assemble; 195 | } 196 | 197 | if (!end_not_reached) 198 | goto assemble; 199 | 200 | // Read the exponent part. 201 | if (*curr == 'e' || *curr == 'E') 202 | { 203 | curr++; 204 | // Figure out if a sign is present and if it is. 205 | if ((end_not_reached = (curr != s_end)) && (*curr == '+' || *curr == '-')) 206 | { 207 | exp_sign = *curr; 208 | curr++; 209 | } 210 | else if (isdigit(*curr)) { /* Pass through. */ } 211 | else 212 | { 213 | // Empty E is not allowed. 214 | goto fail; 215 | } 216 | 217 | read = 0; 218 | while ((end_not_reached = (curr != s_end)) && isdigit(*curr)) 219 | { 220 | exponent *= 10; 221 | exponent += static_cast(*curr - 0x30); 222 | curr++; read++; 223 | } 224 | exponent *= (exp_sign == '+'? 1 : -1); 225 | if (read == 0) 226 | goto fail; 227 | } 228 | 229 | assemble: 230 | *result = (sign == '+'? 1 : -1) * ldexp(mantissa * pow(5, exponent), exponent); 231 | return true; 232 | fail: 233 | return false; 234 | } 235 | static inline float parseFloat(const char *&token) { 236 | token += strspn(token, " \t"); 237 | #ifdef TINY_OBJ_LOADER_OLD_FLOAT_PARSER 238 | float f = (float)atof(token); 239 | token += strcspn(token, " \t\r"); 240 | #else 241 | const char *end = token + strcspn(token, " \t\r"); 242 | double val = 0.0; 243 | tryParseDouble(token, end, &val); 244 | float f = static_cast(val); 245 | token = end; 246 | #endif 247 | return f; 248 | } 249 | 250 | 251 | static inline void parseFloat2(float &x, float &y, const char *&token) { 252 | x = parseFloat(token); 253 | y = parseFloat(token); 254 | } 255 | 256 | static inline void parseFloat3(float &x, float &y, float &z, 257 | const char *&token) { 258 | x = parseFloat(token); 259 | y = parseFloat(token); 260 | z = parseFloat(token); 261 | } 262 | 263 | // Parse triples: i, i/j/k, i//k, i/j 264 | static vertex_index parseTriple(const char *&token, int vsize, int vnsize, 265 | int vtsize) { 266 | vertex_index vi(-1); 267 | 268 | vi.v_idx = fixIndex(atoi(token), vsize); 269 | token += strcspn(token, "/ \t\r"); 270 | if (token[0] != '/') { 271 | return vi; 272 | } 273 | token++; 274 | 275 | // i//k 276 | if (token[0] == '/') { 277 | token++; 278 | vi.vn_idx = fixIndex(atoi(token), vnsize); 279 | token += strcspn(token, "/ \t\r"); 280 | return vi; 281 | } 282 | 283 | // i/j/k or i/j 284 | vi.vt_idx = fixIndex(atoi(token), vtsize); 285 | token += strcspn(token, "/ \t\r"); 286 | if (token[0] != '/') { 287 | return vi; 288 | } 289 | 290 | // i/j/k 291 | token++; // skip '/' 292 | vi.vn_idx = fixIndex(atoi(token), vnsize); 293 | token += strcspn(token, "/ \t\r"); 294 | return vi; 295 | } 296 | 297 | static unsigned int 298 | updateVertex(std::map &vertexCache, 299 | std::vector &positions, std::vector &normals, 300 | std::vector &texcoords, 301 | const std::vector &in_positions, 302 | const std::vector &in_normals, 303 | const std::vector &in_texcoords, const vertex_index &i) { 304 | const std::map::iterator it = vertexCache.find(i); 305 | 306 | if (it != vertexCache.end()) { 307 | // found cache 308 | return it->second; 309 | } 310 | 311 | assert(in_positions.size() > (unsigned int)(3 * i.v_idx + 2)); 312 | 313 | positions.push_back(in_positions[3 * i.v_idx + 0]); 314 | positions.push_back(in_positions[3 * i.v_idx + 1]); 315 | positions.push_back(in_positions[3 * i.v_idx + 2]); 316 | 317 | if (i.vn_idx >= 0) { 318 | normals.push_back(in_normals[3 * i.vn_idx + 0]); 319 | normals.push_back(in_normals[3 * i.vn_idx + 1]); 320 | normals.push_back(in_normals[3 * i.vn_idx + 2]); 321 | } 322 | 323 | if (i.vt_idx >= 0) { 324 | texcoords.push_back(in_texcoords[2 * i.vt_idx + 0]); 325 | texcoords.push_back(in_texcoords[2 * i.vt_idx + 1]); 326 | } 327 | 328 | unsigned int idx = positions.size() / 3 - 1; 329 | vertexCache[i] = idx; 330 | 331 | return idx; 332 | } 333 | 334 | void InitMaterial(material_t &material) { 335 | material.name = ""; 336 | material.ambient_texname = ""; 337 | material.diffuse_texname = ""; 338 | material.specular_texname = ""; 339 | material.normal_texname = ""; 340 | for (int i = 0; i < 3; i++) { 341 | material.ambient[i] = 0.f; 342 | material.diffuse[i] = 0.f; 343 | material.specular[i] = 0.f; 344 | material.transmittance[i] = 0.f; 345 | material.emission[i] = 0.f; 346 | } 347 | material.illum = 0; 348 | material.dissolve = 1.f; 349 | material.shininess = 1.f; 350 | material.ior = 1.f; 351 | material.unknown_parameter.clear(); 352 | } 353 | 354 | static bool exportFaceGroupToShape( 355 | shape_t &shape, std::map vertexCache, 356 | const std::vector &in_positions, 357 | const std::vector &in_normals, 358 | const std::vector &in_texcoords, 359 | const std::vector > &faceGroup, 360 | const int material_id, const std::string &name, bool clearCache) { 361 | if (faceGroup.empty()) { 362 | return false; 363 | } 364 | 365 | // Flatten vertices and indices 366 | for (size_t i = 0; i < faceGroup.size(); i++) { 367 | const std::vector &face = faceGroup[i]; 368 | 369 | vertex_index i0 = face[0]; 370 | vertex_index i1(-1); 371 | vertex_index i2 = face[1]; 372 | 373 | size_t npolys = face.size(); 374 | 375 | // Polygon -> triangle fan conversion 376 | for (size_t k = 2; k < npolys; k++) { 377 | i1 = i2; 378 | i2 = face[k]; 379 | 380 | unsigned int v0 = updateVertex( 381 | vertexCache, shape.mesh.positions, shape.mesh.normals, 382 | shape.mesh.texcoords, in_positions, in_normals, in_texcoords, i0); 383 | unsigned int v1 = updateVertex( 384 | vertexCache, shape.mesh.positions, shape.mesh.normals, 385 | shape.mesh.texcoords, in_positions, in_normals, in_texcoords, i1); 386 | unsigned int v2 = updateVertex( 387 | vertexCache, shape.mesh.positions, shape.mesh.normals, 388 | shape.mesh.texcoords, in_positions, in_normals, in_texcoords, i2); 389 | 390 | shape.mesh.indices.push_back(v0); 391 | shape.mesh.indices.push_back(v1); 392 | shape.mesh.indices.push_back(v2); 393 | 394 | shape.mesh.material_ids.push_back(material_id); 395 | } 396 | } 397 | 398 | shape.name = name; 399 | 400 | if (clearCache) 401 | vertexCache.clear(); 402 | 403 | return true; 404 | } 405 | 406 | std::string LoadMtl(std::map &material_map, 407 | std::vector &materials, 408 | std::istream &inStream) { 409 | material_map.clear(); 410 | std::stringstream err; 411 | 412 | material_t material; 413 | 414 | int maxchars = 8192; // Alloc enough size. 415 | std::vector buf(maxchars); // Alloc enough size. 416 | while (inStream.peek() != -1) { 417 | inStream.getline(&buf[0], maxchars); 418 | 419 | std::string linebuf(&buf[0]); 420 | 421 | // Trim newline '\r\n' or '\n' 422 | if (linebuf.size() > 0) { 423 | if (linebuf[linebuf.size() - 1] == '\n') 424 | linebuf.erase(linebuf.size() - 1); 425 | } 426 | if (linebuf.size() > 0) { 427 | if (linebuf[linebuf.size() - 1] == '\r') 428 | linebuf.erase(linebuf.size() - 1); 429 | } 430 | 431 | // Skip if empty line. 432 | if (linebuf.empty()) { 433 | continue; 434 | } 435 | 436 | // Skip leading space. 437 | const char *token = linebuf.c_str(); 438 | token += strspn(token, " \t"); 439 | 440 | assert(token); 441 | if (token[0] == '\0') 442 | continue; // empty line 443 | 444 | if (token[0] == '#') 445 | continue; // comment line 446 | 447 | // new mtl 448 | if ((0 == strncmp(token, "newmtl", 6)) && isSpace((token[6]))) { 449 | // flush previous material. 450 | if (!material.name.empty()) { 451 | material_map.insert( 452 | std::pair(material.name, materials.size())); 453 | materials.push_back(material); 454 | } 455 | 456 | // initial temporary material 457 | InitMaterial(material); 458 | 459 | // set new mtl name 460 | char namebuf[4096]; 461 | token += 7; 462 | sscanf(token, "%s", namebuf); 463 | material.name = namebuf; 464 | continue; 465 | } 466 | 467 | // ambient 468 | if (token[0] == 'K' && token[1] == 'a' && isSpace((token[2]))) { 469 | token += 2; 470 | float r, g, b; 471 | parseFloat3(r, g, b, token); 472 | material.ambient[0] = r; 473 | material.ambient[1] = g; 474 | material.ambient[2] = b; 475 | continue; 476 | } 477 | 478 | // diffuse 479 | if (token[0] == 'K' && token[1] == 'd' && isSpace((token[2]))) { 480 | token += 2; 481 | float r, g, b; 482 | parseFloat3(r, g, b, token); 483 | material.diffuse[0] = r; 484 | material.diffuse[1] = g; 485 | material.diffuse[2] = b; 486 | continue; 487 | } 488 | 489 | // specular 490 | if (token[0] == 'K' && token[1] == 's' && isSpace((token[2]))) { 491 | token += 2; 492 | float r, g, b; 493 | parseFloat3(r, g, b, token); 494 | material.specular[0] = r; 495 | material.specular[1] = g; 496 | material.specular[2] = b; 497 | continue; 498 | } 499 | 500 | // transmittance 501 | if (token[0] == 'K' && token[1] == 't' && isSpace((token[2]))) { 502 | token += 2; 503 | float r, g, b; 504 | parseFloat3(r, g, b, token); 505 | material.transmittance[0] = r; 506 | material.transmittance[1] = g; 507 | material.transmittance[2] = b; 508 | continue; 509 | } 510 | 511 | // ior(index of refraction) 512 | if (token[0] == 'N' && token[1] == 'i' && isSpace((token[2]))) { 513 | token += 2; 514 | material.ior = parseFloat(token); 515 | continue; 516 | } 517 | 518 | // emission 519 | if (token[0] == 'K' && token[1] == 'e' && isSpace(token[2])) { 520 | token += 2; 521 | float r, g, b; 522 | parseFloat3(r, g, b, token); 523 | material.emission[0] = r; 524 | material.emission[1] = g; 525 | material.emission[2] = b; 526 | continue; 527 | } 528 | 529 | // shininess 530 | if (token[0] == 'N' && token[1] == 's' && isSpace(token[2])) { 531 | token += 2; 532 | material.shininess = parseFloat(token); 533 | continue; 534 | } 535 | 536 | // illum model 537 | if (0 == strncmp(token, "illum", 5) && isSpace(token[5])) { 538 | token += 6; 539 | material.illum = parseInt(token); 540 | continue; 541 | } 542 | 543 | // dissolve 544 | if ((token[0] == 'd' && isSpace(token[1]))) { 545 | token += 1; 546 | material.dissolve = parseFloat(token); 547 | continue; 548 | } 549 | if (token[0] == 'T' && token[1] == 'r' && isSpace(token[2])) { 550 | token += 2; 551 | material.dissolve = parseFloat(token); 552 | continue; 553 | } 554 | 555 | // ambient texture 556 | if ((0 == strncmp(token, "map_Ka", 6)) && isSpace(token[6])) { 557 | token += 7; 558 | material.ambient_texname = token; 559 | continue; 560 | } 561 | 562 | // diffuse texture 563 | if ((0 == strncmp(token, "map_Kd", 6)) && isSpace(token[6])) { 564 | token += 7; 565 | material.diffuse_texname = token; 566 | continue; 567 | } 568 | 569 | // specular texture 570 | if ((0 == strncmp(token, "map_Ks", 6)) && isSpace(token[6])) { 571 | token += 7; 572 | material.specular_texname = token; 573 | continue; 574 | } 575 | 576 | // normal texture 577 | if ((0 == strncmp(token, "map_Ns", 6)) && isSpace(token[6])) { 578 | token += 7; 579 | material.normal_texname = token; 580 | continue; 581 | } 582 | 583 | // unknown parameter 584 | const char *_space = strchr(token, ' '); 585 | if (!_space) { 586 | _space = strchr(token, '\t'); 587 | } 588 | if (_space) { 589 | int len = _space - token; 590 | std::string key(token, len); 591 | std::string value = _space + 1; 592 | material.unknown_parameter.insert( 593 | std::pair(key, value)); 594 | } 595 | } 596 | // flush last material. 597 | material_map.insert( 598 | std::pair(material.name, materials.size())); 599 | materials.push_back(material); 600 | 601 | return err.str(); 602 | } 603 | 604 | std::string MaterialFileReader::operator()(const std::string &matId, 605 | std::vector &materials, 606 | std::map &matMap) { 607 | std::string filepath; 608 | 609 | if (!m_mtlBasePath.empty()) { 610 | filepath = std::string(m_mtlBasePath) + matId; 611 | } else { 612 | filepath = matId; 613 | } 614 | 615 | std::ifstream matIStream(filepath.c_str()); 616 | return LoadMtl(matMap, materials, matIStream); 617 | } 618 | 619 | std::string LoadObj(std::vector &shapes, 620 | std::vector &materials, // [output] 621 | const char *filename, const char *mtl_basepath) { 622 | 623 | shapes.clear(); 624 | 625 | std::stringstream err; 626 | 627 | std::ifstream ifs(filename); 628 | if (!ifs) { 629 | err << "Cannot open file [" << filename << "]" << std::endl; 630 | return err.str(); 631 | } 632 | 633 | std::string basePath; 634 | if (mtl_basepath) { 635 | basePath = mtl_basepath; 636 | } 637 | MaterialFileReader matFileReader(basePath); 638 | 639 | return LoadObj(shapes, materials, ifs, matFileReader); 640 | } 641 | 642 | std::string LoadObj(std::vector &shapes, 643 | std::vector &materials, // [output] 644 | std::istream &inStream, MaterialReader &readMatFn) { 645 | std::stringstream err; 646 | 647 | std::vector v; 648 | std::vector vn; 649 | std::vector vt; 650 | std::vector > faceGroup; 651 | std::string name; 652 | 653 | // material 654 | std::map material_map; 655 | std::map vertexCache; 656 | int material = -1; 657 | 658 | shape_t shape; 659 | 660 | int maxchars = 8192; // Alloc enough size. 661 | std::vector buf(maxchars); // Alloc enough size. 662 | while (inStream.peek() != -1) { 663 | inStream.getline(&buf[0], maxchars); 664 | 665 | std::string linebuf(&buf[0]); 666 | 667 | // Trim newline '\r\n' or '\n' 668 | if (linebuf.size() > 0) { 669 | if (linebuf[linebuf.size() - 1] == '\n') 670 | linebuf.erase(linebuf.size() - 1); 671 | } 672 | if (linebuf.size() > 0) { 673 | if (linebuf[linebuf.size() - 1] == '\r') 674 | linebuf.erase(linebuf.size() - 1); 675 | } 676 | 677 | // Skip if empty line. 678 | if (linebuf.empty()) { 679 | continue; 680 | } 681 | 682 | // Skip leading space. 683 | const char *token = linebuf.c_str(); 684 | token += strspn(token, " \t"); 685 | 686 | assert(token); 687 | if (token[0] == '\0') 688 | continue; // empty line 689 | 690 | if (token[0] == '#') 691 | continue; // comment line 692 | 693 | // vertex 694 | if (token[0] == 'v' && isSpace((token[1]))) { 695 | token += 2; 696 | float x, y, z; 697 | parseFloat3(x, y, z, token); 698 | v.push_back(x); 699 | v.push_back(y); 700 | v.push_back(z); 701 | continue; 702 | } 703 | 704 | // normal 705 | if (token[0] == 'v' && token[1] == 'n' && isSpace((token[2]))) { 706 | token += 3; 707 | float x, y, z; 708 | parseFloat3(x, y, z, token); 709 | vn.push_back(x); 710 | vn.push_back(y); 711 | vn.push_back(z); 712 | continue; 713 | } 714 | 715 | // texcoord 716 | if (token[0] == 'v' && token[1] == 't' && isSpace((token[2]))) { 717 | token += 3; 718 | float x, y; 719 | parseFloat2(x, y, token); 720 | vt.push_back(x); 721 | vt.push_back(y); 722 | continue; 723 | } 724 | 725 | // face 726 | if (token[0] == 'f' && isSpace((token[1]))) { 727 | token += 2; 728 | token += strspn(token, " \t"); 729 | 730 | std::vector face; 731 | while (!isNewLine(token[0])) { 732 | vertex_index vi = 733 | parseTriple(token, v.size() / 3, vn.size() / 3, vt.size() / 2); 734 | face.push_back(vi); 735 | int n = strspn(token, " \t\r"); 736 | token += n; 737 | } 738 | 739 | faceGroup.push_back(face); 740 | 741 | continue; 742 | } 743 | 744 | // use mtl 745 | if ((0 == strncmp(token, "usemtl", 6)) && isSpace((token[6]))) { 746 | 747 | char namebuf[4096]; 748 | token += 7; 749 | sscanf(token, "%s", namebuf); 750 | 751 | // Create face group per material. 752 | bool ret = exportFaceGroupToShape(shape, vertexCache, v, vn, vt, 753 | faceGroup, material, name, true); 754 | if (ret) { 755 | faceGroup.clear(); 756 | } 757 | 758 | if (material_map.find(namebuf) != material_map.end()) { 759 | material = material_map[namebuf]; 760 | } else { 761 | // { error!! material not found } 762 | material = -1; 763 | } 764 | 765 | continue; 766 | } 767 | 768 | // load mtl 769 | if ((0 == strncmp(token, "mtllib", 6)) && isSpace((token[6]))) { 770 | char namebuf[4096]; 771 | token += 7; 772 | sscanf(token, "%s", namebuf); 773 | 774 | std::string err_mtl = readMatFn(namebuf, materials, material_map); 775 | if (!err_mtl.empty()) { 776 | faceGroup.clear(); // for safety 777 | return err_mtl; 778 | } 779 | 780 | continue; 781 | } 782 | 783 | // group name 784 | if (token[0] == 'g' && isSpace((token[1]))) { 785 | 786 | // flush previous face group. 787 | bool ret = exportFaceGroupToShape(shape, vertexCache, v, vn, vt, 788 | faceGroup, material, name, true); 789 | if (ret) { 790 | shapes.push_back(shape); 791 | } 792 | 793 | shape = shape_t(); 794 | 795 | // material = -1; 796 | faceGroup.clear(); 797 | 798 | std::vector names; 799 | while (!isNewLine(token[0])) { 800 | std::string str = parseString(token); 801 | names.push_back(str); 802 | token += strspn(token, " \t\r"); // skip tag 803 | } 804 | 805 | assert(names.size() > 0); 806 | 807 | // names[0] must be 'g', so skip the 0th element. 808 | if (names.size() > 1) { 809 | name = names[1]; 810 | } else { 811 | name = ""; 812 | } 813 | 814 | continue; 815 | } 816 | 817 | // object name 818 | if (token[0] == 'o' && isSpace((token[1]))) { 819 | 820 | // flush previous face group. 821 | bool ret = exportFaceGroupToShape(shape, vertexCache, v, vn, vt, 822 | faceGroup, material, name, true); 823 | if (ret) { 824 | shapes.push_back(shape); 825 | } 826 | 827 | // material = -1; 828 | faceGroup.clear(); 829 | shape = shape_t(); 830 | 831 | // @todo { multiple object name? } 832 | char namebuf[4096]; 833 | token += 2; 834 | sscanf(token, "%s", namebuf); 835 | name = std::string(namebuf); 836 | 837 | continue; 838 | } 839 | 840 | // Ignore unknown command. 841 | } 842 | 843 | bool ret = exportFaceGroupToShape(shape, vertexCache, v, vn, vt, faceGroup, 844 | material, name, true); 845 | if (ret) { 846 | shapes.push_back(shape); 847 | } 848 | faceGroup.clear(); // for safety 849 | 850 | return err.str(); 851 | } 852 | } 853 | --------------------------------------------------------------------------------