skySphere.cpp 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645
  1. //-----------------------------------------------------------------------------
  2. // Copyright (c) 2012 GarageGames, LLC
  3. //
  4. // Permission is hereby granted, free of charge, to any person obtaining a copy
  5. // of this software and associated documentation files (the "Software"), to
  6. // deal in the Software without restriction, including without limitation the
  7. // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
  8. // sell copies of the Software, and to permit persons to whom the Software is
  9. // furnished to do so, subject to the following conditions:
  10. //
  11. // The above copyright notice and this permission notice shall be included in
  12. // all copies or substantial portions of the Software.
  13. //
  14. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  15. // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  16. // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  17. // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  18. // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  19. // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
  20. // IN THE SOFTWARE.
  21. //-----------------------------------------------------------------------------
  22. #include "platform/platform.h"
  23. #include "environment/skySphere.h"
  24. #include "console/consoleTypes.h"
  25. #include "console/engineAPI.h"
  26. #include "scene/sceneRenderState.h"
  27. #include "renderInstance/renderPassManager.h"
  28. #include "gfx/primBuilder.h"
  29. #include "gfx/gfxTransformSaver.h"
  30. #include "core/stream/fileStream.h"
  31. #include "core/stream/bitStream.h"
  32. #include "materials/materialManager.h"
  33. #include "materials/materialFeatureTypes.h"
  34. #include "materials/sceneData.h"
  35. #include "T3D/gameFunctions.h"
  36. #include "renderInstance/renderBinManager.h"
  37. #include "materials/processedMaterial.h"
  38. #include "gfx/gfxDebugEvent.h"
  39. #include "math/util/matrixSet.h"
  40. IMPLEMENT_CO_NETOBJECT_V1(SkySphere);
  41. ConsoleDocClass(SkySphere,
  42. "@brief Represents the sky with an artist-created spherical map.\n\n"
  43. "SkySphere is not a directional light and should be used in conjunction with a Sun object.\n\n"
  44. "@ingroup Atmosphere"
  45. );
  46. SkySphere::SkySphere()
  47. {
  48. mTypeMask |= EnvironmentObjectType | StaticObjectType;
  49. mNetFlags.set(Ghostable | ScopeAlways);
  50. INIT_ASSET(Material);
  51. mMatInstance = NULL;
  52. mIsVBDirty = false;
  53. mPrimCount = 0;
  54. mFogBandHeight = 0;
  55. mFogPrimCount = 0;
  56. mMatrixSet = reinterpret_cast<MatrixSet*>(dMalloc_aligned(sizeof(MatrixSet), 16));
  57. constructInPlace(mMatrixSet);
  58. mFogBandMat = NULL;
  59. mFogBandMatInst = NULL;
  60. }
  61. SkySphere::~SkySphere()
  62. {
  63. dFree_aligned(mMatrixSet);
  64. if (mMatInstance)
  65. SAFE_DELETE(mMatInstance);
  66. SAFE_DELETE(mFogBandMatInst);
  67. if (mFogBandMat)
  68. {
  69. mFogBandMat->deleteObject();
  70. mFogBandMat = NULL;
  71. }
  72. }
  73. bool SkySphere::onAdd()
  74. {
  75. if (!Parent::onAdd())
  76. return false;
  77. setGlobalBounds();
  78. resetWorldBox();
  79. addToScene();
  80. if (isClientObject())
  81. {
  82. _initRender();
  83. _updateMaterial();
  84. }
  85. return true;
  86. }
  87. void SkySphere::onRemove()
  88. {
  89. removeFromScene();
  90. Parent::onRemove();
  91. }
  92. void SkySphere::initPersistFields()
  93. {
  94. addGroup("Sky Sphere");
  95. INITPERSISTFIELD_MATERIALASSET(Material, SkySphere, "The name of a cubemap material for the sky box.");
  96. addField("fogBandHeight", TypeF32, Offset(mFogBandHeight, SkySphere),
  97. "The height (0-1) of the fog band from the horizon to the top of the SkySphere.");
  98. endGroup("Sky Sphere");
  99. Parent::initPersistFields();
  100. }
  101. void SkySphere::inspectPostApply()
  102. {
  103. Parent::inspectPostApply();
  104. _updateMaterial();
  105. }
  106. U32 SkySphere::packUpdate(NetConnection* conn, U32 mask, BitStream* stream)
  107. {
  108. U32 retMask = Parent::packUpdate(conn, mask, stream);
  109. PACK_ASSET(conn, Material);
  110. stream->write(mFogBandHeight);
  111. return retMask;
  112. }
  113. void SkySphere::unpackUpdate(NetConnection* conn, BitStream* stream)
  114. {
  115. Parent::unpackUpdate(conn, stream);
  116. StringTableEntry oldMatName = getMaterial();
  117. UNPACK_ASSET(conn, Material);
  118. if (oldMatName != getMaterial())
  119. {
  120. _updateMaterial();
  121. }
  122. F32 bandHeight = 0;
  123. stream->read(&bandHeight);
  124. // If this flag has changed
  125. // we need to update the vertex buffer.
  126. if ( bandHeight != mFogBandHeight)
  127. {
  128. mFogBandHeight = bandHeight;
  129. mIsVBDirty = true;
  130. _initRender();
  131. }
  132. }
  133. void SkySphere::prepRenderImage(SceneRenderState* state)
  134. {
  135. PROFILE_SCOPE(SkySphere_prepRenderImage);
  136. if (state->isShadowPass() ||
  137. mVB.isNull() ||
  138. mFogBandVB.isNull() ||
  139. !mMatInstance)
  140. return;
  141. mMatrixSet->setSceneView(GFX->getWorldMatrix());
  142. mMatrixSet->setSceneProjection(GFX->getProjectionMatrix());
  143. ObjectRenderInst* ri = state->getRenderPass()->allocInst<ObjectRenderInst>();
  144. ri->renderDelegate.bind(this, &SkySphere::_renderObject);
  145. ri->type = RenderPassManager::RIT_Sky;
  146. ri->defaultKey = 9;
  147. ri->defaultKey2 = 0;
  148. state->getRenderPass()->addInst(ri);
  149. }
  150. void SkySphere::_renderObject(ObjectRenderInst* ri, SceneRenderState* state, BaseMatInstance* mi)
  151. {
  152. GFXDEBUGEVENT_SCOPE(SkySphere_RenderObject, ColorI::WHITE);
  153. GFXTransformSaver saver;
  154. GFX->setVertexBuffer(mVB);
  155. MatrixF worldMat = MatrixF::Identity;
  156. worldMat.setPosition(Point3F(
  157. state->getCameraPosition().x,
  158. state->getCameraPosition().y,
  159. state->getCameraPosition().z));
  160. SceneData sgData;
  161. sgData.init(state);
  162. sgData.objTrans = &worldMat;
  163. mMatrixSet->restoreSceneViewProjection();
  164. mMatrixSet->setWorld(worldMat);
  165. if (state->isReflectPass())
  166. mMatrixSet->setProjection(state->getSceneManager()->getNonClipProjection());
  167. while (mMatInstance->setupPass(state, sgData))
  168. {
  169. mMatInstance->setTransforms(*mMatrixSet, state);
  170. mMatInstance->setSceneInfo(state, sgData);
  171. GFX->drawPrimitive(GFXTriangleList, 0, mPrimCount);
  172. }
  173. // Draw render band.
  174. if (mFogBandHeight > 0 && mFogBandMatInst)
  175. {
  176. const FogData& fog = state->getSceneManager()->getFogData();
  177. if (mLastFogColor != fog.color)
  178. {
  179. mLastFogColor = fog.color;
  180. _initRender();
  181. }
  182. // Just need it to follow the camera... no rotation.
  183. MatrixF camPosMat(MatrixF::Identity);
  184. camPosMat.setPosition(worldMat.getPosition());
  185. sgData.objTrans = &camPosMat;
  186. mMatrixSet->setWorld(*sgData.objTrans);
  187. while (mFogBandMatInst->setupPass(state, sgData))
  188. {
  189. mFogBandMatInst->setTransforms(*mMatrixSet, state);
  190. mFogBandMatInst->setSceneInfo(state, sgData);
  191. GFX->setVertexBuffer(mFogBandVB);
  192. GFX->drawPrimitive(GFXTriangleList, 0, mFogPrimCount);
  193. }
  194. }
  195. }
  196. void SkySphere::clearVectors()
  197. {
  198. tmpVertices.clear();
  199. finalFogVertex.clear();
  200. tempFogVertex.clear();
  201. colVec.clear();
  202. fogVerts.clear();
  203. vertsVec.clear();
  204. normsVec.clear();
  205. texCoordVec.clear();
  206. finalVertData.clear();
  207. }
  208. void SkySphere::addVertex(Point3F vert)
  209. {
  210. vertsVec.push_back(vert.x);
  211. vertsVec.push_back(vert.y);
  212. vertsVec.push_back(vert.z);
  213. }
  214. void SkySphere::addNormal(Point3F nor)
  215. {
  216. normsVec.push_back(nor.x);
  217. normsVec.push_back(nor.y);
  218. normsVec.push_back(nor.z);
  219. }
  220. void SkySphere::addTexcoord(F32 s, F32 t)
  221. {
  222. texCoordVec.push_back(s);
  223. texCoordVec.push_back(t);
  224. }
  225. void SkySphere::addColor(ColorI col)
  226. {
  227. colVec.push_back(col);
  228. }
  229. void SkySphere::BuildFinalVert()
  230. {
  231. U32 count = vertsVec.size();
  232. U32 i, j;
  233. for (i = 0, j = 0; i < count; i += 3, j += 2)
  234. {
  235. FinalVertexData temp;
  236. temp.pos.set(Point3F(vertsVec[i], vertsVec[i + 1], vertsVec[i + 2]));
  237. temp.nor.set(Point3F(normsVec[i], normsVec[i + 1], normsVec[i + 2]));
  238. temp.s = texCoordVec[j];
  239. temp.t = texCoordVec[j+1];
  240. finalVertData.push_back(temp);
  241. }
  242. }
  243. void SkySphere::BuildFinalFogVert()
  244. {
  245. U32 count = vertsVec.size();
  246. U32 i, j;
  247. for (i = 0, j = 0; i < count; i+=3, j++ )
  248. {
  249. FogVertex temp;
  250. temp.pos.set(Point3F(vertsVec[i], vertsVec[i + 1], vertsVec[i + 2]));
  251. temp.col = colVec[j];
  252. finalFogVertex.push_back(temp);
  253. }
  254. }
  255. void SkySphere::_initRender()
  256. {
  257. U32 rings = 32;
  258. U32 height = 16;
  259. U32 radius = 1;
  260. F32 x, y, z, xy; // vertex position
  261. F32 nx, ny, nz, lengthInv = 1.0f / radius; // normal
  262. F32 s, t; // texCoord
  263. F32 ringStep = M_2PI / rings;
  264. F32 heightStep = M_PI / height; // M_HALFPI for dome.
  265. F32 ringAng, heightAng;
  266. //clear vecs
  267. clearVectors();
  268. for (U32 i = 0; i <= height; ++i)
  269. {
  270. heightAng = M_PI / 2 - (F32)i * heightStep;
  271. F32 xy = radius * mCos(heightAng);
  272. F32 z = radius * mSin(heightAng);
  273. for (U32 j = 0; j <= rings; ++j)
  274. {
  275. SphereVertex vert;
  276. ringAng = j * ringStep;
  277. x = xy * mCos(ringAng);
  278. y = xy * mSin(ringAng);
  279. vert.pos.set(Point3F(x,y,z));
  280. nx = x * lengthInv;
  281. ny = y * lengthInv;
  282. nz = z * lengthInv;
  283. vert.nor.set(Point3F(nx, ny, nz));
  284. s = (F32)j / rings;
  285. t = (F32)i / height;
  286. vert.s = s;
  287. vert.t = t;
  288. tmpVertices.push_back(vert);
  289. }
  290. }
  291. SphereVertex v1, v2, v3, v4;
  292. U32 vi1, vi2 = 0;
  293. for (U32 i = 0; i < height; ++i)
  294. {
  295. vi1 = i * (rings + 1);
  296. vi2 = (i + 1) * (rings + 1);
  297. for (U32 j = 0; j < rings; ++j, ++vi1, ++vi2)
  298. {
  299. v1 = tmpVertices[vi1];
  300. v2 = tmpVertices[vi2];
  301. v3 = tmpVertices[vi1 + 1];
  302. v4 = tmpVertices[vi2 + 1];
  303. // 1st = triangle.
  304. if (i == 0)
  305. {
  306. // verts for tri.
  307. addVertex(v1.pos);
  308. addVertex(v2.pos);
  309. addVertex(v4.pos);
  310. // texcoords for tri.
  311. addTexcoord(v1.s, v1.t);
  312. addTexcoord(v2.s, v2.t);
  313. addTexcoord(v4.s, v4.t);
  314. // normals for tri.
  315. addNormal(v1.nor);
  316. addNormal(v2.nor);
  317. addNormal(v4.nor);
  318. }
  319. else if (i == (height - 1))
  320. {
  321. // verts for tri.
  322. addVertex(v1.pos);
  323. addVertex(v2.pos);
  324. addVertex(v3.pos);
  325. // texcoords for tri.
  326. addTexcoord(v1.s, v1.t);
  327. addTexcoord(v2.s, v2.t);
  328. addTexcoord(v3.s, v3.t);
  329. // normals for quad.
  330. addNormal(v1.nor);
  331. addNormal(v2.nor);
  332. addNormal(v3.nor);
  333. }
  334. else
  335. {
  336. // verts for quad.
  337. addVertex(v1.pos);
  338. addVertex(v2.pos);
  339. addVertex(v3.pos);
  340. addVertex(v3.pos);
  341. addVertex(v4.pos);
  342. addVertex(v2.pos);
  343. // texcoords for quad.
  344. addTexcoord(v1.s, v1.t);
  345. addTexcoord(v2.s, v2.t);
  346. addTexcoord(v3.s, v3.t);
  347. addTexcoord(v3.s, v3.t);
  348. addTexcoord(v4.s, v4.t);
  349. addTexcoord(v2.s, v2.t);
  350. // normals for quad.
  351. addNormal(v1.nor);
  352. addNormal(v2.nor);
  353. addNormal(v3.nor);
  354. addNormal(v3.nor);
  355. addNormal(v4.nor);
  356. addNormal(v2.nor);
  357. }
  358. }
  359. }
  360. BuildFinalVert();
  361. GFXVertexPNT* tmpVerts = NULL;
  362. U32 vertCount = finalVertData.size();
  363. tmpVerts = new GFXVertexPNT[(vertCount)];
  364. mPrimCount = vertCount / 3;
  365. for (U32 i = 0; i < vertCount; i++)
  366. {
  367. tmpVerts[i].point.set(finalVertData[i].pos);
  368. tmpVerts[i].normal.set(finalVertData[i].nor);
  369. tmpVerts[i].texCoord.set(finalVertData[i].s, finalVertData[i].t);
  370. }
  371. if (mVB.isNull() || mIsVBDirty)
  372. {
  373. mVB.set(GFX, vertCount, GFXBufferTypeStatic);
  374. mIsVBDirty = false;
  375. }
  376. GFXVertexPNT* vertPtr = mVB.lock();
  377. if (!vertPtr)
  378. {
  379. delete[] tmpVerts;
  380. return;
  381. }
  382. dMemcpy(vertPtr, tmpVerts, sizeof(GFXVertexPNT) * vertCount);
  383. mVB.unlock();
  384. // Clean up temp verts.
  385. delete[] tmpVerts;
  386. // Grab the fog color.
  387. ColorI fogColor(mLastFogColor.red * 255, mLastFogColor.green * 255, mLastFogColor.blue * 255);
  388. ColorI fogColorAlpha(mLastFogColor.red * 255, mLastFogColor.green * 255, mLastFogColor.blue * 255, 0);
  389. clearVectors();
  390. U32 stepCount = 16;
  391. F32 cylStep = M_2PI / stepCount;
  392. F32 cylAngle;
  393. F32 cylRadius = 10;
  394. for (U32 i = 0; i <= stepCount; ++i)
  395. {
  396. cylAngle = (F32)i * cylStep;
  397. fogVerts.push_back(mCos(cylAngle));
  398. fogVerts.push_back(mSin(cylAngle));
  399. }
  400. for (U32 i = 0; i < 2; ++i)
  401. {
  402. for (U32 j = 0, k = 0; j <= stepCount; ++j, k += 2)
  403. {
  404. FogVertex temp;
  405. F32 ux = fogVerts[k];
  406. F32 uy = fogVerts[k+1];
  407. if (i > 0)
  408. {
  409. temp.pos.set(Point3F((ux * cylRadius), (uy * cylRadius), mFogBandHeight));
  410. temp.col = fogColorAlpha;
  411. }
  412. else
  413. {
  414. temp.pos.set(Point3F((ux * cylRadius), (uy * cylRadius), -mFogBandHeight));
  415. temp.col = fogColor;
  416. }
  417. tempFogVertex.push_back(temp);
  418. }
  419. }
  420. FogVertex f1, f2, f3, f4;
  421. U32 k1 = 0;
  422. U32 k2 = stepCount + 1;
  423. for (U32 i = 0; i < stepCount; ++i, ++k1, ++k2)
  424. {
  425. f1 = tempFogVertex[k1];
  426. f2 = tempFogVertex[k1 + 1];
  427. f3 = tempFogVertex[k2];
  428. f4 = tempFogVertex[k2 + 1];
  429. addVertex(f3.pos);
  430. addVertex(f2.pos);
  431. addVertex(f4.pos);
  432. addColor(f3.col);
  433. addColor(f2.col);
  434. addColor(f4.col);
  435. addVertex(f1.pos);
  436. addVertex(f2.pos);
  437. addVertex(f3.pos);
  438. addColor(f1.col);
  439. addColor(f2.col);
  440. addColor(f3.col);
  441. }
  442. BuildFinalFogVert();
  443. U32 fogVertCount = finalFogVertex.size();
  444. mFogPrimCount = fogVertCount / 3;
  445. if (mFogBandVB.isNull())
  446. mFogBandVB.set(GFX, fogVertCount, GFXBufferTypeStatic);
  447. GFXVertexPC* bandVertPtr = mFogBandVB.lock();
  448. if (!bandVertPtr) return;
  449. for (U32 i = 0; i < fogVertCount; i++)
  450. {
  451. bandVertPtr[i].point.set(finalFogVertex[i].pos);
  452. bandVertPtr[i].color.set(finalFogVertex[i].col);
  453. }
  454. mFogBandVB.unlock();
  455. SAFE_DELETE(mFogBandMatInst);
  456. if (mFogBandMat)
  457. {
  458. mFogBandMat->deleteObject();
  459. mFogBandMat = NULL;
  460. }
  461. // Setup the material for this imposter.
  462. mFogBandMat = MATMGR->allocateAndRegister(String::EmptyString);
  463. mFogBandMat->mAutoGenerated = true;
  464. mFogBandMat->mTranslucent = true;
  465. mFogBandMat->mVertColor[0] = true;
  466. mFogBandMat->mDoubleSided = true;
  467. mFogBandMat->mEmissive[0] = true;
  468. FeatureSet features = MATMGR->getDefaultFeatures();
  469. features.addFeature(MFT_isBackground);
  470. mFogBandMatInst = mFogBandMat->createMatInstance();
  471. mFogBandMatInst->init(features, getGFXVertexFormat<GFXVertexPC>());
  472. }
  473. void SkySphere::onStaticModified(const char* slotName, const char* newValue)
  474. {
  475. Parent::onStaticModified(slotName, newValue);
  476. if (dStricmp(slotName, "material") == 0)
  477. setMaskBits(0xFFFFFFFF);
  478. }
  479. void SkySphere::_initMaterial()
  480. {
  481. if (mMatInstance)
  482. SAFE_DELETE(mMatInstance);
  483. if (mMaterial)
  484. mMatInstance = mMaterial->createMatInstance();
  485. else
  486. mMatInstance = MATMGR->createMatInstance("WarningMaterial");
  487. // We want to disable culling and z write.
  488. GFXStateBlockDesc desc;
  489. desc.setCullMode(GFXCullNone);
  490. desc.setBlend(true);
  491. desc.setZReadWrite(true, false);
  492. desc.zFunc = GFXCmpLessEqual;
  493. mMatInstance->addStateBlockDesc(desc);
  494. // Also disable lighting on the skysphere material by default.
  495. FeatureSet features = MATMGR->getDefaultFeatures();
  496. features.removeFeature(MFT_RTLighting);
  497. features.removeFeature(MFT_Visibility);
  498. features.addFeature(MFT_isBackground);
  499. // Now initialize the material.
  500. mMatInstance->init(features, getGFXVertexFormat<GFXVertexPNT>());
  501. }
  502. void SkySphere::_updateMaterial()
  503. {
  504. if (!getMaterialResource().isValid())
  505. {
  506. //If our materialDef isn't valid, try setting it
  507. _setMaterial(getMaterial());
  508. }
  509. if (getMaterialResource().isValid())
  510. {
  511. _initMaterial();
  512. }
  513. }
  514. BaseMatInstance* SkySphere::_getMaterialInstance()
  515. {
  516. if (!mMaterial || !mMatInstance || mMatInstance->getMaterial() != mMaterial)
  517. _initMaterial();
  518. if (!mMatInstance)
  519. return NULL;
  520. return mMatInstance;
  521. }
  522. DefineEngineMethod(SkySphere, postApply, void, (), , "")
  523. {
  524. object->inspectPostApply();
  525. }