BsLightProbes.cpp 37 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184
  1. //********************************** Banshee Engine (www.banshee3d.com) **************************************************//
  2. //**************** Copyright (c) 2016 Marko Pintera ([email protected]). All rights reserved. **********************//
  3. #include "BsLightProbes.h"
  4. #include "Renderer/BsLightProbeVolume.h"
  5. #include "RenderAPI/BsGpuBuffer.h"
  6. #include "BsRendererView.h"
  7. #include "BsRenderBeastIBLUtility.h"
  8. #include "Mesh/BsMesh.h"
  9. #include "RenderAPI/BsVertexDataDesc.h"
  10. #include "Material/BsGpuParamsSet.h"
  11. #include "Renderer/BsRendererUtility.h"
  12. #include "Renderer/BsSkybox.h"
  13. #include "BsRendererTextures.h"
  14. namespace bs { namespace ct
  15. {
  16. ShaderVariation TetrahedraRenderMat::VAR_NoMSAA = ShaderVariation({
  17. ShaderVariation::Param("MSAA", false)
  18. });
  19. ShaderVariation TetrahedraRenderMat::VAR_MSAA = ShaderVariation({
  20. ShaderVariation::Param("MSAA", true)
  21. });
  22. TetrahedraRenderMat::TetrahedraRenderMat()
  23. {
  24. SPtr<GpuParams> params = mParamsSet->getGpuParams();
  25. params->getTextureParam(GPT_FRAGMENT_PROGRAM, "gDepthBufferTex", mDepthBufferTex);
  26. if(params->hasSamplerState(GPT_FRAGMENT_PROGRAM, "gDepthBufferSamp"))
  27. {
  28. SAMPLER_STATE_DESC pointSampDesc;
  29. pointSampDesc.minFilter = FO_POINT;
  30. pointSampDesc.magFilter = FO_POINT;
  31. pointSampDesc.mipFilter = FO_POINT;
  32. pointSampDesc.addressMode.u = TAM_CLAMP;
  33. pointSampDesc.addressMode.v = TAM_CLAMP;
  34. pointSampDesc.addressMode.w = TAM_CLAMP;
  35. SPtr<SamplerState> pointSampState = SamplerState::create(pointSampDesc);
  36. params->setSamplerState(GPT_FRAGMENT_PROGRAM, "gDepthBufferSamp", pointSampState);
  37. }
  38. }
  39. void TetrahedraRenderMat::_initVariations(ShaderVariations& variations)
  40. {
  41. variations.add(VAR_NoMSAA);
  42. variations.add(VAR_MSAA);
  43. }
  44. void TetrahedraRenderMat::execute(const RendererView& view, const SPtr<Texture>& sceneDepth, const SPtr<Mesh>& mesh,
  45. const SPtr<RenderTexture>& output)
  46. {
  47. mDepthBufferTex.set(sceneDepth);
  48. mParamsSet->setParamBlockBuffer("PerCamera", view.getPerViewBuffer(), true);
  49. RenderAPI& rapi = RenderAPI::instance();
  50. rapi.setRenderTarget(output);
  51. gRendererUtility().setPass(mMaterial);
  52. gRendererUtility().setPassParams(mParamsSet);
  53. gRendererUtility().draw(mesh);
  54. }
  55. void TetrahedraRenderMat::getOutputDesc(const RendererView& view, POOLED_RENDER_TEXTURE_DESC& colorDesc,
  56. POOLED_RENDER_TEXTURE_DESC& depthDesc)
  57. {
  58. const RendererViewProperties& viewProps = view.getProperties();
  59. UINT32 width = viewProps.viewRect.width;
  60. UINT32 height = viewProps.viewRect.height;
  61. UINT32 numSamples = viewProps.numSamples;
  62. colorDesc = POOLED_RENDER_TEXTURE_DESC::create2D(PF_R16U, width, height, TU_RENDERTARGET, numSamples);
  63. depthDesc = POOLED_RENDER_TEXTURE_DESC::create2D(PF_D32, width, height, TU_DEPTHSTENCIL, numSamples);
  64. }
  65. TetrahedraRenderMat* TetrahedraRenderMat::getVariation(bool msaa)
  66. {
  67. if (msaa)
  68. return get(VAR_MSAA);
  69. return get(VAR_NoMSAA);
  70. }
  71. IrradianceEvaluateParamDef gIrradianceEvaluateParamDef;
  72. ShaderVariation IrradianceEvaluateMat::VAR_MSAA_Probes = ShaderVariation({
  73. ShaderVariation::Param("MSAA_COUNT", 2),
  74. ShaderVariation::Param("SKY_ONLY", false)
  75. });
  76. ShaderVariation IrradianceEvaluateMat::VAR_NoMSAA_Probes = ShaderVariation({
  77. ShaderVariation::Param("MSAA_COUNT", 1),
  78. ShaderVariation::Param("SKY_ONLY", false)
  79. });
  80. ShaderVariation IrradianceEvaluateMat::VAR_MSAA_Sky = ShaderVariation({
  81. ShaderVariation::Param("MSAA_COUNT", 2),
  82. ShaderVariation::Param("SKY_ONLY", true)
  83. });
  84. ShaderVariation IrradianceEvaluateMat::VAR_NoMSAA_Sky = ShaderVariation({
  85. ShaderVariation::Param("MSAA_COUNT", 1),
  86. ShaderVariation::Param("SKY_ONLY", true)
  87. });
  88. IrradianceEvaluateMat::IrradianceEvaluateMat()
  89. :mGBufferParams(mMaterial, mParamsSet)
  90. {
  91. mSkyOnly = mVariation.getBool("SKY_ONLY");
  92. SPtr<GpuParams> params = mParamsSet->getGpuParams();
  93. params->getTextureParam(GPT_FRAGMENT_PROGRAM, "gSkyIrradianceTex", mParamSkyIrradianceTex);
  94. params->getTextureParam(GPT_FRAGMENT_PROGRAM, "gAmbientOcclusionTex", mParamAmbientOcclusionTex);
  95. if(!mSkyOnly)
  96. {
  97. params->getTextureParam(GPT_FRAGMENT_PROGRAM, "gInputTex", mParamInputTex);
  98. params->getBufferParam(GPT_FRAGMENT_PROGRAM, "gSHCoeffs", mParamSHCoeffsBuffer);
  99. params->getBufferParam(GPT_FRAGMENT_PROGRAM, "gTetrahedra", mParamTetrahedraBuffer);
  100. params->getBufferParam(GPT_FRAGMENT_PROGRAM, "gTetFaces", mParamTetFacesBuffer);
  101. }
  102. mParamBuffer = gIrradianceEvaluateParamDef.createBuffer();
  103. mParamsSet->setParamBlockBuffer("Params", mParamBuffer, true);
  104. }
  105. void IrradianceEvaluateMat::_initVariations(ShaderVariations& variations)
  106. {
  107. variations.add(VAR_MSAA_Probes);
  108. variations.add(VAR_MSAA_Sky);
  109. variations.add(VAR_NoMSAA_Probes);
  110. variations.add(VAR_NoMSAA_Sky);
  111. }
  112. void IrradianceEvaluateMat::execute(const RendererView& view, const GBufferTextures& gbuffer,
  113. const SPtr<Texture>& lightProbeIndices, const LightProbesInfo& lightProbesInfo, const Skybox* skybox,
  114. const SPtr<Texture>& ambientOcclusion, const SPtr<RenderTexture>& output)
  115. {
  116. const RendererViewProperties& viewProps = view.getProperties();
  117. mGBufferParams.bind(gbuffer);
  118. float skyBrightness = 1.0f;
  119. SPtr<Texture> skyIrradiance;
  120. if (skybox != nullptr)
  121. {
  122. skyIrradiance = skybox->getIrradiance();
  123. skyBrightness = skybox->getBrightness();
  124. }
  125. if(skyIrradiance == nullptr)
  126. skyIrradiance = RendererTextures::defaultIndirect;
  127. mParamSkyIrradianceTex.set(skyIrradiance);
  128. mParamAmbientOcclusionTex.set(ambientOcclusion);
  129. if(!mSkyOnly)
  130. {
  131. mParamInputTex.set(lightProbeIndices);
  132. mParamSHCoeffsBuffer.set(lightProbesInfo.shCoefficients);
  133. mParamTetrahedraBuffer.set(lightProbesInfo.tetrahedra);
  134. mParamTetFacesBuffer.set(lightProbesInfo.faces);
  135. }
  136. gIrradianceEvaluateParamDef.gSkyBrightness.set(mParamBuffer, skyBrightness);
  137. gIrradianceEvaluateParamDef.gNumTetrahedra.set(mParamBuffer, lightProbesInfo.numTetrahedra);
  138. mParamBuffer->flushToGPU();
  139. mParamsSet->setParamBlockBuffer("PerCamera", view.getPerViewBuffer(), true);
  140. // Render
  141. RenderAPI& rapi = RenderAPI::instance();
  142. rapi.setRenderTarget(output, FBT_DEPTH | FBT_STENCIL, RT_COLOR0);
  143. gRendererUtility().setPass(mMaterial);
  144. gRendererUtility().setPassParams(mParamsSet);
  145. gRendererUtility().drawScreenQuad(Rect2(0.0f, 0.0f, (float)viewProps.viewRect.width,
  146. (float)viewProps.viewRect.height));
  147. rapi.setRenderTarget(nullptr);
  148. }
  149. IrradianceEvaluateMat* IrradianceEvaluateMat::getVariation(UINT32 msaaCount, bool skyOnly)
  150. {
  151. if(skyOnly)
  152. {
  153. if (msaaCount > 1)
  154. return get(VAR_MSAA_Sky);
  155. return get(VAR_NoMSAA_Sky);
  156. }
  157. else
  158. {
  159. if (msaaCount > 1)
  160. return get(VAR_MSAA_Probes);
  161. return get(VAR_NoMSAA_Probes);
  162. }
  163. }
  164. /** Hash value generator for std::pair<INT32, INT32>. */
  165. struct pair_hash
  166. {
  167. size_t operator()(const std::pair<INT32, INT32>& key) const
  168. {
  169. size_t hash = 0;
  170. bs::hash_combine(hash, key.first);
  171. bs::hash_combine(hash, key.second);
  172. return hash;
  173. }
  174. };
  175. /** Information about a single tetrahedron, for use on the GPU. */
  176. struct TetrahedronDataGPU
  177. {
  178. UINT32 indices[4];
  179. Matrix3x4 transform;
  180. };
  181. /** Information about a single tetrahedron face, for use on the GPU. */
  182. struct TetrahedronFaceDataGPU
  183. {
  184. Vector3 corners[3];
  185. Vector3 normals[3];
  186. UINT32 isQuadratic;
  187. };
  188. LightProbes::LightProbes()
  189. :mTetrahedronVolumeDirty(false), mMaxCoefficients(0), mMaxTetrahedra(0), mMaxFaces(0), mNumValidTetrahedra(0)
  190. { }
  191. void LightProbes::notifyAdded(LightProbeVolume* volume)
  192. {
  193. UINT32 handle = (UINT32)mVolumes.size();
  194. VolumeInfo info;
  195. info.volume = volume;
  196. info.isDirty = true;
  197. mVolumes.push_back(info);
  198. volume->setRendererId(handle);
  199. notifyDirty(volume);
  200. }
  201. void LightProbes::notifyDirty(LightProbeVolume* volume)
  202. {
  203. UINT32 handle = volume->getRendererId();
  204. mVolumes[handle].isDirty = true;
  205. mTetrahedronVolumeDirty = true;
  206. }
  207. void LightProbes::notifyRemoved(LightProbeVolume* volume)
  208. {
  209. UINT32 handle = volume->getRendererId();
  210. LightProbeVolume* lastVolume = mVolumes.back().volume;
  211. UINT32 lastHandle = lastVolume->getRendererId();
  212. if (handle != lastHandle)
  213. {
  214. // Swap current last element with the one we want to erase
  215. std::swap(mVolumes[handle], mVolumes[lastHandle]);
  216. lastVolume->setRendererId(handle);
  217. }
  218. // Erase last (empty) element
  219. mVolumes.erase(mVolumes.end() - 1);
  220. mTetrahedronVolumeDirty = true;
  221. }
  222. void LightProbes::updateProbes()
  223. {
  224. if (!mTetrahedronVolumeDirty)
  225. return;
  226. // Move all coefficients into the global buffer
  227. UINT32 numCoeffs = 0;
  228. for(auto& entry : mVolumes)
  229. {
  230. UINT32 numProbes = (UINT32)entry.volume->getLightProbePositions().size();
  231. numCoeffs += numProbes;
  232. }
  233. if(numCoeffs > mMaxCoefficients)
  234. {
  235. UINT32 newSize = Math::divideAndRoundUp(numCoeffs, 32U) * 32U;
  236. resizeCoefficientBuffer(newSize);
  237. }
  238. UINT32 writePos = 0;
  239. for(auto& entry : mVolumes)
  240. {
  241. UINT32 numProbes = (UINT32)entry.volume->getLightProbePositions().size();
  242. UINT32 size = numProbes * sizeof(LightProbeSHCoefficients);
  243. SPtr<GpuBuffer> localBuffer = entry.volume->getCoefficientsBuffer();
  244. // Note: Some of the coefficients might still be dirty (unrendered). Check for this and write them as black?
  245. mProbeCoefficientsGPU->copyData(*localBuffer, 0, writePos, size);
  246. writePos += size;
  247. }
  248. // Gather all positions
  249. UINT32 bufferOffset = 0;
  250. for(auto& entry : mVolumes)
  251. {
  252. const Vector<LightProbeInfo>& infos = entry.volume->getLightProbeInfos();
  253. const Vector<Vector3>& positions = entry.volume->getLightProbePositions();
  254. UINT32 numProbes = entry.volume->getNumActiveProbes();
  255. if (numProbes == 0)
  256. continue;
  257. Vector3 offset = entry.volume->getPosition();
  258. Quaternion rotation = entry.volume->getRotation();
  259. for(UINT32 i = 0; i < numProbes; i++)
  260. {
  261. Vector3 localPos = positions[i];
  262. Vector3 transformedPos = rotation.rotate(localPos) + offset;
  263. mTempTetrahedronPositions.push_back(transformedPos);
  264. mTempTetrahedronBufferIndices.push_back(bufferOffset + infos[i].bufferIdx);
  265. }
  266. bufferOffset += (UINT32)positions.size();
  267. }
  268. mTetrahedronInfos.clear();
  269. Vector<TetrahedronFaceData> outerFaces;
  270. generateTetrahedronData(mTempTetrahedronPositions, mTetrahedronInfos, outerFaces, true);
  271. // Find valid tetrahedrons
  272. UINT32 numTetrahedra = (UINT32)mTetrahedronInfos.size();
  273. bool* validTets = (bool*)bs_stack_alloc(sizeof(bool) * numTetrahedra);
  274. mNumValidTetrahedra = 0;
  275. for (UINT32 i = 0; i < (UINT32)mTetrahedronInfos.size(); i++)
  276. {
  277. const TetrahedronData& entry = mTetrahedronInfos[i];
  278. const Vector3& P1 = mTempTetrahedronPositions[entry.volume.vertices[0]];
  279. const Vector3& P2 = mTempTetrahedronPositions[entry.volume.vertices[1]];
  280. const Vector3& P3 = mTempTetrahedronPositions[entry.volume.vertices[2]];
  281. const Vector3& P4 = mTempTetrahedronPositions[entry.volume.vertices[3]];
  282. Vector3 E1 = P1 - P4;
  283. Vector3 E2 = P2 - P4;
  284. Vector3 E3 = P3 - P4;
  285. // If tetrahedron is co-planar just ignore it, shader will use some other nearby one instead. We can't
  286. // handle coplanar tetrahedrons because the matrix is not invertible, and for nearly co-planar ones the
  287. // math breaks down because of precision issues.
  288. validTets[i] = fabs(Vector3::dot(Vector3::normalize(Vector3::cross(E1, E2)), E3)) > 0.0001f;
  289. if (validTets[i])
  290. mNumValidTetrahedra++;
  291. }
  292. UINT32 numValidFaces = 0;
  293. for(auto& entry : outerFaces)
  294. {
  295. if (validTets[entry.tetrahedron])
  296. numValidFaces++;
  297. }
  298. // Generate a mesh out of all the tetrahedron triangles
  299. // Note: Currently the entire volume is rendered as a single large mesh, which will isn't optimal as we can't
  300. // perform frustum culling. A better option would be to split the mesh into multiple smaller volumes, do
  301. // frustum culling and possibly even sort by distance from camera.
  302. UINT32 numVertices = mNumValidTetrahedra * 4 * 3 + numValidFaces * 9 * 3;
  303. SPtr<VertexDataDesc> vertexDesc = bs_shared_ptr_new<VertexDataDesc>();
  304. vertexDesc->addVertElem(VET_FLOAT3, VES_POSITION);
  305. vertexDesc->addVertElem(VET_UINT1, VES_TEXCOORD);
  306. SPtr<MeshData> meshData = MeshData::create(numVertices, numVertices, vertexDesc);
  307. auto posIter = meshData->getVec3DataIter(VES_POSITION);
  308. auto idIter = meshData->getDWORDDataIter(VES_TEXCOORD);
  309. UINT32* indices = meshData->getIndices32();
  310. // Insert inner tetrahedron triangles
  311. UINT32 tetIdx = 0;
  312. for (UINT32 i = 0; i < (UINT32)mTetrahedronInfos.size(); i++)
  313. {
  314. if (!validTets[i])
  315. continue;
  316. const Tetrahedron& volume = mTetrahedronInfos[i].volume;
  317. Vector3 center(BsZero);
  318. for(UINT32 j = 0; j < 4; j++)
  319. center += mTempTetrahedronPositions[volume.vertices[j]];
  320. center /= 4.0f;
  321. static const UINT32 Permutations[4][3] =
  322. {
  323. { 0, 1, 2 },
  324. { 0, 1, 3 },
  325. { 0, 2, 3 },
  326. { 1, 2, 3 }
  327. };
  328. for(UINT32 j = 0; j < 4; j++)
  329. {
  330. Vector3 A = mTempTetrahedronPositions[volume.vertices[Permutations[j][0]]];
  331. Vector3 B = mTempTetrahedronPositions[volume.vertices[Permutations[j][1]]];
  332. Vector3 C = mTempTetrahedronPositions[volume.vertices[Permutations[j][2]]];
  333. // Make sure the triangle is clockwise, facing away from the center
  334. Vector3 e0 = A - C;
  335. Vector3 e1 = B - C;
  336. Vector3 normal = e0.cross(e1);
  337. if (normal.dot(A - center) > 0.0f)
  338. std::swap(B, C);
  339. posIter.addValue(A);
  340. posIter.addValue(B);
  341. posIter.addValue(C);
  342. idIter.addValue(tetIdx);
  343. idIter.addValue(tetIdx);
  344. idIter.addValue(tetIdx);
  345. indices[0] = tetIdx * 4 * 3 + j * 3 + 0;
  346. indices[1] = tetIdx * 4 * 3 + j * 3 + 1;
  347. indices[2] = tetIdx * 4 * 3 + j * 3 + 2;
  348. indices += 3;
  349. }
  350. tetIdx++;
  351. }
  352. // Generate an edge map for outer faces (required for step below)
  353. struct Edge
  354. {
  355. UINT32 vertInner[2];
  356. UINT32 vertOuter[2];
  357. UINT32 face[2];
  358. };
  359. FrameUnorderedMap<std::pair<INT32, INT32>, Edge, pair_hash> edgeMap;
  360. for(UINT32 i = 0; i < (UINT32)outerFaces.size(); i++)
  361. {
  362. if (!validTets[outerFaces[i].tetrahedron])
  363. continue;
  364. for (UINT32 j = 0; j < 3; ++j)
  365. {
  366. UINT32 v0 = outerFaces[i].innerVertices[j];
  367. UINT32 v1 = outerFaces[i].innerVertices[(j + 1) % 3];
  368. // Keep the same ordering so other faces can find the same edge
  369. if (v0 > v1)
  370. std::swap(v0, v1);
  371. auto iterFind = edgeMap.find(std::make_pair((INT32)v0, (INT32)v1));
  372. if (iterFind != edgeMap.end())
  373. {
  374. iterFind->second.face[1] = i;
  375. }
  376. else
  377. {
  378. Edge edge;
  379. edge.vertInner[0] = outerFaces[i].innerVertices[j];
  380. edge.vertInner[1] = outerFaces[i].innerVertices[(j + 1) % 3];
  381. edge.vertOuter[0] = outerFaces[i].outerVertices[j];
  382. edge.vertOuter[1] = outerFaces[i].outerVertices[(j + 1) % 3];
  383. edge.face[0] = i;
  384. edge.face[1] = -1;
  385. edgeMap.insert(std::make_pair(std::make_pair((INT32)v0, (INT32)v1), edge));
  386. }
  387. }
  388. }
  389. // Generate front and back triangles for extruded outer faces
  390. UINT32 faceIdx = 0;
  391. for(UINT32 i = 0; i < (UINT32)outerFaces.size(); i++)
  392. {
  393. if (!validTets[outerFaces[i].tetrahedron])
  394. continue;
  395. const TetrahedronFaceData& entry = outerFaces[i];
  396. static const UINT32 Permutations[2][3] = { {0, 1, 2 }, { 3, 4, 5} };
  397. // Make sure the triangle is clockwise, facing away from the center
  398. Vector3 center(BsZero);
  399. for (UINT32 k = 0; k < 3; k++)
  400. {
  401. center += mTempTetrahedronPositions[entry.innerVertices[k]];
  402. center += mTempTetrahedronPositions[entry.outerVertices[k]];
  403. }
  404. center /= 6.0f;
  405. for(UINT32 j = 0; j < 2; ++j)
  406. {
  407. UINT32 idxA = Permutations[j][0];
  408. UINT32 idxB = Permutations[j][1];
  409. UINT32 idxC = Permutations[j][2];
  410. idxA = idxA > 2 ? entry.outerVertices[idxA - 3] : entry.innerVertices[idxA];
  411. idxB = idxB > 2 ? entry.outerVertices[idxB - 3] : entry.innerVertices[idxB];
  412. idxC = idxC > 2 ? entry.outerVertices[idxC - 3] : entry.innerVertices[idxC];
  413. Vector3 A = mTempTetrahedronPositions[idxA];
  414. Vector3 B = mTempTetrahedronPositions[idxB];
  415. Vector3 C = mTempTetrahedronPositions[idxC];
  416. Vector3 e0 = A - C;
  417. Vector3 e1 = B - C;
  418. Vector3 normal = e0.cross(e1);
  419. if (normal.dot(A - center) > 0.0f)
  420. std::swap(A, B);
  421. posIter.addValue(A);
  422. posIter.addValue(B);
  423. posIter.addValue(C);
  424. idIter.addValue(tetIdx + faceIdx);
  425. idIter.addValue(tetIdx + faceIdx);
  426. idIter.addValue(tetIdx + faceIdx);
  427. indices[0] = tetIdx * 4 * 3 + faceIdx * 2 * 3 + j * 3 + 0;
  428. indices[1] = tetIdx * 4 * 3 + faceIdx * 2 * 3 + j * 3 + 1;
  429. indices[2] = tetIdx * 4 * 3 + faceIdx * 2 * 3 + j * 3 + 2;
  430. indices += 3;
  431. }
  432. faceIdx++;
  433. }
  434. // Generate sides for extruded outer faces
  435. UINT32 sideIdx = 0;
  436. for(auto& entry : edgeMap)
  437. {
  438. const Edge& edge = entry.second;
  439. for (UINT32 i = 0; i < 2; i++)
  440. {
  441. const TetrahedronFaceData& face = outerFaces[edge.face[i]];
  442. // Make sure the triangle is clockwise, facing away from the center
  443. Vector3 center(BsZero);
  444. for (UINT32 k = 0; k < 3; k++)
  445. {
  446. center += mTempTetrahedronPositions[face.innerVertices[k]];
  447. center += mTempTetrahedronPositions[face.outerVertices[k]];
  448. }
  449. center /= 6.0f;
  450. static const UINT32 Permutations[2][3] = { {0, 1, 2 }, { 1, 2, 3} };
  451. for(UINT32 j = 0; j < 2; ++j)
  452. {
  453. UINT32 idxA = Permutations[j][0];
  454. UINT32 idxB = Permutations[j][1];
  455. UINT32 idxC = Permutations[j][2];
  456. idxA = idxA > 1 ? edge.vertOuter[idxA - 2] : edge.vertInner[idxA];
  457. idxB = idxB > 1 ? edge.vertOuter[idxB - 2] : edge.vertInner[idxB];
  458. idxC = idxC > 1 ? edge.vertOuter[idxC - 2] : edge.vertInner[idxC];
  459. Vector3 A = mTempTetrahedronPositions[idxA];
  460. Vector3 B = mTempTetrahedronPositions[idxB];
  461. Vector3 C = mTempTetrahedronPositions[idxC];
  462. Vector3 e0 = A - C;
  463. Vector3 e1 = B - C;
  464. Vector3 normal = e0.cross(e1);
  465. if (normal.dot(A - center) > 0.0f)
  466. std::swap(A, B);
  467. posIter.addValue(A);
  468. posIter.addValue(B);
  469. posIter.addValue(C);
  470. idIter.addValue(tetIdx + edge.face[i]);
  471. idIter.addValue(tetIdx + edge.face[i]);
  472. idIter.addValue(tetIdx + edge.face[i]);
  473. indices[0] = tetIdx * 4 * 3 + faceIdx * 2 * 3 + sideIdx * 2 * 3 + j * 3 + 0;
  474. indices[1] = tetIdx * 4 * 3 + faceIdx * 2 * 3 + sideIdx * 2 * 3 + j * 3 + 1;
  475. indices[2] = tetIdx * 4 * 3 + faceIdx * 2 * 3 + sideIdx * 2 * 3 + j * 3 + 2;
  476. indices += 3;
  477. }
  478. sideIdx++;
  479. }
  480. }
  481. // Generate "caps" on the end of the extruded volume
  482. UINT32 capIdx = 0;
  483. for(UINT32 i = 0; i < (UINT32)outerFaces.size(); i++)
  484. {
  485. if (!validTets[outerFaces[i].tetrahedron])
  486. continue;
  487. const TetrahedronFaceData& entry = outerFaces[i];
  488. Vector3 A = mTempTetrahedronPositions[entry.outerVertices[0]];
  489. Vector3 B = mTempTetrahedronPositions[entry.outerVertices[1]];
  490. Vector3 C = mTempTetrahedronPositions[entry.outerVertices[2]];
  491. // Make sure the triangle is clockwise, facing toward the center
  492. const Tetrahedron& tet = mTetrahedronInfos[entry.tetrahedron].volume;
  493. Vector3 center(BsZero);
  494. for(UINT32 j = 0; j < 4; j++)
  495. center += mTempTetrahedronPositions[tet.vertices[j]];
  496. center /= 4.0f;
  497. Vector3 e0 = A - C;
  498. Vector3 e1 = B - C;
  499. Vector3 normal = e0.cross(e1);
  500. if (normal.dot(A - center) < 0.0f)
  501. std::swap(B, C);
  502. posIter.addValue(A);
  503. posIter.addValue(B);
  504. posIter.addValue(C);
  505. idIter.addValue(-1);
  506. idIter.addValue(-1);
  507. idIter.addValue(-1);
  508. indices[0] = tetIdx * 4 * 3 + faceIdx * 8 * 3 + capIdx * 3 + 0;
  509. indices[1] = tetIdx * 4 * 3 + faceIdx * 8 * 3 + capIdx * 3 + 1;
  510. indices[2] = tetIdx * 4 * 3 + faceIdx * 8 * 3 + capIdx * 3 + 2;
  511. indices += 3;
  512. capIdx++;
  513. }
  514. mVolumeMesh = Mesh::create(meshData);
  515. // Map vertices to actual SH coefficient indices, and write GPU buffer with tetrahedron information
  516. if ((mNumValidTetrahedra + numValidFaces) > mMaxTetrahedra)
  517. {
  518. UINT32 newSize = Math::divideAndRoundUp(mNumValidTetrahedra + numValidFaces, 64U) * 64U;
  519. resizeTetrahedronBuffer(newSize);
  520. }
  521. TetrahedronDataGPU* dst = (TetrahedronDataGPU*)mTetrahedronInfosGPU->lock(0, mTetrahedronInfosGPU->getSize(),
  522. GBL_WRITE_ONLY_DISCARD);
  523. // Write inner tetrahedron data
  524. for (UINT32 i = 0; i < (UINT32)mTetrahedronInfos.size(); i++)
  525. {
  526. if (!validTets[i])
  527. continue;
  528. TetrahedronData& entry = mTetrahedronInfos[i];
  529. for(UINT32 j = 0; j < 4; ++j)
  530. entry.volume.vertices[j] = mTempTetrahedronBufferIndices[entry.volume.vertices[j]];
  531. memcpy(dst->indices, entry.volume.vertices, sizeof(UINT32) * 4);
  532. memcpy(&dst->transform, &entry.transform, sizeof(float) * 12);
  533. dst++;
  534. }
  535. // Write extruded face data
  536. for (UINT32 i = 0; i < (UINT32)outerFaces.size(); i++)
  537. {
  538. if (!validTets[outerFaces[i].tetrahedron])
  539. continue;
  540. const TetrahedronFaceData& entry = outerFaces[i];
  541. UINT32 indices[4];
  542. indices[0] = mTempTetrahedronBufferIndices[entry.innerVertices[0]];
  543. indices[1] = mTempTetrahedronBufferIndices[entry.innerVertices[1]];
  544. indices[2] = mTempTetrahedronBufferIndices[entry.innerVertices[2]];
  545. indices[3] = -1;
  546. memcpy(dst->indices, indices, sizeof(UINT32) * 4);
  547. memcpy(&dst->transform, &entry.transform, sizeof(float) * 12);
  548. dst++;
  549. }
  550. mTetrahedronInfosGPU->unlock();
  551. // Write data specific to faces
  552. if (numValidFaces > mMaxFaces)
  553. {
  554. UINT32 newSize = Math::divideAndRoundUp(numValidFaces, 64U) * 64U;
  555. resizeTetrahedronFaceBuffer(newSize);
  556. }
  557. TetrahedronFaceDataGPU* faceDst = (TetrahedronFaceDataGPU*)mTetrahedronFaceInfosGPU->lock(0,
  558. mTetrahedronFaceInfosGPU->getSize(), GBL_WRITE_ONLY_DISCARD);
  559. for (UINT32 i = 0; i < (UINT32)outerFaces.size(); i++)
  560. {
  561. if (!validTets[outerFaces[i].tetrahedron])
  562. continue;
  563. const TetrahedronFaceData& entry = outerFaces[i];
  564. for (UINT32 j = 0; j < 3; j++)
  565. {
  566. faceDst->corners[j] = mTempTetrahedronPositions[entry.innerVertices[j]];
  567. faceDst->normals[j] = entry.normals[j];
  568. }
  569. faceDst->isQuadratic = entry.quadratic ? 1 : 0;
  570. faceDst++;
  571. }
  572. mTetrahedronFaceInfosGPU->unlock();
  573. bs_stack_free(validTets);
  574. mTempTetrahedronPositions.clear();
  575. mTempTetrahedronBufferIndices.clear();
  576. mTetrahedronVolumeDirty = false;
  577. }
  578. bool LightProbes::hasAnyProbes() const
  579. {
  580. for(auto& entry : mVolumes)
  581. {
  582. UINT32 numProbes = entry.volume->getNumActiveProbes();
  583. if (numProbes > 0)
  584. return true;
  585. }
  586. return false;
  587. }
  588. LightProbesInfo LightProbes::getInfo() const
  589. {
  590. LightProbesInfo info;
  591. info.shCoefficients = mProbeCoefficientsGPU;
  592. info.tetrahedra = mTetrahedronInfosGPU;
  593. info.faces = mTetrahedronFaceInfosGPU;
  594. info.tetrahedraVolume = mVolumeMesh;
  595. info.numTetrahedra = mNumValidTetrahedra;
  596. return info;
  597. }
  598. void LightProbes::resizeTetrahedronBuffer(UINT32 count)
  599. {
  600. GPU_BUFFER_DESC desc;
  601. desc.type = GBT_STRUCTURED;
  602. desc.elementSize = sizeof(TetrahedronDataGPU);
  603. desc.elementCount = count;
  604. desc.usage = GBU_STATIC;
  605. desc.format = BF_UNKNOWN;
  606. mTetrahedronInfosGPU = GpuBuffer::create(desc);
  607. mMaxTetrahedra = count;
  608. }
  609. void LightProbes::resizeTetrahedronFaceBuffer(UINT32 count)
  610. {
  611. GPU_BUFFER_DESC desc;
  612. desc.type = GBT_STRUCTURED;
  613. desc.elementSize = sizeof(TetrahedronFaceDataGPU);
  614. desc.elementCount = count;
  615. desc.usage = GBU_STATIC;
  616. desc.format = BF_UNKNOWN;
  617. mTetrahedronFaceInfosGPU = GpuBuffer::create(desc);
  618. mMaxFaces = count;
  619. }
  620. void LightProbes::resizeCoefficientBuffer(UINT32 count)
  621. {
  622. GPU_BUFFER_DESC desc;
  623. desc.type = GBT_STRUCTURED;
  624. desc.elementSize = sizeof(LightProbeSHCoefficients);
  625. desc.elementCount = count;
  626. desc.usage = GBU_STATIC;
  627. desc.format = BF_UNKNOWN;
  628. mProbeCoefficientsGPU = GpuBuffer::create(desc);
  629. mMaxCoefficients = count;
  630. }
  631. void LightProbes::generateTetrahedronData(Vector<Vector3>& positions, Vector<TetrahedronData>& tetrahedra,
  632. Vector<TetrahedronFaceData>& faces, bool generateExtrapolationVolume)
  633. {
  634. bs_frame_mark();
  635. {
  636. TetrahedronVolume volume = Triangulation::tetrahedralize(positions);
  637. if (generateExtrapolationVolume)
  638. {
  639. // Add geometry so we can handle the case when the interpolation position falls outside of the tetrahedra
  640. // volume. We use this geometry to project the position to the nearest face.
  641. UINT32 numOuterFaces = (UINT32)volume.outerFaces.size();
  642. // Calculate face normals for outer faces
  643. //// Make an edge map
  644. struct Edge
  645. {
  646. INT32 faces[2];
  647. INT32 oppositeVerts[2];
  648. };
  649. FrameUnorderedMap<std::pair<INT32, INT32>, Edge, pair_hash> edgeMap;
  650. for (UINT32 i = 0; i < numOuterFaces; ++i)
  651. {
  652. for (UINT32 j = 0; j < 3; ++j)
  653. {
  654. INT32 v0 = volume.outerFaces[i].vertices[j];
  655. INT32 v1 = volume.outerFaces[i].vertices[(j + 1) % 3];
  656. // Keep the same ordering so other faces can find the same edge
  657. if (v0 > v1)
  658. std::swap(v0, v1);
  659. auto iterFind = edgeMap.find(std::make_pair(v0, v1));
  660. if (iterFind != edgeMap.end())
  661. {
  662. iterFind->second.faces[1] = i;
  663. iterFind->second.oppositeVerts[1] = (j + 2) % 3;
  664. }
  665. else
  666. {
  667. Edge edge;
  668. edge.faces[0] = i;
  669. edge.oppositeVerts[0] = (j + 2) % 3;
  670. edgeMap.insert(std::make_pair(std::make_pair(v0, v1), edge));
  671. }
  672. }
  673. }
  674. //// Generate face normals
  675. struct FaceVertex
  676. {
  677. Vector3 normal = Vector3::ZERO;
  678. UINT32 outerIdx = -1;
  679. };
  680. FrameVector<Vector3> faceNormals(volume.outerFaces.size());
  681. for (UINT32 i = 0; i < (UINT32)volume.outerFaces.size(); ++i)
  682. {
  683. const Vector3& v0 = positions[volume.outerFaces[i].vertices[0]];
  684. const Vector3& v1 = positions[volume.outerFaces[i].vertices[1]];
  685. const Vector3& v2 = positions[volume.outerFaces[i].vertices[2]];
  686. Vector3 e0 = v1 - v0;
  687. Vector3 e1 = v2 - v0;
  688. // Make sure the normal is facing away from the center
  689. const Tetrahedron& tet = volume.tetrahedra[volume.outerFaces[i].tetrahedron];
  690. Vector3 center(BsZero);
  691. for(UINT32 j = 0; j < 4; j++)
  692. center += positions[tet.vertices[j]];
  693. center /= 4.0f;
  694. Vector3 normal = Vector3::normalize(e0.cross(e1));
  695. if (normal.dot(v0 - center) < 0.0f)
  696. normal = -normal;
  697. faceNormals[i] = normal;
  698. }
  699. //// Generate vertex normals
  700. FrameUnorderedMap<INT32, FaceVertex> faceVertices;
  701. for (auto& entry : edgeMap)
  702. {
  703. const Edge& edge = entry.second;
  704. auto accumulateNormalForEdgeVertex = [&](UINT32 v0Idx, UINT32 v1Idx)
  705. {
  706. auto iter = faceVertices.insert(std::make_pair(v0Idx, FaceVertex()));
  707. FaceVertex& accum = iter.first->second;
  708. const Vector3& v0 = positions[v0Idx];
  709. auto accumulateNormalForFace = [&](INT32 faceIdx, INT32 v2LocIdx)
  710. {
  711. const TetrahedronFace& face = volume.outerFaces[faceIdx];
  712. // Vertices on the face, that aren't the vertex we're calculating the normal for
  713. const Vector3& v1 = positions[v1Idx];
  714. const Vector3& v2 = positions[face.vertices[v2LocIdx]];
  715. // Weight the contribution to the normal based on the angle spanned by the triangle
  716. Vector3 e0 = Vector3::normalize(v1 - v0);
  717. Vector3 e1 = Vector3::normalize(v2 - v0);
  718. float weight = acos(e0.dot(e1));
  719. accum.normal += weight * faceNormals[faceIdx];
  720. };
  721. accumulateNormalForFace(edge.faces[0], entry.second.oppositeVerts[0]);
  722. accumulateNormalForFace(edge.faces[1], entry.second.oppositeVerts[1]);
  723. };
  724. accumulateNormalForEdgeVertex(entry.first.first, entry.first.second);
  725. accumulateNormalForEdgeVertex(entry.first.second, entry.first.first);
  726. }
  727. for (auto& entry : faceVertices)
  728. entry.second.normal.normalize();
  729. // For each face vertex, generate an outer vertex along its normal
  730. static const float ExtrapolationDistance = 5.0f;
  731. for(auto& entry : faceVertices)
  732. {
  733. entry.second.outerIdx = (UINT32)positions.size();
  734. Vector3 outerPos = positions[entry.first] + entry.second.normal * ExtrapolationDistance;
  735. positions.push_back(outerPos);
  736. }
  737. // Generate face data
  738. for (UINT32 i = 0; i < numOuterFaces; ++i)
  739. {
  740. const TetrahedronFace& face = volume.outerFaces[i];
  741. TetrahedronFaceData faceData;
  742. faceData.tetrahedron = face.tetrahedron;
  743. for (UINT32 j = 0; j < 3; j++)
  744. {
  745. const FaceVertex& faceVertex = faceVertices[face.vertices[j]];
  746. faceData.innerVertices[j] = face.vertices[j];
  747. faceData.outerVertices[j] = faceVertex.outerIdx;
  748. faceData.normals[j] = faceVertex.normal;
  749. }
  750. // Add a link on the source tetrahedron to the face data
  751. Tetrahedron& innerTet = volume.tetrahedra[face.tetrahedron];
  752. for(UINT32 j = 0; j < 4; j++)
  753. {
  754. if (innerTet.neighbors[j] == -1)
  755. {
  756. // Note: Not searching for opposite neighbor here. If tet. has multiple free faces then we
  757. // can't just pick the first one
  758. innerTet.neighbors[j] = (UINT32)volume.tetrahedra.size() + (UINT32)faces.size();
  759. break;
  760. }
  761. }
  762. // We need a way to project a point outside the tetrahedron volume onto an outer face, then calculate
  763. // triangle's barycentric coordinates. Use use the per-vertex normals to extrude the triangle face into
  764. // infinity.
  765. // Our point can be represented as:
  766. // p == a (p0 + t*v0) + b (p1 + t*v1) + c (p2 + t*v2)
  767. //
  768. // where a, b and c are barycentric coordinates,
  769. // p0, p1, p2 are the corners of the face
  770. // v0, v1, v2 are the vertex normals, per corner
  771. // t is the distance from the triangle to the point
  772. //
  773. // Essentially we're calculating the corners of a bigger triangle that's "t" units away from the
  774. // face, and its corners lie along the per-vertex normals. Point "p" will lie on that triangle, for which
  775. // we can then calculate barycentric coordinates normally.
  776. //
  777. // First we substitute: c = 1 - a - b
  778. // p == a (p0 + t v0) + b (p1 + t v1) + (1 - a - b) (p2 + t v2)
  779. // p == a (p0 + t v0) + b (p1 + t v1) + (p2 + t v2) - a (p2 + t v2) - b (p2 + t v2)
  780. // p == a (p0 - p2 + t v0 - t v2) + b (p1 - p2 + t v1 - t v2) + (p2 + t v2)
  781. //
  782. // And move everything to one side:
  783. // p - p2 - t v2 == a (p0 - p2 + t ( v0 - v2)) + b (p1 - p2 + t ( v1 - v2))
  784. // a (p0 - p2 + t ( v0 - v2)) + b (p1 - p2 + t ( v1 - v2)) - (p - p2 - t v2) == 0
  785. //
  786. // We rewrite it using:
  787. // Ap = p0 - p2
  788. // Av = v0 - v2
  789. // Bp = p1 - p2
  790. // Bv = v1 - v2
  791. // Cp = p - p2
  792. // Cv = -v2
  793. //
  794. // Which yields:
  795. // a (Ap + t Av) + b (Bp + t Bv) - (Cp + t Cv) == 0
  796. //
  797. // Which can be written in matrix form:
  798. //
  799. // M = {Ap + t Av, Bp + t Bv, Cp + t Cv}
  800. // a 0
  801. // M * [ b ] = [0]
  802. // -1 0
  803. //
  804. // From that we can tell that matrix M cannot be inverted, because if we multiply the zero vector with the
  805. // inverted matrix the result would be zero, and not [a, b, -1]. Since the matrix cannot be inverted
  806. // det(M) == 0.
  807. //
  808. // We can use that fact to calculate "t". After we have "t" we can calculate barycentric coordinates
  809. // normally.
  810. //
  811. // Solving equation det(M) == 0 yields a cubic in form:
  812. // p t^3 + q t^2 + r t + s = 0
  813. //
  814. // We'll convert this to monic form, by dividing by p:
  815. // t^3 + q/p t^2 + r/p t + s/p = 0
  816. //
  817. // Or if p ends up being zero, we end up with a quadratic instead:
  818. // q t^2 + r t + s = 0
  819. //
  820. // We want to create a matrix that when multiplied with the position, yields us the three coefficients,
  821. // which we can then use to solve for "t". For this we create a 4x3 matrix, where each row represents
  822. // a solution for one of the coefficients. We factor contributons to each coefficient whether they depend on
  823. // position x, y, z, or don't depend on position (row columns, in that order respectively).
  824. const Vector3& p0 = positions[faceData.innerVertices[0]];
  825. const Vector3& p1 = positions[faceData.innerVertices[1]];
  826. const Vector3& p2 = positions[faceData.innerVertices[2]];
  827. const Vector3& v0 = faceVertices[faceData.innerVertices[0]].normal;
  828. const Vector3& v1 = faceVertices[faceData.innerVertices[1]].normal;
  829. const Vector3& v2 = faceVertices[faceData.innerVertices[2]].normal;
  830. float p =
  831. v2.x * v1.y * v0.z -
  832. v1.x * v2.y * v0.z -
  833. v2.x * v0.y * v1.z +
  834. v0.x * v2.y * v1.z +
  835. v1.x * v0.y * v2.z -
  836. v0.x * v1.y * v2.z;
  837. float qx = -v1.y * v0.z + v2.y * v0.z + v0.y * v1.z - v2.y * v1.z - v0.y * v2.z + v1.y * v2.z;
  838. float qy = v1.x * v0.z - v2.x * v0.z - v0.x * v1.z + v2.x * v1.z + v0.x * v2.z - v1.x * v2.z;
  839. float qz = -v1.x * v0.y + v2.x * v0.y + v0.x * v1.y - v2.x * v1.y - v0.x * v2.y + v1.x * v2.y;
  840. float qw = v2.y * v1.z * p0.x - v1.y * v2.z * p0.x - v2.y * v0.z * p1.x + v0.y * v2.z * p1.x +
  841. v1.y * v0.z * p2.x - v0.y * v1.z * p2.x - v2.x * v1.z * p0.y + v1.x * v2.z * p0.y +
  842. v2.x * v0.z * p1.y - v0.x * v2.z * p1.y - v1.x * v0.z * p2.y + v0.x * v1.z * p2.y +
  843. v2.x * v1.y * p0.z - v1.x * v2.y * p0.z - v2.x * v0.y * p1.z + v0.x * v2.y * p1.z +
  844. v1.x * v0.y * p2.z - v0.x * v1.y * p2.z;
  845. float rx = v1.z * p0.y - v2.z * p0.y - v0.z * p1.y + v2.z * p1.y + v0.z * p2.y - v1.z * p2.y -
  846. v1.y * p0.z + v2.y * p0.z + v0.y * p1.z - v2.y * p1.z - v0.y * p2.z + v1.y * p2.z;
  847. float ry = -v1.z * p0.x + v2.z * p0.x + v0.z * p1.x - v2.z * p1.x - v0.z * p2.x + v1.z * p2.x +
  848. v1.x * p0.z - v2.x * p0.z - v0.x * p1.z + v2.x * p1.z + v0.x * p2.z - v1.x * p2.z;
  849. float rz = v1.y * p0.x - v2.y * p0.x - v0.y * p1.x + v2.y * p1.x + v0.y * p2.x - v1.y * p2.x -
  850. v1.x * p0.y + v2.x * p0.y + v0.x * p1.y - v2.x * p1.y - v0.x * p2.y + v1.x * p2.y;
  851. float rw = v2.z * p1.x * p0.y - v1.z * p2.x * p0.y - v2.z * p0.x * p1.y + v0.z * p2.x * p1.y +
  852. v1.z * p0.x * p2.y - v0.z * p1.x * p2.y - v2.y * p1.x * p0.z + v1.y * p2.x * p0.z +
  853. v2.x * p1.y * p0.z - v1.x * p2.y * p0.z + v2.y * p0.x * p1.z - v0.y * p2.x * p1.z -
  854. v2.x * p0.y * p1.z + v0.x * p2.y * p1.z - v1.y * p0.x * p2.z + v0.y * p1.x * p2.z +
  855. v1.x * p0.y * p2.z - v0.x * p1.y * p2.z;
  856. float sx = -p1.y * p0.z + p2.y * p0.z + p0.y * p1.z - p2.y * p1.z - p0.y * p2.z + p1.y * p2.z;
  857. float sy = p1.x * p0.z - p2.x * p0.z - p0.x * p1.z + p2.x * p1.z + p0.x * p2.z - p1.x * p2.z;
  858. float sz = -p1.x * p0.y + p2.x * p0.y + p0.x * p1.y - p2.x * p1.y - p0.x * p2.y + p1.x * p2.y;
  859. float sw = p2.x * p1.y * p0.z - p1.x * p2.y * p0.z - p2.x * p0.y * p1.z +
  860. p0.x * p2.y * p1.z + p1.x * p0.y * p2.z - p0.x * p1.y * p2.z;
  861. faceData.transform[0][0] = qx;
  862. faceData.transform[0][1] = qy;
  863. faceData.transform[0][2] = qz;
  864. faceData.transform[0][3] = qw;
  865. faceData.transform[1][0] = rx;
  866. faceData.transform[1][1] = ry;
  867. faceData.transform[1][2] = rz;
  868. faceData.transform[1][3] = rw;
  869. faceData.transform[2][0] = sx;
  870. faceData.transform[2][1] = sy;
  871. faceData.transform[2][2] = sz;
  872. faceData.transform[2][3] = sw;
  873. // Unused
  874. faceData.transform[3][0] = 0.0f;
  875. faceData.transform[3][1] = 0.0f;
  876. faceData.transform[3][2] = 0.0f;
  877. faceData.transform[3][3] = 0.0f;
  878. if (fabs(p) > 0.00001f)
  879. {
  880. faceData.transform = faceData.transform * (1.0f / p);
  881. faceData.quadratic = false;
  882. }
  883. else // Quadratic
  884. {
  885. faceData.quadratic = true;
  886. }
  887. faces.push_back(faceData);
  888. }
  889. }
  890. else
  891. {
  892. for (UINT32 i = 0; i < (UINT32)volume.outerFaces.size(); ++i)
  893. {
  894. const TetrahedronFace& face = volume.outerFaces[i];
  895. TetrahedronFaceData faceData;
  896. for (UINT32 j = 0; j < 3; j++)
  897. {
  898. faceData.innerVertices[j] = face.vertices[j];
  899. faceData.outerVertices[j] = -1;
  900. faceData.normals[j] = Vector3::ZERO;
  901. }
  902. faceData.tetrahedron = face.tetrahedron;
  903. faceData.transform = Matrix4::IDENTITY;
  904. faceData.quadratic = false;
  905. faces.push_back(faceData);
  906. }
  907. }
  908. // Generate matrices
  909. UINT32 numOutputTets = (UINT32)volume.tetrahedra.size();
  910. tetrahedra.reserve(numOutputTets);
  911. //// For inner tetrahedrons
  912. for(UINT32 i = 0; i < (UINT32)numOutputTets; ++i)
  913. {
  914. TetrahedronData entry;
  915. entry.volume = volume.tetrahedra[i];
  916. // Generate a matrix that can be used for calculating barycentric coordinates
  917. // To determine a point within a tetrahedron, using barycentric coordinates, we use:
  918. // P = (P1 - P4) * a + (P2 - P4) * b + (P3 - P4) * c + P4
  919. //
  920. // Where P1, P2, P3, P4 are the corners of the tetrahedron.
  921. //
  922. // Expanded for each coordinate this is:
  923. // x = (x1 - x4) * a + (x2 - x4) * b + (x3 - x4) * c + x4
  924. // y = (y1 - y4) * a + (y2 - y4) * b + (y3 - y4) * c + y4
  925. // z = (z1 - z4) * a + (z2 - z4) * b + (z3 - z4) * c + z4
  926. //
  927. // In matrix form this is:
  928. // a
  929. // P = [P1 - P4, P2 - P4, P3 - P4, P4] [b]
  930. // c
  931. // 1
  932. //
  933. // Solved for barycentric coordinates:
  934. // a
  935. // [b] = Minv * P
  936. // c
  937. // 1
  938. //
  939. // Where Minv is the inverse of the matrix above.
  940. const Vector3& P1 = positions[volume.tetrahedra[i].vertices[0]];
  941. const Vector3& P2 = positions[volume.tetrahedra[i].vertices[1]];
  942. const Vector3& P3 = positions[volume.tetrahedra[i].vertices[2]];
  943. const Vector3& P4 = positions[volume.tetrahedra[i].vertices[3]];
  944. Vector3 E1 = P1 - P4;
  945. Vector3 E2 = P2 - P4;
  946. Vector3 E3 = P3 - P4;
  947. Matrix4 mat;
  948. mat.setColumn(0, Vector4(E1, 0.0f));
  949. mat.setColumn(1, Vector4(E2, 0.0f));
  950. mat.setColumn(2, Vector4(E3, 0.0f));
  951. mat.setColumn(3, Vector4(P4, 1.0f));
  952. entry.transform = mat.inverse();
  953. tetrahedra.push_back(entry);
  954. }
  955. }
  956. bs_frame_clear();
  957. }
  958. }}