#include "client/Engine.h" #include "client/rendering/wrapper/GLFWWrapper.h" bool Engine::useSSAO = true; float Engine::testRadius = 0.0005; float Engine::testBias = 0.0005; bool Engine::ortho = false; Vector Engine::testOrthoCenter; Engine::Engine(Shaders& shaders, Framebuffers& fb, const Keys& keys, const MouseButtons& buttons, Camera& camera, Ray& ray, const Clock& fps, const WindowSize& size) : shaders(shaders), fb(fb), keys(keys), buttons(buttons), game(keys, buttons, camera, ray), camera(camera), frustum(60.0f, 0.1f, 80.0f), ssaoNoise(4, 4), fps(fps), size(size), running(!shaders.hasError() && !fb.hasError()) { rectangle.add( {-1, -1, 0, 0, 0, 0, 0, 0}); rectangle.add( {1, 1, 0, 1, 1, 0, 0, 0}); rectangle.add( {-1, 1, 0, 0, 1, 0, 0, 0}); rectangle.add( {-1, -1, 0, 0, 0, 0, 0, 0}); rectangle.add( {1, -1, 0, 1, 0, 0, 0, 0}); rectangle.add( {1, 1, 0, 1, 1, 0, 0, 0}); rectangle.build(); } bool Engine::isRunning() const { return running; } void Engine::renderTick(float lag) { camera.update(lag); updateWorldProjection(); updateWorldView(); renderShadow(lag); renderWorld(lag); if(Engine::useSSAO) { renderSSAO(); } renderPostWorld(); renderTextOverlay(lag); } void Engine::tick() { game.tick(); if(keys.test5.getDownTime() == 1) { ortho = !ortho; } if(keys.test.isDown()) { //ortho = !ortho; testRadius /= 0.95f; } if(keys.test2.isDown()) { testRadius *= 0.95f; } if(keys.test3.isDown()) { testBias /= 0.95f; } if(keys.test4.isDown()) { testBias *= 0.95f; } } void Engine::renderShadow(float lag) { fb.shadow.bind(); glEnable(GL_DEPTH_TEST); shaders.shadow.use(); worldShadowProjView = worldShadowProj; worldShadowProjView.mul(worldShadowView); shaders.shadow.setMatrix("projView", worldShadowProjView.getValues()); //glEnable(GL_CULL_FACE); //glCullFace(GL_FRONT); game.renderWorld(lag, model, shaders.shadow); //glCullFace(GL_BACK); } void Engine::renderWorld(float lag) { fb.world.bind(); glEnable(GL_DEPTH_TEST); shaders.world.use(); Matrix rWorldShadowProjView; rWorldShadowProjView.translate(0.5f, 0.5f, 0.5f); rWorldShadowProjView.scale(0.5f, 0.5f, 0.5f); rWorldShadowProjView.mul(worldShadowProjView); shaders.world.setMatrix("projViewShadow", rWorldShadowProjView.getValues()); shaders.world.setMatrix("proj", worldProj.getValues()); shaders.world.setMatrix("view", worldView.getValues()); model.clear(); shaders.world.setMatrix("model", model.get().getValues()); fb.shadow.bindDepthTexture(1); shaders.world.setFloat("radius", Engine::testRadius); shaders.world.setFloat("bias", Engine::testBias); game.renderWorld(lag, model, shaders.world); } void Engine::renderSSAO() { shaders.ssao.use(); Matrix rProj; rProj.translate(0.5f, 0.5f, 0.5f); rProj.scale(0.5f, 0.5f, 0.5f); rProj.mul(worldProj); shaders.ssao.setMatrix("proj", rProj.getValues()); shaders.ssao.setInt("width", size.width); shaders.ssao.setInt("height", size.height); fb.world.bindPositionTexture(0); fb.world.bindNormalTexture(1); fb.world.bindColorTexture(2); fb.world.bindDepthTexture(3); ssaoNoise.bind(4); fb.ssao.bind(); rectangle.draw(); // ssao blur shaders.ssaoBlur.use(); fb.ssao.bindRedTexture(0); fb.ssaoBlur.bind(); rectangle.draw(); } void Engine::renderPostWorld() { glBindFramebuffer(GL_FRAMEBUFFER, 0); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); shaders.postWorld.use(); fb.world.bindColorTexture(0); fb.ssaoBlur.bindRedTexture(1); fb.world.bindRedTexture(2); fb.world.bindNormalTexture(3); shaders.postWorld.setInt("useSSAO", Engine::useSSAO); rectangle.draw(); } void Engine::renderTextOverlay(float lag) { glDisable(GL_DEPTH_TEST); shaders.text.use(); Matrix m; shaders.text.setMatrix("proj", m.getValues()); m.translate(-1.0f, 1.0f, 0.0f); m.scale(2.0f / size.width, -2.0f / size.height, 1.0f); shaders.text.setMatrix("view", m.getValues()); model.clear(); model.get().scale(2.0f, 2.0f, 2.0f); shaders.text.setMatrix("model", model.get().getValues()); glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glBlendEquation(GL_FUNC_ADD); char buffer[50]; snprintf(buffer, 50, "FPS: %f %f %f", fps.getUpdatesPerSecond(), Engine::testRadius, Engine::testBias); fontRenderer.drawString(20, 20, buffer); game.renderTextOverlay(lag, model, shaders.text, fontRenderer); glDisable(GL_BLEND); } void Engine::updateWorldProjection() { frustum.setProjection(worldProj, size.width, size.height); // http://cgvr.informatik.uni-bremen.de/teaching/cg_literatur/lighthouse3d_view_frustum_culling/index.html /*float tan = tanf((0.5f * fovY) * M_PI / 180.0f); float aspect = (float) size.width / size.height; float closeFarClip = 4; float nearHigh = tan * nearClip; float nearWidth = nearHigh * aspect; float farHigh = tan * closeFarClip; float farWidth = farHigh * aspect; Vector farCenter = cam.getPosition(); farCenter.addMul(cam.getFront(), closeFarClip); Vector farTopLeft = farCenter; farTopLeft.addMul(cam.getLeft(), farWidth); farTopLeft.addMul(cam.getUp(), farHigh); Vector farBottomLeft = farCenter; farBottomLeft.addMul(cam.getLeft(), farWidth); farBottomLeft.addMul(cam.getDown(), farHigh); Vector farTopRight = farCenter; farTopRight.addMul(cam.getRight(), farWidth); farTopRight.addMul(cam.getUp(), farHigh); Vector farBottomRight = farCenter; farBottomRight.addMul(cam.getRight(), farWidth); farBottomRight.addMul(cam.getDown(), farHigh); Vector nearCenter = cam.getPosition(); nearCenter.addMul(cam.getFront(), nearClip); Vector nearTopLeft = nearCenter; nearTopLeft.addMul(cam.getLeft(), nearWidth); nearTopLeft.addMul(cam.getUp(), nearHigh); Vector nearBottomLeft = nearCenter; nearBottomLeft.addMul(cam.getLeft(), nearWidth); nearBottomLeft.addMul(cam.getDown(), nearHigh); Vector nearTopRight = nearCenter; nearTopRight.addMul(cam.getRight(), nearWidth); nearTopRight.addMul(cam.getUp(), nearHigh); Vector nearBottomRight = nearCenter; nearBottomRight.addMul(cam.getRight(), nearWidth); nearBottomRight.addMul(cam.getDown(), nearHigh); Vector light(-0.280166, -0.573576, -0.769751); Vector lightLeft = light; lightLeft.cross(0.0f, 1.0f, 0.0f); Vector lightUp = lightLeft; lightUp.cross(light); //std::cout << "-------------------------\n"; Plane plane; plane.set(Vector(), light, lightUp); float f[8]; f[0] = plane.getSignedDistance(farTopLeft); f[1] = plane.getSignedDistance(farBottomLeft); f[2] = plane.getSignedDistance(farTopRight); f[3] = plane.getSignedDistance(farBottomRight); f[4] = plane.getSignedDistance(nearTopLeft); f[5] = plane.getSignedDistance(nearBottomLeft); f[6] = plane.getSignedDistance(nearTopRight); f[7] = plane.getSignedDistance(nearBottomRight); float min = FLT_MAX; float max = -FLT_MAX; for(uint i = 0; i < 8; i++) { if(f[i] < min) { min = f[i]; } if(f[i] > max) { max = f[i]; } } float lightWidth = max - min; //std::cout << lightWidth << "\n"; plane.set(Vector(), light, lightLeft); f[0] = plane.getSignedDistance(farTopLeft); f[1] = plane.getSignedDistance(farBottomLeft); f[2] = plane.getSignedDistance(farTopRight); f[3] = plane.getSignedDistance(farBottomRight); f[4] = plane.getSignedDistance(nearTopLeft); f[5] = plane.getSignedDistance(nearBottomLeft); f[6] = plane.getSignedDistance(nearTopRight); f[7] = plane.getSignedDistance(nearBottomRight); min = FLT_MAX; max = -FLT_MAX; for(uint i = 0; i < 8; i++) { if(f[i] < min) { min = f[i]; } if(f[i] > max) { max = f[i]; } } float lightHeight = max - min; //std::cout << "\n" << max << " - " << min << " " << lightHeight << "\n"; // not the real center, but good guess testOrthoCenter = nearCenter; testOrthoCenter.addMul(cam.getFront(), closeFarClip * 0.5f); if(ortho) { worldProj.setToIdentity(); worldProj.set(0, 2.0f / lightWidth); worldProj.set(5, 2.0f / lightHeight); worldProj.set(10, -2.0f / (farClip - nearClip)); } if(once) { worldShadowProj.setToIdentity(); worldShadowProj.set(0, 2.0f / lightWidth); worldShadowProj.set(5, 2.0f / lightHeight); worldShadowProj.set(10, -2.0f / (farClip - nearClip)); }*/ } void Engine::updateWorldView() { Vector right = camera.getRight(); Vector up = camera.getUp(); Vector back = camera.getBack(); Vector pos = camera.getPosition(); if(ortho) { right.set(0.939693f, 0.0f, -0.34202f); back.set(0.280166f, 0.573576f, 0.769751f); up.set(-0.196175f, 0.819152f, -0.538986f); pos = testOrthoCenter; } worldView.set(0, right.getX()); worldView.set(1, up.getX()); worldView.set(2, back.getX()); worldView.set(4, right.getY()); worldView.set(5, up.getY()); worldView.set(6, back.getY()); worldView.set(8, right.getZ()); worldView.set(9, up.getZ()); worldView.set(10, back.getZ()); worldView.set(12, right.dotInverse(pos)); worldView.set(13, up.dotInverse(pos)); worldView.set(14, back.dotInverse(pos)); //if(once) { // lengthAngle = 20; widthAngle = 35; right.set(0.939693f, 0.0f, -0.34202f); back.set(0.280166f, 0.573576f, 0.769751f); up.set(-0.196175f, 0.819152f, -0.538986f); pos = testOrthoCenter; //once = false; worldShadowView.set(0, right.getX()); worldShadowView.set(1, up.getX()); worldShadowView.set(2, back.getX()); worldShadowView.set(4, right.getY()); worldShadowView.set(5, up.getY()); worldShadowView.set(6, back.getY()); worldShadowView.set(8, right.getZ()); worldShadowView.set(9, up.getZ()); worldShadowView.set(10, back.getZ()); worldShadowView.set(12, right.dotInverse(pos)); worldShadowView.set(13, up.dotInverse(pos)); worldShadowView.set(14, back.dotInverse(pos)); //} }