void DBTexture::loadFromFile(const eastl::string& a_filePath, EFormat a_format, uint a_forcedNumComp) { int w, h, c; byte* textureData = NULL; switch (a_format) { case EFormat::BYTE: textureData = stbi_load(a_filePath.c_str(), &w, &h, &c, a_forcedNumComp); break; case EFormat::FLOAT: textureData = rcast<byte*>(stbi_loadf(a_filePath.c_str(), &w, &h, &c, a_forcedNumComp)); break; default: assert(false); break; } if (!textureData) { print("FAILED TO LOAD IMAGE: %s \n", a_filePath.c_str()); assert(false); return; } m_format = a_format; m_pixColSize = getPixColSize(m_format); m_width = uint(w); m_height = uint(h); m_numComp = a_forcedNumComp ? a_forcedNumComp : uint(c); // If a number of components was forced, use that, otherwise use the number of components in the image. const uint dataSize = m_width * m_height * m_numComp * m_pixColSize; m_rawData.resize(dataSize); memcpy(m_rawData.data(), textureData, dataSize); stbi_image_free(textureData); m_compressedDataUpToDate = false; }
int main(int argc, char** argv) { if (argc < 2) { std::cerr << "Use " << argv[0] << " filename" << std::endl; return 1; } // load image int width, height, nc; float* rgba = stbi_loadf(argv[1], &width, &height, &nc, 4); if (stbi_failure_reason()) { std::cerr << "stbi: " << stbi_failure_reason() << std::endl; return 1; } // create summed area table of luminance image summed_area_table lum_sat; lum_sat.create_lum(rgba, width, height, 4); // apply median cut std::vector<sat_region> regions; median_cut(lum_sat, 9, regions); // max 2^n cuts // create 2d positions from regions std::vector<float2> lights; create_lights(regions, lights); // draw a marker into image for each position size_t i = 0; for (auto l = lights.begin(); l != lights.end(); ++l) { std::cout << "Light " << i++ << ": (" << l->x << ", " << l->y << ")" << std::endl; draw(rgba, width, height, *l); } // save image with marked samples std::vector<unsigned char> conv; conv.resize(width*height*4); for (size_t i = 0; i < width * height * 4; ++i) conv[i] = static_cast<unsigned char>(rgba[i]*255); stbi_write_bmp("test.bmp", width, height, 4, &conv[0]); return 0; }
cudaTextureObject_t create_environment_light_texture(const std::string& filename) { int w = 0, h = 0, n = 0; float* data = stbi_loadf(filename.c_str(), &w, &h, &n, 0); if(!data) { std::cerr<<"Unable to load environment map: "<<filename<<std::endl; exit(0); } //create channel desc cudaChannelFormatDesc channelDesc = cudaCreateChannelDesc<float4>(); //create cudaArray cudaArray* array; checkCudaErrors(cudaMallocArray(&array, &channelDesc, w, h)); if(n == 3) { uint32_t count = w * h; std::vector<float4> ext_data; ext_data.reserve(count); for(auto i = 0; i < count; ++i) ext_data.push_back(make_float4(data[i * 3], data[i * 3 + 1], data[i * 3 + 2], 0.f)); checkCudaErrors(cudaMemcpyToArray(array, 0, 0, ext_data.data(), sizeof(float4) * w * h, cudaMemcpyHostToDevice)); } else checkCudaErrors(cudaMemcpyToArray(array, 0, 0, data, sizeof(float4) * w * h, cudaMemcpyHostToDevice)); //create resource desc cudaResourceDesc resDesc; memset(&resDesc, 0, sizeof(resDesc)); resDesc.resType = cudaResourceTypeArray; resDesc.res.array.array = array; //create texture desc cudaTextureDesc texDesc; memset(&texDesc, 0, sizeof(texDesc)); texDesc.addressMode[0] = cudaAddressModeWrap; texDesc.addressMode[1] = cudaAddressModeWrap; texDesc.filterMode = cudaFilterModeLinear; texDesc.readMode = cudaReadModeElementType; texDesc.normalizedCoords = true; //create cudaTextureObject cudaTextureObject_t tex; checkCudaErrors(cudaCreateTextureObject(&tex, &resDesc, &texDesc, NULL)); return tex; }
void Image::load(std::string const& path, float gamma) { int num_components; stbi_ldr_to_hdr_gamma(gamma); float *data = stbi_loadf(path.c_str(), &m_width, &m_height, &num_components, 4); if(!data) { std::cerr << "error: could not load image \"" << path << "\"" << std::endl; return; } m_pixels.resize(m_width * m_height); /* flip image in Y */ for(int y = 0; y < m_height; y++) { memcpy(&m_pixels[(m_height - y - 1) * m_width], data + y * m_width * 4, 4 * m_width * sizeof(float)); } stbi_image_free(data); }
int load_images(const char** img_filenames, view_img** imgs) { int nimgs = 0; for (const char** f = img_filenames; *f; f++) nimgs++; assert(nimgs > 0); *imgs = (view_img*)calloc(nimgs, sizeof(view_img)); for (int i = 0; i < nimgs; i++) { view_img* img = *imgs + i; img->filename = img_filenames[i]; img->pixels = stbi_loadf(img->filename, &img->w, &img->h, &img->nc, 0); if (!img->pixels) { printf("cannot load image %s\n", img->filename); exit(1); } img->tex_glid = 0; } return nimgs; }
HDRImage loadHDRImage(const std::string& filename, int convertToChannels) { int width=0,height=0,channels=0; auto pixels = stbi_loadf(filename.c_str(), &width,&height,&channels, convertToChannels); if(!pixels) { throw std::runtime_error(std::string("HDRImage load error: \nFile")+filename+"\nReason:"+stbi_failure_reason()); } std::array<std::size_t ,3> arr= {{(std::size_t)channels,(std::size_t)width,(std::size_t)height}}; return HDRImage(std::shared_ptr<float>(pixels,StbiDeleter<float>()), arr // {{(std::size_t)channels,(std::size_t)width,(std::size_t)height} } );// }
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); // 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 stb_to_srv(ID3D11Device* device, LPCSTR filename, ID3D11ShaderResourceView** srv) { if (!srv) throw exception(L"No SRV"); *srv = nullptr; bool is_hdr = std::string(filename).find(".hdr") != std::string::npos; bool is_jpg = std::string(filename).find(".jpg") != std::string::npos; D3D11_TEXTURE2D_DESC tex_desc; ZeroMemory(&tex_desc, sizeof(tex_desc)); D3D11_SUBRESOURCE_DATA subdata; ZeroMemory(&subdata, sizeof(subdata)); int width, height, nc; unsigned char* ldr_data = nullptr; float* hdr_data = nullptr; if (!is_hdr) { ldr_data = stbi_load(filename, &width, &height, &nc, 4); subdata.SysMemPitch = width * 4; subdata.pSysMem = ldr_data; if (is_jpg) tex_desc.Format = DXGI_FORMAT_R8G8B8A8_UNORM_SRGB; else // TODO: Remap to SRGB later when throwing out D3DX tex_desc.Format = DXGI_FORMAT_R8G8B8A8_UNORM; // TODO: Need to create mipmaps } else { hdr_data = stbi_loadf(filename, &width, &height, &nc, 4); subdata.SysMemPitch = width * 4 * 4; subdata.pSysMem = hdr_data; tex_desc.Format = DXGI_FORMAT_R32G32B32A32_FLOAT; } if (!ldr_data && !hdr_data) { tstring error = L"can't load"; if (stbi_failure_reason()) error = to_tstring(std::string(stbi_failure_reason())); throw exception(tstring(L"stbi: ") + error); } tex_desc.Width = width; tex_desc.Height = height; tex_desc.MipLevels = 1; tex_desc.ArraySize = 1; tex_desc.SampleDesc.Count = 1; tex_desc.SampleDesc.Quality = 0; tex_desc.Usage = D3D11_USAGE_DEFAULT; tex_desc.BindFlags = D3D11_BIND_SHADER_RESOURCE; tex_desc.CPUAccessFlags = 0; tex_desc.MiscFlags = 0; ID3D11Texture2D* texture; assert_hr(device->CreateTexture2D(&tex_desc, &subdata, &texture)); assert_hr(device->CreateShaderResourceView(texture, nullptr, srv)); safe_release(texture); if (is_hdr) stbi_image_free(hdr_data); else stbi_image_free(ldr_data); }