kick
|
00001 // 00002 // camera.cpp 00003 // KickCPP 00004 // 00005 // Created by morten on 8/12/13. 00006 // Copyright (c) 2013 Morten Nobel-Joergensen. All rights reserved. 00007 // 00008 00009 #include "kick/scene/camera.h" 00010 #include <iostream> 00011 #include <glm/ext.hpp> 00012 #include <cmath> 00013 #include <algorithm> 00014 #include "kick/scene/game_object.h" 00015 #include "kick/scene/transform.h" 00016 #include "kick/scene/scene.h" 00017 #include "kick/scene/component_renderable.h" 00018 #include "kick/texture/texture_render_target.h" 00019 #include "kick/core/engine.h" 00020 #include "kick/scene/light.h" 00021 #include "kick/math/misc.h" 00022 #include "kick/material/material.h" 00023 #include "kick/core/debug.h" 00024 #include "time.h" 00025 00026 using namespace std; 00027 using namespace glm; 00028 00029 namespace kick { 00030 00031 Camera::Camera(GameObject *gameObject) 00032 :Component(gameObject){ 00033 Scene* scene = gameObject->scene(); 00034 componentListener = scene->componentEvents.createListener([&](pair<std::shared_ptr<Component>, ComponentUpdateStatus> value){ 00035 auto r = std::dynamic_pointer_cast<ComponentRenderable>(value.first); 00036 if (r) { 00037 if (value.second == ComponentUpdateStatus::Created) { 00038 mRenderableComponents.push_back(r); 00039 00040 } else if (value.second == ComponentUpdateStatus::Destroyed) { 00041 auto iter = find(mRenderableComponents.begin(), mRenderableComponents.end(), r); 00042 if (iter != mRenderableComponents.end()) { 00043 mRenderableComponents.erase(iter); 00044 } 00045 } 00046 } 00047 }); 00048 createComponentList(); 00049 } 00050 00051 Camera::~Camera() { 00052 destroyShadowMap(); 00053 delete mPickingRenderTarget; 00054 } 00055 00056 00057 00058 void Camera::createComponentList(){ 00059 mRenderableComponents.clear(); 00060 for (auto & gameObject_ : *gameObject()->scene()) { 00061 for (auto & component : *gameObject_){ 00062 auto r = std::dynamic_pointer_cast<ComponentRenderable>(component); 00063 if (r){ 00064 mRenderableComponents.push_back(r); 00065 } 00066 } 00067 } 00068 } 00069 00070 void Camera::deactivated(){ 00071 // remove listener 00072 componentListener = {}; 00073 } 00074 00075 glm::vec4 Camera::clearColor(){ 00076 return mClearColor; 00077 } 00078 00079 void Camera::setClearColor(glm::vec4 clearColor){ 00080 this->mClearColor = clearColor; 00081 } 00082 00083 void Camera::setupViewport(vec2 &offset, vec2 &dim){ 00084 offset = round(offset); 00085 dim = round(dim); 00086 int offsetX = (int)offset.x; 00087 int offsetY = (int)offset.y; 00088 int width = (int)dim.x; 00089 int height = (int)dim.y; 00090 glViewport(offsetX, offsetY, width, height); 00091 glScissor(offsetX, offsetY, width, height); 00092 } 00093 00094 void Camera::setupCamera(EngineUniforms *engineUniforms) { 00095 00096 vec2 viewportDimension = (vec2)/*renderTarget? renderTarget.dimension : */ engineUniforms->viewportDimension.getValue(); 00097 vec2 offset = viewportDimension * mNormalizedViewportOffset; 00098 vec2 dim = viewportDimension * mNormalizedViewportDim; 00099 setupViewport(offset, dim); 00100 if (mClearFlag) { 00101 if (clearColorBuffer()) { 00102 glClearColor(mClearColor.r, mClearColor.g, mClearColor.b, mClearColor.a); 00103 } 00104 glClear(mClearFlag); 00105 } 00106 00107 engineUniforms->viewMatrix = viewMatrix(); 00108 engineUniforms->viewProjectionMatrix = mProjectionMatrix * engineUniforms->viewMatrix; 00109 engineUniforms->projectionMatrix = mProjectionMatrix; 00110 } 00111 00112 glm::mat4 Camera::viewMatrix(){ 00113 return mGameObject->transform()->globalTRSInverse(); 00114 } 00115 00116 void Camera::renderShadowMap(Light* directionalLight){ 00117 00118 } 00119 00120 void Camera::render(EngineUniforms *engineUniforms){ 00121 auto sceneLights = engineUniforms->sceneLights; 00122 engineUniforms->currentCameraTransform = transform().get(); 00123 00124 if (mShadow && sceneLights->directionalLight && sceneLights->directionalLight->shadowType() != ShadowType::None) { 00125 renderShadowMap(sceneLights->directionalLight.get()); 00126 } 00127 00128 if (mTarget){ 00129 mTarget->bind(); 00130 } 00131 bool customViewport = mNormalizedViewportOffset != vec2{0} || mNormalizedViewportDim != vec2{1}; 00132 if (customViewport){ 00133 glEnable(GL_SCISSOR_TEST); 00134 } 00135 setupCamera(engineUniforms); 00136 engineUniforms->sceneLights->recomputeLight(engineUniforms->viewMatrix); 00137 auto components = cull(); 00138 00139 sort(components.begin(), components.end(), [](ComponentRenderable* r1, ComponentRenderable* r2){ 00140 return r1->renderOrder() < r2->renderOrder(); 00141 }); 00142 00143 for (auto c : components){ 00144 c->render(engineUniforms, mReplacementMaterial.get()); 00145 } 00146 if (mTarget){ 00147 mTarget->unbind(); 00148 } 00149 00150 if (mPickQueue.size() > 0){ 00151 handleObjectPicking(engineUniforms, components); 00152 } 00153 if (customViewport){ 00154 glDisable(GL_SCISSOR_TEST); 00155 } 00156 } 00157 00158 void Camera::handleObjectPicking(EngineUniforms *engineUniforms, std::vector<ComponentRenderable*>& components) { 00159 auto viewportSize = engineUniforms->viewportDimension.getValue(); 00160 if (mPickingRenderTarget == nullptr || viewportSize != mPickingRenderTarget->size()){ 00161 delete mPickingRenderTarget; 00162 mPickingRenderTarget = new TextureRenderTarget(); 00163 mPickingRenderTarget->setSize(viewportSize); 00164 if (mPickingTexture == nullptr){ 00165 mPickingTexture = make_shared<Texture2D>(); 00166 } 00167 ImageFormat imageFormat{}; 00168 imageFormat.mipmap = Mipmap::None; 00169 TextureSampler sampler{}; 00170 sampler.filterMag = TextureFilter::Nearest; 00171 sampler.filterMin = TextureFilter::Nearest; 00172 sampler.wrapS = TextureWrap::ClampToEdge; 00173 sampler.wrapT = TextureWrap::ClampToEdge; 00174 mPickingTexture->setTextureSampler(sampler); 00175 mPickingTexture->setData(viewportSize.x, viewportSize.y, nullptr, imageFormat); 00176 00177 mPickingRenderTarget->setColorTexture(0, mPickingTexture); 00178 if (mPickingMaterial.get() == nullptr){ 00179 mPickingMaterial = std::shared_ptr<Material>(new Material()); 00180 mPickingMaterial->setShader(Project::loadShader("assets/shaders/__pick.shader")); 00181 } 00182 mPickingRenderTarget->apply(); 00183 glPixelStorei(GL_UNPACK_ALIGNMENT, 1); 00184 glPixelStorei(GL_PACK_ALIGNMENT, 1); 00185 } 00186 mPickingRenderTarget->bind(); 00187 glClearColor(0, 0, 0, 0); 00188 glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT); 00189 for (auto c : components){ 00190 c->render(engineUniforms, mPickingMaterial.get()); 00191 } 00192 for (auto q : mPickQueue){ 00193 vector<glm::u8vec4> data((int)(q.size.x * q.size.y)); 00194 glReadPixels(q.point.x, q.point.y, q.size.x, q.size.y, GL_RGBA, GL_UNSIGNED_BYTE, (GLvoid *) glm::value_ptr(*data.data())); 00195 std::map<int,int> gameObjectFrequency; 00196 for (auto p : data){ 00197 int uid = vec4ToUint32(p); 00198 if (uid != 0){ 00199 auto iter = gameObjectFrequency.find(uid); 00200 if (iter != gameObjectFrequency.end()){ 00201 iter->second++; 00202 } else { 00203 gameObjectFrequency.insert(pair<int,int>(uid,1)); 00204 } 00205 } 00206 } 00207 auto scene = mGameObject->scene(); 00208 for (auto uid : gameObjectFrequency){ 00209 auto hitGameObject = scene->gameObjectByUID(uid.first); 00210 if (hitGameObject) { 00211 q.onPicked(hitGameObject, uid.second); 00212 } 00213 } 00214 if (gameObjectFrequency.empty() && q.returnNullptrOnNoHit){ 00215 q.onPicked(nullptr, 0); 00216 } 00217 } 00218 mPickingRenderTarget->unbind(); 00219 mPickQueue.clear(); 00220 } 00221 00222 void Camera::setClearColorBuffer(bool clear){ 00223 if (clear){ 00224 mClearFlag |= GL_COLOR_BUFFER_BIT; 00225 } else { 00226 mClearFlag &= ~GL_COLOR_BUFFER_BIT; 00227 } 00228 } 00229 00230 bool Camera::clearColorBuffer(){ 00231 return (bool) (mClearFlag & GL_COLOR_BUFFER_BIT); 00232 } 00233 00234 void Camera::setClearDepthBuffer(bool clear){ 00235 if (clear){ 00236 mClearFlag |= GL_DEPTH_BUFFER_BIT; 00237 } else { 00238 mClearFlag &= ~GL_DEPTH_BUFFER_BIT; 00239 } 00240 } 00241 00242 bool Camera::clearDepthBuffer(){ 00243 return (bool) (mClearFlag & GL_DEPTH_BUFFER_BIT); 00244 } 00245 00246 void Camera::setClearStencilBuffer(bool clear){ 00247 if (clear){ 00248 mClearFlag |= GL_STENCIL_BUFFER_BIT; 00249 } else { 00250 mClearFlag &= ~GL_STENCIL_BUFFER_BIT; 00251 } 00252 } 00253 00254 bool Camera::clearStencilBuffer(){ 00255 return (bool) (mClearFlag & GL_STENCIL_BUFFER_BIT); 00256 } 00257 00258 glm::mat4 Camera::projectionMatrix() { 00259 return mProjectionMatrix; 00260 } 00261 00262 void Camera::setProjectionMatrix(glm::mat4 projectionMatrix) { 00263 this->mProjectionMatrix = projectionMatrix; 00264 } 00265 00266 void Camera::resetProjectionMatrix(){ 00267 } 00268 00269 bool Camera::shadow() const { 00270 return mShadow; 00271 } 00272 00273 void Camera::setShadow(bool renderShadow) { 00274 if (Camera::mShadow != renderShadow) { 00275 Camera::mShadow = renderShadow; 00276 if (renderShadow){ 00277 initShadowMap(); 00278 } else { 00279 destroyShadowMap(); 00280 } 00281 } 00282 } 00283 00284 void Camera::initShadowMap() { 00285 mShadowMapShader = Project::loadShader("assets/shaders/__shadowmap.shader"); 00286 mShadowMapMaterial = new Material(); 00287 mShadowMapMaterial->setShader(mShadowMapShader); 00288 } 00289 00290 void Camera::destroyShadowMap() { 00291 } 00292 00293 int Camera::cullingMask() const { 00294 return mCullingMask; 00295 } 00296 00297 void Camera::setCullingMask(int cullingMask) { 00298 Camera::mCullingMask = cullingMask; 00299 } 00300 00301 TextureRenderTarget *Camera::target() const { 00302 return mTarget; 00303 } 00304 00305 void Camera::setTarget(TextureRenderTarget *target) { 00306 Camera::mTarget = target; 00307 } 00308 00309 void Camera::pick(glm::ivec2 point, std::function<void(GameObject*,int)> onPicked, glm::ivec2 size, bool returnNullptrOnNoHit){ 00310 mPickQueue.push_back({point, size, onPicked, returnNullptrOnNoHit}); 00311 } 00312 00313 std::shared_ptr<Material> const &Camera::replacementMaterial() const { 00314 return mReplacementMaterial; 00315 } 00316 00317 void Camera::setReplacementMaterial(std::shared_ptr<Material> const &replacementMaterial) { 00318 Camera::mReplacementMaterial = replacementMaterial; 00319 } 00320 00321 glm::vec2 const &Camera::viewportOffset() const { 00322 return mNormalizedViewportOffset; 00323 } 00324 00325 void Camera::setViewportOffset(glm::vec2 const &normalizedViewportOffset) { 00326 Camera::mNormalizedViewportOffset = normalizedViewportOffset; 00327 } 00328 00329 glm::vec2 const &Camera::viewportDim() const { 00330 return mNormalizedViewportDim; 00331 } 00332 00333 void Camera::setViewportDim(glm::vec2 const &normalizedViewportDim) { 00334 Camera::mNormalizedViewportDim = normalizedViewportDim; 00335 } 00336 00337 Ray Camera::screenPointToRay(glm::vec2 point){ 00338 00339 vec3 zoomDirection = transform()->forward(); 00340 00341 vec2 surfaceDim = (vec2)(Engine::context()->getContextSurfaceDim()); 00342 vec3 mousePosNormalizedNear{(vec2(point) / surfaceDim)*2.0f-vec2(1.0f),1.0f}; 00343 vec3 mousePosNormalizedFar{(vec2(point) / surfaceDim)*2.0f-vec2(1.0f),-1.0f}; 00344 // inverse 00345 mousePosNormalizedNear.y *=-1; 00346 mousePosNormalizedFar.y *=-1; 00347 00348 mat4 invProjection = inverse(projectionMatrix()); 00349 mat4 invView = transform()->globalMatrix(); 00350 00351 vec4 mousePosViewNear = invProjection * vec4(mousePosNormalizedNear, 1.0); 00352 vec4 mousePosViewFar = invProjection * vec4(mousePosNormalizedFar, 1.0); 00353 mousePosViewNear /= 1.0f/mousePosViewNear.w; 00354 mousePosViewFar /= 1.0f/mousePosViewFar.w; 00355 mousePosViewNear.w = 1; 00356 mousePosViewFar.w = 1; 00357 00358 vec4 mousePosWorldNear = invView * mousePosViewNear; 00359 vec4 mousePosWorldFar = invView * mousePosViewFar; 00360 00361 return Ray{(vec3)mousePosWorldNear, normalize((vec3)mousePosWorldFar - (vec3)mousePosWorldNear)}; 00362 } 00363 00364 bool Camera::main() {return mMainCamera;} 00365 00366 void Camera::setMain(bool main) { mMainCamera = main;} 00367 00368 int Camera::index() {return mIndex;} 00369 00370 void Camera::setIndex(int index) {mIndex = index;} 00371 00372 std::vector<ComponentRenderable *> Camera::cull() { 00373 std::vector<ComponentRenderable *> res; 00374 for (auto c : mRenderableComponents){ 00375 if (c->gameObject()->layer() & mCullingMask) { 00376 res.push_back(c.get()); 00377 } 00378 } 00379 return res; 00380 } 00381 00382 std::shared_ptr<Camera> Camera::mainCamera() { 00383 return Engine::activeScene()->mainCamera(); 00384 } 00385 }