void FrameBufferObject::Begin(GraphicsState & glstate, std::ostream & error_output, float viewscale) { CheckForOpenGLErrors("before FBO begin", error_output); assert(inited); assert(framebuffer_object > 0); assert(!textures.empty()); glstate.BindFramebuffer(GL_FRAMEBUFFER, framebuffer_object); CheckForOpenGLErrors("FBO bind to framebuffer", error_output); FrameBufferTexture * tex = textures.back(); if (tex->GetTarget() == FrameBufferTexture::CUBEMAP) { glFramebufferTexture2D(GL_FRAMEBUFFER, tex->GetAttachment(), tex->GetSide(), tex->GetId(), 0); CheckForOpenGLErrors("FBO cubemap side attachment", error_output); } assert(CheckStatus(error_output)); glstate.SetViewport(int(tex->GetW() * viewscale), int(tex->GetH() * viewscale)); CheckForOpenGLErrors("during FBO begin", error_output); }
void RenderInputScene::Render(GraphicsState & glstate, std::ostream & error_output) { assert(shader && "RenderInputScene::Render No shader set."); glstate.SetColor(1,1,1,1); glMatrixMode(GL_PROJECTION); glLoadMatrixf(projMatrix.GetArray()); glMatrixMode(GL_MODELVIEW); glLoadMatrixf(viewMatrix.GetArray()); Quat cam_look; cam_look.Rotate(M_PI_2, 1, 0, 0); cam_look.Rotate(-M_PI_2, 0, 0, 1); Quat cube_rotation; cube_rotation = (-cam_look) * (-cam_rotation); // experimentally derived float cube_matrix[9]; cube_rotation.GetMatrix3(cube_matrix); Vec3 lightvec = lightposition; (cam_rotation).RotateVector(lightvec); shader->Enable(); shader->SetUniform3f(Uniforms::LightDirection, lightvec[0], lightvec[1], lightvec[2]); shader->SetUniform1f(Uniforms::Contrast, contrast); shader->SetUniformMat3f(Uniforms::ReflectionMatrix, cube_matrix); last_transform_valid = false; Draw(glstate, *dynamic_drawlist_ptr, false); Draw(glstate, *static_drawlist_ptr, true); }
Camera *MakeCamera(const std::string &name, const ParamSet ¶mSet, const TransformSet &cam2worldSet, Float transformStart, Float transformEnd, Film *film) { Camera *camera = nullptr; MediumInterface mediumInterface = graphicsState.CreateMediumInterface(); Assert(MaxTransforms == 2); Transform *cam2world[2]; transformCache.Lookup(cam2worldSet[0], &cam2world[0], nullptr); transformCache.Lookup(cam2worldSet[1], &cam2world[1], nullptr); AnimatedTransform animatedCam2World(cam2world[0], transformStart, cam2world[1], transformEnd); if (name == "perspective") camera = CreatePerspectiveCamera(paramSet, animatedCam2World, film, mediumInterface.outside); else if (name == "orthographic") camera = CreateOrthographicCamera(paramSet, animatedCam2World, film, mediumInterface.outside); else if (name == "realistic") camera = CreateRealisticCamera(paramSet, animatedCam2World, film, mediumInterface.outside); else if (name == "environment") camera = CreateEnvironmentCamera(paramSet, animatedCam2World, film, mediumInterface.outside); else Warning("Camera \"%s\" unknown.", name.c_str()); paramSet.ReportUnused(); return camera; }
void FrameBufferObject::End(GraphicsState & glstate, std::ostream & error_output) { CheckForOpenGLErrors("start of FBO end", error_output); if (singlesample_framebuffer_object) { glstate.BindFramebuffer(GL_READ_FRAMEBUFFER, framebuffer_object); glstate.BindFramebuffer(GL_DRAW_FRAMEBUFFER, singlesample_framebuffer_object->framebuffer_object); assert(glCheckFramebufferStatus(GL_READ_FRAMEBUFFER) == GL_FRAMEBUFFER_COMPLETE); assert(glCheckFramebufferStatus(GL_DRAW_FRAMEBUFFER) == GL_FRAMEBUFFER_COMPLETE); CheckForOpenGLErrors("FBO end multisample binding", error_output); const int w = singlesample_framebuffer_object->GetWidth(); const int h = singlesample_framebuffer_object->GetHeight(); glBlitFramebuffer(0, 0, w, h, 0, 0, w, h, GL_COLOR_BUFFER_BIT, GL_NEAREST); CheckForOpenGLErrors("FBO end multisample blit", error_output); } CheckForOpenGLErrors("FBO multisample blit", error_output); // optionally rebuild mipmaps for (std::vector <FrameBufferTexture*>::const_iterator i = textures.begin(); i != textures.end(); i++) { if ((*i)->HasMipMap()) { glstate.BindTexture(0, (*i)->GetTarget(), (*i)->GetId()); glGenerateMipmap((*i)->GetTarget()); glstate.BindTexture(0, (*i)->GetTarget(), 0); } } CheckForOpenGLErrors("end of FBO end", error_output); }
void RenderInputScene::SetTextures( GraphicsState & glstate, const std::vector <TextureInterface*> & textures, std::ostream & error_output) { for (unsigned i = 0; i < textures.size(); i++) { if (textures[i]) { glstate.BindTexture(i, textures[i]->GetTarget(), textures[i]->GetId()); if (CheckForOpenGLErrors("RenderDrawlists extra texture bind", error_output)) { error_output << "this error occurred while binding texture " << i << " id=" << textures[i]->GetId() << std::endl; } } } }
void RenderInputScene::SetFlags(const Drawable & d, GraphicsState & glstate) { glstate.DepthOffset(d.GetDecal()); if (d.GetCull()) { glstate.CullFace(true); if (d.GetCullFront()) glstate.CullFaceMode(GL_FRONT); else glstate.CullFaceMode(GL_BACK); } else { glstate.CullFace(false); } const Vec4 & color = d.GetColor(); glstate.SetColor(color[0], color[1], color[2], color[3]); }
void RenderInputScene::SetBlendMode(GraphicsState & glstate, BlendMode::Enum mode) { switch (mode) { case BlendMode::DISABLED: { glstate.Blend(false); } break; case BlendMode::ADD: { glstate.Blend(true); glstate.BlendFunc(GL_SRC_ALPHA, GL_ONE); } break; case BlendMode::ALPHABLEND: { glstate.Blend(true); glstate.BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); } break; case BlendMode::PREMULTIPLIED_ALPHA: { glstate.Blend(true); glstate.BlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA); } break; default: assert(0); break; } }
void RenderInputPostprocess::Render(GraphicsState & glstate, std::ostream & error_output) { assert(shader); CheckForOpenGLErrors("postprocess begin", error_output); glstate.SetColorMask(writecolor, writealpha); glstate.SetDepthMask(writedepth); if (clearcolor && cleardepth) glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); else if (clearcolor) glClear(GL_COLOR_BUFFER_BIT); else if (cleardepth) glClear(GL_DEPTH_BUFFER_BIT); shader->Enable(); CheckForOpenGLErrors("postprocess shader enable", error_output); Mat4 projMatrix, viewMatrix; projMatrix.SetOrthographic(0, 1, 0, 1, -1, 1); viewMatrix.LoadIdentity(); glMatrixMode(GL_PROJECTION); glLoadMatrixf(projMatrix.GetArray()); glMatrixMode(GL_MODELVIEW); glLoadMatrixf(viewMatrix.GetArray()); glstate.SetColor(1,1,1,1); SetBlendMode(glstate); if (writedepth || depth_mode != GL_ALWAYS) glstate.Enable(GL_DEPTH_TEST); else glstate.Disable(GL_DEPTH_TEST); glDepthFunc( depth_mode ); glstate.Enable(GL_TEXTURE_2D); glActiveTexture(GL_TEXTURE0); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE, GL_NONE); glTexParameteri(GL_TEXTURE_2D, GL_DEPTH_TEXTURE_MODE, GL_LUMINANCE); CheckForOpenGLErrors("postprocess flag set", error_output); float maxu = 1.f; float maxv = 1.f; int num_nonnull = 0; for (unsigned int i = 0; i < source_textures.size(); i++) { //std::cout << i << ": " << source_textures[i] << std::endl; glActiveTexture(GL_TEXTURE0+i); if (source_textures[i]) { source_textures[i]->Activate(); num_nonnull++; if (source_textures[i]->IsRect()) { maxu = source_textures[i]->GetW(); maxv = source_textures[i]->GetH(); } } } if (source_textures.size() && !num_nonnull) { error_output << "Out of the " << source_textures.size() << " input textures provided as inputs to this postprocess stage, zero are available. This stage will have no effect." << std::endl; return; } glActiveTexture(GL_TEXTURE0); CheckForOpenGLErrors("postprocess texture set", error_output); // build the frustum corners float ratio = w/h; std::vector <Vec3 > frustum_corners(4); frustum_corners[0].Set(-lod_far,-lod_far,-lod_far); //BL frustum_corners[1].Set(lod_far,-lod_far,-lod_far); //BR frustum_corners[2].Set(lod_far,lod_far,-lod_far); //TR frustum_corners[3].Set(-lod_far,lod_far,-lod_far); //TL Mat4 inv_proj; inv_proj.InvPerspective(camfov, ratio, 0.1, lod_far); for (int i = 0; i < 4; i++) { inv_proj.TransformVectorOut(frustum_corners[i][0], frustum_corners[i][1], frustum_corners[i][2]); frustum_corners[i][2] = -lod_far; } // frustum corners in world space for dynamic sky shader std::vector <Vec3 > frustum_corners_w(4); Mat4 inv_view_rot; (-cam_rotation).GetMatrix4(inv_view_rot); for (int i = 0; i < 4; i++) { frustum_corners_w[i] = frustum_corners[i]; inv_view_rot.TransformVectorOut(frustum_corners_w[i][0], frustum_corners_w[i][1], frustum_corners_w[i][2]); } // send shader parameters { Vec3 lightvec = lightposition; cam_rotation.RotateVector(lightvec); shader->UploadActiveShaderParameter3f("directlight_eyespace_direction", lightvec); shader->UploadActiveShaderParameter1f("contrast", contrast); shader->UploadActiveShaderParameter1f("znear", 0.1); //std::cout << lightvec << std::endl; shader->UploadActiveShaderParameter3f("frustum_corner_bl", frustum_corners[0]); shader->UploadActiveShaderParameter3f("frustum_corner_br_delta", frustum_corners[1]-frustum_corners[0]); shader->UploadActiveShaderParameter3f("frustum_corner_tl_delta", frustum_corners[3]-frustum_corners[0]); } // draw a quad unsigned faces[2 * 3] = { 0, 1, 2, 2, 3, 0, }; float pos[4 * 3] = { 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, }; // send the UV corners in UV set 0 float tc0[4 * 2] = { 0.0f, 0.0f, maxu, 0.0f, maxu, maxv, 0.0f, maxv, }; // send the frustum corners in UV set 1 float tc1[4 * 3] = { frustum_corners[0][0], frustum_corners[0][1], frustum_corners[0][2], frustum_corners[1][0], frustum_corners[1][1], frustum_corners[1][2], frustum_corners[2][0], frustum_corners[2][1], frustum_corners[2][2], frustum_corners[3][0], frustum_corners[3][1], frustum_corners[3][2], }; // fructum corners in world space in uv set 2 float tc2[4 * 3] = { frustum_corners_w[0][0], frustum_corners_w[0][1], frustum_corners_w[0][2], frustum_corners_w[1][0], frustum_corners_w[1][1], frustum_corners_w[1][2], frustum_corners_w[2][0], frustum_corners_w[2][1], frustum_corners_w[2][2], frustum_corners_w[3][0], frustum_corners_w[3][1], frustum_corners_w[3][2], }; glEnableClientState(GL_VERTEX_ARRAY); glVertexPointer(3, GL_FLOAT, 0, pos); glClientActiveTexture(GL_TEXTURE0); glEnableClientState(GL_TEXTURE_COORD_ARRAY); glTexCoordPointer(2, GL_FLOAT, 0, tc0); glClientActiveTexture(GL_TEXTURE1); glEnableClientState(GL_TEXTURE_COORD_ARRAY); glTexCoordPointer(3, GL_FLOAT, 0, tc1); glClientActiveTexture(GL_TEXTURE2); glEnableClientState(GL_TEXTURE_COORD_ARRAY); glTexCoordPointer(3, GL_FLOAT, 0, tc2); glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, faces); glDisableClientState(GL_TEXTURE_COORD_ARRAY); glClientActiveTexture(GL_TEXTURE1); glDisableClientState(GL_TEXTURE_COORD_ARRAY); glClientActiveTexture(GL_TEXTURE0); glDisableClientState(GL_TEXTURE_COORD_ARRAY); glDisableClientState(GL_VERTEX_ARRAY); CheckForOpenGLErrors("postprocess draw", error_output); glstate.Enable(GL_DEPTH_TEST); glstate.Disable(GL_TEXTURE_2D); for (unsigned int i = 0; i < source_textures.size(); i++) { //std::cout << i << ": " << source_textures[i] << std::endl; glActiveTexture(GL_TEXTURE0+i); if (source_textures[i]) source_textures[i]->Deactivate(); } glActiveTexture(GL_TEXTURE0); CheckForOpenGLErrors("postprocess end", error_output); }
void RenderInputPostprocess::SetBlendMode(GraphicsState & glstate) { assert(blendmode != BlendMode::ALPHATEST); switch (blendmode) { case BlendMode::DISABLED: { glstate.Disable(GL_ALPHA_TEST); glstate.Disable(GL_BLEND); glstate.Disable(GL_SAMPLE_ALPHA_TO_COVERAGE); } break; case BlendMode::ADD: { glstate.Disable(GL_ALPHA_TEST); glstate.Enable(GL_BLEND); glstate.Disable(GL_SAMPLE_ALPHA_TO_COVERAGE); glstate.SetBlendFunc(GL_ONE, GL_ONE); } break; case BlendMode::ALPHABLEND: { glstate.Disable(GL_ALPHA_TEST); glstate.Enable(GL_BLEND); glstate.Disable(GL_SAMPLE_ALPHA_TO_COVERAGE); glstate.SetBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); } break; case BlendMode::PREMULTIPLIED_ALPHA: { glstate.Disable(GL_ALPHA_TEST); glstate.Enable(GL_BLEND); glstate.Disable(GL_SAMPLE_ALPHA_TO_COVERAGE); glstate.SetBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA); } break; default: assert(0); break; } }
void FrameBufferObject::Init( GraphicsState & glstate, const std::vector <FrameBufferTexture*> & newtextures, std::ostream & error_output, bool force_multisample_off) { CheckForOpenGLErrors("FBO init start", error_output); const bool verbose = false; if (inited) { if (verbose) error_output << "INFO: deinitializing existing FBO" << std::endl; DeInit(); CheckForOpenGLErrors("FBO deinit", error_output); } inited = true; // need at least some textures assert(!newtextures.empty()); textures = newtextures; width = -1; height = -1; std::vector <FrameBufferTexture*> color_textures; FrameBufferTexture * depth_texture = 0; for (std::vector <FrameBufferTexture*>::const_iterator i = textures.begin(); i != textures.end(); i++) { // ensure consistent sizes if (width == -1) width = (*i)->GetW(); if (height == -1) height = (*i)->GetH(); assert(width == int((*i)->GetW())); assert(height == int((*i)->GetH())); // separate textures by type if ((*i)->GetFormat() == FrameBufferTexture::DEPTH24) { // can't have more than one depth attachment assert(!depth_texture); depth_texture = *i; } else { color_textures.push_back(*i); } } if (verbose) error_output << "INFO: width " << width << ", height " << height << std::endl; if (verbose) error_output << "INFO: color textures: " << color_textures.size() << std::endl; if (verbose && depth_texture) error_output << "INFO: depth texture: 1" << std::endl; // can't have more than 4 color attachments assert(color_textures.size() < 5); // check for cubemaps for (std::vector <FrameBufferTexture*>::const_iterator i = color_textures.begin(); i != color_textures.end(); i++) { if ((*i)->GetTarget() == FrameBufferTexture::CUBEMAP) { if (verbose) error_output << "INFO: found cubemap" << std::endl; // can't have MRT with cubemaps assert(color_textures.size() == 1); // can't have multisample with cubemaps assert((*i)->GetMultiSample() == 0); // can't have depth texture with cubemaps assert(!depth_texture); } } // find what multisample value to use int multisample = 0; if (!color_textures.empty()) { multisample = -1; for (std::vector <FrameBufferTexture*>::const_iterator i = textures.begin(); i != textures.end(); i++) { if (multisample == -1) multisample = (*i)->GetMultiSample(); // all must have the same multisample assert(multisample == (*i)->GetMultiSample()); } } if (verbose) error_output << "INFO: multisample " << multisample << " found, " << force_multisample_off << std::endl; if (force_multisample_off) multisample = 0; // either we have no multisample or multisample and no depth texture assert((multisample == 0) || ((multisample > 0) && depth_texture)); // initialize framebuffer object glGenFramebuffers(1, &framebuffer_object); if (verbose) error_output << "INFO: generated FBO " << framebuffer_object << std::endl; CheckForOpenGLErrors("FBO generation", error_output); // bind framebuffer glstate.BindFramebuffer(GL_FRAMEBUFFER, framebuffer_object); CheckForOpenGLErrors("FBO binding", error_output); if (!depth_texture) { // create depth render buffer if we're not using a depth texture glGenRenderbuffers(1, &depth_renderbuffer); glBindRenderbuffer(GL_RENDERBUFFER, depth_renderbuffer); if (verbose) error_output << "INFO: generating depth renderbuffer" << std::endl; CheckForOpenGLErrors("FBO renderbuffer generation", error_output); if (multisample > 0) { glRenderbufferStorageMultisample(GL_RENDERBUFFER, multisample, GL_DEPTH_COMPONENT, width, height); if (verbose) error_output << "INFO: using multisampling for depth renderbuffer" << std::endl; } else { glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT, width, height); } CheckForOpenGLErrors("FBO renderbuffer initialization", error_output); // attach depth render buffer to the FBO glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, depth_renderbuffer); if (verbose) error_output << "INFO: depth renderbuffer attached to FBO" << std::endl; CheckForOpenGLErrors("FBO renderbuffer attachment", error_output); } if (multisample > 0) { // create/attach separate multisample color buffers for each color texture multisample_renderbuffers.resize(color_textures.size(), 0); for (size_t i = 0; i < color_textures.size(); i++) { glGenRenderbuffers(1, &multisample_renderbuffers[i]); glBindRenderbuffer(GL_RENDERBUFFER, multisample_renderbuffers[i]); glRenderbufferStorageMultisample(GL_RENDERBUFFER, multisample, color_textures[i]->GetFormat(), width, height); glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + i, GL_RENDERBUFFER, multisample_renderbuffers[i]); if (verbose) error_output << "INFO: generating separate multisample color buffer " << i << std::endl; CheckForOpenGLErrors("FBO multisample color renderbuffer", error_output); } } else { // attach color textures to frame buffer object int count = 0; for (std::vector <FrameBufferTexture*>::iterator i = color_textures.begin(); i != color_textures.end(); i++, count++) { int attachment = GL_COLOR_ATTACHMENT0 + count; if ((*i)->GetTarget() == FrameBufferTexture::CUBEMAP) { // if we're using a cubemap, arbitrarily pick one of the faces to activate so we can check that the FBO is complete glFramebufferTexture2D(GL_FRAMEBUFFER, attachment, GL_TEXTURE_CUBE_MAP_POSITIVE_X, (*i)->GetId(), 0); if (verbose) error_output << "INFO: attaching arbitrary cubemap face to color attachment " << count << std::endl; } else { glFramebufferTexture2D(GL_FRAMEBUFFER, attachment, (*i)->GetTarget(), (*i)->GetId(), 0); if (verbose) error_output << "INFO: attaching texture to color attachment " << count << std::endl; } (*i)->SetAttachment(attachment); CheckForOpenGLErrors("FBO attachment", error_output); } if (depth_texture) { // attach depth texture to frame buffer object glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, depth_texture->GetTarget(), depth_texture->GetId(), 0); depth_texture->SetAttachment(GL_DEPTH_ATTACHMENT); if (verbose) error_output << "INFO: attaching depth texture" << std::endl; CheckForOpenGLErrors("FBO attachment", error_output); } } GLenum buffers[4] = {GL_NONE, GL_NONE, GL_NONE, GL_NONE}; { int count = 0; for (std::vector <FrameBufferTexture*>::const_iterator i = color_textures.begin(); i != color_textures.end(); i++, count++) { buffers[count] = GL_COLOR_ATTACHMENT0 + count; } glDrawBuffers(count, buffers); glReadBuffer(buffers[0]); CheckForOpenGLErrors("FBO buffer mask set", error_output); } if (verbose) error_output << "INFO: set draw buffers: " << buffers[0] << ", " << buffers[1] << ", " << buffers[2] << ", " << buffers[3] << std::endl; if (verbose) error_output << "INFO: set read buffer: " << buffers[0] << std::endl; if (!CheckStatus(error_output)) { error_output << "Error initializing FBO:" << std::endl; int count = 0; for (std::vector <FrameBufferTexture*>::const_iterator i = textures.begin(); i != textures.end(); i++) { error_output << "\t" << count << ". " << TargetToString(FrameBufferTexture::Target((*i)->GetTarget())); error_output << ": " << FormatToString((*i)->GetFormat()) << std::endl; count++; } assert(0); } // explicitely unbind framebuffer object glstate.BindFramebuffer(GL_FRAMEBUFFER, 0); CheckForOpenGLErrors("FBO unbinding", error_output); // if multisampling is on, create another framebuffer object for the single sample version of these textures if (multisample > 0) { if (verbose) error_output << "INFO: creating secondary single sample framebuffer object" << std::endl; assert(!singlesample_framebuffer_object); singlesample_framebuffer_object = new FrameBufferObject(); singlesample_framebuffer_object->Init(glstate, newtextures, error_output, true); } }
void RenderInputScene::SetDepthMode(GraphicsState & glstate, int mode, bool write_depth) { glstate.DepthTest(mode, write_depth); }
void RenderInputScene::SetColorMask(GraphicsState & glstate, bool write_color, bool write_alpha) { glstate.ColorMask(write_color, write_alpha); }
void RenderInputScene::ClearOutput(GraphicsState & glstate, bool color, bool depth) { glstate.ClearDrawBuffer(color, depth); }
void RenderInputScene::SetTextures(const Drawable & d, GraphicsState & glstate) { glstate.BindTexture(0, GL_TEXTURE_2D, d.GetTexture0()); glstate.BindTexture(1, GL_TEXTURE_2D, d.GetTexture1()); glstate.BindTexture(2, GL_TEXTURE_2D, d.GetTexture2()); }