Renderer.cpp 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584
  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. mSprites.emplace_back(sprite);
  186. // Resort sprites by draw order
  187. std::sort(mSprites.begin(), mSprites.end(), [](SpriteComponent* a, SpriteComponent* b) {
  188. return a->GetDrawOrder() < b->GetDrawOrder();
  189. });
  190. }
  191. void Renderer::RemoveSprite(SpriteComponent* sprite)
  192. {
  193. auto iter = std::find(mSprites.begin(), mSprites.end(), sprite);
  194. mSprites.erase(iter);
  195. }
  196. void Renderer::AddMeshComp(MeshComponent* mesh)
  197. {
  198. if (mesh->GetIsSkeletal())
  199. {
  200. SkeletalMeshComponent* sk = static_cast<SkeletalMeshComponent*>(mesh);
  201. mSkeletalMeshes.emplace_back(sk);
  202. }
  203. else
  204. {
  205. mMeshComps.emplace_back(mesh);
  206. }
  207. }
  208. void Renderer::RemoveMeshComp(MeshComponent* mesh)
  209. {
  210. if (mesh->GetIsSkeletal())
  211. {
  212. SkeletalMeshComponent* sk = static_cast<SkeletalMeshComponent*>(mesh);
  213. auto iter = std::find(mSkeletalMeshes.begin(), mSkeletalMeshes.end(), sk);
  214. mSkeletalMeshes.erase(iter);
  215. }
  216. else
  217. {
  218. auto iter = std::find(mMeshComps.begin(), mMeshComps.end(), mesh);
  219. mMeshComps.erase(iter);
  220. }
  221. }
  222. void Renderer::AddPointLight(PointLightComponent* light)
  223. {
  224. mPointLights.emplace_back(light);
  225. }
  226. void Renderer::RemovePointLight(PointLightComponent* light)
  227. {
  228. auto iter = std::find(mPointLights.begin(), mPointLights.end(), light);
  229. mPointLights.erase(iter);
  230. }
  231. Texture* Renderer::GetTexture(const std::string& fileName)
  232. {
  233. Texture* tex = nullptr;
  234. auto iter = mTextures.find(fileName);
  235. if (iter != mTextures.end())
  236. {
  237. tex = iter->second;
  238. }
  239. else
  240. {
  241. tex = new Texture();
  242. if (tex->Load(fileName))
  243. {
  244. mTextures.emplace(fileName, tex);
  245. }
  246. else
  247. {
  248. delete tex;
  249. tex = nullptr;
  250. }
  251. }
  252. return tex;
  253. }
  254. Mesh* Renderer::GetMesh(const std::string & fileName)
  255. {
  256. Mesh* m = nullptr;
  257. auto iter = mMeshes.find(fileName);
  258. if (iter != mMeshes.end())
  259. {
  260. m = iter->second;
  261. }
  262. else
  263. {
  264. m = new Mesh();
  265. if (m->Load(fileName, this))
  266. {
  267. mMeshes.emplace(fileName, m);
  268. }
  269. else
  270. {
  271. delete m;
  272. m = nullptr;
  273. }
  274. }
  275. return m;
  276. }
  277. void Renderer::Draw3DScene(unsigned int framebuffer, const Matrix4& view, const Matrix4& proj,
  278. float viewPortScale, bool lit)
  279. {
  280. // Set the current frame buffer
  281. glBindFramebuffer(GL_FRAMEBUFFER, framebuffer);
  282. // Set viewport size based on scale
  283. glViewport(0, 0,
  284. static_cast<int>(mScreenWidth * viewPortScale),
  285. static_cast<int>(mScreenHeight * viewPortScale)
  286. );
  287. // Clear color buffer/depth buffer
  288. glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
  289. glDepthMask(GL_TRUE);
  290. glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
  291. // Draw mesh components
  292. // Enable depth buffering/disable alpha blend
  293. glEnable(GL_DEPTH_TEST);
  294. glDisable(GL_BLEND);
  295. // Set the mesh shader active
  296. mMeshShader->SetActive();
  297. // Update view-projection matrix
  298. mMeshShader->SetMatrixUniform("uViewProj", view * proj);
  299. // Update lighting uniforms
  300. if (lit)
  301. {
  302. SetLightUniforms(mMeshShader, view);
  303. }
  304. for (auto mc : mMeshComps)
  305. {
  306. if (mc->GetVisible())
  307. {
  308. mc->Draw(mMeshShader);
  309. }
  310. }
  311. // Draw any skinned meshes now
  312. mSkinnedShader->SetActive();
  313. // Update view-projection matrix
  314. mSkinnedShader->SetMatrixUniform("uViewProj", view * proj);
  315. // Update lighting uniforms
  316. if (lit)
  317. {
  318. SetLightUniforms(mSkinnedShader, view);
  319. }
  320. for (auto sk : mSkeletalMeshes)
  321. {
  322. if (sk->GetVisible())
  323. {
  324. sk->Draw(mSkinnedShader);
  325. }
  326. }
  327. }
  328. bool Renderer::CreateMirrorTarget()
  329. {
  330. int width = static_cast<int>(mScreenWidth) / 4;
  331. int height = static_cast<int>(mScreenHeight) / 4;
  332. // Generate a frame buffer for the mirror texture
  333. glGenFramebuffers(1, &mMirrorBuffer);
  334. glBindFramebuffer(GL_FRAMEBUFFER, mMirrorBuffer);
  335. // Create the texture we'll use for rendering
  336. mMirrorTexture = new Texture();
  337. mMirrorTexture->CreateForRendering(width, height, GL_RGB);
  338. // Add a depth buffer to this target
  339. GLuint depthBuffer;
  340. glGenRenderbuffers(1, &depthBuffer);
  341. glBindRenderbuffer(GL_RENDERBUFFER, depthBuffer);
  342. glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT, width, height);
  343. glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, depthBuffer);
  344. // Attach mirror texture as the output target for the frame buffer
  345. glFramebufferTexture(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, mMirrorTexture->GetTextureID(), 0);
  346. // Set the list of buffers to draw to for this frame buffer
  347. GLenum drawBuffers[] = { GL_COLOR_ATTACHMENT0 };
  348. glDrawBuffers(1, drawBuffers);
  349. // Make sure everything worked
  350. if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
  351. {
  352. // If it didn't work, delete the framebuffer,
  353. // unload/delete the texture and return false
  354. glDeleteFramebuffers(1, &mMirrorBuffer);
  355. mMirrorTexture->Unload();
  356. delete mMirrorTexture;
  357. mMirrorTexture = nullptr;
  358. return false;
  359. }
  360. return true;
  361. }
  362. void Renderer::DrawFromGBuffer()
  363. {
  364. // Disable depth testing for the global lighting pass
  365. glDisable(GL_DEPTH_TEST);
  366. // Activate global G-buffer shader
  367. mGGlobalShader->SetActive();
  368. // Activate sprite verts quad
  369. mSpriteVerts->SetActive();
  370. // Set the G-buffer textures to sample
  371. mGBuffer->SetTexturesActive();
  372. // Set the lighting uniforms
  373. SetLightUniforms(mGGlobalShader, mView);
  374. // Draw the triangles
  375. glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, nullptr);
  376. // Copy depth buffer from G-buffer to default frame buffer
  377. glBindFramebuffer(GL_READ_FRAMEBUFFER, mGBuffer->GetBufferID());
  378. int width = static_cast<int>(mScreenWidth);
  379. int height = static_cast<int>(mScreenHeight);
  380. glBlitFramebuffer(0, 0, width, height,
  381. 0, 0, width, height,
  382. GL_DEPTH_BUFFER_BIT, GL_NEAREST);
  383. // Enable depth test, but disable writes to depth buffer
  384. glEnable(GL_DEPTH_TEST);
  385. glDepthMask(GL_FALSE);
  386. // Set the point light shader and mesh as active
  387. mGPointLightShader->SetActive();
  388. mPointLightMesh->GetVertexArray()->SetActive();
  389. // Set the view-projeciton matrix
  390. mGPointLightShader->SetMatrixUniform("uViewProj",
  391. mView * mProjection);
  392. // Set the G-buffer textures for sampling
  393. mGBuffer->SetTexturesActive();
  394. // The point light color should add to existing color
  395. glEnable(GL_BLEND);
  396. glBlendFunc(GL_ONE, GL_ONE);
  397. // Draw the point lights
  398. for (PointLightComponent* p : mPointLights)
  399. {
  400. p->Draw(mGPointLightShader, mPointLightMesh);
  401. }
  402. }
  403. bool Renderer::LoadShaders()
  404. {
  405. // Create sprite shader
  406. mSpriteShader = new Shader();
  407. if (!mSpriteShader->Load("Shaders/Sprite.vert", "Shaders/Sprite.frag"))
  408. {
  409. return false;
  410. }
  411. mSpriteShader->SetActive();
  412. // Set the view-projection matrix
  413. Matrix4 spriteViewProj = Matrix4::CreateSimpleViewProj(mScreenWidth, mScreenHeight);
  414. mSpriteShader->SetMatrixUniform("uViewProj", spriteViewProj);
  415. // Create basic mesh shader
  416. mMeshShader = new Shader();
  417. if (!mMeshShader->Load("Shaders/Phong.vert", "Shaders/GBufferWrite.frag"))
  418. {
  419. return false;
  420. }
  421. mMeshShader->SetActive();
  422. // Set the view-projection matrix
  423. mView = Matrix4::CreateLookAt(Vector3::Zero, Vector3::UnitX, Vector3::UnitZ);
  424. mProjection = Matrix4::CreatePerspectiveFOV(Math::ToRadians(70.0f),
  425. mScreenWidth, mScreenHeight, 10.0f, 10000.0f);
  426. mMeshShader->SetMatrixUniform("uViewProj", mView * mProjection);
  427. // Create skinned shader
  428. mSkinnedShader = new Shader();
  429. if (!mSkinnedShader->Load("Shaders/Skinned.vert", "Shaders/GBufferWrite.frag"))
  430. {
  431. return false;
  432. }
  433. mSkinnedShader->SetActive();
  434. mSkinnedShader->SetMatrixUniform("uViewProj", mView * mProjection);
  435. // Create shader for drawing from GBuffer (global lighting)
  436. mGGlobalShader = new Shader();
  437. if (!mGGlobalShader->Load("Shaders/GBufferGlobal.vert", "Shaders/GBufferGlobal.frag"))
  438. {
  439. return false;
  440. }
  441. // For the GBuffer, we need to associate each sampler with an index
  442. mGGlobalShader->SetActive();
  443. mGGlobalShader->SetIntUniform("uGDiffuse", 0);
  444. mGGlobalShader->SetIntUniform("uGNormal", 1);
  445. mGGlobalShader->SetIntUniform("uGWorldPos", 2);
  446. // The view projection is just the sprite one
  447. mGGlobalShader->SetMatrixUniform("uViewProj", spriteViewProj);
  448. // The world transform scales to the screen and flips y
  449. Matrix4 gbufferWorld = Matrix4::CreateScale(mScreenWidth, -mScreenHeight,
  450. 1.0f);
  451. mGGlobalShader->SetMatrixUniform("uWorldTransform", gbufferWorld);
  452. // Create a shader for point lights from GBuffer
  453. mGPointLightShader = new Shader();
  454. if (!mGPointLightShader->Load("Shaders/BasicMesh.vert",
  455. "Shaders/GBufferPointLight.frag"))
  456. {
  457. return false;
  458. }
  459. // Set sampler indices
  460. mGPointLightShader->SetActive();
  461. mGPointLightShader->SetIntUniform("uGDiffuse", 0);
  462. mGPointLightShader->SetIntUniform("uGNormal", 1);
  463. mGPointLightShader->SetIntUniform("uGWorldPos", 2);
  464. mGPointLightShader->SetVector2Uniform("uScreenDimensions",
  465. Vector2(mScreenWidth, mScreenHeight));
  466. return true;
  467. }
  468. void Renderer::CreateSpriteVerts()
  469. {
  470. float vertices[] = {
  471. -0.5f, 0.5f, 0.f, 0.f, 0.f, 0.0f, 0.f, 0.f, // top left
  472. 0.5f, 0.5f, 0.f, 0.f, 0.f, 0.0f, 1.f, 0.f, // top right
  473. 0.5f,-0.5f, 0.f, 0.f, 0.f, 0.0f, 1.f, 1.f, // bottom right
  474. -0.5f,-0.5f, 0.f, 0.f, 0.f, 0.0f, 0.f, 1.f // bottom left
  475. };
  476. unsigned int indices[] = {
  477. 0, 1, 2,
  478. 2, 3, 0
  479. };
  480. mSpriteVerts = new VertexArray(vertices, 4, VertexArray::PosNormTex, indices, 6);
  481. }
  482. void Renderer::SetLightUniforms(Shader* shader, const Matrix4& view)
  483. {
  484. // Camera position is from inverted view
  485. Matrix4 invView = view;
  486. invView.Invert();
  487. shader->SetVectorUniform("uCameraPos", invView.GetTranslation());
  488. // Ambient light
  489. shader->SetVectorUniform("uAmbientLight", mAmbientLight);
  490. // Directional light
  491. shader->SetVectorUniform("uDirLight.mDirection",
  492. mDirLight.mDirection);
  493. shader->SetVectorUniform("uDirLight.mDiffuseColor",
  494. mDirLight.mDiffuseColor);
  495. shader->SetVectorUniform("uDirLight.mSpecColor",
  496. mDirLight.mSpecColor);
  497. }
  498. Vector3 Renderer::Unproject(const Vector3& screenPoint) const
  499. {
  500. // Convert screenPoint to device coordinates (between -1 and +1)
  501. Vector3 deviceCoord = screenPoint;
  502. deviceCoord.x /= (mScreenWidth) * 0.5f;
  503. deviceCoord.y /= (mScreenHeight) * 0.5f;
  504. // Transform vector by unprojection matrix
  505. Matrix4 unprojection = mView * mProjection;
  506. unprojection.Invert();
  507. return Vector3::TransformWithPerspDiv(deviceCoord, unprojection);
  508. }
  509. void Renderer::GetScreenDirection(Vector3& outStart, Vector3& outDir) const
  510. {
  511. // Get start point (in center of screen on near plane)
  512. Vector3 screenPoint(0.0f, 0.0f, 0.0f);
  513. outStart = Unproject(screenPoint);
  514. // Get end point (in center of screen, between near and far)
  515. screenPoint.z = 0.9f;
  516. Vector3 end = Unproject(screenPoint);
  517. // Get direction vector
  518. outDir = end - outStart;
  519. outDir.Normalize();
  520. }