Renderer.cpp 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595
  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.txt 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 13)", 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, 0.25f);
  152. // Draw the 3D scene to the G-buffer
  153. Draw3DScene(mGBuffer->GetBufferID(), mView, mProjection, 1.0f, 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,
  288. float viewPortScale, bool lit)
  289. {
  290. // Set the current frame buffer
  291. glBindFramebuffer(GL_FRAMEBUFFER, framebuffer);
  292. // Set viewport size based on scale
  293. glViewport(0, 0,
  294. static_cast<int>(mScreenWidth * viewPortScale),
  295. static_cast<int>(mScreenHeight * viewPortScale)
  296. );
  297. // Clear color buffer/depth buffer
  298. glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
  299. glDepthMask(GL_TRUE);
  300. glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
  301. // Draw mesh components
  302. // Enable depth buffering/disable alpha blend
  303. glEnable(GL_DEPTH_TEST);
  304. glDisable(GL_BLEND);
  305. // Set the mesh shader active
  306. mMeshShader->SetActive();
  307. // Update view-projection matrix
  308. mMeshShader->SetMatrixUniform("uViewProj", view * proj);
  309. // Update lighting uniforms
  310. if (lit)
  311. {
  312. SetLightUniforms(mMeshShader, view);
  313. }
  314. for (auto mc : mMeshComps)
  315. {
  316. if (mc->GetVisible())
  317. {
  318. mc->Draw(mMeshShader);
  319. }
  320. }
  321. // Draw any skinned meshes now
  322. mSkinnedShader->SetActive();
  323. // Update view-projection matrix
  324. mSkinnedShader->SetMatrixUniform("uViewProj", view * proj);
  325. // Update lighting uniforms
  326. if (lit)
  327. {
  328. SetLightUniforms(mSkinnedShader, view);
  329. }
  330. for (auto sk : mSkeletalMeshes)
  331. {
  332. if (sk->GetVisible())
  333. {
  334. sk->Draw(mSkinnedShader);
  335. }
  336. }
  337. }
  338. bool Renderer::CreateMirrorTarget()
  339. {
  340. int width = static_cast<int>(mScreenWidth) / 4;
  341. int height = static_cast<int>(mScreenHeight) / 4;
  342. // Generate a frame buffer for the mirror texture
  343. glGenFramebuffers(1, &mMirrorBuffer);
  344. glBindFramebuffer(GL_FRAMEBUFFER, mMirrorBuffer);
  345. // Create the texture we'll use for rendering
  346. mMirrorTexture = new Texture();
  347. mMirrorTexture->CreateForRendering(width, height, GL_RGB);
  348. // Add a depth buffer to this target
  349. GLuint depthBuffer;
  350. glGenRenderbuffers(1, &depthBuffer);
  351. glBindRenderbuffer(GL_RENDERBUFFER, depthBuffer);
  352. glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT, width, height);
  353. glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, depthBuffer);
  354. // Attach mirror texture as the output target for the frame buffer
  355. glFramebufferTexture(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, mMirrorTexture->GetTextureID(), 0);
  356. // Set the list of buffers to draw to for this frame buffer
  357. GLenum drawBuffers[] = { GL_COLOR_ATTACHMENT0 };
  358. glDrawBuffers(1, drawBuffers);
  359. // Make sure everything worked
  360. if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
  361. {
  362. // If it didn't work, delete the framebuffer,
  363. // unload/delete the texture and return false
  364. glDeleteFramebuffers(1, &mMirrorBuffer);
  365. mMirrorTexture->Unload();
  366. delete mMirrorTexture;
  367. mMirrorTexture = nullptr;
  368. return false;
  369. }
  370. return true;
  371. }
  372. void Renderer::DrawFromGBuffer()
  373. {
  374. // Disable depth testing for the global lighting pass
  375. glDisable(GL_DEPTH_TEST);
  376. // Activate global G-buffer shader
  377. mGGlobalShader->SetActive();
  378. // Activate sprite verts quad
  379. mSpriteVerts->SetActive();
  380. // Set the G-buffer textures to sample
  381. mGBuffer->SetTexturesActive();
  382. // Set the lighting uniforms
  383. SetLightUniforms(mGGlobalShader, mView);
  384. // Draw the triangles
  385. glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, nullptr);
  386. // Copy depth buffer from G-buffer to default frame buffer
  387. glBindFramebuffer(GL_READ_FRAMEBUFFER, mGBuffer->GetBufferID());
  388. int width = static_cast<int>(mScreenWidth);
  389. int height = static_cast<int>(mScreenHeight);
  390. glBlitFramebuffer(0, 0, width, height,
  391. 0, 0, width, height,
  392. GL_DEPTH_BUFFER_BIT, GL_NEAREST);
  393. // Enable depth test, but disable writes to depth buffer
  394. glEnable(GL_DEPTH_TEST);
  395. glDepthMask(GL_FALSE);
  396. // Set the point light shader and mesh as active
  397. mGPointLightShader->SetActive();
  398. mPointLightMesh->GetVertexArray()->SetActive();
  399. // Set the view-projection matrix
  400. mGPointLightShader->SetMatrixUniform("uViewProj",
  401. mView * mProjection);
  402. // Set the G-buffer textures for sampling
  403. mGBuffer->SetTexturesActive();
  404. // The point light color should add to existing color
  405. glEnable(GL_BLEND);
  406. glBlendFunc(GL_ONE, GL_ONE);
  407. // Draw the point lights
  408. for (PointLightComponent* p : mPointLights)
  409. {
  410. p->Draw(mGPointLightShader, mPointLightMesh);
  411. }
  412. }
  413. bool Renderer::LoadShaders()
  414. {
  415. // Create sprite shader
  416. mSpriteShader = new Shader();
  417. if (!mSpriteShader->Load("Shaders/Sprite.vert", "Shaders/Sprite.frag"))
  418. {
  419. return false;
  420. }
  421. mSpriteShader->SetActive();
  422. // Set the view-projection matrix
  423. Matrix4 spriteViewProj = Matrix4::CreateSimpleViewProj(mScreenWidth, mScreenHeight);
  424. mSpriteShader->SetMatrixUniform("uViewProj", spriteViewProj);
  425. // Create basic mesh shader
  426. mMeshShader = new Shader();
  427. if (!mMeshShader->Load("Shaders/Phong.vert", "Shaders/GBufferWrite.frag"))
  428. {
  429. return false;
  430. }
  431. mMeshShader->SetActive();
  432. // Set the view-projection matrix
  433. mView = Matrix4::CreateLookAt(Vector3::Zero, Vector3::UnitX, Vector3::UnitZ);
  434. mProjection = Matrix4::CreatePerspectiveFOV(Math::ToRadians(70.0f),
  435. mScreenWidth, mScreenHeight, 10.0f, 10000.0f);
  436. mMeshShader->SetMatrixUniform("uViewProj", mView * mProjection);
  437. // Create skinned shader
  438. mSkinnedShader = new Shader();
  439. if (!mSkinnedShader->Load("Shaders/Skinned.vert", "Shaders/GBufferWrite.frag"))
  440. {
  441. return false;
  442. }
  443. mSkinnedShader->SetActive();
  444. mSkinnedShader->SetMatrixUniform("uViewProj", mView * mProjection);
  445. // Create shader for drawing from GBuffer (global lighting)
  446. mGGlobalShader = new Shader();
  447. if (!mGGlobalShader->Load("Shaders/GBufferGlobal.vert", "Shaders/GBufferGlobal.frag"))
  448. {
  449. return false;
  450. }
  451. // For the GBuffer, we need to associate each sampler with an index
  452. mGGlobalShader->SetActive();
  453. mGGlobalShader->SetIntUniform("uGDiffuse", 0);
  454. mGGlobalShader->SetIntUniform("uGNormal", 1);
  455. mGGlobalShader->SetIntUniform("uGWorldPos", 2);
  456. // The view projection is just the sprite one
  457. mGGlobalShader->SetMatrixUniform("uViewProj", spriteViewProj);
  458. // The world transform scales to the screen and flips y
  459. Matrix4 gbufferWorld = Matrix4::CreateScale(mScreenWidth, -mScreenHeight,
  460. 1.0f);
  461. mGGlobalShader->SetMatrixUniform("uWorldTransform", gbufferWorld);
  462. // Create a shader for point lights from GBuffer
  463. mGPointLightShader = new Shader();
  464. if (!mGPointLightShader->Load("Shaders/BasicMesh.vert",
  465. "Shaders/GBufferPointLight.frag"))
  466. {
  467. return false;
  468. }
  469. // Set sampler indices
  470. mGPointLightShader->SetActive();
  471. mGPointLightShader->SetIntUniform("uGDiffuse", 0);
  472. mGPointLightShader->SetIntUniform("uGNormal", 1);
  473. mGPointLightShader->SetIntUniform("uGWorldPos", 2);
  474. mGPointLightShader->SetVector2Uniform("uScreenDimensions",
  475. Vector2(mScreenWidth, mScreenHeight));
  476. return true;
  477. }
  478. void Renderer::CreateSpriteVerts()
  479. {
  480. float vertices[] = {
  481. -0.5f, 0.5f, 0.f, 0.f, 0.f, 0.0f, 0.f, 0.f, // top left
  482. 0.5f, 0.5f, 0.f, 0.f, 0.f, 0.0f, 1.f, 0.f, // top right
  483. 0.5f,-0.5f, 0.f, 0.f, 0.f, 0.0f, 1.f, 1.f, // bottom right
  484. -0.5f,-0.5f, 0.f, 0.f, 0.f, 0.0f, 0.f, 1.f // bottom left
  485. };
  486. unsigned int indices[] = {
  487. 0, 1, 2,
  488. 2, 3, 0
  489. };
  490. mSpriteVerts = new VertexArray(vertices, 4, VertexArray::PosNormTex, indices, 6);
  491. }
  492. void Renderer::SetLightUniforms(Shader* shader, const Matrix4& view)
  493. {
  494. // Camera position is from inverted view
  495. Matrix4 invView = view;
  496. invView.Invert();
  497. shader->SetVectorUniform("uCameraPos", invView.GetTranslation());
  498. // Ambient light
  499. shader->SetVectorUniform("uAmbientLight", mAmbientLight);
  500. // Directional light
  501. shader->SetVectorUniform("uDirLight.mDirection",
  502. mDirLight.mDirection);
  503. shader->SetVectorUniform("uDirLight.mDiffuseColor",
  504. mDirLight.mDiffuseColor);
  505. shader->SetVectorUniform("uDirLight.mSpecColor",
  506. mDirLight.mSpecColor);
  507. }
  508. Vector3 Renderer::Unproject(const Vector3& screenPoint) const
  509. {
  510. // Convert screenPoint to device coordinates (between -1 and +1)
  511. Vector3 deviceCoord = screenPoint;
  512. deviceCoord.x /= (mScreenWidth) * 0.5f;
  513. deviceCoord.y /= (mScreenHeight) * 0.5f;
  514. // Transform vector by unprojection matrix
  515. Matrix4 unprojection = mView * mProjection;
  516. unprojection.Invert();
  517. return Vector3::TransformWithPerspDiv(deviceCoord, unprojection);
  518. }
  519. void Renderer::GetScreenDirection(Vector3& outStart, Vector3& outDir) const
  520. {
  521. // Get start point (in center of screen on near plane)
  522. Vector3 screenPoint(0.0f, 0.0f, 0.0f);
  523. outStart = Unproject(screenPoint);
  524. // Get end point (in center of screen, between near and far)
  525. screenPoint.z = 0.9f;
  526. Vector3 end = Unproject(screenPoint);
  527. // Get direction vector
  528. outDir = end - outStart;
  529. outDir.Normalize();
  530. }