skySphere.cpp 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647
  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. docsURL;
  95. addGroup("Sky Sphere");
  96. INITPERSISTFIELD_MATERIALASSET(Material, SkySphere, "The name of a cubemap material for the sky box.");
  97. addField("fogBandHeight", TypeF32, Offset(mFogBandHeight, SkySphere),
  98. "The height (0-1) of the fog band from the horizon to the top of the SkySphere.");
  99. endGroup("Sky Sphere");
  100. Parent::initPersistFields();
  101. }
  102. void SkySphere::inspectPostApply()
  103. {
  104. Parent::inspectPostApply();
  105. _updateMaterial();
  106. }
  107. U32 SkySphere::packUpdate(NetConnection* conn, U32 mask, BitStream* stream)
  108. {
  109. U32 retMask = Parent::packUpdate(conn, mask, stream);
  110. PACK_ASSET(conn, Material);
  111. stream->write(mFogBandHeight);
  112. return retMask;
  113. }
  114. void SkySphere::unpackUpdate(NetConnection* conn, BitStream* stream)
  115. {
  116. Parent::unpackUpdate(conn, stream);
  117. StringTableEntry oldMatName = getMaterial();
  118. UNPACK_ASSET(conn, Material);
  119. if (oldMatName != getMaterial())
  120. {
  121. _updateMaterial();
  122. }
  123. F32 bandHeight = 0;
  124. stream->read(&bandHeight);
  125. // If this flag has changed
  126. // we need to update the vertex buffer.
  127. if ( bandHeight != mFogBandHeight)
  128. {
  129. mFogBandHeight = bandHeight;
  130. mIsVBDirty = true;
  131. _initRender();
  132. }
  133. }
  134. void SkySphere::prepRenderImage(SceneRenderState* state)
  135. {
  136. PROFILE_SCOPE(SkySphere_prepRenderImage);
  137. if (state->isShadowPass() ||
  138. mVB.isNull() ||
  139. mFogBandVB.isNull() ||
  140. !mMatInstance)
  141. return;
  142. mMatrixSet->setSceneView(GFX->getWorldMatrix());
  143. mMatrixSet->setSceneProjection(GFX->getProjectionMatrix());
  144. ObjectRenderInst* ri = state->getRenderPass()->allocInst<ObjectRenderInst>();
  145. ri->renderDelegate.bind(this, &SkySphere::_renderObject);
  146. ri->type = RenderPassManager::RIT_Sky;
  147. ri->defaultKey = 9;
  148. ri->defaultKey2 = 0;
  149. state->getRenderPass()->addInst(ri);
  150. }
  151. void SkySphere::_renderObject(ObjectRenderInst* ri, SceneRenderState* state, BaseMatInstance* mi)
  152. {
  153. GFXDEBUGEVENT_SCOPE(SkySphere_RenderObject, ColorI::WHITE);
  154. GFXTransformSaver saver;
  155. GFX->setVertexBuffer(mVB);
  156. MatrixF worldMat = MatrixF::Identity;
  157. worldMat.setPosition(Point3F(
  158. state->getCameraPosition().x,
  159. state->getCameraPosition().y,
  160. state->getCameraPosition().z));
  161. SceneData sgData;
  162. sgData.init(state);
  163. sgData.objTrans = &worldMat;
  164. mMatrixSet->restoreSceneViewProjection();
  165. mMatrixSet->setWorld(worldMat);
  166. if (state->isReflectPass())
  167. mMatrixSet->setProjection(state->getSceneManager()->getNonClipProjection());
  168. while (mMatInstance->setupPass(state, sgData))
  169. {
  170. mMatInstance->setTransforms(*mMatrixSet, state);
  171. mMatInstance->setSceneInfo(state, sgData);
  172. GFX->drawPrimitive(GFXTriangleList, 0, mPrimCount);
  173. }
  174. // Draw render band.
  175. if (mFogBandHeight > 0 && mFogBandMatInst)
  176. {
  177. const FogData& fog = state->getSceneManager()->getFogData();
  178. if (mLastFogColor != fog.color)
  179. {
  180. mLastFogColor = fog.color;
  181. _initRender();
  182. }
  183. // Just need it to follow the camera... no rotation.
  184. MatrixF camPosMat(MatrixF::Identity);
  185. camPosMat.setPosition(worldMat.getPosition());
  186. sgData.objTrans = &camPosMat;
  187. mMatrixSet->setWorld(*sgData.objTrans);
  188. while (mFogBandMatInst->setupPass(state, sgData))
  189. {
  190. mFogBandMatInst->setTransforms(*mMatrixSet, state);
  191. mFogBandMatInst->setSceneInfo(state, sgData);
  192. GFX->setVertexBuffer(mFogBandVB);
  193. GFX->drawPrimitive(GFXTriangleList, 0, mFogPrimCount);
  194. }
  195. }
  196. }
  197. void SkySphere::clearVectors()
  198. {
  199. tmpVertices.clear();
  200. finalFogVertex.clear();
  201. tempFogVertex.clear();
  202. colVec.clear();
  203. fogVerts.clear();
  204. vertsVec.clear();
  205. normsVec.clear();
  206. texCoordVec.clear();
  207. finalVertData.clear();
  208. }
  209. void SkySphere::addVertex(Point3F vert)
  210. {
  211. vertsVec.push_back(vert.x);
  212. vertsVec.push_back(vert.y);
  213. vertsVec.push_back(vert.z);
  214. }
  215. void SkySphere::addNormal(Point3F nor)
  216. {
  217. normsVec.push_back(nor.x);
  218. normsVec.push_back(nor.y);
  219. normsVec.push_back(nor.z);
  220. }
  221. void SkySphere::addTexcoord(F32 s, F32 t)
  222. {
  223. texCoordVec.push_back(s);
  224. texCoordVec.push_back(t);
  225. }
  226. void SkySphere::addColor(ColorI col)
  227. {
  228. colVec.push_back(col);
  229. }
  230. void SkySphere::BuildFinalVert()
  231. {
  232. U32 count = vertsVec.size();
  233. U32 i, j;
  234. for (i = 0, j = 0; i < count; i += 3, j += 2)
  235. {
  236. FinalVertexData temp;
  237. temp.pos.set(Point3F(vertsVec[i], vertsVec[i + 1], vertsVec[i + 2]));
  238. temp.nor.set(Point3F(normsVec[i], normsVec[i + 1], normsVec[i + 2]));
  239. temp.s = texCoordVec[j];
  240. temp.t = texCoordVec[j+1];
  241. finalVertData.push_back(temp);
  242. }
  243. }
  244. void SkySphere::BuildFinalFogVert()
  245. {
  246. U32 count = vertsVec.size();
  247. U32 i, j;
  248. for (i = 0, j = 0; i < count; i+=3, j++ )
  249. {
  250. FogVertex temp;
  251. temp.pos.set(Point3F(vertsVec[i], vertsVec[i + 1], vertsVec[i + 2]));
  252. temp.col = colVec[j];
  253. finalFogVertex.push_back(temp);
  254. }
  255. }
  256. void SkySphere::_initRender()
  257. {
  258. U32 rings = 32;
  259. U32 height = 16;
  260. U32 radius = 1;
  261. F32 x, y, z, xy; // vertex position
  262. F32 nx, ny, nz, lengthInv = 1.0f / radius; // normal
  263. F32 s, t; // texCoord
  264. F32 ringStep = M_2PI / rings;
  265. F32 heightStep = M_PI / height; // M_HALFPI for dome.
  266. F32 ringAng, heightAng;
  267. //clear vecs
  268. clearVectors();
  269. for (U32 i = 0; i <= height; ++i)
  270. {
  271. heightAng = M_PI / 2 - (F32)i * heightStep;
  272. F32 xy = radius * mCos(heightAng);
  273. F32 z = radius * mSin(heightAng);
  274. for (U32 j = 0; j <= rings; ++j)
  275. {
  276. SphereVertex vert;
  277. ringAng = j * ringStep;
  278. x = xy * mCos(ringAng);
  279. y = xy * mSin(ringAng);
  280. vert.pos.set(Point3F(x,y,z));
  281. nx = x * lengthInv;
  282. ny = y * lengthInv;
  283. nz = z * lengthInv;
  284. vert.nor.set(Point3F(nx, ny, nz));
  285. s = (F32)j / rings;
  286. t = (F32)i / height;
  287. vert.s = s;
  288. vert.t = t;
  289. tmpVertices.push_back(vert);
  290. }
  291. }
  292. SphereVertex v1, v2, v3, v4;
  293. U32 vi1, vi2 = 0;
  294. for (U32 i = 0; i < height; ++i)
  295. {
  296. vi1 = i * (rings + 1);
  297. vi2 = (i + 1) * (rings + 1);
  298. for (U32 j = 0; j < rings; ++j, ++vi1, ++vi2)
  299. {
  300. v1 = tmpVertices[vi1];
  301. v2 = tmpVertices[vi2];
  302. v3 = tmpVertices[vi1 + 1];
  303. v4 = tmpVertices[vi2 + 1];
  304. // 1st = triangle.
  305. if (i == 0)
  306. {
  307. // verts for tri.
  308. addVertex(v1.pos);
  309. addVertex(v2.pos);
  310. addVertex(v4.pos);
  311. // texcoords for tri.
  312. addTexcoord(v1.s, v1.t);
  313. addTexcoord(v2.s, v2.t);
  314. addTexcoord(v4.s, v4.t);
  315. // normals for tri.
  316. addNormal(v1.nor);
  317. addNormal(v2.nor);
  318. addNormal(v4.nor);
  319. }
  320. else if (i == (height - 1))
  321. {
  322. // verts for tri.
  323. addVertex(v1.pos);
  324. addVertex(v2.pos);
  325. addVertex(v3.pos);
  326. // texcoords for tri.
  327. addTexcoord(v1.s, v1.t);
  328. addTexcoord(v2.s, v2.t);
  329. addTexcoord(v3.s, v3.t);
  330. // normals for quad.
  331. addNormal(v1.nor);
  332. addNormal(v2.nor);
  333. addNormal(v3.nor);
  334. }
  335. else
  336. {
  337. // verts for quad.
  338. addVertex(v1.pos);
  339. addVertex(v2.pos);
  340. addVertex(v3.pos);
  341. addVertex(v3.pos);
  342. addVertex(v4.pos);
  343. addVertex(v2.pos);
  344. // texcoords for quad.
  345. addTexcoord(v1.s, v1.t);
  346. addTexcoord(v2.s, v2.t);
  347. addTexcoord(v3.s, v3.t);
  348. addTexcoord(v3.s, v3.t);
  349. addTexcoord(v4.s, v4.t);
  350. addTexcoord(v2.s, v2.t);
  351. // normals for quad.
  352. addNormal(v1.nor);
  353. addNormal(v2.nor);
  354. addNormal(v3.nor);
  355. addNormal(v3.nor);
  356. addNormal(v4.nor);
  357. addNormal(v2.nor);
  358. }
  359. }
  360. }
  361. BuildFinalVert();
  362. GFXVertexPNT* tmpVerts = NULL;
  363. U32 vertCount = finalVertData.size();
  364. tmpVerts = new GFXVertexPNT[(vertCount)];
  365. mPrimCount = vertCount / 3;
  366. for (U32 i = 0; i < vertCount; i++)
  367. {
  368. tmpVerts[i].point.set(finalVertData[i].pos);
  369. tmpVerts[i].normal.set(finalVertData[i].nor);
  370. tmpVerts[i].texCoord.set(finalVertData[i].s, finalVertData[i].t);
  371. }
  372. if (mVB.isNull() || mIsVBDirty)
  373. {
  374. mVB.set(GFX, vertCount, GFXBufferTypeStatic);
  375. mIsVBDirty = false;
  376. }
  377. GFXVertexPNT* vertPtr = mVB.lock();
  378. if (!vertPtr)
  379. {
  380. delete[] tmpVerts;
  381. return;
  382. }
  383. dMemcpy(vertPtr, tmpVerts, sizeof(GFXVertexPNT) * vertCount);
  384. mVB.unlock();
  385. // Clean up temp verts.
  386. delete[] tmpVerts;
  387. // Grab the fog color.
  388. ColorI fogColor(mLastFogColor.red * 255, mLastFogColor.green * 255, mLastFogColor.blue * 255);
  389. ColorI fogColorAlpha(mLastFogColor.red * 255, mLastFogColor.green * 255, mLastFogColor.blue * 255, 0);
  390. clearVectors();
  391. U32 stepCount = 16;
  392. F32 cylStep = M_2PI / stepCount;
  393. F32 cylAngle;
  394. F32 cylRadius = 10;
  395. for (U32 i = 0; i <= stepCount; ++i)
  396. {
  397. cylAngle = (F32)i * cylStep;
  398. fogVerts.push_back(mCos(cylAngle));
  399. fogVerts.push_back(mSin(cylAngle));
  400. }
  401. for (U32 i = 0; i < 2; ++i)
  402. {
  403. for (U32 j = 0, k = 0; j <= stepCount; ++j, k += 2)
  404. {
  405. FogVertex temp;
  406. F32 ux = fogVerts[k];
  407. F32 uy = fogVerts[k+1];
  408. if (i > 0)
  409. {
  410. temp.pos.set(Point3F((ux * cylRadius), (uy * cylRadius), mFogBandHeight));
  411. temp.col = fogColorAlpha;
  412. }
  413. else
  414. {
  415. temp.pos.set(Point3F((ux * cylRadius), (uy * cylRadius), -mFogBandHeight));
  416. temp.col = fogColor;
  417. }
  418. tempFogVertex.push_back(temp);
  419. }
  420. }
  421. FogVertex f1, f2, f3, f4;
  422. U32 k1 = 0;
  423. U32 k2 = stepCount + 1;
  424. for (U32 i = 0; i < stepCount; ++i, ++k1, ++k2)
  425. {
  426. f1 = tempFogVertex[k1];
  427. f2 = tempFogVertex[k1 + 1];
  428. f3 = tempFogVertex[k2];
  429. f4 = tempFogVertex[k2 + 1];
  430. addVertex(f3.pos);
  431. addVertex(f2.pos);
  432. addVertex(f4.pos);
  433. addColor(f3.col);
  434. addColor(f2.col);
  435. addColor(f4.col);
  436. addVertex(f1.pos);
  437. addVertex(f2.pos);
  438. addVertex(f3.pos);
  439. addColor(f1.col);
  440. addColor(f2.col);
  441. addColor(f3.col);
  442. }
  443. BuildFinalFogVert();
  444. U32 fogVertCount = finalFogVertex.size();
  445. mFogPrimCount = fogVertCount / 3;
  446. if (mFogBandVB.isNull())
  447. mFogBandVB.set(GFX, fogVertCount, GFXBufferTypeStatic);
  448. GFXVertexPC* bandVertPtr = mFogBandVB.lock();
  449. if (!bandVertPtr) return;
  450. for (U32 i = 0; i < fogVertCount; i++)
  451. {
  452. bandVertPtr[i].point.set(finalFogVertex[i].pos);
  453. bandVertPtr[i].color.set(finalFogVertex[i].col);
  454. }
  455. mFogBandVB.unlock();
  456. SAFE_DELETE(mFogBandMatInst);
  457. if (mFogBandMat)
  458. {
  459. mFogBandMat->deleteObject();
  460. mFogBandMat = NULL;
  461. }
  462. // Setup the material for this imposter.
  463. mFogBandMat = MATMGR->allocateAndRegister(String::EmptyString);
  464. mFogBandMat->mAutoGenerated = true;
  465. mFogBandMat->mTranslucent = true;
  466. mFogBandMat->mVertColor[0] = true;
  467. mFogBandMat->mDoubleSided = true;
  468. mFogBandMat->mReceiveShadows[0] = false;
  469. FeatureSet features = MATMGR->getDefaultFeatures();
  470. features.addFeature(MFT_isBackground);
  471. mFogBandMatInst = mFogBandMat->createMatInstance();
  472. mFogBandMatInst->init(features, getGFXVertexFormat<GFXVertexPC>());
  473. }
  474. void SkySphere::onStaticModified(const char* slotName, const char* newValue)
  475. {
  476. Parent::onStaticModified(slotName, newValue);
  477. if (dStricmp(slotName, "material") == 0)
  478. setMaskBits(0xFFFFFFFF);
  479. }
  480. void SkySphere::_initMaterial()
  481. {
  482. if (mMatInstance)
  483. SAFE_DELETE(mMatInstance);
  484. if (mMaterial)
  485. mMatInstance = mMaterial->createMatInstance();
  486. else
  487. mMatInstance = MATMGR->createMatInstance("WarningMaterial");
  488. // We want to disable culling and z write.
  489. GFXStateBlockDesc desc;
  490. desc.setCullMode(GFXCullNone);
  491. desc.setBlend(true);
  492. desc.setZReadWrite(true, false);
  493. desc.zFunc = GFXCmpLessEqual;
  494. mMatInstance->addStateBlockDesc(desc);
  495. // Also disable lighting on the skysphere material by default.
  496. FeatureSet features = MATMGR->getDefaultFeatures();
  497. features.removeFeature(MFT_RTLighting);
  498. features.removeFeature(MFT_Visibility);
  499. features.removeFeature(MFT_ReflectionProbes);
  500. features.addFeature(MFT_isBackground);
  501. // Now initialize the material.
  502. mMatInstance->init(features, getGFXVertexFormat<GFXVertexPNT>());
  503. }
  504. void SkySphere::_updateMaterial()
  505. {
  506. if (!getMaterialResource().isValid())
  507. {
  508. //If our materialDef isn't valid, try setting it
  509. _setMaterial(getMaterial());
  510. }
  511. if (getMaterialResource().isValid())
  512. {
  513. _initMaterial();
  514. }
  515. }
  516. BaseMatInstance* SkySphere::_getMaterialInstance()
  517. {
  518. if (!mMaterial || !mMatInstance || mMatInstance->getMaterial() != mMaterial)
  519. _initMaterial();
  520. if (!mMatInstance)
  521. return NULL;
  522. return mMatInstance;
  523. }
  524. DefineEngineMethod(SkySphere, postApply, void, (), , "")
  525. {
  526. object->inspectPostApply();
  527. }