OGLES2ShadowMapping.cpp 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767
  1. /******************************************************************************
  2. @File OGLES2ShadowMapping.cpp
  3. @Title Introducing the POD 3D file format
  4. @Version
  5. @Copyright Copyright (C) Imagination Technologies Limited.
  6. @Platform Independent
  7. @Description Shows how to load POD files and play the animation with basic
  8. lighting
  9. ******************************************************************************/
  10. #include <string.h>
  11. #include "PVRShell.h"
  12. #include "OGLES2Tools.h"
  13. /******************************************************************************
  14. Defines
  15. ******************************************************************************/
  16. // Index to bind the attributes to vertex shaders
  17. #define VERTEX_ARRAY 0
  18. #define NORMAL_ARRAY 1
  19. #define TEXCOORD_ARRAY 2
  20. /******************************************************************************
  21. Consts
  22. ******************************************************************************/
  23. // Camera constants. Used for making the projection matrix
  24. const float g_fCameraNear = 5.0f;
  25. const float g_fCameraFar = 400.0f;
  26. // Const for the shadow map texture size
  27. const unsigned int m_ui32ShadowMapSize = 512;
  28. /******************************************************************************
  29. Content file names
  30. ******************************************************************************/
  31. // Source and binary shaders
  32. const char c_szFragShaderSrcFile[] = "FragShader.fsh";
  33. const char c_szFragShaderBinFile[] = "FragShader.fsc";
  34. const char c_szVertShaderSrcFile[] = "VertShader.vsh";
  35. const char c_szVertShaderBinFile[] = "VertShader.vsc";
  36. const char c_szShadowMapppingFragSrcFile[] = "ShadowFragShader.fsh";
  37. const char c_szShadowMapppingFragBinFile[] = "ShadowFragShader.fsc";
  38. const char c_szShadowMapppingVertSrcFile[] = "ShadowVertShader.vsh";
  39. const char c_szShadowMapppingVertBinFile[] = "ShadowVertShader.vsc";
  40. // POD scene files
  41. const char c_szSceneFile[] = "Scene.pod";
  42. const char c_szMaskTex[] = "Mask.pvr";
  43. const char c_szTableCoverTex[] = "TableCover.pvr";
  44. const char c_szTorusTex[] = "Torus.pvr";
  45. /*!****************************************************************************
  46. Class implementing the PVRShell functions.
  47. ******************************************************************************/
  48. class OGLES2ShadowMapping : public PVRShell
  49. {
  50. // Print3D class used to display text
  51. CPVRTPrint3D m_Print3D;
  52. // 3D Model
  53. CPVRTModelPOD m_Scene;
  54. // OpenGL handles for shaders, textures and VBOs
  55. GLuint m_uiSimpleVertShader;
  56. GLuint m_uiSimpleFragShader;
  57. GLuint m_uiShadowVertShader;
  58. GLuint m_uiShadowFragShader;
  59. GLuint* m_puiVbo;
  60. GLuint* m_puiIndexVbo;
  61. GLuint* m_puiTextureIDs;
  62. GLuint m_uiMask;
  63. GLuint m_uiTableCover;
  64. GLuint m_uiTorus;
  65. GLuint m_uiShadowMapTexture;
  66. GLuint m_uiFrameBufferObject;
  67. float m_fLightDistance;
  68. float m_fLightAngle;
  69. // Group shader programs and their uniform locations together
  70. struct
  71. {
  72. GLuint uiId;
  73. GLuint uiLightDirLoc;
  74. GLuint uiProjectionMatrixLoc;
  75. GLuint uiTexProjMatrixLoc;
  76. GLuint uiModelViewMatrixLoc;
  77. }
  78. m_ShadowShaderProgram;
  79. struct
  80. {
  81. GLuint uiId;
  82. GLuint uiModelViewMatrixLoc;
  83. GLuint uiProjectionMatrixLoc;
  84. }
  85. m_SimpleShaderProgram;
  86. PVRTVec4 m_vLightDirection;
  87. PVRTVec3 m_vLightPosition;
  88. PVRTMat4 m_View, m_Projection;
  89. PVRTMat4 m_LightProjection, m_LightView;
  90. PVRTMat4 m_BiasMatrix;
  91. // Screen orientation variable
  92. bool m_bRotate;
  93. public:
  94. virtual bool InitApplication();
  95. virtual bool InitView();
  96. virtual bool ReleaseView();
  97. virtual bool QuitApplication();
  98. virtual bool RenderScene();
  99. bool LoadTextures(CPVRTString* pErrorStr);
  100. bool LoadShaders(CPVRTString* pErrorStr);
  101. bool LoadVbos(CPVRTString* pErrorStr);
  102. void SetUpMatrices();
  103. void DrawSceneWithShadow(PVRTMat4 viewMat);
  104. void DrawMesh(int i32NodeIndex);
  105. void RenderWorld();
  106. };
  107. /*!****************************************************************************
  108. @Function LoadTextures
  109. @Output pErrorStr A CPVRTString describing the error on failure
  110. @Return bool true if no error occured
  111. @Description Loads the textures required for this training course
  112. ******************************************************************************/
  113. bool OGLES2ShadowMapping::LoadTextures(CPVRTString* const pErrorStr)
  114. {
  115. /*
  116. Loads the textures.
  117. For a more detailed explanation, see Texturing and IntroducingPVRTools
  118. */
  119. /*
  120. Initialises an array to lookup the textures
  121. for each material in the scene.
  122. */
  123. m_puiTextureIDs = new GLuint[m_Scene.nNumMaterial];
  124. if(!m_puiTextureIDs)
  125. {
  126. *pErrorStr = "ERROR: Insufficient memory.";
  127. return false;
  128. }
  129. if(PVRTTextureLoadFromPVR(c_szTableCoverTex, &m_uiTableCover) != PVR_SUCCESS)
  130. return false;
  131. if(PVRTTextureLoadFromPVR(c_szTorusTex, &m_uiTorus) != PVR_SUCCESS)
  132. return false;
  133. if(PVRTTextureLoadFromPVR(c_szMaskTex, &m_uiMask) != PVR_SUCCESS)
  134. return false;
  135. for(unsigned int i = 0; i < m_Scene.nNumMaterial; ++i)
  136. {
  137. m_puiTextureIDs[i] = 0;
  138. SPODMaterial* pMaterial = &m_Scene.pMaterial[i];
  139. if(!strcmp(pMaterial->pszName, "Material #1"))
  140. m_puiTextureIDs[i] = m_uiTableCover;
  141. else if(!strcmp(pMaterial->pszName, "Material #2"))
  142. m_puiTextureIDs[i] = m_uiTorus;
  143. else
  144. m_puiTextureIDs[i] = m_uiMask;
  145. }
  146. //Create the shadow map texture
  147. glGenTextures(1, &m_uiShadowMapTexture);
  148. glBindTexture(GL_TEXTURE_2D, m_uiShadowMapTexture);
  149. // Create the depth texture.
  150. glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT, m_ui32ShadowMapSize, m_ui32ShadowMapSize, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, NULL);
  151. // Set the textures parameters
  152. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
  153. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
  154. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
  155. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
  156. return true;
  157. }
  158. /*!****************************************************************************
  159. @Function SetUpMatrices
  160. @Description Creates the view and projection matrices for the light and camera
  161. ******************************************************************************/
  162. void OGLES2ShadowMapping::SetUpMatrices()
  163. {
  164. PVRTVec3 vFrom = PVRTVec3(-130.0f, 130.0f, -130.0f ),
  165. vTo = PVRTVec3( 0, 10, 0 ),
  166. vUp = PVRTVec3( 0, 1, 0 );
  167. float fFOV= 0.78539819f;
  168. m_BiasMatrix = PVRTMat4(0.5f, 0.0f, 0.0f, 0.0f,
  169. 0.0f, 0.5f, 0.0f, 0.0f,
  170. 0.0f, 0.0f, 0.5f, 0.0f,
  171. 0.5f, 0.5f, 0.5f, 1.0f);
  172. bool bRotate = PVRShellGet(prefIsRotated) && PVRShellGet(prefFullScreen);
  173. m_Projection = PVRTMat4::PerspectiveFovRH(fFOV, (float)PVRShellGet(prefWidth)/(float)PVRShellGet(prefHeight), g_fCameraNear, g_fCameraFar, PVRTMat4::OGL, bRotate);
  174. m_View = PVRTMat4::LookAtRH(vFrom, vTo, vUp);
  175. m_LightProjection = PVRTMat4::PerspectiveFovRH(fFOV, 1.0f, 70.0f, 270.0f, PVRTMat4::OGL, m_bRotate);
  176. m_LightView = PVRTMat4::LookAtRH(m_vLightPosition, vTo, vUp);
  177. }
  178. /*!****************************************************************************
  179. @Function LoadShaders
  180. @Output pErrorStr A string describing the error on failure
  181. @Return bool true if no error occured
  182. @Description Loads and compiles the shaders and links the shader programs
  183. required for this training course
  184. ******************************************************************************/
  185. bool OGLES2ShadowMapping::LoadShaders(CPVRTString* pErrorStr)
  186. {
  187. const char* aszAttribs[] = { "inVertex", "inNormal", "inTexCoord" };
  188. /*
  189. Load and compile the shaders from files.
  190. Binary shaders are tried first, source shaders
  191. are used as fallback.
  192. */
  193. if(PVRTShaderLoadFromFile(
  194. c_szVertShaderBinFile, c_szVertShaderSrcFile, GL_VERTEX_SHADER, GL_SGX_BINARY_IMG, &m_uiSimpleVertShader, pErrorStr) != PVR_SUCCESS)
  195. {
  196. return false;
  197. }
  198. if(PVRTShaderLoadFromFile(
  199. c_szFragShaderBinFile, c_szFragShaderSrcFile, GL_FRAGMENT_SHADER, GL_SGX_BINARY_IMG, &m_uiSimpleFragShader, pErrorStr) != PVR_SUCCESS)
  200. {
  201. return false;
  202. }
  203. if(PVRTCreateProgram(&m_SimpleShaderProgram.uiId, m_uiSimpleVertShader, m_uiSimpleFragShader, aszAttribs, 3, pErrorStr) != PVR_SUCCESS)
  204. {
  205. PVRShellSet(prefExitMessage, pErrorStr->c_str());
  206. return false;
  207. }
  208. m_SimpleShaderProgram.uiModelViewMatrixLoc = glGetUniformLocation(m_SimpleShaderProgram.uiId, "ModelViewMatrix");
  209. m_SimpleShaderProgram.uiProjectionMatrixLoc = glGetUniformLocation(m_SimpleShaderProgram.uiId, "ProjectionMatrix");
  210. if(PVRTShaderLoadFromFile(
  211. c_szShadowMapppingVertBinFile, c_szShadowMapppingVertSrcFile, GL_VERTEX_SHADER, GL_SGX_BINARY_IMG, &m_uiShadowVertShader, pErrorStr) != PVR_SUCCESS)
  212. {
  213. return false;
  214. }
  215. if(PVRTShaderLoadFromFile(
  216. c_szShadowMapppingFragBinFile, c_szShadowMapppingFragSrcFile, GL_FRAGMENT_SHADER, GL_SGX_BINARY_IMG, &m_uiShadowFragShader, pErrorStr) != PVR_SUCCESS)
  217. {
  218. return false;
  219. }
  220. if(PVRTCreateProgram(&m_ShadowShaderProgram.uiId, m_uiShadowVertShader, m_uiShadowFragShader, aszAttribs, 3, pErrorStr) != PVR_SUCCESS)
  221. {
  222. PVRShellSet(prefExitMessage, pErrorStr->c_str());
  223. return false;
  224. }
  225. m_ShadowShaderProgram.uiTexProjMatrixLoc = glGetUniformLocation(m_ShadowShaderProgram.uiId, "TexProjectionMatrix");
  226. m_ShadowShaderProgram.uiModelViewMatrixLoc = glGetUniformLocation(m_ShadowShaderProgram.uiId, "ModelViewMatrix");
  227. m_ShadowShaderProgram.uiProjectionMatrixLoc = glGetUniformLocation(m_ShadowShaderProgram.uiId, "ProjectionMatrix");
  228. m_ShadowShaderProgram.uiLightDirLoc = glGetUniformLocation(m_ShadowShaderProgram.uiId, "LightDirection");
  229. glUniform1i(glGetUniformLocation(m_ShadowShaderProgram.uiId, "sShadow"), 0);
  230. glUniform1i(glGetUniformLocation(m_ShadowShaderProgram.uiId, "sTexture"), 1);
  231. return true;
  232. }
  233. /*!****************************************************************************
  234. @Function LoadVbos
  235. @Description Loads the mesh data required for this training course into
  236. vertex buffer objects
  237. ******************************************************************************/
  238. bool OGLES2ShadowMapping::LoadVbos(CPVRTString* pErrorStr)
  239. {
  240. if(!m_Scene.pMesh[0].pInterleaved)
  241. {
  242. *pErrorStr = "ERROR: IntroducingPOD requires the pod data to be interleaved. Please re-export with the interleaved option enabled.";
  243. return false;
  244. }
  245. if (!m_puiVbo) m_puiVbo = new GLuint[m_Scene.nNumMesh];
  246. if (!m_puiIndexVbo) m_puiIndexVbo = new GLuint[m_Scene.nNumMesh];
  247. /*
  248. Load vertex data of all meshes in the scene into VBOs
  249. The meshes have been exported with the "Interleave Vectors" option,
  250. so all data is interleaved in the buffer at pMesh->pInterleaved.
  251. Interleaving data improves the memory access pattern and cache efficiency,
  252. thus it can be read faster by the hardware.
  253. */
  254. glGenBuffers(m_Scene.nNumMesh, m_puiVbo);
  255. for (unsigned int i = 0; i < m_Scene.nNumMesh; ++i)
  256. {
  257. // Load vertex data into buffer object
  258. SPODMesh& Mesh = m_Scene.pMesh[i];
  259. unsigned int uiSize = Mesh.nNumVertex * Mesh.sVertex.nStride;
  260. glBindBuffer(GL_ARRAY_BUFFER, m_puiVbo[i]);
  261. glBufferData(GL_ARRAY_BUFFER, uiSize, Mesh.pInterleaved, GL_STATIC_DRAW);
  262. // Load index data into buffer object if available
  263. m_puiIndexVbo[i] = 0;
  264. if (Mesh.sFaces.pData)
  265. {
  266. glGenBuffers(1, &m_puiIndexVbo[i]);
  267. uiSize = PVRTModelPODCountIndices(Mesh) * sizeof(GLshort);
  268. glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_puiIndexVbo[i]);
  269. glBufferData(GL_ELEMENT_ARRAY_BUFFER, uiSize, Mesh.sFaces.pData, GL_STATIC_DRAW);
  270. }
  271. }
  272. glBindBuffer(GL_ARRAY_BUFFER, 0);
  273. glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
  274. return true;
  275. }
  276. /*!****************************************************************************
  277. @Function InitApplication
  278. @Return bool true if no error occured
  279. @Description Code in InitApplication() will be called by PVRShell once per
  280. run, before the rendering context is created.
  281. Used to initialize variables that are not dependant on it
  282. (e.g. external modules, loading meshes, etc.)
  283. If the rendering context is lost, InitApplication() will
  284. not be called again.
  285. ******************************************************************************/
  286. bool OGLES2ShadowMapping::InitApplication()
  287. {
  288. m_puiVbo = 0;
  289. m_puiIndexVbo = 0;
  290. m_puiTextureIDs = 0;
  291. // Get and set the read path for content files
  292. CPVRTResourceFile::SetReadPath((char*)PVRShellGet(prefReadPath));
  293. // Load the scene
  294. if (m_Scene.ReadFromFile(c_szSceneFile) != PVR_SUCCESS)
  295. {
  296. PVRShellSet(prefExitMessage, "ERROR: Couldn't load the .pod file\n");
  297. return false;
  298. }
  299. m_vLightPosition.x = 0.f;
  300. m_vLightPosition.y = 90.f;
  301. m_vLightPosition.z = 0.f;
  302. m_vLightDirection.x = -m_vLightPosition.x;
  303. m_vLightDirection.y = -m_vLightPosition.y;
  304. m_vLightDirection.z = -m_vLightPosition.z;
  305. m_vLightDirection.w = 1.0f;
  306. // Specify the light distance from origin. This should be at a distance to fit everything into the viewport
  307. // when rendering from the lights POV.
  308. m_fLightDistance = 100.0f;
  309. m_fLightAngle = PVRT_PI;
  310. return true;
  311. }
  312. /*!****************************************************************************
  313. @Function QuitApplication
  314. @Return bool true if no error occured
  315. @Description Code in QuitApplication() will be called by PVRShell once per
  316. run, just before exiting the program.
  317. If the rendering context is lost, QuitApplication() will
  318. not be called.
  319. ******************************************************************************/
  320. bool OGLES2ShadowMapping::QuitApplication()
  321. {
  322. // Free the memory allocated for the scene
  323. m_Scene.Destroy();
  324. delete [] m_puiVbo;
  325. delete [] m_puiIndexVbo;
  326. return true;
  327. }
  328. /*!****************************************************************************
  329. @Function InitView
  330. @Return bool true if no error occured
  331. @Description Code in InitView() will be called by PVRShell upon
  332. initialization or after a change in the rendering context.
  333. Used to initialize variables that are dependant on the rendering
  334. context (e.g. textures, vertex buffers, etc.)
  335. ******************************************************************************/
  336. bool OGLES2ShadowMapping::InitView()
  337. {
  338. CPVRTString ErrorStr;
  339. if(!CPVRTgles2Ext::IsGLExtensionSupported("GL_OES_depth_texture"))
  340. {
  341. PVRShellSet(prefExitMessage, "Error: Unable to run this training course as it requires extension 'GL_OES_depth_texture'");
  342. return false;
  343. }
  344. m_bRotate = PVRShellGet(prefIsRotated) && PVRShellGet(prefFullScreen);
  345. // Initialize VBO data
  346. if(!LoadVbos(&ErrorStr))
  347. {
  348. PVRShellSet(prefExitMessage, ErrorStr.c_str());
  349. return false;
  350. }
  351. // Load textures
  352. if (!LoadTextures(&ErrorStr))
  353. {
  354. PVRShellSet(prefExitMessage, ErrorStr.c_str());
  355. return false;
  356. }
  357. // Load and compile the shaders & link programs
  358. if (!LoadShaders(&ErrorStr))
  359. {
  360. PVRShellSet(prefExitMessage, ErrorStr.c_str());
  361. return false;
  362. }
  363. // Create a frame buffer with only the depth buffer attached
  364. glGenFramebuffers(1, &m_uiFrameBufferObject);
  365. glBindFramebuffer(GL_FRAMEBUFFER, m_uiFrameBufferObject);
  366. glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, m_uiShadowMapTexture, 0);
  367. /*if(glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
  368. {
  369. PVRShellSet(prefExitMessage, "ERROR: Frame buffer not set up correctly\n");
  370. return false;
  371. }*/
  372. glBindFramebuffer(GL_FRAMEBUFFER, 0);
  373. // Initialize Print3D
  374. if(m_Print3D.SetTextures(0,PVRShellGet(prefWidth),PVRShellGet(prefHeight),m_bRotate) != PVR_SUCCESS)
  375. {
  376. PVRShellSet(prefExitMessage, "ERROR: Cannot initialise Print3D\n");
  377. return false;
  378. }
  379. // Use a nice bright blue as clear colour
  380. glClearColor(0.6f, 0.8f, 1.0f, 1.0f);
  381. return true;
  382. }
  383. /*!****************************************************************************
  384. @Function ReleaseView
  385. @Return bool true if no error occured
  386. @Description Code in ReleaseView() will be called by PVRShell when the
  387. application quits or before a change in the rendering context.
  388. ******************************************************************************/
  389. bool OGLES2ShadowMapping::ReleaseView()
  390. {
  391. // Deletes the textures
  392. glDeleteTextures(m_Scene.nNumMaterial, &m_puiTextureIDs[0]);
  393. // Frees the texture lookup array
  394. delete[] m_puiTextureIDs;
  395. m_puiTextureIDs = 0;
  396. // Delete program and shader objects
  397. glDeleteProgram(m_ShadowShaderProgram.uiId);
  398. glDeleteShader(m_uiShadowVertShader);
  399. glDeleteShader(m_uiShadowFragShader);
  400. // Delete program and shader objects
  401. glDeleteProgram(m_SimpleShaderProgram.uiId);
  402. glDeleteShader(m_uiSimpleVertShader);
  403. glDeleteShader(m_uiSimpleFragShader);
  404. // Delete buffer objects
  405. glDeleteBuffers(m_Scene.nNumMesh, m_puiVbo);
  406. glDeleteBuffers(m_Scene.nNumMesh, m_puiIndexVbo);
  407. // Release Print3D Textures
  408. m_Print3D.ReleaseTextures();
  409. return true;
  410. }
  411. /*!****************************************************************************
  412. @Function RenderScene
  413. @Return bool true if no error occured
  414. @Description Main rendering loop function of the program. The shell will
  415. call this function every frame.
  416. eglSwapBuffers() will be performed by PVRShell automatically.
  417. PVRShell will also manage important OS events.
  418. Will also manage relevent OS events. The user has access to
  419. these events through an abstraction layer provided by PVRShell.
  420. ******************************************************************************/
  421. bool OGLES2ShadowMapping::RenderScene()
  422. {
  423. //rotate light position
  424. m_fLightAngle += 0.01f;
  425. m_vLightPosition.x = m_fLightDistance * (float) cos(m_fLightAngle);
  426. m_vLightPosition.z = m_fLightDistance * (float) sin(m_fLightAngle);
  427. m_vLightDirection.x = -m_vLightPosition.x;
  428. m_vLightDirection.z = -m_vLightPosition.z;
  429. SetUpMatrices();
  430. glEnable(GL_DEPTH_TEST);
  431. // Bind the frame buffer object
  432. glBindFramebuffer(GL_FRAMEBUFFER, m_uiFrameBufferObject);
  433. if(glCheckFramebufferStatus(GL_FRAMEBUFFER) == GL_FRAMEBUFFER_COMPLETE)
  434. {
  435. // Clear the screen and depth buffer so we can render from the light's view
  436. glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
  437. // Set the current viewport to our texture size
  438. glViewport(0, 0, m_ui32ShadowMapSize, m_ui32ShadowMapSize);
  439. // Since we don't care about colour when rendering the depth values to
  440. // the shadow-map texture, we disable color writing to increase speed.
  441. glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
  442. // Enable the simple shader for the light view pass. This render will not be shown to the user
  443. // so only the simplest render needs to be implemented
  444. glUseProgram(m_SimpleShaderProgram.uiId);
  445. // Set the light projection matrix
  446. glUniformMatrix4fv(m_SimpleShaderProgram.uiProjectionMatrixLoc, 1, GL_FALSE, m_LightProjection.f);
  447. // Draw everything that we would like to cast a shadow
  448. for(unsigned int i = 2; i < m_Scene.nNumMeshNode; ++i)
  449. {
  450. SPODNode& Node = m_Scene.pNode[i];
  451. PVRTMat4 mWorld, mModelView;
  452. m_Scene.GetWorldMatrix(mWorld, Node);
  453. PVRTMatrixMultiply(mModelView, mWorld, m_LightView);
  454. glUniformMatrix4fv(m_SimpleShaderProgram.uiModelViewMatrixLoc, 1, GL_FALSE, mModelView.f);
  455. DrawMesh(i);
  456. }
  457. // We can turn color writing back on since we already stored the depth values
  458. #if defined(__PALMPDK__)
  459. glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_FALSE); // The alpha part is false as we don't want to blend with the video layer on the Palm Pre
  460. #else
  461. glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
  462. #endif
  463. // Restore our normal viewport size to our screen width and height
  464. glViewport(0, 0,PVRShellGet(prefWidth),PVRShellGet(prefHeight));
  465. }
  466. glBindFramebuffer(GL_FRAMEBUFFER, 0);
  467. // Clear the colour and depth buffers, we are now going to render the scene again from scratch
  468. glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
  469. // Load the shadow shader. This shader requires additional parameters; texProjMatrix for the depth buffer
  470. // look up and the light direction for diffuse light (the effect is a lot nicer with the additon of the
  471. // diffuse light).
  472. glUseProgram(m_ShadowShaderProgram.uiId);
  473. glActiveTexture(GL_TEXTURE0);
  474. glBindTexture(GL_TEXTURE_2D, m_uiShadowMapTexture);
  475. glUniformMatrix4fv(m_ShadowShaderProgram.uiProjectionMatrixLoc, 1, GL_FALSE, m_Projection.f);
  476. PVRTMat4 mViewInv, mTextureMatrix, mMatrix;
  477. mViewInv = m_View.inverse();
  478. // We need to calculate the texture projection matrix. This matrix takes the pixels from world space to previously rendered light projection space
  479. //where we can look up values from our saved depth buffer. The matrix is constructed from the light view and projection matrices as used for the previous render and
  480. //then multiplied by the inverse of the current view matrix.
  481. mTextureMatrix = m_BiasMatrix * m_LightProjection * m_LightView * mViewInv;
  482. glUniformMatrix4fv(m_ShadowShaderProgram.uiTexProjMatrixLoc, 1, GL_FALSE, mTextureMatrix.f);
  483. DrawSceneWithShadow(m_View);
  484. // Re-enable the simple shader to draw the light source object
  485. glUseProgram(m_SimpleShaderProgram.uiId);
  486. SPODNode& Node = m_Scene.pNode[1];
  487. PVRTMat4 mWorld, mModelView;
  488. m_Scene.GetWorldMatrix(mWorld, Node);
  489. mWorld.f[12] = m_vLightPosition.x;
  490. mWorld.f[13] = m_vLightPosition.y;
  491. mWorld.f[14] = m_vLightPosition.z;
  492. mModelView = m_View * mWorld;
  493. glUniformMatrix4fv(m_SimpleShaderProgram.uiModelViewMatrixLoc, 1, GL_FALSE, mModelView.f);
  494. glUniformMatrix4fv(m_SimpleShaderProgram.uiProjectionMatrixLoc, 1, GL_FALSE, m_LightProjection.f);
  495. DrawMesh(1);
  496. m_Print3D.DisplayDefaultTitle("ShadowMap", "", ePVRTPrint3DSDKLogo);
  497. m_Print3D.Flush();
  498. return true;
  499. }
  500. /*!****************************************************************************
  501. @Function DrawSceneWithShadow
  502. @Input viewMat The view matrix to use for rendering
  503. @Description Draws the scene with the shadow
  504. ******************************************************************************/
  505. void OGLES2ShadowMapping::DrawSceneWithShadow(PVRTMat4 viewMat)
  506. {
  507. for (unsigned int i = 0; i < m_Scene.nNumMeshNode; ++i)
  508. {
  509. if(i == 1) continue;
  510. SPODNode& Node = m_Scene.pNode[i];
  511. PVRTMat4 mWorld, mModelView;
  512. m_Scene.GetWorldMatrix(mWorld, Node);
  513. PVRTMatrixMultiply(mModelView, mWorld, viewMat);
  514. glUniformMatrix4fv(m_ShadowShaderProgram.uiModelViewMatrixLoc, 1, GL_FALSE, mModelView.f);
  515. // Calculate the light direction for the diffuse lighting
  516. PVRTVec4 vLightDir;
  517. PVRTTransformBack(&vLightDir, &m_vLightDirection, &mWorld);
  518. PVRTVec3 vLightDirModel = *(PVRTVec3*)&vLightDir;
  519. PVRTMatrixVec3Normalize(vLightDirModel, vLightDirModel);
  520. glUniform3fv(m_ShadowShaderProgram.uiLightDirLoc, 1, &vLightDirModel.x);
  521. // Load the correct texture using our texture lookup table
  522. GLuint uiTex = 0;
  523. if (Node.nIdxMaterial != -1)
  524. uiTex = m_puiTextureIDs[Node.nIdxMaterial];
  525. glActiveTexture(GL_TEXTURE1);
  526. glBindTexture(GL_TEXTURE_2D, uiTex);
  527. DrawMesh(i);
  528. }
  529. }
  530. /*!****************************************************************************
  531. @Function DrawMesh
  532. @Input i32NodeIndex Node index of the mesh to draw
  533. @Description Draws a SPODMesh after the model view matrix has been set and
  534. the meterial prepared.
  535. ******************************************************************************/
  536. void OGLES2ShadowMapping::DrawMesh(int i32NodeIndex)
  537. {
  538. int i32MeshIndex = m_Scene.pNode[i32NodeIndex].nIdx;
  539. SPODMesh* pMesh = &m_Scene.pMesh[i32MeshIndex];
  540. // bind the VBO for the mesh
  541. glBindBuffer(GL_ARRAY_BUFFER, m_puiVbo[i32MeshIndex]);
  542. // bind the index buffer, won't hurt if the handle is 0
  543. glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_puiIndexVbo[i32MeshIndex]);
  544. // Enable the vertex attribute arrays
  545. glEnableVertexAttribArray(VERTEX_ARRAY);
  546. glEnableVertexAttribArray(NORMAL_ARRAY);
  547. glEnableVertexAttribArray(TEXCOORD_ARRAY);
  548. // Set the vertex attribute offsets
  549. glVertexAttribPointer(VERTEX_ARRAY, 3, GL_FLOAT, GL_FALSE, pMesh->sVertex.nStride, pMesh->sVertex.pData);
  550. glVertexAttribPointer(NORMAL_ARRAY, 3, GL_FLOAT, GL_FALSE, pMesh->sNormals.nStride, pMesh->sNormals.pData);
  551. glVertexAttribPointer(TEXCOORD_ARRAY, 2, GL_FLOAT, GL_FALSE, pMesh->psUVW[0].nStride, pMesh->psUVW[0].pData);
  552. /*
  553. The geometry can be exported in 4 ways:
  554. - Indexed Triangle list
  555. - Non-Indexed Triangle list
  556. - Indexed Triangle strips
  557. - Non-Indexed Triangle strips
  558. */
  559. if(pMesh->nNumStrips == 0)
  560. {
  561. if(m_puiIndexVbo[i32MeshIndex])
  562. {
  563. // Indexed Triangle list
  564. glDrawElements(GL_TRIANGLES, pMesh->nNumFaces*3, GL_UNSIGNED_SHORT, 0);
  565. }
  566. else
  567. {
  568. // Non-Indexed Triangle list
  569. glDrawArrays(GL_TRIANGLES, 0, pMesh->nNumFaces*3);
  570. }
  571. }
  572. else
  573. {
  574. int offset = 0;
  575. for(int i = 0; i < (int)pMesh->nNumStrips; ++i)
  576. {
  577. if(m_puiIndexVbo[i32MeshIndex])
  578. {
  579. // Indexed Triangle strips
  580. glDrawElements(GL_TRIANGLE_STRIP, pMesh->pnStripLength[i]+2, GL_UNSIGNED_SHORT, &((GLshort*)0)[offset]);
  581. }
  582. else
  583. {
  584. // Non-Indexed Triangle strips
  585. glDrawArrays(GL_TRIANGLE_STRIP, offset, pMesh->pnStripLength[i]+2);
  586. }
  587. offset += pMesh->pnStripLength[i]+2;
  588. }
  589. }
  590. // Safely disable the vertex attribute arrays
  591. glDisableVertexAttribArray(VERTEX_ARRAY);
  592. glDisableVertexAttribArray(NORMAL_ARRAY);
  593. glDisableVertexAttribArray(TEXCOORD_ARRAY);
  594. glBindBuffer(GL_ARRAY_BUFFER, 0);
  595. glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
  596. }
  597. /*!****************************************************************************
  598. @Function NewDemo
  599. @Return PVRShell* The demo supplied by the user
  600. @Description This function must be implemented by the user of the shell.
  601. The user should return its PVRShell object defining the
  602. behaviour of the application.
  603. ******************************************************************************/
  604. PVRShell* NewDemo()
  605. {
  606. return new OGLES2ShadowMapping();
  607. }
  608. /******************************************************************************
  609. End of file (OGLES2ShadowMapping.cpp)
  610. ******************************************************************************/