skySphere.cpp 16 KB

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