void SkeletonModel::renderBoundingCollisionShapes(gpu::Batch& batch, float alpha) { const int BALL_SUBDIVISIONS = 10; auto geometryCache = DependencyManager::get<GeometryCache>(); auto deferredLighting = DependencyManager::get<DeferredLightingEffect>(); Transform transform; // = Transform(); // draw a blue sphere at the capsule top point glm::vec3 topPoint = _translation + _boundingCapsuleLocalOffset + (0.5f * _boundingCapsuleHeight) * glm::vec3(0.0f, 1.0f, 0.0f); transform.setTranslation(topPoint); batch.setModelTransform(transform); deferredLighting->bindSimpleProgram(batch); geometryCache->renderSphere(batch, _boundingCapsuleRadius, BALL_SUBDIVISIONS, BALL_SUBDIVISIONS, glm::vec4(0.6f, 0.6f, 0.8f, alpha)); // draw a yellow sphere at the capsule bottom point glm::vec3 bottomPoint = topPoint - glm::vec3(0.0f, -_boundingCapsuleHeight, 0.0f); glm::vec3 axis = topPoint - bottomPoint; transform.setTranslation(bottomPoint); batch.setModelTransform(transform); deferredLighting->bindSimpleProgram(batch); geometryCache->renderSphere(batch, _boundingCapsuleRadius, BALL_SUBDIVISIONS, BALL_SUBDIVISIONS, glm::vec4(0.8f, 0.8f, 0.6f, alpha)); // draw a green cylinder between the two points glm::vec3 origin(0.0f); Avatar::renderJointConnectingCone(batch, origin, axis, _boundingCapsuleRadius, _boundingCapsuleRadius, glm::vec4(0.6f, 0.8f, 0.6f, alpha)); }
void SkeletonModel::renderBoundingCollisionShapes(gpu::Batch& batch, float alpha) { const int BALL_SUBDIVISIONS = 10; if (_shapes.isEmpty()) { // the bounding shape has not been propery computed // so no need to render it return; } Application::getInstance()->loadTranslatedViewMatrix(_translation); // draw a blue sphere at the capsule endpoint glm::vec3 endPoint; _boundingShape.getEndPoint(endPoint); endPoint = endPoint - _translation; Transform transform = Transform(); transform.setTranslation(endPoint); batch.setModelTransform(transform); auto geometryCache = DependencyManager::get<GeometryCache>(); geometryCache->renderSphere(batch, _boundingShape.getRadius(), BALL_SUBDIVISIONS, BALL_SUBDIVISIONS, glm::vec4(0.6f, 0.6f, 0.8f, alpha)); // draw a yellow sphere at the capsule startpoint glm::vec3 startPoint; _boundingShape.getStartPoint(startPoint); startPoint = startPoint - _translation; glm::vec3 axis = endPoint - startPoint; glTranslatef(-axis.x, -axis.y, -axis.z); geometryCache->renderSphere(_boundingShape.getRadius(), BALL_SUBDIVISIONS, BALL_SUBDIVISIONS, glm::vec4(0.8f, 0.8f, 0.6f, alpha)); // draw a green cylinder between the two points glm::vec3 origin(0.0f); Avatar::renderJointConnectingCone(batch, origin, axis, _boundingShape.getRadius(), _boundingShape.getRadius(), glm::vec4(0.6f, 0.8f, 0.6f, alpha)); }
void display(void) { glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); renderSphere(0); renderSphere(1); glFlush(); }
/* display() draws 5 spheres at different z positions. */ void display(void) { glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); renderSphere (-2., -0.5, -1.0); renderSphere (-1., -0.5, -2.0); renderSphere (0., -0.5, -3.0); renderSphere (1., -0.5, -4.0); renderSphere (2., -0.5, -5.0); glFlush(); }
/* display() draws 5 spheres at different z positions. */ static void display(UGWindow uwin) { glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); renderSphere (-2., -0.5, -1.0); renderSphere (-1., -0.5, -2.0); renderSphere (0., -0.5, -3.0); renderSphere (1., -0.5, -4.0); renderSphere (2., -0.5, -5.0); glFlush(); ugSwapBuffers(uwin); }
// virtual void SkeletonModel::renderJointCollisionShapes(float alpha) { if (!_ragdoll) { return; } glPushMatrix(); Application::getInstance()->loadTranslatedViewMatrix(_translation); glm::vec3 simulationTranslation = _ragdoll->getTranslationInSimulationFrame(); for (int i = 0; i < _shapes.size(); i++) { Shape* shape = _shapes[i]; if (!shape) { continue; } auto geometryCache = DependencyManager::get<GeometryCache>(); glPushMatrix(); // shapes are stored in simulation-frame but we want position to be model-relative if (shape->getType() == SPHERE_SHAPE) { glm::vec3 position = shape->getTranslation() - simulationTranslation; glTranslatef(position.x, position.y, position.z); // draw a grey sphere at shape position geometryCache->renderSphere(shape->getBoundingRadius(), BALL_SUBDIVISIONS, BALL_SUBDIVISIONS, glm::vec4(0.75f, 0.75f, 0.75f, alpha)); } else if (shape->getType() == CAPSULE_SHAPE) { CapsuleShape* capsule = static_cast<CapsuleShape*>(shape); // draw a blue sphere at the capsule endpoint glm::vec3 endPoint; capsule->getEndPoint(endPoint); endPoint = endPoint - simulationTranslation; glTranslatef(endPoint.x, endPoint.y, endPoint.z); geometryCache->renderSphere(capsule->getRadius(), BALL_SUBDIVISIONS, BALL_SUBDIVISIONS, glm::vec4(0.6f, 0.6f, 0.8f, alpha)); // draw a yellow sphere at the capsule startpoint glm::vec3 startPoint; capsule->getStartPoint(startPoint); startPoint = startPoint - simulationTranslation; glm::vec3 axis = endPoint - startPoint; glTranslatef(-axis.x, -axis.y, -axis.z); geometryCache->renderSphere(capsule->getRadius(), BALL_SUBDIVISIONS, BALL_SUBDIVISIONS, glm::vec4(0.8f, 0.8f, 0.6f, alpha)); // draw a green cylinder between the two points glm::vec3 origin(0.0f); Avatar::renderJointConnectingCone( origin, axis, capsule->getRadius(), capsule->getRadius(), glm::vec4(0.6f, 0.8f, 0.6f, alpha)); } glPopMatrix(); } glPopMatrix(); }
void PointLightSource::render(const UsefulRenderData& render_data) { // If we are inside the sphere affected by the light source, render a full // quad. Otherwize just render the light sphere glm::vec4 position_world_space = glm::vec4(absoluteTransform()[3]); glm::vec3 position_view_space = glm::vec3(render_data.camera.viewTransform() * position_world_space); float distance_to_light_source = glm::length(position_view_space); // Probably not the best way of handling rescaled light sources, // but works for now.. glm::vec3 scale; glm::quat rotation; glm::vec3 translation; glm::vec3 skew; glm::vec4 perspective; glm::decompose( absoluteTransform(), scale, rotation, translation, skew,perspective); float transform_scale = scale.x; if (distance_to_light_source < _sphere_scale * transform_scale) renderQuad(render_data); else renderSphere(render_data); }
void SkeletonModel::renderRagdoll() { if (!_ragdoll) { return; } const QVector<VerletPoint>& points = _ragdoll->getPoints(); const int BALL_SUBDIVISIONS = 6; glDisable(GL_DEPTH_TEST); glDisable(GL_LIGHTING); glPushMatrix(); Application::getInstance()->loadTranslatedViewMatrix(_translation); int numPoints = points.size(); float alpha = 0.3f; float radius1 = 0.008f; float radius2 = 0.01f; glm::vec3 simulationTranslation = _ragdoll->getTranslationInSimulationFrame(); auto geometryCache = DependencyManager::get<GeometryCache>(); for (int i = 0; i < numPoints; ++i) { glPushMatrix(); // NOTE: ragdollPoints are in simulation-frame but we want them to be model-relative glm::vec3 position = points[i]._position - simulationTranslation; glTranslatef(position.x, position.y, position.z); // draw each point as a yellow hexagon with black border geometryCache->renderSphere(radius2, BALL_SUBDIVISIONS, BALL_SUBDIVISIONS, glm::vec4(0.0f, 0.0f, 0.0f, alpha)); geometryCache->renderSphere(radius1, BALL_SUBDIVISIONS, BALL_SUBDIVISIONS, glm::vec4(1.0f, 1.0f, 0.0f, alpha)); glPopMatrix(); } glPopMatrix(); glEnable(GL_DEPTH_TEST); glEnable(GL_LIGHTING); }
void CFog6_7::displayEvent() { glDisable(GL_LIGHTING); glDisable(GL_FOG); CLearnOpenGLBase::displayEvent(); glEnable(GL_LIGHTING); glEnable(GL_FOG); renderSphere(0, 0.5, -0.3); renderSphere(0, 0.5, -0.7); renderSphere(0, 0.5, -1.1); renderSphere(0, 0.5, -1.5); renderSphere(0, 0.5, -1.9); glutSwapBuffers(); }
void AssetRenderer::renderPolygon(const mat4f &cameraPerspective, const Polygonf &poly, const vec3f &color, float height) { for (const auto &segment : poly.segments()) { renderCylinder(cameraPerspective, vec3f(segment.p0(), height), vec3f(segment.p1(), height), color); renderSphere(cameraPerspective, vec3f(segment.p0(), height), 0.02f, color); } }
/** * Renders a similar scene used for the raytracer: * 5 colored spheres with a single light */ void MainWindow::renderRaytracerScene() { QVector3D lightpos = QVector3D(-200,600,1500); // Blue sphere renderSphere(QVector3D(90,320,100),QVector3D(0,0,1),QVector4D(0.2f,0.7f,0.5f,64),lightpos); // Green sphere renderSphere(QVector3D(210,270,300),QVector3D(0,1,0),QVector4D(0.2f,0.3f,0.5f,8),lightpos); // Red sphere renderSphere(QVector3D(290,170,150),QVector3D(1,0,0),QVector4D(0.2f,0.7f,0.8f,32),lightpos); // Yellow sphere renderSphere(QVector3D(140,220,400),QVector3D(1,0.8f,0),QVector4D(0.2f,0.8f,0.0f,1),lightpos); // Orange sphere renderSphere(QVector3D(110,130,200),QVector3D(1,0.5f,0),QVector4D(0.2f,0.8f,0.5f,32),lightpos); }
void render() { if (initialized == false) { glEnable(GL_CULL_FACE); glEnable(GL_DEPTH_TEST); spherePositionsId = createSpherePositions(); sphereNormalsId = createSphereNormals(positions); createProgram(); startTimeMillis = currentTimeMillis(); initialized = true; } frameCount++; totalFrameCount++; long now = currentTimeMillis(); long elapsed = now - startTimeMillis; static long lastTimerCall = 0; if ((now - lastTimerCall) > 250) { timer(0); lastTimerCall = now; } glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glUseProgram(programId); // // calculate the ModelViewProjection and ModelViewProjection matrices // matrix44 tmp, mv, mvp, frustumMat, translateMat, rotateMat1, rotateMat2; frustum(frustumMat, left, right, bottom / aspectRatio, top / aspectRatio, nearPlane, farPlane); translate(translateMat, 0.0f, 0.0f, -3.0f); rotate(rotateMat1, 1.0f * elapsed / 50, 1.0f, 0.0f, 0.0f); rotate(rotateMat2, 1.0f * elapsed / 100, 0.0f, 1.0f, 0.0f); multm(tmp, rotateMat1, rotateMat2); multm(mv, translateMat, tmp); multm(mvp, frustumMat, mv); // set the uniforms before rendering GLuint mvpMatrixUniform = glGetUniformLocation(programId, "mvpMatrix"); GLuint mvMatrixUniform = glGetUniformLocation(programId, "mvMatrix"); GLuint colorUniform = glGetUniformLocation(programId, "color"); GLuint ambientUniform = glGetUniformLocation(programId, "ambient"); GLuint lightDirUniform = glGetUniformLocation(programId, "lightDir"); glUniformMatrix4fv(mvpMatrixUniform, 1, false, mvp); glUniformMatrix4fv(mvMatrixUniform, 1, false, mv); glUniform3f(lightDirUniform, 1.0f, -1.0f, -1.0f); glUniform4f(colorUniform, 0.5f, 0.5f, 0.5f, 1.0f); glUniform4f(ambientUniform, 0.1f, 0.1f, 0.1f, 1.0f); // render! renderSphere(); // display rendering buffer SDL_GL_SwapBuffers(); }
/******************************************************************************* Function to draw a geometry object. *******************************************************************************/ void GOdeObject::drawGeom( dGeomID g, const dReal *position, const dReal *orientation ) const { if( !g ) //If the geometry object is missing, end the function. return; if( !position ) //Position was not passed? position = dGeomGetPosition( g ); //Then, get the geometry position. if( !orientation ) //Orientation was not given? orientation = dGeomGetRotation( g ); //And get existing geometry orientation. int type = dGeomGetClass( g ); //Get the type of geometry. if( type == dBoxClass ) //Is it a box? { dReal sides[3]; dGeomBoxGetLengths( g, sides ); //Get length of sides. renderBox( sides, position, orientation ); //Render the actual box in environment. } if( type == dSphereClass ) //Is it a sphere? { dReal radius; radius = dGeomSphereGetRadius( g ); //Get the radius. renderSphere( radius, position, orientation ); //Render sphere in environment. } if( type == dCapsuleClass ) { dReal radius; dReal length; dGeomCapsuleGetParams( g, &radius, &length ); //Get both radius and length. renderCapsule( radius, length, position, orientation ); //Render capsule in environment. } if( type == dGeomTransformClass ) //Is it an embeded geom in a composite body. { dGeomID g2 = dGeomTransformGetGeom( g ); //Get the actual geometry inside the wrapper. const dReal *position2 = dGeomGetPosition( g2 ); //Get position and orientation of wrapped geometry. const dReal *orientation2 = dGeomGetRotation( g2 ); dVector3 actualPosition; //Real world coordinated position and orientation dMatrix3 actualOrientation; //of the wrapped geometry. dMultiply0_331( actualPosition, orientation, position2 ); //Get world coordinates of geometry position. actualPosition[0] += position[0]; actualPosition[1] += position[1]; actualPosition[2] += position[2]; dMultiply0_333( actualOrientation, orientation, orientation2 ); //Get world coordinates of geom orientation. drawGeom( g2, actualPosition, actualOrientation ); //Draw embeded geometry. } }
void SkeletonModel::renderBoundingCollisionShapes(gpu::Batch& batch, float alpha) { const int BALL_SUBDIVISIONS = 10; if (_shapes.isEmpty()) { // the bounding shape has not been properly computed // so no need to render it return; } auto geometryCache = DependencyManager::get<GeometryCache>(); auto deferredLighting = DependencyManager::get<DeferredLightingEffect>(); Transform transform; // = Transform(); // draw a blue sphere at the capsule end point glm::vec3 endPoint; _boundingShape.getEndPoint(endPoint); endPoint = endPoint + _translation; transform.setTranslation(endPoint); batch.setModelTransform(transform); deferredLighting->bindSimpleProgram(batch); geometryCache->renderSphere(batch, _boundingShape.getRadius(), BALL_SUBDIVISIONS, BALL_SUBDIVISIONS, glm::vec4(0.6f, 0.6f, 0.8f, alpha)); // draw a yellow sphere at the capsule start point glm::vec3 startPoint; _boundingShape.getStartPoint(startPoint); startPoint = startPoint + _translation; glm::vec3 axis = endPoint - startPoint; transform.setTranslation(startPoint); batch.setModelTransform(transform); deferredLighting->bindSimpleProgram(batch); geometryCache->renderSphere(batch, _boundingShape.getRadius(), BALL_SUBDIVISIONS, BALL_SUBDIVISIONS, glm::vec4(0.8f, 0.8f, 0.6f, alpha)); // draw a green cylinder between the two points glm::vec3 origin(0.0f); Avatar::renderJointConnectingCone(batch, origin, axis, _boundingShape.getRadius(), _boundingShape.getRadius(), glm::vec4(0.6f, 0.8f, 0.6f, alpha)); }
int main() { // glfw: initialize and configure // ------------------------------ glfwInit(); glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3); glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3); glfwWindowHint(GLFW_SAMPLES, 4); glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); #ifdef __APPLE__ glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE); // uncomment this statement to fix compilation on OS X #endif // glfw window creation // -------------------- GLFWwindow* window = glfwCreateWindow(SCR_WIDTH, SCR_HEIGHT, "LearnOpenGL", NULL, NULL); glfwMakeContextCurrent(window); if (window == NULL) { std::cout << "Failed to create GLFW window" << std::endl; glfwTerminate(); return -1; } glfwSetFramebufferSizeCallback(window, framebuffer_size_callback); glfwSetCursorPosCallback(window, mouse_callback); glfwSetScrollCallback(window, scroll_callback); // tell GLFW to capture our mouse glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_DISABLED); // glad: load all OpenGL function pointers // --------------------------------------- if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress)) { std::cout << "Failed to initialize GLAD" << std::endl; return -1; } // configure global opengl state // ----------------------------- glEnable(GL_DEPTH_TEST); // build and compile shaders // ------------------------- Shader shader("1.2.pbr.vs", "1.2.pbr.fs"); shader.use(); shader.setInt("albedoMap", 0); shader.setInt("normalMap", 1); shader.setInt("metallicMap", 2); shader.setInt("roughnessMap", 3); shader.setInt("aoMap", 4); // load PBR material textures // -------------------------- unsigned int albedo = loadTexture(FileSystem::getPath("resources/textures/pbr/rusted_iron/albedo.png").c_str()); unsigned int normal = loadTexture(FileSystem::getPath("resources/textures/pbr/rusted_iron/normal.png").c_str()); unsigned int metallic = loadTexture(FileSystem::getPath("resources/textures/pbr/rusted_iron/metallic.png").c_str()); unsigned int roughness = loadTexture(FileSystem::getPath("resources/textures/pbr/rusted_iron/roughness.png").c_str()); unsigned int ao = loadTexture(FileSystem::getPath("resources/textures/pbr/rusted_iron/ao.png").c_str()); // lights // ------ glm::vec3 lightPositions[] = { glm::vec3(0.0f, 0.0f, 10.0f), }; glm::vec3 lightColors[] = { glm::vec3(150.0f, 150.0f, 150.0f), }; int nrRows = 7; int nrColumns = 7; float spacing = 2.5; // initialize static shader uniforms before rendering // -------------------------------------------------- glm::mat4 projection = glm::perspective(glm::radians(camera.Zoom), (float)SCR_WIDTH / (float)SCR_HEIGHT, 0.1f, 100.0f); shader.use(); shader.setMat4("projection", projection); // render loop // ----------- while (!glfwWindowShouldClose(window)) { // per-frame time logic // -------------------- float currentFrame = glfwGetTime(); deltaTime = currentFrame - lastFrame; lastFrame = currentFrame; // input // ----- processInput(window); // render // ------ glClearColor(0.1f, 0.1f, 0.1f, 1.0f); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); shader.use(); glm::mat4 view = camera.GetViewMatrix(); shader.setMat4("view", view); shader.setVec3("camPos", camera.Position); glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, albedo); glActiveTexture(GL_TEXTURE1); glBindTexture(GL_TEXTURE_2D, normal); glActiveTexture(GL_TEXTURE2); glBindTexture(GL_TEXTURE_2D, metallic); glActiveTexture(GL_TEXTURE3); glBindTexture(GL_TEXTURE_2D, roughness); glActiveTexture(GL_TEXTURE4); glBindTexture(GL_TEXTURE_2D, ao); // render rows*column number of spheres with material properties defined by textures (they all have the same material properties) glm::mat4 model = glm::mat4(1.0f); for (int row = 0; row < nrRows; ++row) { for (int col = 0; col < nrColumns; ++col) { model = glm::mat4(1.0f); model = glm::translate(model, glm::vec3( (float)(col - (nrColumns / 2)) * spacing, (float)(row - (nrRows / 2)) * spacing, 0.0f )); shader.setMat4("model", model); renderSphere(); } } // render light source (simply re-render sphere at light positions) // this looks a bit off as we use the same shader, but it'll make their positions obvious and // keeps the codeprint small. for (unsigned int i = 0; i < sizeof(lightPositions) / sizeof(lightPositions[0]); ++i) { glm::vec3 newPos = lightPositions[i] + glm::vec3(sin(glfwGetTime() * 5.0) * 5.0, 0.0, 0.0); newPos = lightPositions[i]; shader.setVec3("lightPositions[" + std::to_string(i) + "]", newPos); shader.setVec3("lightColors[" + std::to_string(i) + "]", lightColors[i]); model = glm::mat4(1.0f); model = glm::translate(model, newPos); model = glm::scale(model, glm::vec3(0.5f)); shader.setMat4("model", model); renderSphere(); } // glfw: swap buffers and poll IO events (keys pressed/released, mouse moved etc.) // ------------------------------------------------------------------------------- glfwSwapBuffers(window); glfwPollEvents(); } // glfw: terminate, clearing all previously allocated GLFW resources. // ------------------------------------------------------------------ glfwTerminate(); return 0; }
int main() { // glfw: initialize and configure // ------------------------------ glfwInit(); glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3); glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3); glfwWindowHint(GLFW_SAMPLES, 4); glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); // glfw window creation // -------------------- GLFWwindow* window = glfwCreateWindow(SCR_WIDTH, SCR_HEIGHT, "LearnOpenGL", NULL, NULL); glfwMakeContextCurrent(window); if (window == NULL) { std::cout << "Failed to create GLFW window" << std::endl; glfwTerminate(); return -1; } glfwSetFramebufferSizeCallback(window, framebuffer_size_callback); glfwSetCursorPosCallback(window, mouse_callback); glfwSetScrollCallback(window, scroll_callback); // tell GLFW to capture our mouse glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_DISABLED); // glad: load all OpenGL function pointers // --------------------------------------- if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress)) { std::cout << "Failed to initialize GLAD" << std::endl; return -1; } // configure global opengl state // ----------------------------- glEnable(GL_DEPTH_TEST); glDepthFunc(GL_LEQUAL); // set depth function to less than AND equal for skybox depth trick. // build and compile shaders // ------------------------- Shader pbrShader("2.1.2.pbr.vs", "2.1.2.pbr.fs"); Shader equirectangularToCubemapShader("2.1.2.cubemap.vs", "2.1.2.equirectangular_to_cubemap.fs"); Shader irradianceShader("2.1.2.cubemap.vs", "2.1.2.irradiance_convolution.fs"); Shader backgroundShader("2.1.2.background.vs", "2.1.2.background.fs"); pbrShader.use(); pbrShader.setInt("irradianceMap", 0); pbrShader.setVec3("albedo", 0.5f, 0.0f, 0.0f); pbrShader.setFloat("ao", 1.0f); backgroundShader.use(); backgroundShader.setInt("environmentMap", 0); // lights // ------ glm::vec3 lightPositions[] = { glm::vec3(-10.0f, 10.0f, 10.0f), glm::vec3( 10.0f, 10.0f, 10.0f), glm::vec3(-10.0f, -10.0f, 10.0f), glm::vec3( 10.0f, -10.0f, 10.0f), }; glm::vec3 lightColors[] = { glm::vec3(300.0f, 300.0f, 300.0f), glm::vec3(300.0f, 300.0f, 300.0f), glm::vec3(300.0f, 300.0f, 300.0f), glm::vec3(300.0f, 300.0f, 300.0f) }; int nrRows = 7; int nrColumns = 7; float spacing = 2.5; // pbr: setup framebuffer // ---------------------- unsigned int captureFBO; unsigned int captureRBO; glGenFramebuffers(1, &captureFBO); glGenRenderbuffers(1, &captureRBO); glBindFramebuffer(GL_FRAMEBUFFER, captureFBO); glBindRenderbuffer(GL_RENDERBUFFER, captureRBO); glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT24, 512, 512); glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, captureRBO); // pbr: load the HDR environment map // --------------------------------- stbi_set_flip_vertically_on_load(true); int width, height, nrComponents; float *data = stbi_loadf(FileSystem::getPath("resources/textures/hdr/newport_loft.hdr").c_str(), &width, &height, &nrComponents, 0); unsigned int hdrTexture; if (data) { glGenTextures(1, &hdrTexture); glBindTexture(GL_TEXTURE_2D, hdrTexture); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB16F, width, height, 0, GL_RGB, GL_FLOAT, data); // note how we specify the texture's data value to be float glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); stbi_image_free(data); } else { std::cout << "Failed to load HDR image." << std::endl; } // pbr: setup cubemap to render to and attach to framebuffer // --------------------------------------------------------- unsigned int envCubemap; glGenTextures(1, &envCubemap); glBindTexture(GL_TEXTURE_CUBE_MAP, envCubemap); for (unsigned int i = 0; i < 6; ++i) { glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, GL_RGB16F, 512, 512, 0, GL_RGB, GL_FLOAT, nullptr); } glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_LINEAR); // pbr: set up projection and view matrices for capturing data onto the 6 cubemap face directions // ---------------------------------------------------------------------------------------------- glm::mat4 captureProjection = glm::perspective(glm::radians(90.0f), 1.0f, 0.1f, 10.0f); glm::mat4 captureViews[] = { glm::lookAt(glm::vec3(0.0f, 0.0f, 0.0f), glm::vec3(1.0f, 0.0f, 0.0f), glm::vec3(0.0f, -1.0f, 0.0f)), glm::lookAt(glm::vec3(0.0f, 0.0f, 0.0f), glm::vec3(-1.0f, 0.0f, 0.0f), glm::vec3(0.0f, -1.0f, 0.0f)), glm::lookAt(glm::vec3(0.0f, 0.0f, 0.0f), glm::vec3(0.0f, 1.0f, 0.0f), glm::vec3(0.0f, 0.0f, 1.0f)), glm::lookAt(glm::vec3(0.0f, 0.0f, 0.0f), glm::vec3(0.0f, -1.0f, 0.0f), glm::vec3(0.0f, 0.0f, -1.0f)), glm::lookAt(glm::vec3(0.0f, 0.0f, 0.0f), glm::vec3(0.0f, 0.0f, 1.0f), glm::vec3(0.0f, -1.0f, 0.0f)), glm::lookAt(glm::vec3(0.0f, 0.0f, 0.0f), glm::vec3(0.0f, 0.0f, -1.0f), glm::vec3(0.0f, -1.0f, 0.0f)) }; // pbr: convert HDR equirectangular environment map to cubemap equivalent // ---------------------------------------------------------------------- equirectangularToCubemapShader.use(); equirectangularToCubemapShader.setInt("equirectangularMap", 0); equirectangularToCubemapShader.setMat4("projection", captureProjection); glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, hdrTexture); glViewport(0, 0, 512, 512); // don't forget to configure the viewport to the capture dimensions. glBindFramebuffer(GL_FRAMEBUFFER, captureFBO); for (unsigned int i = 0; i < 6; ++i) { equirectangularToCubemapShader.setMat4("view", captureViews[i]); glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, envCubemap, 0); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); renderCube(); } glBindFramebuffer(GL_FRAMEBUFFER, 0); // pbr: create an irradiance cubemap, and re-scale capture FBO to irradiance scale. // -------------------------------------------------------------------------------- unsigned int irradianceMap; glGenTextures(1, &irradianceMap); glBindTexture(GL_TEXTURE_CUBE_MAP, irradianceMap); for (unsigned int i = 0; i < 6; ++i) { glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, GL_RGB16F, 32, 32, 0, GL_RGB, GL_FLOAT, nullptr); } glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glBindFramebuffer(GL_FRAMEBUFFER, captureFBO); glBindRenderbuffer(GL_RENDERBUFFER, captureRBO); glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT24, 32, 32); // pbr: solve diffuse integral by convolution to create an irradiance (cube)map. // ----------------------------------------------------------------------------- irradianceShader.use(); irradianceShader.setInt("environmentMap", 0); irradianceShader.setMat4("projection", captureProjection); glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_CUBE_MAP, envCubemap); glViewport(0, 0, 32, 32); // don't forget to configure the viewport to the capture dimensions. glBindFramebuffer(GL_FRAMEBUFFER, captureFBO); for (unsigned int i = 0; i < 6; ++i) { irradianceShader.setMat4("view", captureViews[i]); glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, irradianceMap, 0); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); renderCube(); } glBindFramebuffer(GL_FRAMEBUFFER, 0); // initialize static shader uniforms before rendering // -------------------------------------------------- glm::mat4 projection = glm::perspective(camera.Zoom, (float)SCR_WIDTH / (float)SCR_HEIGHT, 0.1f, 100.0f); pbrShader.use(); pbrShader.setMat4("projection", projection); backgroundShader.use(); backgroundShader.setMat4("projection", projection); // then before rendering, configure the viewport to the original framebuffer's screen dimensions int scrWidth, scrHeight; glfwGetFramebufferSize(window, &scrWidth, &scrHeight); glViewport(0, 0, scrWidth, scrHeight); // render loop // ----------- while (!glfwWindowShouldClose(window)) { // per-frame time logic // -------------------- float currentFrame = glfwGetTime(); deltaTime = currentFrame - lastFrame; lastFrame = currentFrame; // input // ----- processInput(window); // render // ------ glClearColor(0.2f, 0.3f, 0.3f, 1.0f); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // render scene, supplying the convoluted irradiance map to the final shader. // ------------------------------------------------------------------------------------------ pbrShader.use(); glm::mat4 view = camera.GetViewMatrix(); pbrShader.setMat4("view", view); pbrShader.setVec3("camPos", camera.Position); // bind pre-computed IBL data glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_CUBE_MAP, irradianceMap); // render rows*column number of spheres with material properties defined by textures (they all have the same material properties) glm::mat4 model; for (int row = 0; row < nrRows; ++row) { pbrShader.setFloat("metallic", (float)row / (float)nrRows); for (int col = 0; col < nrColumns; ++col) { // we clamp the roughness to 0.025 - 1.0 as perfectly smooth surfaces (roughness of 0.0) tend to look a bit off // on direct lighting. pbrShader.setFloat("roughness", glm::clamp((float)col / (float)nrColumns, 0.05f, 1.0f)); model = glm::mat4(); model = glm::translate(model, glm::vec3( (float)(col - (nrColumns / 2)) * spacing, (float)(row - (nrRows / 2)) * spacing, -2.0f )); pbrShader.setMat4("model", model); renderSphere(); } } // render light source (simply re-render sphere at light positions) // this looks a bit off as we use the same shader, but it'll make their positions obvious and // keeps the codeprint small. for (unsigned int i = 0; i < sizeof(lightPositions) / sizeof(lightPositions[0]); ++i) { glm::vec3 newPos = lightPositions[i] + glm::vec3(sin(glfwGetTime() * 5.0) * 5.0, 0.0, 0.0); newPos = lightPositions[i]; pbrShader.setVec3("lightPositions[" + std::to_string(i) + "]", newPos); pbrShader.setVec3("lightColors[" + std::to_string(i) + "]", lightColors[i]); model = glm::mat4(); model = glm::translate(model, newPos); model = glm::scale(model, glm::vec3(0.5f)); pbrShader.setMat4("model", model); renderSphere(); } // render skybox (render as last to prevent overdraw) backgroundShader.use(); backgroundShader.setMat4("view", view); glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_CUBE_MAP, envCubemap); //glBindTexture(GL_TEXTURE_CUBE_MAP, irradianceMap); // display irradiance map renderCube(); // glfw: swap buffers and poll IO events (keys pressed/released, mouse moved etc.) // ------------------------------------------------------------------------------- glfwSwapBuffers(window); glfwPollEvents(); } // glfw: terminate, clearing all previously allocated GLFW resources. // ------------------------------------------------------------------ glfwTerminate(); return 0; }
void DeferredLightingEffect::render(RenderArgs* args) { // perform deferred lighting, rendering to free fbo glDisable(GL_BLEND); glDisable(GL_LIGHTING); glDisable(GL_DEPTH_TEST); glDisable(GL_COLOR_MATERIAL); glDepthMask(false); auto textureCache = DependencyManager::get<TextureCache>(); glBindFramebuffer(GL_FRAMEBUFFER, 0 ); QSize framebufferSize = textureCache->getFrameBufferSize(); // binding the first framebuffer auto freeFBO = DependencyManager::get<GlowEffect>()->getFreeFramebuffer(); glBindFramebuffer(GL_FRAMEBUFFER, gpu::GLBackend::getFramebufferID(freeFBO)); glClear(GL_COLOR_BUFFER_BIT); // glEnable(GL_FRAMEBUFFER_SRGB); // glBindTexture(GL_TEXTURE_2D, primaryFBO->texture()); glBindTexture(GL_TEXTURE_2D, textureCache->getPrimaryColorTextureID()); glActiveTexture(GL_TEXTURE1); glBindTexture(GL_TEXTURE_2D, textureCache->getPrimaryNormalTextureID()); glActiveTexture(GL_TEXTURE2); glBindTexture(GL_TEXTURE_2D, textureCache->getPrimarySpecularTextureID()); glActiveTexture(GL_TEXTURE3); glBindTexture(GL_TEXTURE_2D, textureCache->getPrimaryDepthTextureID()); // get the viewport side (left, right, both) int viewport[4]; glGetIntegerv(GL_VIEWPORT, viewport); const int VIEWPORT_X_INDEX = 0; const int VIEWPORT_Y_INDEX = 1; const int VIEWPORT_WIDTH_INDEX = 2; const int VIEWPORT_HEIGHT_INDEX = 3; float sMin = viewport[VIEWPORT_X_INDEX] / (float)framebufferSize.width(); float sWidth = viewport[VIEWPORT_WIDTH_INDEX] / (float)framebufferSize.width(); float tMin = viewport[VIEWPORT_Y_INDEX] / (float)framebufferSize.height(); float tHeight = viewport[VIEWPORT_HEIGHT_INDEX] / (float)framebufferSize.height(); bool useSkyboxCubemap = (_skybox) && (_skybox->getCubemap()); // Fetch the ViewMatrix; glm::mat4 invViewMat; _viewState->getViewTransform().getMatrix(invViewMat); ProgramObject* program = &_directionalLight; const LightLocations* locations = &_directionalLightLocations; bool shadowsEnabled = _viewState->getShadowsEnabled(); if (shadowsEnabled) { glActiveTexture(GL_TEXTURE4); glBindTexture(GL_TEXTURE_2D, textureCache->getShadowDepthTextureID()); program = &_directionalLightShadowMap; locations = &_directionalLightShadowMapLocations; if (_viewState->getCascadeShadowsEnabled()) { program = &_directionalLightCascadedShadowMap; locations = &_directionalLightCascadedShadowMapLocations; if (useSkyboxCubemap) { program = &_directionalSkyboxLightCascadedShadowMap; locations = &_directionalSkyboxLightCascadedShadowMapLocations; } else if (_ambientLightMode > -1) { program = &_directionalAmbientSphereLightCascadedShadowMap; locations = &_directionalAmbientSphereLightCascadedShadowMapLocations; } program->bind(); program->setUniform(locations->shadowDistances, _viewState->getShadowDistances()); } else { if (useSkyboxCubemap) { program = &_directionalSkyboxLightShadowMap; locations = &_directionalSkyboxLightShadowMapLocations; } else if (_ambientLightMode > -1) { program = &_directionalAmbientSphereLightShadowMap; locations = &_directionalAmbientSphereLightShadowMapLocations; } program->bind(); } program->setUniformValue(locations->shadowScale, 1.0f / textureCache->getShadowFramebuffer()->getWidth()); } else { if (useSkyboxCubemap) { program = &_directionalSkyboxLight; locations = &_directionalSkyboxLightLocations; } else if (_ambientLightMode > -1) { program = &_directionalAmbientSphereLight; locations = &_directionalAmbientSphereLightLocations; } program->bind(); } { auto globalLight = _allocatedLights[_globalLights.front()]; if (locations->ambientSphere >= 0) { gpu::SphericalHarmonics sh = globalLight->getAmbientSphere(); if (useSkyboxCubemap && _skybox->getCubemap()->getIrradiance()) { sh = (*_skybox->getCubemap()->getIrradiance()); } for (int i =0; i <gpu::SphericalHarmonics::NUM_COEFFICIENTS; i++) { program->setUniformValue(locations->ambientSphere + i, *(((QVector4D*) &sh) + i)); } } if (useSkyboxCubemap) { glActiveTexture(GL_TEXTURE5); glBindTexture(GL_TEXTURE_CUBE_MAP, gpu::GLBackend::getTextureID(_skybox->getCubemap())); } if (locations->lightBufferUnit >= 0) { gpu::Batch batch; batch.setUniformBuffer(locations->lightBufferUnit, globalLight->getSchemaBuffer()); gpu::GLBackend::renderBatch(batch); } if (_atmosphere && (locations->atmosphereBufferUnit >= 0)) { gpu::Batch batch; batch.setUniformBuffer(locations->atmosphereBufferUnit, _atmosphere->getDataBuffer()); gpu::GLBackend::renderBatch(batch); } glUniformMatrix4fv(locations->invViewMat, 1, false, reinterpret_cast< const GLfloat* >(&invViewMat)); } float left, right, bottom, top, nearVal, farVal; glm::vec4 nearClipPlane, farClipPlane; _viewState->computeOffAxisFrustum(left, right, bottom, top, nearVal, farVal, nearClipPlane, farClipPlane); program->setUniformValue(locations->nearLocation, nearVal); float depthScale = (farVal - nearVal) / farVal; program->setUniformValue(locations->depthScale, depthScale); float nearScale = -1.0f / nearVal; float depthTexCoordScaleS = (right - left) * nearScale / sWidth; float depthTexCoordScaleT = (top - bottom) * nearScale / tHeight; float depthTexCoordOffsetS = left * nearScale - sMin * depthTexCoordScaleS; float depthTexCoordOffsetT = bottom * nearScale - tMin * depthTexCoordScaleT; program->setUniformValue(locations->depthTexCoordOffset, depthTexCoordOffsetS, depthTexCoordOffsetT); program->setUniformValue(locations->depthTexCoordScale, depthTexCoordScaleS, depthTexCoordScaleT); renderFullscreenQuad(sMin, sMin + sWidth, tMin, tMin + tHeight); program->release(); if (useSkyboxCubemap) { glBindTexture(GL_TEXTURE_CUBE_MAP, 0); if (!shadowsEnabled) { glActiveTexture(GL_TEXTURE3); } } if (shadowsEnabled) { glBindTexture(GL_TEXTURE_2D, 0); glActiveTexture(GL_TEXTURE3); } // additive blending glEnable(GL_BLEND); glBlendFunc(GL_ONE, GL_ONE); glEnable(GL_CULL_FACE); glm::vec4 sCoefficients(sWidth / 2.0f, 0.0f, 0.0f, sMin + sWidth / 2.0f); glm::vec4 tCoefficients(0.0f, tHeight / 2.0f, 0.0f, tMin + tHeight / 2.0f); glTexGenfv(GL_S, GL_OBJECT_PLANE, (const GLfloat*)&sCoefficients); glTexGenfv(GL_T, GL_OBJECT_PLANE, (const GLfloat*)&tCoefficients); // enlarge the scales slightly to account for tesselation const float SCALE_EXPANSION = 0.05f; const glm::vec3& eyePoint = _viewState->getCurrentViewFrustum()->getPosition(); float nearRadius = glm::distance(eyePoint, _viewState->getCurrentViewFrustum()->getNearTopLeft()); auto geometryCache = DependencyManager::get<GeometryCache>(); if (!_pointLights.empty()) { _pointLight.bind(); _pointLight.setUniformValue(_pointLightLocations.nearLocation, nearVal); _pointLight.setUniformValue(_pointLightLocations.depthScale, depthScale); _pointLight.setUniformValue(_pointLightLocations.depthTexCoordOffset, depthTexCoordOffsetS, depthTexCoordOffsetT); _pointLight.setUniformValue(_pointLightLocations.depthTexCoordScale, depthTexCoordScaleS, depthTexCoordScaleT); for (auto lightID : _pointLights) { auto light = _allocatedLights[lightID]; if (_pointLightLocations.lightBufferUnit >= 0) { gpu::Batch batch; batch.setUniformBuffer(_pointLightLocations.lightBufferUnit, light->getSchemaBuffer()); gpu::GLBackend::renderBatch(batch); } glUniformMatrix4fv(_pointLightLocations.invViewMat, 1, false, reinterpret_cast< const GLfloat* >(&invViewMat)); glPushMatrix(); float expandedRadius = light->getMaximumRadius() * (1.0f + SCALE_EXPANSION); if (glm::distance(eyePoint, glm::vec3(light->getPosition())) < expandedRadius + nearRadius) { glLoadIdentity(); glTranslatef(0.0f, 0.0f, -1.0f); glMatrixMode(GL_PROJECTION); glPushMatrix(); glLoadIdentity(); renderFullscreenQuad(); glPopMatrix(); glMatrixMode(GL_MODELVIEW); } else { glTranslatef(light->getPosition().x, light->getPosition().y, light->getPosition().z); geometryCache->renderSphere(expandedRadius, 32, 32, glm::vec4(1.0f, 1.0f, 1.0f, 1.0f)); } glPopMatrix(); } _pointLights.clear(); _pointLight.release(); } if (!_spotLights.empty()) { _spotLight.bind(); _spotLight.setUniformValue(_spotLightLocations.nearLocation, nearVal); _spotLight.setUniformValue(_spotLightLocations.depthScale, depthScale); _spotLight.setUniformValue(_spotLightLocations.depthTexCoordOffset, depthTexCoordOffsetS, depthTexCoordOffsetT); _spotLight.setUniformValue(_spotLightLocations.depthTexCoordScale, depthTexCoordScaleS, depthTexCoordScaleT); for (auto lightID : _spotLights) { auto light = _allocatedLights[lightID]; if (_spotLightLocations.lightBufferUnit >= 0) { gpu::Batch batch; batch.setUniformBuffer(_spotLightLocations.lightBufferUnit, light->getSchemaBuffer()); gpu::GLBackend::renderBatch(batch); } glUniformMatrix4fv(_spotLightLocations.invViewMat, 1, false, reinterpret_cast< const GLfloat* >(&invViewMat)); glPushMatrix(); float expandedRadius = light->getMaximumRadius() * (1.0f + SCALE_EXPANSION); float edgeRadius = expandedRadius / glm::cos(light->getSpotAngle()); if (glm::distance(eyePoint, glm::vec3(light->getPosition())) < edgeRadius + nearRadius) { glLoadIdentity(); glTranslatef(0.0f, 0.0f, -1.0f); glMatrixMode(GL_PROJECTION); glPushMatrix(); glLoadIdentity(); renderFullscreenQuad(); glPopMatrix(); glMatrixMode(GL_MODELVIEW); } else { glTranslatef(light->getPosition().x, light->getPosition().y, light->getPosition().z); glm::quat spotRotation = rotationBetween(glm::vec3(0.0f, 0.0f, -1.0f), light->getDirection()); glm::vec3 axis = glm::axis(spotRotation); glRotatef(glm::degrees(glm::angle(spotRotation)), axis.x, axis.y, axis.z); glTranslatef(0.0f, 0.0f, -light->getMaximumRadius() * (1.0f + SCALE_EXPANSION * 0.5f)); geometryCache->renderCone(expandedRadius * glm::tan(light->getSpotAngle()), expandedRadius, 32, 1); } glPopMatrix(); } _spotLights.clear(); _spotLight.release(); } glBindTexture(GL_TEXTURE_2D, 0); glActiveTexture(GL_TEXTURE2); glBindTexture(GL_TEXTURE_2D, 0); glActiveTexture(GL_TEXTURE1); glBindTexture(GL_TEXTURE_2D, 0); glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, 0); // glDisable(GL_FRAMEBUFFER_SRGB); // End of the Lighting pass }
int main() { // glfw: initialize and configure // ------------------------------ glfwInit(); glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3); glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3); glfwWindowHint(GLFW_SAMPLES, 4); glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); //glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE); // uncomment this statement to fix compilation on OS X // glfw window creation // -------------------- GLFWwindow* window = glfwCreateWindow(SCR_WIDTH, SCR_HEIGHT, "LearnOpenGL", NULL, NULL); glfwMakeContextCurrent(window); if (window == NULL) { std::cout << "Failed to create GLFW window" << std::endl; glfwTerminate(); return -1; } glfwSetFramebufferSizeCallback(window, framebuffer_size_callback); glfwSetCursorPosCallback(window, mouse_callback); glfwSetScrollCallback(window, scroll_callback); // tell GLFW to capture our mouse glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_DISABLED); // glad: load all OpenGL function pointers // --------------------------------------- if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress)) { std::cout << "Failed to initialize GLAD" << std::endl; return -1; } // configure global opengl state // ----------------------------- glEnable(GL_DEPTH_TEST); // set depth function to less than AND equal for skybox depth trick. glDepthFunc(GL_LEQUAL); // enable seamless cubemap sampling for lower mip levels in the pre-filter map. glEnable(GL_TEXTURE_CUBE_MAP_SEAMLESS); // build and compile shaders // ------------------------- Shader pbrShader("2.2.2.pbr.vs", "2.2.2.pbr.fs"); Shader equirectangularToCubemapShader("2.2.2.cubemap.vs", "2.2.2.equirectangular_to_cubemap.fs"); Shader irradianceShader("2.2.2.cubemap.vs", "2.2.2.irradiance_convolution.fs"); Shader prefilterShader("2.2.2.cubemap.vs", "2.2.2.prefilter.fs"); Shader brdfShader("2.2.2.brdf.vs", "2.2.2.brdf.fs"); Shader backgroundShader("2.2.2.background.vs", "2.2.2.background.fs"); pbrShader.use(); pbrShader.setInt("irradianceMap", 0); pbrShader.setInt("prefilterMap", 1); pbrShader.setInt("brdfLUT", 2); pbrShader.setInt("albedoMap", 3); pbrShader.setInt("normalMap", 4); pbrShader.setInt("metallicMap", 5); pbrShader.setInt("roughnessMap", 6); pbrShader.setInt("aoMap", 7); backgroundShader.use(); backgroundShader.setInt("environmentMap", 0); // load PBR material textures // -------------------------- // rusted iron unsigned int ironAlbedoMap = loadTexture(FileSystem::getPath("resources/textures/pbr/rusted_iron/albedo.png").c_str()); unsigned int ironNormalMap = loadTexture(FileSystem::getPath("resources/textures/pbr/rusted_iron/normal.png").c_str()); unsigned int ironMetallicMap = loadTexture(FileSystem::getPath("resources/textures/pbr/rusted_iron/metallic.png").c_str()); unsigned int ironRoughnessMap = loadTexture(FileSystem::getPath("resources/textures/pbr/rusted_iron/roughness.png").c_str()); unsigned int ironAOMap = loadTexture(FileSystem::getPath("resources/textures/pbr/rusted_iron/ao.png").c_str()); // gold unsigned int goldAlbedoMap = loadTexture(FileSystem::getPath("resources/textures/pbr/gold/albedo.png").c_str()); unsigned int goldNormalMap = loadTexture(FileSystem::getPath("resources/textures/pbr/gold/normal.png").c_str()); unsigned int goldMetallicMap = loadTexture(FileSystem::getPath("resources/textures/pbr/gold/metallic.png").c_str()); unsigned int goldRoughnessMap = loadTexture(FileSystem::getPath("resources/textures/pbr/gold/roughness.png").c_str()); unsigned int goldAOMap = loadTexture(FileSystem::getPath("resources/textures/pbr/gold/ao.png").c_str()); // grass unsigned int grassAlbedoMap = loadTexture(FileSystem::getPath("resources/textures/pbr/grass/albedo.png").c_str()); unsigned int grassNormalMap = loadTexture(FileSystem::getPath("resources/textures/pbr/grass/normal.png").c_str()); unsigned int grassMetallicMap = loadTexture(FileSystem::getPath("resources/textures/pbr/grass/metallic.png").c_str()); unsigned int grassRoughnessMap = loadTexture(FileSystem::getPath("resources/textures/pbr/grass/roughness.png").c_str()); unsigned int grassAOMap = loadTexture(FileSystem::getPath("resources/textures/pbr/grass/ao.png").c_str()); // plastic unsigned int plasticAlbedoMap = loadTexture(FileSystem::getPath("resources/textures/pbr/plastic/albedo.png").c_str()); unsigned int plasticNormalMap = loadTexture(FileSystem::getPath("resources/textures/pbr/plastic/normal.png").c_str()); unsigned int plasticMetallicMap = loadTexture(FileSystem::getPath("resources/textures/pbr/plastic/metallic.png").c_str()); unsigned int plasticRoughnessMap = loadTexture(FileSystem::getPath("resources/textures/pbr/plastic/roughness.png").c_str()); unsigned int plasticAOMap = loadTexture(FileSystem::getPath("resources/textures/pbr/plastic/ao.png").c_str()); // wall unsigned int wallAlbedoMap = loadTexture(FileSystem::getPath("resources/textures/pbr/wall/albedo.png").c_str()); unsigned int wallNormalMap = loadTexture(FileSystem::getPath("resources/textures/pbr/wall/normal.png").c_str()); unsigned int wallMetallicMap = loadTexture(FileSystem::getPath("resources/textures/pbr/wall/metallic.png").c_str()); unsigned int wallRoughnessMap = loadTexture(FileSystem::getPath("resources/textures/pbr/wall/roughness.png").c_str()); unsigned int wallAOMap = loadTexture(FileSystem::getPath("resources/textures/pbr/wall/ao.png").c_str()); // lights // ------ glm::vec3 lightPositions[] = { glm::vec3(-10.0f, 10.0f, 10.0f), glm::vec3( 10.0f, 10.0f, 10.0f), glm::vec3(-10.0f, -10.0f, 10.0f), glm::vec3( 10.0f, -10.0f, 10.0f), }; glm::vec3 lightColors[] = { glm::vec3(300.0f, 300.0f, 300.0f), glm::vec3(300.0f, 300.0f, 300.0f), glm::vec3(300.0f, 300.0f, 300.0f), glm::vec3(300.0f, 300.0f, 300.0f) }; int nrRows = 7; int nrColumns = 7; float spacing = 2.5; // pbr: setup framebuffer // ---------------------- unsigned int captureFBO; unsigned int captureRBO; glGenFramebuffers(1, &captureFBO); glGenRenderbuffers(1, &captureRBO); glBindFramebuffer(GL_FRAMEBUFFER, captureFBO); glBindRenderbuffer(GL_RENDERBUFFER, captureRBO); glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT24, 512, 512); glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, captureRBO); // pbr: load the HDR environment map // --------------------------------- stbi_set_flip_vertically_on_load(true); int width, height, nrComponents; float *data = stbi_loadf(FileSystem::getPath("resources/textures/hdr/newport_loft.hdr").c_str(), &width, &height, &nrComponents, 0); unsigned int hdrTexture; if (data) { glGenTextures(1, &hdrTexture); glBindTexture(GL_TEXTURE_2D, hdrTexture); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB16F, width, height, 0, GL_RGB, GL_FLOAT, data); // note how we specify the texture's data value to be float glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); stbi_image_free(data); } else { std::cout << "Failed to load HDR image." << std::endl; } // pbr: setup cubemap to render to and attach to framebuffer // --------------------------------------------------------- unsigned int envCubemap; glGenTextures(1, &envCubemap); glBindTexture(GL_TEXTURE_CUBE_MAP, envCubemap); for (unsigned int i = 0; i < 6; ++i) { glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, GL_RGB16F, 512, 512, 0, GL_RGB, GL_FLOAT, nullptr); } glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); // enable pre-filter mipmap sampling (combatting visible dots artifact) glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_LINEAR); // pbr: set up projection and view matrices for capturing data onto the 6 cubemap face directions // ---------------------------------------------------------------------------------------------- glm::mat4 captureProjection = glm::perspective(glm::radians(90.0f), 1.0f, 0.1f, 10.0f); glm::mat4 captureViews[] = { glm::lookAt(glm::vec3(0.0f, 0.0f, 0.0f), glm::vec3( 1.0f, 0.0f, 0.0f), glm::vec3(0.0f, -1.0f, 0.0f)), glm::lookAt(glm::vec3(0.0f, 0.0f, 0.0f), glm::vec3(-1.0f, 0.0f, 0.0f), glm::vec3(0.0f, -1.0f, 0.0f)), glm::lookAt(glm::vec3(0.0f, 0.0f, 0.0f), glm::vec3( 0.0f, 1.0f, 0.0f), glm::vec3(0.0f, 0.0f, 1.0f)), glm::lookAt(glm::vec3(0.0f, 0.0f, 0.0f), glm::vec3( 0.0f, -1.0f, 0.0f), glm::vec3(0.0f, 0.0f, -1.0f)), glm::lookAt(glm::vec3(0.0f, 0.0f, 0.0f), glm::vec3( 0.0f, 0.0f, 1.0f), glm::vec3(0.0f, -1.0f, 0.0f)), glm::lookAt(glm::vec3(0.0f, 0.0f, 0.0f), glm::vec3( 0.0f, 0.0f, -1.0f), glm::vec3(0.0f, -1.0f, 0.0f)) }; // pbr: convert HDR equirectangular environment map to cubemap equivalent // ---------------------------------------------------------------------- equirectangularToCubemapShader.use(); equirectangularToCubemapShader.setInt("equirectangularMap", 0); equirectangularToCubemapShader.setMat4("projection", captureProjection); glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, hdrTexture); glViewport(0, 0, 512, 512); // don't forget to configure the viewport to the capture dimensions. glBindFramebuffer(GL_FRAMEBUFFER, captureFBO); for (unsigned int i = 0; i < 6; ++i) { equirectangularToCubemapShader.setMat4("view", captureViews[i]); glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, envCubemap, 0); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); renderCube(); } glBindFramebuffer(GL_FRAMEBUFFER, 0); // then let OpenGL generate mipmaps from first mip face (combatting visible dots artifact) glBindTexture(GL_TEXTURE_CUBE_MAP, envCubemap); glGenerateMipmap(GL_TEXTURE_CUBE_MAP); // pbr: create an irradiance cubemap, and re-scale capture FBO to irradiance scale. // -------------------------------------------------------------------------------- unsigned int irradianceMap; glGenTextures(1, &irradianceMap); glBindTexture(GL_TEXTURE_CUBE_MAP, irradianceMap); for (unsigned int i = 0; i < 6; ++i) { glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, GL_RGB16F, 32, 32, 0, GL_RGB, GL_FLOAT, nullptr); } glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glBindFramebuffer(GL_FRAMEBUFFER, captureFBO); glBindRenderbuffer(GL_RENDERBUFFER, captureRBO); glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT24, 32, 32); // pbr: solve diffuse integral by convolution to create an irradiance (cube)map. // ----------------------------------------------------------------------------- irradianceShader.use(); irradianceShader.setInt("environmentMap", 0); irradianceShader.setMat4("projection", captureProjection); glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_CUBE_MAP, envCubemap); glViewport(0, 0, 32, 32); // don't forget to configure the viewport to the capture dimensions. glBindFramebuffer(GL_FRAMEBUFFER, captureFBO); for (unsigned int i = 0; i < 6; ++i) { irradianceShader.setMat4("view", captureViews[i]); glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, irradianceMap, 0); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); renderCube(); } glBindFramebuffer(GL_FRAMEBUFFER, 0); // pbr: create a pre-filter cubemap, and re-scale capture FBO to pre-filter scale. // -------------------------------------------------------------------------------- unsigned int prefilterMap; glGenTextures(1, &prefilterMap); glBindTexture(GL_TEXTURE_CUBE_MAP, prefilterMap); for (unsigned int i = 0; i < 6; ++i) { glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, GL_RGB16F, 128, 128, 0, GL_RGB, GL_FLOAT, nullptr); } glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); // be sure to set minifcation filter to mip_linear glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_LINEAR); // generate mipmaps for the cubemap so OpenGL automatically allocates the required memory. glGenerateMipmap(GL_TEXTURE_CUBE_MAP); // pbr: run a quasi monte-carlo simulation on the environment lighting to create a prefilter (cube)map. // ---------------------------------------------------------------------------------------------------- prefilterShader.use(); prefilterShader.setInt("environmentMap", 0); prefilterShader.setMat4("projection", captureProjection); glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_CUBE_MAP, envCubemap); glBindFramebuffer(GL_FRAMEBUFFER, captureFBO); unsigned int maxMipLevels = 5; for (unsigned int mip = 0; mip < maxMipLevels; ++mip) { // reisze framebuffer according to mip-level size. unsigned int mipWidth = 128 * std::pow(0.5, mip); unsigned int mipHeight = 128 * std::pow(0.5, mip); glBindRenderbuffer(GL_RENDERBUFFER, captureRBO); glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT24, mipWidth, mipHeight); glViewport(0, 0, mipWidth, mipHeight); float roughness = (float)mip / (float)(maxMipLevels - 1); prefilterShader.setFloat("roughness", roughness); for (unsigned int i = 0; i < 6; ++i) { prefilterShader.setMat4("view", captureViews[i]); glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, prefilterMap, mip); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); renderCube(); } } glBindFramebuffer(GL_FRAMEBUFFER, 0); // pbr: generate a 2D LUT from the BRDF equations used. // ---------------------------------------------------- unsigned int brdfLUTTexture; glGenTextures(1, &brdfLUTTexture); // pre-allocate enough memory for the LUT texture. glBindTexture(GL_TEXTURE_2D, brdfLUTTexture); glTexImage2D(GL_TEXTURE_2D, 0, GL_RG16F, 512, 512, 0, GL_RG, GL_FLOAT, 0); // be sure to set wrapping mode to GL_CLAMP_TO_EDGE glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); // then re-configure capture framebuffer object and render screen-space quad with BRDF shader. glBindFramebuffer(GL_FRAMEBUFFER, captureFBO); glBindRenderbuffer(GL_RENDERBUFFER, captureRBO); glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT24, 512, 512); glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, brdfLUTTexture, 0); glViewport(0, 0, 512, 512); brdfShader.use(); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); renderQuad(); glBindFramebuffer(GL_FRAMEBUFFER, 0); // initialize static shader uniforms before rendering // -------------------------------------------------- glm::mat4 projection = glm::perspective(camera.Zoom, (float)SCR_WIDTH / (float)SCR_HEIGHT, 0.1f, 100.0f); pbrShader.use(); pbrShader.setMat4("projection", projection); backgroundShader.use(); backgroundShader.setMat4("projection", projection); // then before rendering, configure the viewport to the original framebuffer's screen dimensions int scrWidth, scrHeight; glfwGetFramebufferSize(window, &scrWidth, &scrHeight); glViewport(0, 0, scrWidth, scrHeight); // render loop // ----------- while (!glfwWindowShouldClose(window)) { // per-frame time logic // -------------------- float currentFrame = glfwGetTime(); deltaTime = currentFrame - lastFrame; lastFrame = currentFrame; // input // ----- processInput(window); // render // ------ glClearColor(0.2f, 0.3f, 0.3f, 1.0f); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // render scene, supplying the convoluted irradiance map to the final shader. // ------------------------------------------------------------------------------------------ pbrShader.use(); glm::mat4 model; glm::mat4 view = camera.GetViewMatrix(); pbrShader.setMat4("view", view); pbrShader.setVec3("camPos", camera.Position); // bind pre-computed IBL data glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_CUBE_MAP, irradianceMap); glActiveTexture(GL_TEXTURE1); glBindTexture(GL_TEXTURE_CUBE_MAP, prefilterMap); glActiveTexture(GL_TEXTURE2); glBindTexture(GL_TEXTURE_2D, brdfLUTTexture); // rusted iron glActiveTexture(GL_TEXTURE3); glBindTexture(GL_TEXTURE_2D, ironAlbedoMap); glActiveTexture(GL_TEXTURE4); glBindTexture(GL_TEXTURE_2D, ironNormalMap); glActiveTexture(GL_TEXTURE5); glBindTexture(GL_TEXTURE_2D, ironMetallicMap); glActiveTexture(GL_TEXTURE6); glBindTexture(GL_TEXTURE_2D, ironRoughnessMap); glActiveTexture(GL_TEXTURE7); glBindTexture(GL_TEXTURE_2D, ironAOMap); model = glm::mat4(); model = glm::translate(model, glm::vec3(-5.0, 0.0, 2.0)); pbrShader.setMat4("model", model); renderSphere(); // gold glActiveTexture(GL_TEXTURE3); glBindTexture(GL_TEXTURE_2D, goldAlbedoMap); glActiveTexture(GL_TEXTURE4); glBindTexture(GL_TEXTURE_2D, goldNormalMap); glActiveTexture(GL_TEXTURE5); glBindTexture(GL_TEXTURE_2D, goldMetallicMap); glActiveTexture(GL_TEXTURE6); glBindTexture(GL_TEXTURE_2D, goldRoughnessMap); glActiveTexture(GL_TEXTURE7); glBindTexture(GL_TEXTURE_2D, goldAOMap); model = glm::mat4(); model = glm::translate(model, glm::vec3(-3.0, 0.0, 2.0)); pbrShader.setMat4("model", model); renderSphere(); // grass glActiveTexture(GL_TEXTURE3); glBindTexture(GL_TEXTURE_2D, grassAlbedoMap); glActiveTexture(GL_TEXTURE4); glBindTexture(GL_TEXTURE_2D, grassNormalMap); glActiveTexture(GL_TEXTURE5); glBindTexture(GL_TEXTURE_2D, grassMetallicMap); glActiveTexture(GL_TEXTURE6); glBindTexture(GL_TEXTURE_2D, grassRoughnessMap); glActiveTexture(GL_TEXTURE7); glBindTexture(GL_TEXTURE_2D, grassAOMap); model = glm::mat4(); model = glm::translate(model, glm::vec3(-1.0, 0.0, 2.0)); pbrShader.setMat4("model", model); renderSphere(); // plastic glActiveTexture(GL_TEXTURE3); glBindTexture(GL_TEXTURE_2D, plasticAlbedoMap); glActiveTexture(GL_TEXTURE4); glBindTexture(GL_TEXTURE_2D, plasticNormalMap); glActiveTexture(GL_TEXTURE5); glBindTexture(GL_TEXTURE_2D, plasticMetallicMap); glActiveTexture(GL_TEXTURE6); glBindTexture(GL_TEXTURE_2D, plasticRoughnessMap); glActiveTexture(GL_TEXTURE7); glBindTexture(GL_TEXTURE_2D, plasticAOMap); model = glm::mat4(); model = glm::translate(model, glm::vec3(1.0, 0.0, 2.0)); pbrShader.setMat4("model", model); renderSphere(); // wall glActiveTexture(GL_TEXTURE3); glBindTexture(GL_TEXTURE_2D, wallAlbedoMap); glActiveTexture(GL_TEXTURE4); glBindTexture(GL_TEXTURE_2D, wallNormalMap); glActiveTexture(GL_TEXTURE5); glBindTexture(GL_TEXTURE_2D, wallMetallicMap); glActiveTexture(GL_TEXTURE6); glBindTexture(GL_TEXTURE_2D, wallRoughnessMap); glActiveTexture(GL_TEXTURE7); glBindTexture(GL_TEXTURE_2D, wallAOMap); model = glm::mat4(); model = glm::translate(model, glm::vec3(3.0, 0.0, 2.0)); pbrShader.setMat4("model", model); renderSphere(); // render light source (simply re-render sphere at light positions) // this looks a bit off as we use the same shader, but it'll make their positions obvious and // keeps the codeprint small. for (unsigned int i = 0; i < sizeof(lightPositions) / sizeof(lightPositions[0]); ++i) { glm::vec3 newPos = lightPositions[i] + glm::vec3(sin(glfwGetTime() * 5.0) * 5.0, 0.0, 0.0); newPos = lightPositions[i]; pbrShader.setVec3("lightPositions[" + std::to_string(i) + "]", newPos); pbrShader.setVec3("lightColors[" + std::to_string(i) + "]", lightColors[i]); model = glm::mat4(); model = glm::translate(model, newPos); model = glm::scale(model, glm::vec3(0.5f)); pbrShader.setMat4("model", model); renderSphere(); } // render skybox (render as last to prevent overdraw) backgroundShader.use(); backgroundShader.setMat4("view", view); glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_CUBE_MAP, envCubemap); //glBindTexture(GL_TEXTURE_CUBE_MAP, irradianceMap); // display irradiance map //glBindTexture(GL_TEXTURE_CUBE_MAP, prefilterMap); // display prefilter map renderCube(); // render BRDF map to screen //brdfShader.Use(); //renderQuad(); // glfw: swap buffers and poll IO events (keys pressed/released, mouse moved etc.) // ------------------------------------------------------------------------------- glfwSwapBuffers(window); glfwPollEvents(); } // glfw: terminate, clearing all previously allocated GLFW resources. // ------------------------------------------------------------------ glfwTerminate(); return 0; }
int main() { // glfw: initialize and configure // ------------------------------ glfwInit(); glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3); glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3); glfwWindowHint(GLFW_SAMPLES, 4); glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); //glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE); // uncomment this statement to fix compilation on OS X // glfw window creation // -------------------- GLFWwindow* window = glfwCreateWindow(SCR_WIDTH, SCR_HEIGHT, "LearnOpenGL", NULL, NULL); glfwMakeContextCurrent(window); if (window == NULL) { std::cout << "Failed to create GLFW window" << std::endl; glfwTerminate(); return -1; } glfwSetFramebufferSizeCallback(window, framebuffer_size_callback); glfwSetCursorPosCallback(window, mouse_callback); glfwSetScrollCallback(window, scroll_callback); // tell GLFW to capture our mouse glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_DISABLED); // glad: load all OpenGL function pointers // --------------------------------------- if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress)) { std::cout << "Failed to initialize GLAD" << std::endl; return -1; } // configure global opengl state // ----------------------------- glEnable(GL_DEPTH_TEST); // build and compile shaders // ------------------------- Shader shader("1.1.pbr.vs", "1.1.pbr.fs"); shader.use(); shader.setVec3("albedo", 0.5f, 0.0f, 0.0f); shader.setFloat("ao", 1.0f); // lights // ------ glm::vec3 lightPositions[] = { glm::vec3(-10.0f, 10.0f, 10.0f), glm::vec3( 10.0f, 10.0f, 10.0f), glm::vec3(-10.0f, -10.0f, 10.0f), glm::vec3( 10.0f, -10.0f, 10.0f), }; glm::vec3 lightColors[] = { glm::vec3(300.0f, 300.0f, 300.0f), glm::vec3(300.0f, 300.0f, 300.0f), glm::vec3(300.0f, 300.0f, 300.0f), glm::vec3(300.0f, 300.0f, 300.0f) }; int nrRows = 7; int nrColumns = 7; float spacing = 2.5; // initialize static shader uniforms before rendering // -------------------------------------------------- glm::mat4 projection = glm::perspective(camera.Zoom, (float)SCR_WIDTH / (float)SCR_HEIGHT, 0.1f, 100.0f); shader.use(); shader.setMat4("projection", projection); // render loop // ----------- while (!glfwWindowShouldClose(window)) { // per-frame time logic // -------------------- float currentFrame = glfwGetTime(); deltaTime = currentFrame - lastFrame; lastFrame = currentFrame; // input // ----- processInput(window); // render // ------ glClearColor(0.1f, 0.1f, 0.1f, 1.0f); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); shader.use(); glm::mat4 view = camera.GetViewMatrix(); shader.setMat4("view", view); shader.setVec3("camPos", camera.Position); // render rows*column number of spheres with varying metallic/roughness values scaled by rows and columns respectively glm::mat4 model; for (unsigned int row = 0; row < nrRows; ++row) { shader.setFloat("metallic", (float)row / (float)nrRows); for (unsigned int col = 0; col < nrColumns; ++col) { // we clamp the roughness to 0.025 - 1.0 as perfectly smooth surfaces (roughness of 0.0) tend to look a bit off // on direct lighting. shader.setFloat("roughness", glm::clamp((float)col / (float)nrColumns, 0.05f, 1.0f)); model = glm::mat4(); model = glm::translate(model, glm::vec3( (float)(col - (nrColumns / 2)) * spacing, (float)(row - (nrRows / 2)) * spacing, 0.0f )); shader.setMat4("model", model); renderSphere(); } } // render light source (simply re-render sphere at light positions) // this looks a bit off as we use the same shader, but it'll make their positions obvious and // keeps the codeprint small. for (unsigned int i = 0; i < sizeof(lightPositions) / sizeof(lightPositions[0]); ++i) { glm::vec3 newPos = lightPositions[i] + glm::vec3(sin(glfwGetTime() * 5.0) * 5.0, 0.0, 0.0); newPos = lightPositions[i]; shader.setVec3("lightPositions[" + std::to_string(i) + "]", newPos); shader.setVec3("lightColors[" + std::to_string(i) + "]", lightColors[i]); model = glm::mat4(); model = glm::translate(model, newPos); model = glm::scale(model, glm::vec3(0.5f)); shader.setMat4("model", model); renderSphere(); } // glfw: swap buffers and poll IO events (keys pressed/released, mouse moved etc.) // ------------------------------------------------------------------------------- glfwSwapBuffers(window); glfwPollEvents(); } // glfw: terminate, clearing all previously allocated GLFW resources. // ------------------------------------------------------------------ glfwTerminate(); return 0; }
/////////////////////////////////////////////////////////////////////////////// // runOne: Run a single test case /////////////////////////////////////////////////////////////////////////////// void TexgenTest::runOne(BasicResult& r, Window&) { // Temporary buffer to store pixels we've read back for verification. GLfloat pixels[50*50*3]; // Colors for matching against when we readback pixels. GLfloat matchBlue[3] = {0,0,1}; GLfloat matchRed[3] = {1,0,0}; // A sphere to draw. Sphere3D theSphere(9.9, 32, 16); // A GeomRenderer to draw it with. GeomRenderer sphereRenderer; sphereRenderer.setDrawMethod(GeomRenderer::GLVERTEX_MODE); sphereRenderer.setParameterBits(GeomRenderer::NORMAL_BIT); sphereRenderer.setVArrayIndices(theSphere.getNumIndices(),GL_UNSIGNED_INT,theSphere.getIndices()); sphereRenderer.setVertexPointer(theSphere.getNumVertices(), 3, GL_FLOAT, 0, theSphere.getVertices()); sphereRenderer.setNormalPointer(GL_FLOAT, 0, theSphere.getNormals()); // draw the sphere in a 50x50 pixel window for some precision. glViewport(0, 0, 50, 50); // Basic GL setup. glDisable(GL_DITHER); glEnable(GL_CULL_FACE); glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); glColor3f(1,1,1); // Setup the projection. glMatrixMode(GL_PROJECTION); glLoadIdentity(); glOrtho(-10,10,-10,10,-10,10); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); // Set up our texture. glEnable(GL_TEXTURE_2D); GLuint checkerTextureHandle; glGenTextures(1, &checkerTextureHandle); glBindTexture(GL_TEXTURE_2D, checkerTextureHandle); glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); glEnable(GL_TEXTURE_GEN_S); glEnable(GL_TEXTURE_GEN_T); // Make a little checker texture. unsigned char redBlueCheck[256*256*3]; for (int x=0; x<256; x++) { for (int y=0; y<256; y++) { bool xPastHalf = x >= 128; bool yPastHalf = y >= 128; redBlueCheck[(x+(256*y))*3 + 0] = ((xPastHalf && yPastHalf) || (!xPastHalf && !yPastHalf)) ? 255 : 0; redBlueCheck[(x+(256*y))*3 + 1] = 0; redBlueCheck[(x+(256*y))*3 + 2] = ((xPastHalf && !yPastHalf) || (!xPastHalf && yPastHalf)) ? 255 : 0; } } gluBuild2DMipmaps(GL_TEXTURE_2D, GL_RGB, 256, 256, GL_RGB, GL_UNSIGNED_BYTE, redBlueCheck); // Setup our arrays of configuration info; we loop over the rendering pass a number of times, // using a different GL primitive path each time. GeomRenderer::DrawMethod drawMethods[] = {GeomRenderer::GLVERTEX_MODE, GeomRenderer::GLARRAYELEMENT_MODE, GeomRenderer::GLDRAWELEMENTS_MODE, GeomRenderer::GLARRAYELEMENT_MODE, GeomRenderer::GLDRAWELEMENTS_MODE}; bool arraysCompiled[] = {false, false, false, true, true}; // Iterate once for all immediate mode styles, then once for retained mode styles. for (int retainedMode=0; retainedMode<2; retainedMode++) { for (int testIteration=0; testIteration<5; testIteration++) { sphereRenderer.setDrawMethod(drawMethods[testIteration]); if (!sphereRenderer.setArraysCompiled(arraysCompiled[testIteration])) { // We don't have the extension... not sure what we should do. // May as well just keep going, it's no big deal (it should still // yield correct results, of course, it's just redundant). } // GL_SPHERE_MAP: with spheremap, the UL corner is blue glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_SPHERE_MAP); glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_SPHERE_MAP); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); renderSphere(retainedMode, sphereRenderer); glReadPixels(0,0,50,50, GL_RGB, GL_FLOAT, pixels); // Validate it. std::string sphereMapResult; if (!verifyCheckers(pixels, matchBlue, matchRed, sphereMapResult)) { FailMessage(r, std::string("GL_SPHERE_MAP"), drawMethods[testIteration], arraysCompiled[testIteration], retainedMode, sphereMapResult); r.pass = false; glDeleteTextures(1, &checkerTextureHandle); return; } // GL_OBJECT_LINEAR: with object linear and the below planes, the UL corner is red. glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR); glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR); float sObjPlane[4] = {0,0.05,0,1.5}; // We flip the checker by setting W to 1.5 (phases by half a period) float tObjPlane[4] = {0.05,0,0,1}; glTexGenfv(GL_S, GL_OBJECT_PLANE, sObjPlane); glTexGenfv(GL_T, GL_OBJECT_PLANE, tObjPlane); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); renderSphere(retainedMode, sphereRenderer); glReadPixels(0,0,50,50, GL_RGB, GL_FLOAT, pixels); // Validate it. std::string objectLinearResult; if (!verifyCheckers(pixels, matchRed, matchBlue, objectLinearResult)) { FailMessage(r, std::string("GL_OBJECT_LINEAR"), drawMethods[testIteration], arraysCompiled[testIteration], retainedMode, objectLinearResult); r.pass = false; glDeleteTextures(1, &checkerTextureHandle); return; } // GL_EYE_LINEAR: with eye linear and the below planes, the UL corner is blue. glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR); glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR); float sEyePlane[4] = {0,0.05,0,1}; float tEyePlane[4] = {0.05,0,0,1}; glTexGenfv(GL_S, GL_EYE_PLANE, sEyePlane); glTexGenfv(GL_T, GL_EYE_PLANE, tEyePlane); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); renderSphere(retainedMode, sphereRenderer); glReadPixels(0,0,50,50, GL_RGB, GL_FLOAT, pixels); // Validate it. std::string eyeLinearResult; if (!verifyCheckers(pixels, matchBlue, matchRed, eyeLinearResult)) { FailMessage(r, std::string("GL_EYE_LINEAR"), drawMethods[testIteration], arraysCompiled[testIteration], retainedMode, eyeLinearResult); r.pass = false; glDeleteTextures(1, &checkerTextureHandle); return; } } } // success r.pass = true; } // TexgenTest::runOne