Renderer.cpp 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590
  1. // ----------------------------------------------------------------
  2. // From Game Programming in C++ by Sanjay Madhav
  3. // Copyright (C) 2017 Sanjay Madhav. All rights reserved.
  4. //
  5. // Released under the BSD License
  6. // See LICENSE in root directory for full details.
  7. // ----------------------------------------------------------------
  8. #include "Renderer.h"
  9. #include "Texture.h"
  10. #include "Mesh.h"
  11. #include <algorithm>
  12. #include "Shader.h"
  13. #include "VertexArray.h"
  14. #include "SpriteComponent.h"
  15. #include "MeshComponent.h"
  16. #include "UIScreen.h"
  17. #include "Game.h"
  18. #include <GL/glew.h>
  19. #include "SkeletalMeshComponent.h"
  20. #include "GBuffer.h"
  21. #include "PointLightComponent.h"
  22. Renderer::Renderer(Game* game)
  23. :mGame(game)
  24. ,mSpriteShader(nullptr)
  25. ,mMeshShader(nullptr)
  26. ,mSkinnedShader(nullptr)
  27. ,mMirrorBuffer(0)
  28. ,mMirrorTexture(nullptr)
  29. ,mGBuffer(nullptr)
  30. ,mGGlobalShader(nullptr)
  31. ,mGPointLightShader(nullptr)
  32. {
  33. }
  34. Renderer::~Renderer()
  35. {
  36. }
  37. bool Renderer::Initialize(float screenWidth, float screenHeight)
  38. {
  39. mScreenWidth = screenWidth;
  40. mScreenHeight = screenHeight;
  41. // Set OpenGL attributes
  42. // Use the core OpenGL profile
  43. SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE);
  44. // Specify version 3.3
  45. SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3);
  46. SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 3);
  47. // Request a color buffer with 8-bits per RGBA channel
  48. SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 8);
  49. SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, 8);
  50. SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, 8);
  51. SDL_GL_SetAttribute(SDL_GL_ALPHA_SIZE, 8);
  52. SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 24);
  53. // Enable double buffering
  54. SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
  55. // Force OpenGL to use hardware acceleration
  56. SDL_GL_SetAttribute(SDL_GL_ACCELERATED_VISUAL, 1);
  57. mWindow = SDL_CreateWindow("Game Programming in C++ (Chapter 14)", 100, 100,
  58. static_cast<int>(mScreenWidth), static_cast<int>(mScreenHeight), SDL_WINDOW_OPENGL);
  59. if (!mWindow)
  60. {
  61. SDL_Log("Failed to create window: %s", SDL_GetError());
  62. return false;
  63. }
  64. // Create an OpenGL context
  65. mContext = SDL_GL_CreateContext(mWindow);
  66. // Initialize GLEW
  67. glewExperimental = GL_TRUE;
  68. if (glewInit() != GLEW_OK)
  69. {
  70. SDL_Log("Failed to initialize GLEW.");
  71. return false;
  72. }
  73. // On some platforms, GLEW will emit a benign error code,
  74. // so clear it
  75. glGetError();
  76. // Make sure we can create/compile shaders
  77. if (!LoadShaders())
  78. {
  79. SDL_Log("Failed to load shaders.");
  80. return false;
  81. }
  82. // Create quad for drawing sprites
  83. CreateSpriteVerts();
  84. // Create render target for mirror
  85. //if (!CreateMirrorTarget())
  86. //{
  87. // SDL_Log("Failed to create render target for mirror.");
  88. // return false;
  89. //}
  90. // Create G-buffer
  91. mGBuffer = new GBuffer();
  92. int width = static_cast<int>(mScreenWidth);
  93. int height = static_cast<int>(mScreenHeight);
  94. if (!mGBuffer->Create(width, height))
  95. {
  96. SDL_Log("Failed to create G-buffer.");
  97. return false;
  98. }
  99. // Load point light mesh
  100. mPointLightMesh = GetMesh("Assets/PointLight.gpmesh");
  101. return true;
  102. }
  103. void Renderer::Shutdown()
  104. {
  105. // Get rid of any render target textures, if they exist
  106. if (mMirrorTexture != nullptr)
  107. {
  108. glDeleteFramebuffers(1, &mMirrorBuffer);
  109. mMirrorTexture->Unload();
  110. delete mMirrorTexture;
  111. }
  112. // Get rid of G-buffer
  113. if (mGBuffer != nullptr)
  114. {
  115. mGBuffer->Destroy();
  116. delete mGBuffer;
  117. }
  118. // Delete point lights
  119. while (!mPointLights.empty())
  120. {
  121. delete mPointLights.back();
  122. }
  123. delete mSpriteVerts;
  124. mSpriteShader->Unload();
  125. delete mSpriteShader;
  126. mMeshShader->Unload();
  127. delete mMeshShader;
  128. SDL_GL_DeleteContext(mContext);
  129. SDL_DestroyWindow(mWindow);
  130. }
  131. void Renderer::UnloadData()
  132. {
  133. // Destroy textures
  134. for (auto i : mTextures)
  135. {
  136. i.second->Unload();
  137. delete i.second;
  138. }
  139. mTextures.clear();
  140. // Destroy meshes
  141. for (auto i : mMeshes)
  142. {
  143. i.second->Unload();
  144. delete i.second;
  145. }
  146. mMeshes.clear();
  147. }
  148. void Renderer::Draw()
  149. {
  150. // Draw to the mirror texture first
  151. //Draw3DScene(mMirrorBuffer, mMirrorView, mProjection);
  152. // Draw the 3D scene to the G-buffer
  153. Draw3DScene(mGBuffer->GetBufferID(), mView, mProjection, false);
  154. // Set the frame buffer back to zero (screen's frame buffer)
  155. glBindFramebuffer(GL_FRAMEBUFFER, 0);
  156. // Draw from the GBuffer
  157. DrawFromGBuffer();
  158. // Draw all sprite components
  159. // Disable depth buffering
  160. glDisable(GL_DEPTH_TEST);
  161. // Enable alpha blending on the color buffer
  162. glEnable(GL_BLEND);
  163. glBlendEquationSeparate(GL_FUNC_ADD, GL_FUNC_ADD);
  164. glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ZERO);
  165. // Set shader/vao as active
  166. mSpriteShader->SetActive();
  167. mSpriteVerts->SetActive();
  168. for (auto sprite : mSprites)
  169. {
  170. if (sprite->GetVisible())
  171. {
  172. sprite->Draw(mSpriteShader);
  173. }
  174. }
  175. // Draw any UI screens
  176. for (auto ui : mGame->GetUIStack())
  177. {
  178. ui->Draw(mSpriteShader);
  179. }
  180. // Swap the buffers
  181. SDL_GL_SwapWindow(mWindow);
  182. }
  183. void Renderer::AddSprite(SpriteComponent* sprite)
  184. {
  185. // Find the insertion point in the sorted vector
  186. // (The first element with a higher draw order than me)
  187. int myDrawOrder = sprite->GetDrawOrder();
  188. auto iter = mSprites.begin();
  189. for (;
  190. iter != mSprites.end();
  191. ++iter)
  192. {
  193. if (myDrawOrder < (*iter)->GetDrawOrder())
  194. {
  195. break;
  196. }
  197. }
  198. // Inserts element before position of iterator
  199. mSprites.insert(iter, sprite);
  200. }
  201. void Renderer::RemoveSprite(SpriteComponent* sprite)
  202. {
  203. auto iter = std::find(mSprites.begin(), mSprites.end(), sprite);
  204. mSprites.erase(iter);
  205. }
  206. void Renderer::AddMeshComp(MeshComponent* mesh)
  207. {
  208. if (mesh->GetIsSkeletal())
  209. {
  210. SkeletalMeshComponent* sk = static_cast<SkeletalMeshComponent*>(mesh);
  211. mSkeletalMeshes.emplace_back(sk);
  212. }
  213. else
  214. {
  215. mMeshComps.emplace_back(mesh);
  216. }
  217. }
  218. void Renderer::RemoveMeshComp(MeshComponent* mesh)
  219. {
  220. if (mesh->GetIsSkeletal())
  221. {
  222. SkeletalMeshComponent* sk = static_cast<SkeletalMeshComponent*>(mesh);
  223. auto iter = std::find(mSkeletalMeshes.begin(), mSkeletalMeshes.end(), sk);
  224. mSkeletalMeshes.erase(iter);
  225. }
  226. else
  227. {
  228. auto iter = std::find(mMeshComps.begin(), mMeshComps.end(), mesh);
  229. mMeshComps.erase(iter);
  230. }
  231. }
  232. void Renderer::AddPointLight(PointLightComponent * light)
  233. {
  234. mPointLights.emplace_back(light);
  235. }
  236. void Renderer::RemovePointLight(PointLightComponent * light)
  237. {
  238. auto iter = std::find(mPointLights.begin(), mPointLights.end(), light);
  239. mPointLights.erase(iter);
  240. }
  241. Texture* Renderer::GetTexture(const std::string& fileName)
  242. {
  243. Texture* tex = nullptr;
  244. auto iter = mTextures.find(fileName);
  245. if (iter != mTextures.end())
  246. {
  247. tex = iter->second;
  248. }
  249. else
  250. {
  251. tex = new Texture();
  252. if (tex->Load(fileName))
  253. {
  254. mTextures.emplace(fileName, tex);
  255. }
  256. else
  257. {
  258. delete tex;
  259. tex = nullptr;
  260. }
  261. }
  262. return tex;
  263. }
  264. Mesh* Renderer::GetMesh(const std::string & fileName)
  265. {
  266. Mesh* m = nullptr;
  267. auto iter = mMeshes.find(fileName);
  268. if (iter != mMeshes.end())
  269. {
  270. m = iter->second;
  271. }
  272. else
  273. {
  274. m = new Mesh();
  275. if (m->Load(fileName, this))
  276. {
  277. mMeshes.emplace(fileName, m);
  278. }
  279. else
  280. {
  281. delete m;
  282. m = nullptr;
  283. }
  284. }
  285. return m;
  286. }
  287. void Renderer::Draw3DScene(unsigned int framebuffer, const Matrix4& view, const Matrix4& proj, bool lit)
  288. {
  289. // Set the current frame buffer
  290. glBindFramebuffer(GL_FRAMEBUFFER, framebuffer);
  291. // Clear color buffer/depth buffer
  292. glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
  293. glDepthMask(GL_TRUE);
  294. glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
  295. // Draw mesh components
  296. // Enable depth buffering/disable alpha blend
  297. glEnable(GL_DEPTH_TEST);
  298. glDisable(GL_BLEND);
  299. // Set the mesh shader active
  300. mMeshShader->SetActive();
  301. // Update view-projection matrix
  302. mMeshShader->SetMatrixUniform("uViewProj", view * proj);
  303. // Update lighting uniforms
  304. if (lit)
  305. {
  306. SetLightUniforms(mMeshShader, view);
  307. }
  308. for (auto mc : mMeshComps)
  309. {
  310. if (mc->GetVisible())
  311. {
  312. mc->Draw(mMeshShader);
  313. }
  314. }
  315. // Draw any skinned meshes now
  316. mSkinnedShader->SetActive();
  317. // Update view-projection matrix
  318. mSkinnedShader->SetMatrixUniform("uViewProj", view * proj);
  319. // Update lighting uniforms
  320. if (lit)
  321. {
  322. SetLightUniforms(mSkinnedShader, view);
  323. }
  324. for (auto sk : mSkeletalMeshes)
  325. {
  326. if (sk->GetVisible())
  327. {
  328. sk->Draw(mSkinnedShader);
  329. }
  330. }
  331. }
  332. bool Renderer::CreateMirrorTarget()
  333. {
  334. // Generate a frame buffer for the mirror texture
  335. glGenFramebuffers(1, &mMirrorBuffer);
  336. glBindFramebuffer(GL_FRAMEBUFFER, mMirrorBuffer);
  337. // Create the texture we'll use for rendering
  338. int width = static_cast<int>(mScreenWidth);
  339. int height = static_cast<int>(mScreenHeight);
  340. mMirrorTexture = new Texture();
  341. mMirrorTexture->CreateForRendering(width, height, GL_RGB);
  342. // Add a depth buffer to this target
  343. GLuint depthBuffer;
  344. glGenRenderbuffers(1, &depthBuffer);
  345. glBindRenderbuffer(GL_RENDERBUFFER, depthBuffer);
  346. glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT, width, height);
  347. glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, depthBuffer);
  348. // Attach mirror texture as the output target for the frame buffer
  349. glFramebufferTexture(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, mMirrorTexture->GetTextureID(), 0);
  350. // Set the list of buffers to draw to for this frame buffer
  351. GLenum drawBuffers[] = { GL_COLOR_ATTACHMENT0 };
  352. glDrawBuffers(1, drawBuffers);
  353. // Make sure everything worked
  354. if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
  355. {
  356. // If it didn't work, delete the framebuffer,
  357. // unload/delete the texture and return false
  358. glDeleteFramebuffers(1, &mMirrorBuffer);
  359. mMirrorTexture->Unload();
  360. delete mMirrorTexture;
  361. mMirrorTexture = nullptr;
  362. return false;
  363. }
  364. return true;
  365. }
  366. void Renderer::DrawFromGBuffer()
  367. {
  368. // Clear the current framebuffer
  369. glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
  370. glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
  371. // Disable depth testing for the global lighting pass
  372. glDisable(GL_DEPTH_TEST);
  373. // Activate global G-buffer shader
  374. mGGlobalShader->SetActive();
  375. // Activate sprite verts quad
  376. mSpriteVerts->SetActive();
  377. // Set the G-buffer textures to sample
  378. mGBuffer->SetTexturesActive();
  379. // Set the lighting uniforms
  380. SetLightUniforms(mGGlobalShader, mView);
  381. // Draw the triangles
  382. glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, nullptr);
  383. // Copy depth buffer from G-buffer to default frame buffer
  384. glBindFramebuffer(GL_READ_FRAMEBUFFER, mGBuffer->GetBufferID());
  385. int width = static_cast<int>(mScreenWidth);
  386. int height = static_cast<int>(mScreenHeight);
  387. glBlitFramebuffer(0, 0, width, height,
  388. 0, 0, width, height,
  389. GL_DEPTH_BUFFER_BIT, GL_NEAREST);
  390. // Enable depth test, but disable writes to depth buffer
  391. glEnable(GL_DEPTH_TEST);
  392. glDepthMask(GL_FALSE);
  393. // Set the point light shader and mesh as active
  394. mGPointLightShader->SetActive();
  395. mPointLightMesh->GetVertexArray()->SetActive();
  396. // Set the view-projection matrix
  397. mGPointLightShader->SetMatrixUniform("uViewProj",
  398. mView * mProjection);
  399. // Set the G-buffer textures for sampling
  400. mGBuffer->SetTexturesActive();
  401. // The point light color should add to existing color
  402. glEnable(GL_BLEND);
  403. glBlendFunc(GL_ONE, GL_ONE);
  404. // Draw the point lights
  405. for (PointLightComponent* p : mPointLights)
  406. {
  407. p->Draw(mGPointLightShader, mPointLightMesh);
  408. }
  409. }
  410. bool Renderer::LoadShaders()
  411. {
  412. // Create sprite shader
  413. mSpriteShader = new Shader();
  414. if (!mSpriteShader->Load("Shaders/Sprite.vert", "Shaders/Sprite.frag"))
  415. {
  416. return false;
  417. }
  418. mSpriteShader->SetActive();
  419. // Set the view-projection matrix
  420. Matrix4 spriteViewProj = Matrix4::CreateSimpleViewProj(mScreenWidth, mScreenHeight);
  421. mSpriteShader->SetMatrixUniform("uViewProj", spriteViewProj);
  422. // Create basic mesh shader
  423. mMeshShader = new Shader();
  424. if (!mMeshShader->Load("Shaders/Phong.vert", "Shaders/GBufferWrite.frag"))
  425. {
  426. return false;
  427. }
  428. mMeshShader->SetActive();
  429. // Set the view-projection matrix
  430. mView = Matrix4::CreateLookAt(Vector3::Zero, Vector3::UnitX, Vector3::UnitZ);
  431. mProjection = Matrix4::CreatePerspectiveFOV(Math::ToRadians(70.0f),
  432. mScreenWidth, mScreenHeight, 10.0f, 10000.0f);
  433. mMeshShader->SetMatrixUniform("uViewProj", mView * mProjection);
  434. // Create skinned shader
  435. mSkinnedShader = new Shader();
  436. if (!mSkinnedShader->Load("Shaders/Skinned.vert", "Shaders/GBufferWrite.frag"))
  437. {
  438. return false;
  439. }
  440. mSkinnedShader->SetActive();
  441. mSkinnedShader->SetMatrixUniform("uViewProj", mView * mProjection);
  442. // Create shader for drawing from GBuffer (global lighting)
  443. mGGlobalShader = new Shader();
  444. if (!mGGlobalShader->Load("Shaders/GBufferGlobal.vert", "Shaders/GBufferGlobal.frag"))
  445. {
  446. return false;
  447. }
  448. // For the GBuffer, we need to associate each sampler with an index
  449. mGGlobalShader->SetActive();
  450. mGGlobalShader->SetIntUniform("uGDiffuse", 0);
  451. mGGlobalShader->SetIntUniform("uGNormal", 1);
  452. mGGlobalShader->SetIntUniform("uGWorldPos", 2);
  453. // The view projection is just the sprite one
  454. mGGlobalShader->SetMatrixUniform("uViewProj", spriteViewProj);
  455. // The world transform scales to the screen and flips y
  456. Matrix4 gbufferWorld = Matrix4::CreateScale(mScreenWidth, -mScreenHeight,
  457. 1.0f);
  458. mGGlobalShader->SetMatrixUniform("uWorldTransform", gbufferWorld);
  459. // Create a shader for point lights from GBuffer
  460. mGPointLightShader = new Shader();
  461. if (!mGPointLightShader->Load("Shaders/BasicMesh.vert",
  462. "Shaders/GBufferPointLight.frag"))
  463. {
  464. return false;
  465. }
  466. // Set sampler indices
  467. mGPointLightShader->SetActive();
  468. mGPointLightShader->SetIntUniform("uGDiffuse", 0);
  469. mGPointLightShader->SetIntUniform("uGNormal", 1);
  470. mGPointLightShader->SetIntUniform("uGWorldPos", 2);
  471. mGPointLightShader->SetVector2Uniform("uScreenDimensions",
  472. Vector2(mScreenWidth, mScreenHeight));
  473. return true;
  474. }
  475. void Renderer::CreateSpriteVerts()
  476. {
  477. float vertices[] = {
  478. -0.5f, 0.5f, 0.f, 0.f, 0.f, 0.0f, 0.f, 0.f, // top left
  479. 0.5f, 0.5f, 0.f, 0.f, 0.f, 0.0f, 1.f, 0.f, // top right
  480. 0.5f,-0.5f, 0.f, 0.f, 0.f, 0.0f, 1.f, 1.f, // bottom right
  481. -0.5f,-0.5f, 0.f, 0.f, 0.f, 0.0f, 0.f, 1.f // bottom left
  482. };
  483. unsigned int indices[] = {
  484. 0, 1, 2,
  485. 2, 3, 0
  486. };
  487. mSpriteVerts = new VertexArray(vertices, 4, VertexArray::PosNormTex, indices, 6);
  488. }
  489. void Renderer::SetLightUniforms(Shader* shader, const Matrix4& view)
  490. {
  491. // Camera position is from inverted view
  492. Matrix4 invView = view;
  493. invView.Invert();
  494. shader->SetVectorUniform("uCameraPos", invView.GetTranslation());
  495. // Ambient light
  496. shader->SetVectorUniform("uAmbientLight", mAmbientLight);
  497. // Directional light
  498. shader->SetVectorUniform("uDirLight.mDirection",
  499. mDirLight.mDirection);
  500. shader->SetVectorUniform("uDirLight.mDiffuseColor",
  501. mDirLight.mDiffuseColor);
  502. shader->SetVectorUniform("uDirLight.mSpecColor",
  503. mDirLight.mSpecColor);
  504. }
  505. Vector3 Renderer::Unproject(const Vector3& screenPoint) const
  506. {
  507. // Convert screenPoint to device coordinates (between -1 and +1)
  508. Vector3 deviceCoord = screenPoint;
  509. deviceCoord.x /= (mScreenWidth) * 0.5f;
  510. deviceCoord.y /= (mScreenHeight) * 0.5f;
  511. // Transform vector by unprojection matrix
  512. Matrix4 unprojection = mView * mProjection;
  513. unprojection.Invert();
  514. return Vector3::TransformWithPerspDiv(deviceCoord, unprojection);
  515. }
  516. void Renderer::GetScreenDirection(Vector3& outStart, Vector3& outDir) const
  517. {
  518. // Get start point (in center of screen on near plane)
  519. Vector3 screenPoint(0.0f, 0.0f, 0.0f);
  520. outStart = Unproject(screenPoint);
  521. // Get end point (in center of screen, between near and far)
  522. screenPoint.z = 0.9f;
  523. Vector3 end = Unproject(screenPoint);
  524. // Get direction vector
  525. outDir = end - outStart;
  526. outDir.Normalize();
  527. }