Impostor.cpp
上传用户:ghyvgy
上传日期:2009-05-26
资源大小:547k
文件大小:8k
源码类别:

其他游戏

开发平台:

Python

  1. /*
  2. s_p_oneil@hotmail.com
  3. Copyright (c) 2000, Sean O'Neil
  4. All rights reserved.
  5. Redistribution and use in source and binary forms, with or without
  6. modification, are permitted provided that the following conditions are met:
  7. * Redistributions of source code must retain the above copyright notice,
  8.   this list of conditions and the following disclaimer.
  9. * Redistributions in binary form must reproduce the above copyright notice,
  10.   this list of conditions and the following disclaimer in the documentation
  11.   and/or other materials provided with the distribution.
  12. * Neither the name of this project nor the names of its contributors
  13.   may be used to endorse or promote products derived from this software
  14.   without specific prior written permission.
  15. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
  16. AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  17. IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  18. ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
  19. LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
  20. CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
  21. SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
  22. INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
  23. CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
  24. ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  25. POSSIBILITY OF SUCH DAMAGE.
  26. */
  27. #include "Master.h"
  28. #include "GameApp.h"
  29. #include "Impostor.h"
  30. float CImpostor::CalculateError(C3DObject *pCamera)
  31. {
  32. CVector vOffset = m_vCamera - pCamera->GetPosition();
  33. return vOffset.Magnitude();
  34. }
  35. bool CImpostor::IsInView(C3DObject *pCamera)
  36. {
  37. // Create the 8 corner vertices of the model's 3D bounding box
  38. CVector vCorner[8];
  39. vCorner[0] = CVector(m_vDimension.x, m_vDimension.y, m_vDimension.z);
  40. vCorner[1] = CVector(m_vDimension.x, m_vDimension.y, -m_vDimension.z);
  41. vCorner[2] = CVector(m_vDimension.x, -m_vDimension.y, -m_vDimension.z);
  42. vCorner[3] = CVector(m_vDimension.x, -m_vDimension.y, m_vDimension.z);
  43. vCorner[4] = CVector(-m_vDimension.x, m_vDimension.y, m_vDimension.z);
  44. vCorner[5] = CVector(-m_vDimension.x, m_vDimension.y, -m_vDimension.z);
  45. vCorner[6] = CVector(-m_vDimension.x, -m_vDimension.y, -m_vDimension.z);
  46. vCorner[7] = CVector(-m_vDimension.x, -m_vDimension.y, m_vDimension.z);
  47. // Calculate the camera model-view matrix for testing the bounding box
  48. CVector v = m_vPosition - pCamera->GetPosition();
  49. CMatrix mView = pCamera->GetViewMatrix();
  50. CMatrix mModel;
  51. mModel.ModelMatrix(*this, v);
  52. CMatrix mCamera = mView * mModel;
  53. CVector vActual;
  54. for(int i=0; i<8; i++)
  55. {
  56. // Transform each corner vertex and divide by -z (equivalent to 90 degree fov projection)
  57. // This will help us find the 2D bounding box we need to fit around our impostor
  58. vActual = mCamera.TransformVector(vCorner[i]);
  59. if(vActual.z < 0)
  60. {
  61. vActual.x /= -vActual.z;
  62. vActual.y /= -vActual.z;
  63. if(Abs(vActual.x) < 1 && Abs(vActual.y) < 1)
  64. return true;
  65. }
  66. }
  67. return false;
  68. }
  69. void CImpostor::InitImpostorRender(C3DObject *pCamera)
  70. {
  71. // Create the 8 corner vertices of the model's 3D bounding box
  72. CVector vCorner[8];
  73. vCorner[0] = CVector(m_vDimension.x, m_vDimension.y, m_vDimension.z);
  74. vCorner[1] = CVector(m_vDimension.x, m_vDimension.y, -m_vDimension.z);
  75. vCorner[2] = CVector(m_vDimension.x, -m_vDimension.y, -m_vDimension.z);
  76. vCorner[3] = CVector(m_vDimension.x, -m_vDimension.y, m_vDimension.z);
  77. vCorner[4] = CVector(-m_vDimension.x, m_vDimension.y, m_vDimension.z);
  78. vCorner[5] = CVector(-m_vDimension.x, m_vDimension.y, -m_vDimension.z);
  79. vCorner[6] = CVector(-m_vDimension.x, -m_vDimension.y, -m_vDimension.z);
  80. vCorner[7] = CVector(-m_vDimension.x, -m_vDimension.y, m_vDimension.z);
  81. // Calculate the impostor model-view matrix so we can find the 2D bounding box for the billboard texture
  82. // Currently the up vector is arbitrary. It is chosen in such a way that it can't be parallel to the view vector.
  83. // (We can optimize impostor resolution by picking a better up vector, but we'd have to be careful that it is always perpendicular to the view vector.)
  84. CVector v = m_vPosition - pCamera->GetPosition();
  85. CMatrix mModel, mView;
  86. mModel.ModelMatrix(*this, v);
  87. mView.ViewMatrix(CVector(0.0f), v, CVector(v.y, -v.z, v.x));
  88. m_vUp = CVector(mView.f12, mView.f22, mView.f32);
  89. CMatrix m = mView * mModel;
  90. m_fMinx = 1; m_fMiny = 1; m_fMaxx = -1; m_fMaxy = -1;
  91. for(int i=0; i<8; i++)
  92. {
  93. // Transform each corner vertex and divide by -z (equivalent to 90 degree fov projection)
  94. // This will help us find the 2D bounding box we need to fit around our impostor
  95. vCorner[i] = m.TransformVector(vCorner[i]);
  96. vCorner[i] /= -vCorner[i].z;
  97. m_fMinx = Min(m_fMinx, vCorner[i].x);
  98. m_fMiny = Min(m_fMiny, vCorner[i].y);
  99. m_fMaxx = Max(m_fMaxx, vCorner[i].x);
  100. m_fMaxy = Max(m_fMaxy, vCorner[i].y);
  101. }
  102. // Use the size of the bounding box to determine the resolution we need for the impostor
  103. float fTemp = Max(m_fMaxx-m_fMinx, m_fMaxy-m_fMiny) * 0.5f;
  104. // If it goes too far past the boundaries of the screen, handle it as a special case
  105. m_vOffset = CVector(0.0f);
  106. if(fTemp > 1.0f)
  107. {
  108. // When really close to the impostor, these numbers tend to approach infinity. We need to do something to address that
  109. float fDist = Max(v.Magnitude(), 32);
  110. m_fMinx = -fDist;
  111. m_fMaxx = fDist;
  112. m_fMiny = -fDist;
  113. m_fMaxy = fDist;
  114. m_nResolution = 256;
  115. m_vUp = pCamera->GetUpAxis();
  116. m_vOffset = GetPosition() - (pCamera->GetPosition() + pCamera->GetViewAxis()*fDist);
  117. glViewport(0, 0, m_nResolution, m_nResolution);
  118. glMatrixMode(GL_MODELVIEW);
  119. glPushMatrix();
  120. v = m_vPosition - pCamera->GetPosition();
  121. CMatrix mView = pCamera->GetViewMatrix();
  122. CMatrix mModel;
  123. mModel.ModelMatrix(*this, v);
  124. CMatrix mCamera = mView * mModel;
  125. glLoadMatrixf(mCamera);
  126. glMatrixMode(GL_PROJECTION);
  127. glPushMatrix();
  128. glLoadIdentity();
  129. glFrustum(-1.0f, 1.0f, -1.0f, 1.0f, 1.0, 1000.0);
  130. return;
  131. }
  132. if(fTemp > 0.75f)
  133. m_nResolution = 256;
  134. else if(fTemp > 0.25f)
  135. m_nResolution = 128;
  136. else if(fTemp > 0.1f)
  137. m_nResolution = 64;
  138. else
  139. m_nResolution = 32;
  140. // Set up the necessary viewport, modelview matrix, and projection matrix for rendering to the impostor texture
  141. glViewport(0, 0, m_nResolution, m_nResolution);
  142. glMatrixMode(GL_MODELVIEW);
  143. glPushMatrix();
  144. glLoadMatrixf(m);
  145. glMatrixMode(GL_PROJECTION);
  146. glPushMatrix();
  147. glLoadIdentity();
  148. glFrustum(m_fMinx, m_fMaxx, m_fMiny, m_fMaxy, 1.0, 1000.0);
  149. // Scale these up by distance so they can be used to determine billboard vertices
  150. float fDist = v.Magnitude();
  151. m_fMinx *= fDist;
  152. m_fMiny *= fDist;
  153. m_fMaxx *= fDist;
  154. m_fMaxy *= fDist;
  155. }
  156. void CImpostor::FinishImpostorRender()
  157. {
  158. // Copy the currently rendered viewport into the impostor texture
  159. m_tImpostor.InitCopy(0, 0, m_nResolution, m_nResolution);
  160. // Clean up the OpenGL matrix stack and viewport
  161. glMatrixMode(GL_PROJECTION);
  162. glPopMatrix();
  163. glMatrixMode(GL_MODELVIEW);
  164. glPopMatrix();
  165. glViewport(0, 0, GetGameApp()->GetWidth(), GetGameApp()->GetHeight());
  166. }
  167. void CImpostor::Draw(C3DObject *pCamera)
  168. {
  169. // First determine the actual normal, up, and right vectors for the billboard
  170. CVector vPos = (m_vPosition - m_vOffset) - pCamera->GetPosition();
  171. float fDistance = vPos.Magnitude();
  172. CVector vNormal = vPos / -fDistance;
  173. CVector vRight = m_vUp ^ vNormal;
  174. vRight.Normalize();
  175. CVector vUp = vNormal ^ vRight;
  176. vUp.Normalize();
  177. // Then draw the billboarded rectangle
  178. m_tImpostor.Enable();
  179. glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
  180. glEnable(GL_BLEND);
  181. glBegin(GL_QUADS);
  182. glTexCoord2f(0, 1);
  183. glVertex3fv(vPos + vUp*m_fMaxy + vRight*m_fMinx);
  184. glTexCoord2f(0, 0);
  185. glVertex3fv(vPos + vUp*m_fMiny + vRight*m_fMinx);
  186. glTexCoord2f(1, 0);
  187. glVertex3fv(vPos + vUp*m_fMiny + vRight*m_fMaxx);
  188. glTexCoord2f(1, 1);
  189. glVertex3fv(vPos + vUp*m_fMaxy + vRight*m_fMaxx);
  190. glEnd();
  191. glDisable(GL_BLEND);
  192. m_tImpostor.Disable();
  193. }