2
0

Hair.cpp 45 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033
  1. // Jolt Physics Library (https://github.com/jrouwe/JoltPhysics)
  2. // SPDX-FileCopyrightText: 2026 Jorrit Rouwe
  3. // SPDX-License-Identifier: MIT
  4. #include <Jolt/Jolt.h>
  5. #include <Jolt/Physics/Hair/Hair.h>
  6. #include <Jolt/Physics/Hair/HairShaders.h>
  7. #include <Jolt/Physics/Collision/Shape/ConvexHullShape.h>
  8. #include <Jolt/Physics/Collision/Shape/ScaleHelpers.h>
  9. #include <Jolt/Physics/PhysicsSystem.h>
  10. #include <Jolt/Core/Profiler.h>
  11. #ifdef JPH_DEBUG_RENDERER
  12. #include <Jolt/Renderer/DebugRenderer.h>
  13. #endif
  14. JPH_NAMESPACE_BEGIN
  15. Hair::Hair(const HairSettings *inSettings, RVec3Arg inPosition, QuatArg inRotation, ObjectLayer inLayer) :
  16. mSettings(inSettings),
  17. mPrevPosition(inPosition),
  18. mPosition(inPosition),
  19. mPrevRotation(inRotation),
  20. mRotation(inRotation),
  21. mLayer(inLayer)
  22. {
  23. }
  24. Hair::~Hair()
  25. {
  26. // Delete debug data
  27. if (mPositions != nullptr)
  28. delete [] mPositions;
  29. if (mRotations != nullptr)
  30. delete [] mRotations;
  31. if (mVelocities != nullptr)
  32. delete [] mVelocities;
  33. if (mRenderPositionsOverridden)
  34. delete [] mRenderPositions;
  35. }
  36. void Hair::Init(ComputeSystem *inComputeSystem)
  37. {
  38. // Create compute buffers
  39. size_t num_vertices_padded = mSettings->GetNumVerticesPadded();
  40. size_t grid_size = mSettings->mNeutralDensity.size();
  41. size_t num_render_vertices = mSettings->mRenderVertices.size();
  42. if (!mSettings->mScalpInverseBindPose.empty() && !mSettings->mScalpVertices.empty())
  43. {
  44. mScalpJointMatricesCB = inComputeSystem->CreateComputeBuffer(ComputeBuffer::EType::UploadBuffer, mSettings->mScalpInverseBindPose.size() * sizeof(Mat44), sizeof(Mat44)).Get();
  45. mScalpVerticesCB = inComputeSystem->CreateComputeBuffer(ComputeBuffer::EType::RWBuffer, mSettings->mScalpVertices.size(), sizeof(Float3)).Get();
  46. mScalpTrianglesCB = mSettings->mScalpTrianglesCB;
  47. }
  48. if (mScalpVerticesCB != nullptr)
  49. {
  50. mGlobalPoseTransformsCB = inComputeSystem->CreateComputeBuffer(ComputeBuffer::EType::RWBuffer, mSettings->mSimStrands.size(), sizeof(JPH_HairGlobalPoseTransform)).Get();
  51. }
  52. else
  53. {
  54. // No vertices provided externally and none in settings, use identity transforms
  55. JPH_HairGlobalPoseTransform identity;
  56. identity.mPosition = JPH_float3(0, 0, 0);
  57. identity.mRotation = JPH_float4(0, 0, 0, 1);
  58. Array<JPH_HairGlobalPoseTransform> identity_array(mSettings->mSimStrands.size(), identity);
  59. mGlobalPoseTransformsCB = inComputeSystem->CreateComputeBuffer(ComputeBuffer::EType::RWBuffer, mSettings->mSimStrands.size(), sizeof(JPH_HairGlobalPoseTransform), identity_array.data()).Get();
  60. }
  61. mCollisionPlanesCB = inComputeSystem->CreateComputeBuffer(ComputeBuffer::EType::RWBuffer, num_vertices_padded, sizeof(JPH_HairCollisionPlane)).Get();
  62. mMaterialsCB = inComputeSystem->CreateComputeBuffer(ComputeBuffer::EType::UploadBuffer, mSettings->mMaterials.size(), sizeof(JPH_HairMaterial)).Get();
  63. mPreviousPositionsCB = inComputeSystem->CreateComputeBuffer(ComputeBuffer::EType::RWBuffer, num_vertices_padded, sizeof(JPH_HairPosition)).Get();
  64. mPositionsCB = inComputeSystem->CreateComputeBuffer(ComputeBuffer::EType::RWBuffer, num_vertices_padded, sizeof(JPH_HairPosition)).Get();
  65. mVelocitiesCB = inComputeSystem->CreateComputeBuffer(ComputeBuffer::EType::RWBuffer, num_vertices_padded, sizeof(JPH_HairVelocity)).Get();
  66. mConstantsCB = inComputeSystem->CreateComputeBuffer(ComputeBuffer::EType::ConstantBuffer, 1, sizeof(JPH_HairUpdateContext)).Get();
  67. mVelocityAndDensityCB = inComputeSystem->CreateComputeBuffer(ComputeBuffer::EType::RWBuffer, grid_size, sizeof(Float4)).Get();
  68. if (!mRenderPositionsOverridden)
  69. mRenderPositionsCB = inComputeSystem->CreateComputeBuffer(ComputeBuffer::EType::RWBuffer, num_render_vertices, sizeof(Float3)).Get();
  70. }
  71. void Hair::InitializeContext(UpdateContext &outCtx, float inDeltaTime, const PhysicsSystem &inSystem)
  72. {
  73. float clamped_delta_time = min(inDeltaTime, mSettings->mMaxDeltaTime);
  74. outCtx.mNumIterations = (uint)std::round(clamped_delta_time * mSettings->mNumIterationsPerSecond);
  75. outCtx.mDeltaTime = outCtx.mNumIterations > 0? clamped_delta_time / outCtx.mNumIterations : 0.0f;
  76. outCtx.mTimeRatio = outCtx.mDeltaTime * float(HairSettings::cDefaultIterationsPerSecond);
  77. outCtx.mHalfDeltaTime = 0.5f * outCtx.mDeltaTime;
  78. outCtx.mInvDeltaTimeSq = outCtx.mDeltaTime > 0.0f? 1.0f / Square(outCtx.mDeltaTime) : 1.0e12f;
  79. outCtx.mTwoDivDeltaTime = outCtx.mDeltaTime > 0.0f? 2.0f / outCtx.mDeltaTime : 1.0e12f;
  80. outCtx.mSubStepGravity = (mRotation.Conjugated() * inSystem.GetGravity()) * outCtx.mDeltaTime;
  81. // Calculate delta transform from previous to current position and rotation
  82. outCtx.mHasTransformChanged = mPosition != mPrevPosition || mRotation != mPrevRotation;
  83. RMat44 prev_com = RMat44::sRotationTranslation(mPrevRotation, mPrevPosition);
  84. outCtx.mDeltaTransform = (GetWorldTransform().InversedRotationTranslation() * prev_com).ToMat44();
  85. outCtx.mDeltaTransformQuat = outCtx.mDeltaTransform.GetQuaternion();
  86. mPrevPosition = mPosition;
  87. mPrevRotation = mRotation;
  88. // Check if we need collision detection / grid
  89. outCtx.mNeedsCollision = false;
  90. outCtx.mNeedsGrid = false;
  91. outCtx.mGlobalPoseOnly = true;
  92. for (const HairSettings::Material &material : mSettings->mMaterials)
  93. {
  94. outCtx.mNeedsCollision |= material.mEnableCollision;
  95. outCtx.mNeedsGrid |= material.NeedsGrid();
  96. outCtx.mGlobalPoseOnly &= material.GlobalPoseOnly();
  97. }
  98. if (outCtx.mNeedsCollision)
  99. {
  100. struct Collector : public CollideShapeBodyCollector
  101. {
  102. Collector(const PhysicsSystem &inSystem, RMat44Arg inTransform, const AABox &inLocalBounds, Array<LeafShape> &ioHits) :
  103. mSystem(inSystem),
  104. mTransform(inTransform),
  105. mInverseTransform(inTransform.InversedRotationTranslation()),
  106. mLocalBounds(inLocalBounds),
  107. mHits(ioHits)
  108. {
  109. }
  110. virtual void AddHit(const BodyID &inResult) override
  111. {
  112. BodyLockRead lock(mSystem.GetBodyLockInterface(), inResult);
  113. if (lock.Succeeded())
  114. {
  115. const Body &body = lock.GetBody();
  116. if (body.IsRigidBody()
  117. && !body.IsSensor())
  118. {
  119. // Calculate transform of this body relative to the hair instance
  120. Mat44 com = (mInverseTransform * body.GetCenterOfMassTransform()).ToMat44();
  121. // Collect leaf shapes
  122. struct LeafShapeCollector : public TransformedShapeCollector
  123. {
  124. LeafShapeCollector(RMat44Arg inHeadTransform, const Body &inBody, Array<LeafShape> &ioHits) : mHeadTransform(inHeadTransform), mBody(inBody), mHits(ioHits) { }
  125. virtual void AddHit(const TransformedShape &inResult) override
  126. {
  127. mHits.emplace_back(Mat44::sRotationTranslation(inResult.mShapeRotation, Vec3(inResult.mShapePositionCOM)),
  128. inResult.GetShapeScale(),
  129. mHeadTransform.Multiply3x3Transposed(mBody.GetPointVelocity(mHeadTransform * inResult.mShapePositionCOM)), // Calculate velocity of shape at its center of mass position
  130. mHeadTransform.Multiply3x3Transposed(mBody.GetAngularVelocity()),
  131. inResult.mShape);
  132. }
  133. RMat44 mHeadTransform;
  134. const Body & mBody;
  135. Array<LeafShape> & mHits;
  136. };
  137. LeafShapeCollector collector(mTransform, body, mHits);
  138. body.GetShape()->CollectTransformedShapes(mLocalBounds, com.GetTranslation(), com.GetQuaternion(), Vec3::sOne(), SubShapeIDCreator(), collector, { });
  139. }
  140. }
  141. }
  142. private:
  143. const PhysicsSystem & mSystem;
  144. RMat44 mTransform;
  145. RMat44 mInverseTransform;
  146. AABox mLocalBounds;
  147. Array<LeafShape> & mHits;
  148. };
  149. // Calculate world space bounding box
  150. RMat44 transform = GetWorldTransform();
  151. AABox world_bounds = mSettings->mSimulationBounds.Transformed(transform);
  152. // Collect shapes that intersect with the bounding box
  153. Collector collector(inSystem, transform, mSettings->mSimulationBounds, outCtx.mShapes);
  154. DefaultBroadPhaseLayerFilter broadphase_layer_filter = inSystem.GetDefaultBroadPhaseLayerFilter(mLayer);
  155. DefaultObjectLayerFilter object_layer_filter = inSystem.GetDefaultLayerFilter(mLayer);
  156. inSystem.GetBroadPhaseQuery().CollideAABox(world_bounds, collector, broadphase_layer_filter, object_layer_filter);
  157. // If no shapes were found, we don't need collision
  158. if (outCtx.mShapes.empty())
  159. outCtx.mNeedsCollision = false;
  160. }
  161. }
  162. void Hair::Update(float inDeltaTime, Mat44Arg inJointToHair, const Mat44 *inJointMatrices, const PhysicsSystem &inSystem, const HairShaders &inShaders, ComputeSystem *inComputeSystem, ComputeQueue *inComputeQueue)
  163. {
  164. UpdateContext ctx;
  165. InitializeContext(ctx, inDeltaTime, inSystem);
  166. if (inJointMatrices != nullptr && mScalpJointMatricesCB != nullptr)
  167. {
  168. JPH_PROFILE("Prepare for Skinning");
  169. Mat44 *joints = mScalpJointMatricesCB->Map<Mat44>(ComputeBuffer::EMode::Write);
  170. mSettings->PrepareForScalpSkinning(inJointToHair, inJointMatrices, joints);
  171. mScalpJointMatricesCB->Unmap();
  172. }
  173. if (ctx.mNeedsCollision)
  174. {
  175. JPH_PROFILE("Create Collision Shapes");
  176. // First determine buffer sizes
  177. uint num_shapes = 0;
  178. uint num_faces = 0;
  179. uint num_vertices = 0;
  180. uint num_header = 0;
  181. uint num_indices = 0;
  182. uint max_vertices_per_face = 0;
  183. uint max_points = 0;
  184. for (const LeafShape &shape : ctx.mShapes)
  185. if (shape.mShape->GetSubType() == EShapeSubType::ConvexHull)
  186. {
  187. const ConvexHullShape *ch = static_cast<const ConvexHullShape *>(shape.mShape.GetPtr());
  188. ++num_shapes;
  189. ++num_header; // Write number of vertices
  190. uint np = ch->GetNumPoints();
  191. max_points = max(max_points, np);
  192. num_vertices += np;
  193. uint nf = ch->GetNumFaces();
  194. num_faces += nf;
  195. for (uint f = 0; f < nf; ++f)
  196. {
  197. num_header += 2; // Write indices start + end
  198. uint num_vertices_in_face = ch->GetNumVerticesInFace(f);
  199. num_indices += num_vertices_in_face;
  200. max_vertices_per_face = max(max_vertices_per_face, num_vertices_in_face);
  201. }
  202. }
  203. ++num_header; // Terminator
  204. num_indices += num_header;
  205. // Now allocate buffers
  206. if (mCollisionShapesCB == nullptr || mCollisionShapesCB->GetSize() < num_shapes)
  207. {
  208. mCollisionShapesCB = nullptr;
  209. mCollisionShapesCB = inComputeSystem->CreateComputeBuffer(ComputeBuffer::EType::UploadBuffer, num_shapes, sizeof(JPH_HairCollisionShape)).Get();
  210. }
  211. if (mShapePlanesCB == nullptr || mShapePlanesCB->GetSize() < num_faces)
  212. {
  213. mShapePlanesCB = nullptr;
  214. mShapePlanesCB = inComputeSystem->CreateComputeBuffer(ComputeBuffer::EType::UploadBuffer, max(num_faces, 1u), sizeof(Float4)).Get();
  215. }
  216. if (mShapeVerticesCB == nullptr || mShapeVerticesCB->GetSize() < num_vertices)
  217. {
  218. mShapeVerticesCB = nullptr;
  219. mShapeVerticesCB = inComputeSystem->CreateComputeBuffer(ComputeBuffer::EType::UploadBuffer, max(num_vertices, 1u), sizeof(Float3)).Get();
  220. }
  221. if (mShapeIndicesCB == nullptr || mShapeIndicesCB->GetSize() < num_indices)
  222. {
  223. mShapeIndicesCB = nullptr;
  224. mShapeIndicesCB = inComputeSystem->CreateComputeBuffer(ComputeBuffer::EType::UploadBuffer, num_indices, sizeof(uint32)).Get();
  225. }
  226. JPH_HairCollisionShape *collision_shapes = mCollisionShapesCB->Map<JPH_HairCollisionShape>(ComputeBuffer::EMode::Write);
  227. Float4 *shape_planes = mShapePlanesCB->Map<Float4>(ComputeBuffer::EMode::Write);
  228. Float3 *shape_vertices = mShapeVerticesCB->Map<Float3>(ComputeBuffer::EMode::Write);
  229. uint32 *shape_indices = mShapeIndicesCB->Map<uint32>(ComputeBuffer::EMode::Write);
  230. uint *face_indices = (uint *)JPH_STACK_ALLOC(max_vertices_per_face * sizeof(uint));
  231. Vec3 *points = (Vec3 *)JPH_STACK_ALLOC(max_points * sizeof(Vec3));
  232. // Convert the hulls to compute buffers
  233. Float4 *sp = shape_planes;
  234. Float3 *sv = shape_vertices;
  235. uint32 *sh = shape_indices;
  236. JPH_HairCollisionShape *cs = collision_shapes;
  237. uint32 *si = shape_indices + num_header;
  238. for (const LeafShape &shape : ctx.mShapes)
  239. if (shape.mShape->GetSubType() == EShapeSubType::ConvexHull)
  240. {
  241. const ConvexHullShape *ch = static_cast<const ConvexHullShape *>(shape.mShape.GetPtr());
  242. // Store collision shape
  243. shape.mTransform.GetTranslation().StoreFloat3(&cs->mCenterOfMass);
  244. shape.mLinearVelocity.StoreFloat3(&cs->mLinearVelocity);
  245. shape.mAngularVelocity.StoreFloat3(&cs->mAngularVelocity);
  246. ++cs;
  247. // Store points transformed to hair space
  248. Mat44 shape_transform = shape.mTransform.PreScaled(shape.mScale);
  249. uint first_vertex_index = uint(sv - shape_vertices);
  250. for (uint p = 0, np = ch->GetNumPoints(); p < np; ++p)
  251. {
  252. Vec3 v = shape_transform * ch->GetPoint(p);
  253. points[p] = v; // Store points in a temporary buffer so we avoid reading from GPU memory
  254. v.StoreFloat3(sv);
  255. ++sv;
  256. }
  257. // Store number of faces
  258. uint nf = ch->GetNumFaces();
  259. *sh = nf;
  260. ++sh;
  261. // Store the indices
  262. if (ScaleHelpers::IsInsideOut(shape.mScale))
  263. {
  264. // Reverse winding order
  265. for (uint f = 0; f < nf; ++f)
  266. {
  267. // Store indices
  268. uint nv = ch->GetFaceVertices(f, max_vertices_per_face, face_indices);
  269. uint32 indices_start = uint32(si - shape_indices);
  270. *sh = indices_start;
  271. ++sh;
  272. *sh = indices_start + nv;
  273. ++sh;
  274. for (int v = int(nv) - 1; v >= 0; --v, ++si)
  275. *si = face_indices[v] + first_vertex_index;
  276. // Calculate plane (avoids reading from GPU memory)
  277. Plane::sFromPointsCCW(points[face_indices[2]], points[face_indices[1]], points[face_indices[0]]).StoreFloat4(sp);
  278. ++sp;
  279. }
  280. }
  281. else
  282. {
  283. // Keep winding order
  284. for (uint f = 0; f < nf; ++f)
  285. {
  286. // Store indices
  287. uint nv = ch->GetFaceVertices(f, max_vertices_per_face, face_indices);
  288. uint32 indices_start = uint32(si - shape_indices);
  289. *sh++ = indices_start;
  290. *sh++ = indices_start + nv;
  291. for (uint v = 0; v < nv; ++v)
  292. *si++ = face_indices[v] + first_vertex_index;
  293. // Calculate plane (avoids reading from GPU memory)
  294. Plane::sFromPointsCCW(points[face_indices[0]], points[face_indices[1]], points[face_indices[2]]).StoreFloat4(sp);
  295. ++sp;
  296. }
  297. }
  298. }
  299. *sh = 0; // Terminator
  300. ++sh;
  301. JPH_ASSERT(uint(cs - collision_shapes) == num_shapes);
  302. JPH_ASSERT(uint(sp - shape_planes) == num_faces);
  303. JPH_ASSERT(uint(sv - shape_vertices) == num_vertices);
  304. JPH_ASSERT(uint(sh - shape_indices) == num_header);
  305. JPH_ASSERT(uint(si - shape_indices) == num_indices);
  306. // Unmap buffers
  307. mCollisionShapesCB->Unmap();
  308. mShapePlanesCB->Unmap();
  309. mShapeVerticesCB->Unmap();
  310. mShapeIndicesCB->Unmap();
  311. }
  312. {
  313. JPH_PROFILE("Set materials");
  314. JPH_HairMaterial *materials = mMaterialsCB->Map<JPH_HairMaterial>(ComputeBuffer::EMode::Write);
  315. for (size_t i = 0, n = mSettings->mMaterials.size(); i < n; ++i)
  316. {
  317. const HairSettings::Material &m_in = mSettings->mMaterials[i];
  318. JPH_HairMaterial &m_out = materials[i];
  319. GradientSampler world_transform_influence(m_in.mWorldTransformInfluence);
  320. m_out.mWorldTransformInfluence = world_transform_influence.ToFloat4();
  321. GradientSampler global_pose(ctx.mGlobalPoseOnly? m_in.mGlobalPose : m_in.mGlobalPose.MakeStepDependent(ctx.mTimeRatio));
  322. m_out.mGlobalPose = global_pose.ToFloat4();
  323. GradientSampler global_pose_skin_to_root(m_in.mSkinGlobalPose);
  324. m_out.mSkinGlobalPose = global_pose_skin_to_root.ToFloat4();
  325. GradientSampler gravity_factor(m_in.mGravityFactor);
  326. m_out.mGravityFactor = gravity_factor.ToFloat4();
  327. GradientSampler hair_radius(m_in.mHairRadius);
  328. m_out.mHairRadius = hair_radius.ToFloat4();
  329. m_out.mBendComplianceMultiplier = m_in.mBendComplianceMultiplier;
  330. GradientSampler grid_velocity_factor(m_in.mGridVelocityFactor.MakeStepDependent(ctx.mTimeRatio));
  331. m_out.mGridVelocityFactor = grid_velocity_factor.ToFloat4();
  332. m_out.mEnableCollision = ctx.mNeedsCollision && m_in.mEnableCollision? 1 : 0;
  333. m_out.mEnableLRA = m_in.mEnableLRA? 1 : 0;
  334. m_out.mEnableGrid = m_in.mGridVelocityFactor.mMin != 0.0f || m_in.mGridVelocityFactor.mMax != 0.0f || m_in.mGridDensityForceFactor != 0.0f;
  335. m_out.mFriction = m_in.mFriction;
  336. m_out.mExpLinearDampingDeltaTime = std::exp(-m_in.mLinearDamping * ctx.mDeltaTime);
  337. m_out.mExpAngularDampingDeltaTime = std::exp(-m_in.mAngularDamping * ctx.mDeltaTime);
  338. m_out.mBendComplianceInvDeltaTimeSq = m_in.mBendCompliance * ctx.mInvDeltaTimeSq;
  339. m_out.mStretchComplianceInvDeltaTimeSq = m_in.mStretchCompliance * ctx.mInvDeltaTimeSq;
  340. m_out.mGridDensityForceFactor = m_in.mGridDensityForceFactor;
  341. m_out.mInertiaMultiplier = m_in.mInertiaMultiplier;
  342. m_out.mMaxLinearVelocitySq = Square(m_in.mMaxLinearVelocity);
  343. m_out.mMaxAngularVelocitySq = Square(m_in.mMaxAngularVelocity);
  344. }
  345. mMaterialsCB->Unmap();
  346. }
  347. {
  348. JPH_PROFILE("Set constants");
  349. JPH_HairUpdateContext *cdata = mConstantsCB->Map<JPH_HairUpdateContext>(ComputeBuffer::EMode::Write);
  350. cdata->cNumStrands = uint32(mSettings->mSimStrands.size());
  351. cdata->cNumVertices = mSettings->GetNumVerticesPadded();
  352. cdata->cNumGridPoints = (uint32)mSettings->mNeutralDensity.size();
  353. cdata->cNumRenderVertices = (uint)mSettings->mRenderVertices.size();
  354. HairSettings::GridSampler grid_sampler(mSettings);
  355. memcpy(&cdata->cGridSizeMin2, &grid_sampler.mGridSizeMin2, 3 * sizeof(float));
  356. cdata->cTwoDivDeltaTime = ctx.mTwoDivDeltaTime;
  357. grid_sampler.mGridSizeMin1.StoreFloat3(&cdata->cGridSizeMin1);
  358. cdata->cDeltaTime = ctx.mDeltaTime;
  359. grid_sampler.mOffset.StoreFloat3(&cdata->cGridOffset);
  360. cdata->cHalfDeltaTime = ctx.mHalfDeltaTime;
  361. grid_sampler.mScale.StoreFloat3(&cdata->cGridScale);
  362. cdata->cInvDeltaTimeSq = ctx.mInvDeltaTimeSq;
  363. ctx.mSubStepGravity.StoreFloat3(&cdata->cSubStepGravity);
  364. cdata->cNumSkinVertices = (uint)mSettings->mScalpVertices.size();
  365. memcpy(&cdata->cGridStride, &grid_sampler.mGridStride, 3 * sizeof(uint32));
  366. cdata->cNumSkinWeightsPerVertex = mSettings->mScalpNumSkinWeightsPerVertex;
  367. for (int i = 0; i < 4; ++i)
  368. ctx.mDeltaTransform.GetColumn4(i).StoreFloat4(&cdata->cDeltaTransform[i]);
  369. for (int i = 0; i < 4; ++i)
  370. mScalpToHead.GetColumn4(i).StoreFloat4(&cdata->cScalpToHead[i]);
  371. ctx.mDeltaTransformQuat.StoreFloat4(&cdata->cDeltaTransformQuat);
  372. mConstantsCB->Unmap();
  373. }
  374. {
  375. JPH_PROFILE("Set iteration constants");
  376. // Ensure that we have the right number of constant buffers allocated
  377. uint old_size = uint(mIterationConstantsCB.size());
  378. if (old_size < ctx.mNumIterations)
  379. {
  380. mIterationConstantsCB.resize(ctx.mNumIterations);
  381. for (uint i = old_size; i < ctx.mNumIterations; ++i)
  382. mIterationConstantsCB[i] = inComputeSystem->CreateComputeBuffer(ComputeBuffer::EType::ConstantBuffer, 1, sizeof(JPH_HairIterationContext)).Get();
  383. }
  384. // Fill in the constant buffers
  385. JPH_HairIterationContext iteration_data;
  386. for (uint i = 0; i < ctx.mNumIterations; ++i)
  387. {
  388. iteration_data.cAccumulatedDeltaTime = ctx.mDeltaTime * (i + 1);
  389. iteration_data.cIterationFraction = 1.0f / float(ctx.mNumIterations - i);
  390. JPH_HairIterationContext *idata = mIterationConstantsCB[i]->Map<JPH_HairIterationContext>(ComputeBuffer::EMode::Write);
  391. *idata = iteration_data;
  392. mIterationConstantsCB[i]->Unmap();
  393. }
  394. }
  395. {
  396. JPH_PROFILE("Queue Compute");
  397. uint dispatch_per_vertex = (mSettings->GetNumVerticesPadded() + cHairPerVertexBatch - 1) / cHairPerVertexBatch;
  398. uint dispatch_per_vertex_skip_first_vertex = (mSettings->GetNumVerticesPadded() - (uint)mSettings->mSimStrands.size() + cHairPerVertexBatch - 1) / cHairPerVertexBatch; // Skip the first vertex of each strand
  399. uint dispatch_per_grid_cell = uint((mSettings->mNeutralDensity.size() + cHairPerGridCellBatch - 1) / cHairPerGridCellBatch);
  400. uint dispatch_per_strand = uint((mSettings->mSimStrands.size() + cHairPerStrandBatch - 1) / cHairPerStrandBatch);
  401. uint dispatch_per_render_vertex = uint((mSettings->mRenderVertices.size() + cHairPerRenderVertexBatch - 1) / cHairPerRenderVertexBatch);
  402. bool was_teleported = mTeleported;
  403. mTeleported = false;
  404. if (was_teleported)
  405. {
  406. // Initialize positions and velocities
  407. inComputeQueue->SetShader(inShaders.mTeleportCS);
  408. inComputeQueue->SetConstantBuffer("gContext", mConstantsCB);
  409. inComputeQueue->SetBuffer("gInitialPositions", mSettings->mVerticesPositionCB);
  410. inComputeQueue->SetBuffer("gInitialBishops", mSettings->mVerticesBishopCB);
  411. inComputeQueue->SetRWBuffer("gPositions", mPositionsCB);
  412. inComputeQueue->SetRWBuffer("gVelocities", mVelocitiesCB);
  413. inComputeQueue->Dispatch(dispatch_per_vertex);
  414. }
  415. else if (!ctx.mGlobalPoseOnly && ctx.mHasTransformChanged)
  416. {
  417. // Apply delta transform
  418. inComputeQueue->SetShader(inShaders.mApplyDeltaTransformCS);
  419. inComputeQueue->SetConstantBuffer("gContext", mConstantsCB);
  420. inComputeQueue->SetBuffer("gVerticesFixed", mSettings->mVerticesFixedCB);
  421. inComputeQueue->SetBuffer("gStrandFractions", mSettings->mVerticesStrandFractionCB);
  422. inComputeQueue->SetBuffer("gMaterials", mMaterialsCB);
  423. inComputeQueue->SetBuffer("gStrandMaterialIndex", mSettings->mStrandMaterialIndexCB);
  424. inComputeQueue->SetRWBuffer("gPositions", mPositionsCB);
  425. inComputeQueue->SetRWBuffer("gVelocities", mVelocitiesCB);
  426. inComputeQueue->Dispatch(dispatch_per_vertex_skip_first_vertex);
  427. }
  428. if (mScalpJointMatricesCB != nullptr)
  429. {
  430. // Skin the scalp mesh
  431. inComputeQueue->SetShader(inShaders.mSkinVerticesCS);
  432. inComputeQueue->SetConstantBuffer("gContext", mConstantsCB);
  433. inComputeQueue->SetBuffer("gScalpVertices", mSettings->mScalpVerticesCB);
  434. inComputeQueue->SetBuffer("gScalpSkinWeights", mSettings->mScalpSkinWeightsCB);
  435. inComputeQueue->SetBuffer("gScalpJointMatrices", mScalpJointMatricesCB);
  436. inComputeQueue->SetRWBuffer("gScalpVerticesOut", mScalpVerticesCB);
  437. inComputeQueue->Dispatch(uint((mSettings->mScalpVertices.size() + cHairPerVertexBatch - 1) / cHairPerVertexBatch));
  438. }
  439. if (mScalpVerticesCB != nullptr)
  440. {
  441. // Determine if we directly write to the position / transform buffers or if we need to interpolate
  442. bool needs_interpolate = !ctx.mGlobalPoseOnly && !was_teleported;
  443. // Create target buffers if they don't exist yet
  444. if (mTargetPositionsCB == nullptr && needs_interpolate)
  445. {
  446. mTargetPositionsCB = inComputeSystem->CreateComputeBuffer(ComputeBuffer::EType::RWBuffer, mSettings->mSimStrands.size(), sizeof(JPH_HairPosition)).Get();
  447. mTargetGlobalPoseTransformsCB = inComputeSystem->CreateComputeBuffer(ComputeBuffer::EType::RWBuffer, mSettings->mSimStrands.size(), sizeof(JPH_HairGlobalPoseTransform)).Get();
  448. }
  449. // Skin the strand roots to the scalp mesh
  450. inComputeQueue->SetShader(inShaders.mSkinRootsCS);
  451. inComputeQueue->SetConstantBuffer("gContext", mConstantsCB);
  452. inComputeQueue->SetBuffer("gSkinPoints", mSettings->mSkinPointsCB);
  453. inComputeQueue->SetBuffer("gScalpVertices", mScalpVerticesCB);
  454. inComputeQueue->SetBuffer("gScalpTriangles", mScalpTrianglesCB);
  455. inComputeQueue->SetBuffer("gInitialPositions", mSettings->mVerticesPositionCB);
  456. inComputeQueue->SetBuffer("gInitialBishops", mSettings->mVerticesBishopCB);
  457. inComputeQueue->SetRWBuffer("gPositions", needs_interpolate? mTargetPositionsCB : mPositionsCB);
  458. inComputeQueue->SetRWBuffer("gGlobalPoseTransforms", needs_interpolate? mTargetGlobalPoseTransformsCB : mGlobalPoseTransformsCB);
  459. inComputeQueue->Dispatch(dispatch_per_strand);
  460. }
  461. if (ctx.mGlobalPoseOnly)
  462. {
  463. // Only run global pose logic
  464. inComputeQueue->SetShader(inShaders.mApplyGlobalPoseCS);
  465. inComputeQueue->SetConstantBuffer("gContext", mConstantsCB);
  466. inComputeQueue->SetBuffer("gVerticesFixed", mSettings->mVerticesFixedCB);
  467. inComputeQueue->SetBuffer("gStrandFractions", mSettings->mVerticesStrandFractionCB);
  468. inComputeQueue->SetBuffer("gInitialPositions", mSettings->mVerticesPositionCB);
  469. inComputeQueue->SetBuffer("gInitialBishops", mSettings->mVerticesBishopCB);
  470. inComputeQueue->SetBuffer("gStrandMaterialIndex", mSettings->mStrandMaterialIndexCB);
  471. inComputeQueue->SetBuffer("gMaterials", mMaterialsCB);
  472. inComputeQueue->SetBuffer("gGlobalPoseTransforms", mGlobalPoseTransformsCB);
  473. inComputeQueue->SetRWBuffer("gPositions", mPositionsCB);
  474. inComputeQueue->Dispatch(dispatch_per_vertex_skip_first_vertex);
  475. }
  476. else if (ctx.mNumIterations > 0)
  477. {
  478. if (ctx.mNeedsCollision)
  479. {
  480. // Calculate collision planes
  481. inComputeQueue->SetShader(inShaders.mCalculateCollisionPlanesCS);
  482. inComputeQueue->SetConstantBuffer("gContext", mConstantsCB);
  483. inComputeQueue->SetBuffer("gPositions", mPositionsCB);
  484. inComputeQueue->SetBuffer("gShapePlanes", mShapePlanesCB);
  485. inComputeQueue->SetBuffer("gShapeVertices", mShapeVerticesCB);
  486. inComputeQueue->SetBuffer("gShapeIndices", mShapeIndicesCB);
  487. inComputeQueue->SetRWBuffer("gCollisionPlanes", mCollisionPlanesCB);
  488. inComputeQueue->Dispatch(dispatch_per_vertex_skip_first_vertex);
  489. }
  490. if (ctx.mNeedsGrid)
  491. {
  492. // Clear the grid
  493. inComputeQueue->SetShader(inShaders.mGridClearCS);
  494. inComputeQueue->SetConstantBuffer("gContext", mConstantsCB);
  495. inComputeQueue->SetRWBuffer("gVelocityAndDensity", mVelocityAndDensityCB);
  496. inComputeQueue->Dispatch(dispatch_per_grid_cell);
  497. // Accumulate vertices into the grid
  498. inComputeQueue->SetShader(inShaders.mGridAccumulateCS);
  499. inComputeQueue->SetConstantBuffer("gContext", mConstantsCB);
  500. inComputeQueue->SetBuffer("gVerticesFixed", mSettings->mVerticesFixedCB);
  501. inComputeQueue->SetBuffer("gPositions", mPositionsCB);
  502. inComputeQueue->SetBuffer("gVelocities", mVelocitiesCB);
  503. inComputeQueue->SetRWBuffer("gVelocityAndDensity", mVelocityAndDensityCB);
  504. inComputeQueue->Dispatch(dispatch_per_vertex_skip_first_vertex);
  505. // Normalize velocities in the grid
  506. inComputeQueue->SetShader(inShaders.mGridNormalizeCS);
  507. inComputeQueue->SetConstantBuffer("gContext", mConstantsCB);
  508. inComputeQueue->SetRWBuffer("gVelocityAndDensity", mVelocityAndDensityCB);
  509. inComputeQueue->Dispatch(dispatch_per_grid_cell);
  510. }
  511. // First integrate
  512. inComputeQueue->SetShader(inShaders.mIntegrateCS);
  513. inComputeQueue->SetConstantBuffer("gContext", mConstantsCB);
  514. inComputeQueue->SetBuffer("gVerticesFixed", mSettings->mVerticesFixedCB);
  515. inComputeQueue->SetBuffer("gStrandFractions", mSettings->mVerticesStrandFractionCB);
  516. inComputeQueue->SetBuffer("gNeutralDensity", mSettings->mNeutralDensityCB);
  517. inComputeQueue->SetBuffer("gVelocityAndDensity", mVelocityAndDensityCB);
  518. inComputeQueue->SetBuffer("gStrandMaterialIndex", mSettings->mStrandMaterialIndexCB);
  519. inComputeQueue->SetBuffer("gMaterials", mMaterialsCB);
  520. inComputeQueue->SetBuffer("gVelocities", mVelocitiesCB);
  521. inComputeQueue->SetRWBuffer("gPositions", mPositionsCB);
  522. inComputeQueue->SetRWBuffer("gPreviousPositions", mPreviousPositionsCB);
  523. inComputeQueue->Dispatch(dispatch_per_vertex_skip_first_vertex);
  524. for (uint it = 0; it < ctx.mNumIterations; ++it)
  525. {
  526. if (mTargetPositionsCB != nullptr && !was_teleported)
  527. {
  528. // Update skinned roots for this iteration (interpolate them towards the target positions)
  529. inComputeQueue->SetShader(inShaders.mUpdateRootsCS);
  530. inComputeQueue->SetConstantBuffer("gContext", mConstantsCB);
  531. inComputeQueue->SetConstantBuffer("gIterationContext", mIterationConstantsCB[it]);
  532. inComputeQueue->SetBuffer("gTargetPositions", mTargetPositionsCB);
  533. inComputeQueue->SetBuffer("gTargetGlobalPoseTransforms", mTargetGlobalPoseTransformsCB);
  534. inComputeQueue->SetRWBuffer("gPositions", mPositionsCB);
  535. inComputeQueue->SetRWBuffer("gGlobalPoseTransforms", mGlobalPoseTransformsCB);
  536. inComputeQueue->Dispatch(dispatch_per_strand);
  537. }
  538. // Then update the constraints per strand
  539. inComputeQueue->SetShader(inShaders.mUpdateStrandsCS);
  540. inComputeQueue->SetConstantBuffer("gContext", mConstantsCB);
  541. inComputeQueue->SetBuffer("gVerticesFixed", mSettings->mVerticesFixedCB);
  542. inComputeQueue->SetBuffer("gStrandFractions", mSettings->mVerticesStrandFractionCB);
  543. inComputeQueue->SetBuffer("gInitialPositions", mSettings->mVerticesPositionCB);
  544. inComputeQueue->SetBuffer("gOmega0s", mSettings->mVerticesOmega0CB);
  545. inComputeQueue->SetBuffer("gInitialLengths", mSettings->mVerticesLengthCB);
  546. inComputeQueue->SetBuffer("gStrandVertexCounts", mSettings->mStrandVertexCountsCB);
  547. inComputeQueue->SetBuffer("gStrandMaterialIndex", mSettings->mStrandMaterialIndexCB);
  548. inComputeQueue->SetBuffer("gMaterials", mMaterialsCB);
  549. inComputeQueue->SetRWBuffer("gPositions", mPositionsCB);
  550. inComputeQueue->Dispatch(dispatch_per_strand);
  551. if (it == ctx.mNumIterations - 1)
  552. {
  553. // Last iteration: only update velocities
  554. inComputeQueue->SetShader(inShaders.mUpdateVelocityCS);
  555. inComputeQueue->SetConstantBuffer("gContext", mConstantsCB);
  556. inComputeQueue->SetConstantBuffer("gIterationContext", mIterationConstantsCB[it]);
  557. inComputeQueue->SetBuffer("gVerticesFixed", mSettings->mVerticesFixedCB);
  558. inComputeQueue->SetBuffer("gStrandFractions", mSettings->mVerticesStrandFractionCB);
  559. inComputeQueue->SetBuffer("gInitialPositions", mSettings->mVerticesPositionCB);
  560. inComputeQueue->SetBuffer("gInitialBishops", mSettings->mVerticesBishopCB);
  561. inComputeQueue->SetBuffer("gStrandMaterialIndex", mSettings->mStrandMaterialIndexCB);
  562. inComputeQueue->SetBuffer("gMaterials", mMaterialsCB);
  563. inComputeQueue->SetBuffer("gPreviousPositions", mPreviousPositionsCB);
  564. inComputeQueue->SetBuffer("gGlobalPoseTransforms", mGlobalPoseTransformsCB);
  565. inComputeQueue->SetBuffer("gCollisionShapes", mCollisionShapesCB);
  566. inComputeQueue->SetBuffer("gCollisionPlanes", mCollisionPlanesCB);
  567. inComputeQueue->SetRWBuffer("gPositions", mPositionsCB);
  568. inComputeQueue->SetRWBuffer("gVelocities", mVelocitiesCB);
  569. inComputeQueue->Dispatch(dispatch_per_vertex_skip_first_vertex);
  570. }
  571. else
  572. {
  573. // Other iterations: update velocities then integrate again
  574. inComputeQueue->SetShader(inShaders.mUpdateVelocityIntegrateCS);
  575. inComputeQueue->SetConstantBuffer("gContext", mConstantsCB);
  576. inComputeQueue->SetConstantBuffer("gIterationContext", mIterationConstantsCB[it]);
  577. inComputeQueue->SetBuffer("gVerticesFixed", mSettings->mVerticesFixedCB);
  578. inComputeQueue->SetBuffer("gStrandFractions", mSettings->mVerticesStrandFractionCB);
  579. inComputeQueue->SetBuffer("gInitialPositions", mSettings->mVerticesPositionCB);
  580. inComputeQueue->SetBuffer("gInitialBishops", mSettings->mVerticesBishopCB);
  581. inComputeQueue->SetBuffer("gNeutralDensity", mSettings->mNeutralDensityCB);
  582. inComputeQueue->SetBuffer("gVelocityAndDensity", mVelocityAndDensityCB);
  583. inComputeQueue->SetBuffer("gStrandMaterialIndex", mSettings->mStrandMaterialIndexCB);
  584. inComputeQueue->SetBuffer("gMaterials", mMaterialsCB);
  585. inComputeQueue->SetBuffer("gGlobalPoseTransforms", mGlobalPoseTransformsCB);
  586. inComputeQueue->SetBuffer("gCollisionShapes", mCollisionShapesCB);
  587. inComputeQueue->SetBuffer("gCollisionPlanes", mCollisionPlanesCB);
  588. inComputeQueue->SetRWBuffer("gPreviousPositions", mPreviousPositionsCB);
  589. inComputeQueue->SetRWBuffer("gPositions", mPositionsCB);
  590. inComputeQueue->Dispatch(dispatch_per_vertex_skip_first_vertex);
  591. }
  592. }
  593. }
  594. // Remap simulation positions to render positions
  595. inComputeQueue->SetShader(inShaders.mCalculateRenderPositionsCS);
  596. inComputeQueue->SetConstantBuffer("gContext", mConstantsCB);
  597. inComputeQueue->SetBuffer("gSVertexInfluences", mSettings->mSVertexInfluencesCB);
  598. inComputeQueue->SetBuffer("gPositions", mPositionsCB);
  599. inComputeQueue->SetRWBuffer("gRenderPositions", mRenderPositionsCB);
  600. inComputeQueue->Dispatch(dispatch_per_render_vertex);
  601. }
  602. }
  603. void Hair::ReadBackGPUState(ComputeQueue *inComputeQueue)
  604. {
  605. if (mPositionsReadBackCB == nullptr)
  606. {
  607. // Create read back buffers
  608. if (mScalpVerticesCB != nullptr)
  609. mScalpVerticesReadBackCB = mScalpVerticesCB->CreateReadBackBuffer().Get();
  610. mPositionsReadBackCB = mPositionsCB->CreateReadBackBuffer().Get();
  611. mVelocitiesReadBackCB = mVelocitiesCB->CreateReadBackBuffer().Get();
  612. mVelocityAndDensityReadBackCB = mVelocityAndDensityCB->CreateReadBackBuffer().Get();
  613. mRenderPositionsReadBackCB = mRenderPositionsCB->CreateReadBackBuffer().Get();
  614. }
  615. {
  616. JPH_PROFILE("Transfer data from GPU");
  617. // Read back the skinned vertices
  618. if (mScalpVerticesCB != nullptr)
  619. inComputeQueue->ScheduleReadback(mScalpVerticesReadBackCB, mScalpVerticesCB);
  620. // Read back the vertices
  621. inComputeQueue->ScheduleReadback(mPositionsReadBackCB, mPositionsCB);
  622. inComputeQueue->ScheduleReadback(mVelocitiesReadBackCB, mVelocitiesCB);
  623. inComputeQueue->ScheduleReadback(mRenderPositionsReadBackCB, mRenderPositionsCB);
  624. // Read back the velocity and density
  625. inComputeQueue->ScheduleReadback(mVelocityAndDensityReadBackCB, mVelocityAndDensityCB);
  626. // Wait for the compute queue to finish
  627. inComputeQueue->ExecuteAndWait();
  628. }
  629. {
  630. JPH_PROFILE("Reorder hair data");
  631. // Reorder position and velocity data
  632. const JPH_HairPosition *positions = mPositionsReadBackCB->Map<JPH_HairPosition>(ComputeBuffer::EMode::Read);
  633. const JPH_HairVelocity *velocities = mVelocitiesReadBackCB->Map<JPH_HairVelocity>(ComputeBuffer::EMode::Read);
  634. size_t num_vertices = mSettings->mSimVertices.size();
  635. if (mPositions == nullptr)
  636. mPositions = new Float3 [num_vertices];
  637. if (mRotations == nullptr)
  638. mRotations = new Quat [num_vertices];
  639. if (mVelocities == nullptr)
  640. mVelocities = new JPH_HairVelocity [num_vertices];
  641. uint32 num_strands = (uint32)mSettings->mSimStrands.size();
  642. for (uint32 s = 0; s < num_strands; ++s)
  643. {
  644. const HairSettings::SStrand &strand = mSettings->mSimStrands[s];
  645. for (uint32 v = 0; v < strand.VertexCount(); ++v)
  646. {
  647. uint32 in_index = s + v * num_strands;
  648. uint32 out_index = strand.mStartVtx + v;
  649. mPositions[out_index] = Float3(positions[in_index].mPosition);
  650. mRotations[out_index] = Quat(positions[in_index].mRotation);
  651. mVelocities[out_index] = velocities[in_index];
  652. }
  653. }
  654. mPositionsReadBackCB->Unmap();
  655. mVelocitiesReadBackCB->Unmap();
  656. }
  657. }
  658. void Hair::LockReadBackBuffers()
  659. {
  660. if (mScalpVerticesReadBackCB != nullptr)
  661. mScalpVertices = mScalpVerticesReadBackCB->Map<Float3>(ComputeBuffer::EMode::Read);
  662. mVelocityAndDensity = mVelocityAndDensityReadBackCB->Map<Float4>(ComputeBuffer::EMode::Read);
  663. if (mRenderPositionsOverridden)
  664. {
  665. uint num_render_vertices = (uint)mSettings->mRenderVertices.size();
  666. if (mRenderPositions == nullptr)
  667. mRenderPositions = new Float3 [num_render_vertices];
  668. mRenderPositionsToFloat3(mRenderPositionsReadBackCB, const_cast<Float3 *>(mRenderPositions), num_render_vertices);
  669. }
  670. else
  671. mRenderPositions = mRenderPositionsReadBackCB->Map<Float3>(ComputeBuffer::EMode::Read);
  672. }
  673. void Hair::UnlockReadBackBuffers()
  674. {
  675. if (mScalpVerticesReadBackCB != nullptr)
  676. mScalpVerticesReadBackCB->Unmap();
  677. mVelocityAndDensityReadBackCB->Unmap();
  678. if (!mRenderPositionsOverridden)
  679. mRenderPositionsReadBackCB->Unmap();
  680. }
  681. #ifdef JPH_DEBUG_RENDERER
  682. void Hair::Draw(const DrawSettings &inSettings, DebugRenderer *inRenderer)
  683. {
  684. LockReadBackBuffers();
  685. const Float3 *positions = GetPositions();
  686. const Float3 *render_positions = GetRenderPositions();
  687. const Quat *rotations = GetRotations();
  688. StridedPtr<const Float3> velocities = GetVelocities();
  689. StridedPtr<const Float3> angular_velocities = GetAngularVelocities();
  690. const Float4 *grid_velocity_and_density = GetGridVelocityAndDensity();
  691. const Float3 *scalp_vertices = GetScalpVertices();
  692. float arrow_size = 0.01f * mSettings->mSimulationBounds.GetSize().ReduceMin();
  693. RMat44 com = GetWorldTransform();
  694. // Draw the render strands
  695. if (inSettings.mDrawRenderStrands)
  696. {
  697. JPH_PROFILE("Draw Render Strands");
  698. // Calculate a map of sim vertex index to strand index
  699. Array<uint> sim_vertex_to_strand;
  700. sim_vertex_to_strand.resize(mSettings->mSimVertices.size(), 0);
  701. for (uint i = 0, n = (uint)mSettings->mSimStrands.size(); i < n; ++i)
  702. {
  703. const HairSettings::SStrand &strand = mSettings->mSimStrands[i];
  704. for (uint v = strand.mStartVtx; v < strand.mEndVtx; ++v)
  705. sim_vertex_to_strand[v] = i;
  706. }
  707. Hash<uint32> hasher;
  708. switch (inSettings.mRenderStrandColor)
  709. {
  710. case ERenderStrandColor::PerRenderStrand:
  711. {
  712. Color color = Color::sGreen;
  713. for (const HairSettings::RStrand &strand : mSettings->mRenderStrands)
  714. {
  715. uint32 strand_idx = sim_vertex_to_strand[mSettings->mRenderVertices[strand.mStartVtx].mInfluences[0].mVertexIndex];
  716. if (strand_idx >= inSettings.mSimulationStrandBegin && strand_idx < inSettings.mSimulationStrandEnd)
  717. {
  718. RVec3 x0 = com * Vec3(render_positions[strand.mStartVtx]);
  719. for (uint32 v = strand.mStartVtx + 1; v < strand.mEndVtx; ++v)
  720. {
  721. RVec3 x1 = com * Vec3(render_positions[v]);
  722. inRenderer->DrawLine(x0, x1, color);
  723. x0 = x1;
  724. }
  725. color = Color(uint32(hasher(color.GetUInt32())) | 0xff000000);
  726. }
  727. }
  728. }
  729. break;
  730. case ERenderStrandColor::PerSimulatedStrand:
  731. for (const HairSettings::RStrand &strand : mSettings->mRenderStrands)
  732. {
  733. uint32 strand_idx = sim_vertex_to_strand[mSettings->mRenderVertices[strand.mStartVtx].mInfluences[0].mVertexIndex];
  734. if (strand_idx >= inSettings.mSimulationStrandBegin && strand_idx < inSettings.mSimulationStrandEnd)
  735. {
  736. Color color = Color(uint32(hasher(strand_idx)) | 0xff000000);
  737. RVec3 x0 = com * Vec3(render_positions[strand.mStartVtx]);
  738. for (uint32 v = strand.mStartVtx + 1; v < strand.mEndVtx; ++v)
  739. {
  740. RVec3 x1 = com * Vec3(render_positions[v]);
  741. inRenderer->DrawLine(x0, x1, color);
  742. x0 = x1;
  743. }
  744. }
  745. }
  746. break;
  747. case ERenderStrandColor::GravityFactor:
  748. case ERenderStrandColor::WorldTransformInfluence:
  749. case ERenderStrandColor::GridVelocityFactor:
  750. case ERenderStrandColor::GlobalPose:
  751. case ERenderStrandColor::SkinGlobalPose:
  752. for (const HairSettings::RStrand &strand : mSettings->mRenderStrands)
  753. {
  754. uint32 strand_idx = sim_vertex_to_strand[mSettings->mRenderVertices[strand.mStartVtx].mInfluences[0].mVertexIndex];
  755. const HairSettings::Material &material = mSettings->mMaterials[mSettings->mSimStrands[strand_idx].mMaterialIndex];
  756. // Prepare sampler
  757. GradientSampler sampler;
  758. if (inSettings.mRenderStrandColor == ERenderStrandColor::GravityFactor)
  759. sampler = GradientSampler(material.mGravityFactor);
  760. else if (inSettings.mRenderStrandColor == ERenderStrandColor::WorldTransformInfluence)
  761. sampler = GradientSampler(material.mWorldTransformInfluence);
  762. else if (inSettings.mRenderStrandColor == ERenderStrandColor::GridVelocityFactor)
  763. sampler = GradientSampler(material.mGridVelocityFactor);
  764. else if (inSettings.mRenderStrandColor == ERenderStrandColor::GlobalPose)
  765. sampler = GradientSampler(material.mGlobalPose);
  766. else
  767. sampler = GradientSampler(material.mSkinGlobalPose);
  768. if (strand_idx >= inSettings.mSimulationStrandBegin && strand_idx < inSettings.mSimulationStrandEnd)
  769. {
  770. RVec3 x0 = com * Vec3(render_positions[strand.mStartVtx]);
  771. for (uint32 v = strand.mStartVtx + 1; v < strand.mEndVtx; ++v)
  772. {
  773. RVec3 x1 = com * Vec3(render_positions[v]);
  774. uint32 simulated_vtx = mSettings->mRenderVertices[v].mInfluences[0].mVertexIndex;
  775. float factor = sampler.Sample(mSettings->mSimVertices[simulated_vtx].mStrandFraction);
  776. inRenderer->DrawLine(x0, x1, Color::sGreenRedGradient(factor));
  777. x0 = x1;
  778. }
  779. }
  780. }
  781. break;
  782. }
  783. }
  784. // Draw the rods
  785. if (inSettings.mDrawRods)
  786. {
  787. JPH_PROFILE("Draw Rods");
  788. Color color = Color::sRed;
  789. Hash<uint32> hasher;
  790. for (uint i = 0, n = (uint)mSettings->mSimStrands.size(); i < n; ++i)
  791. if (i >= inSettings.mSimulationStrandBegin && i < inSettings.mSimulationStrandEnd)
  792. {
  793. const HairSettings::SStrand &strand = mSettings->mSimStrands[i];
  794. RVec3 x0 = com * Vec3(positions[strand.mStartVtx]);
  795. for (uint32 v = strand.mStartVtx + 1; v < strand.mEndVtx; ++v)
  796. {
  797. RVec3 x1 = com * Vec3(positions[v]);
  798. inRenderer->DrawLine(x0, x1, color);
  799. x0 = x1;
  800. }
  801. color = Color(uint32(hasher(color.GetUInt32())) | 0xff000000);
  802. }
  803. }
  804. // Draw the rods in their unloaded pose
  805. if (inSettings.mDrawUnloadedRods)
  806. {
  807. JPH_PROFILE("Draw Unloaded Rods");
  808. Color color = Color::sYellow;
  809. Hash<uint32> hasher;
  810. for (uint i = 0, n = (uint)mSettings->mSimStrands.size(); i < n; ++i)
  811. if (i >= inSettings.mSimulationStrandBegin && i < inSettings.mSimulationStrandEnd)
  812. {
  813. const HairSettings::SStrand &strand = mSettings->mSimStrands[i];
  814. RVec3 x0 = com * Vec3(positions[strand.mStartVtx]);
  815. Quat rotation = mRotation * rotations[strand.mStartVtx];
  816. for (uint32 v = strand.mStartVtx + 1; v < strand.mEndVtx; ++v)
  817. {
  818. RVec3 x1 = x0 + rotation.RotateAxisZ() * mSettings->mSimVertices[v - 1].mLength;
  819. inRenderer->DrawLine(x0, x1, color);
  820. rotation = (rotation * Quat(mSettings->mSimVertices[v].mOmega0)).Normalized();
  821. x0 = x1;
  822. }
  823. color = Color(uint32(hasher(color.GetUInt32())) | 0xff000000);
  824. }
  825. }
  826. // Draw vertex velocities
  827. if (inSettings.mDrawVertexVelocity)
  828. for (uint i = 0, n = (uint)mSettings->mSimStrands.size(); i < n; ++i)
  829. if (i >= inSettings.mSimulationStrandBegin && i < inSettings.mSimulationStrandEnd)
  830. {
  831. const HairSettings::SStrand &strand = mSettings->mSimStrands[i];
  832. for (uint32 v = strand.mStartVtx; v < strand.mEndVtx; ++v)
  833. {
  834. Vec3 velocity(velocities[v]);
  835. if (velocity.LengthSq() > 1.0e-6f)
  836. {
  837. Vec3 pos = Vec3(positions[v]);
  838. inRenderer->DrawArrow(com * pos, com * (pos + velocity), Color::sGreen, arrow_size);
  839. }
  840. }
  841. }
  842. // Draw angular velocities
  843. if (inSettings.mDrawAngularVelocity)
  844. for (uint i = 0, n = (uint)mSettings->mSimStrands.size(); i < n; ++i)
  845. if (i >= inSettings.mSimulationStrandBegin && i < inSettings.mSimulationStrandEnd)
  846. {
  847. const HairSettings::SStrand &strand = mSettings->mSimStrands[i];
  848. for (uint32 v = strand.mStartVtx; v < strand.mEndVtx; ++v)
  849. {
  850. Vec3 angular_velocity(angular_velocities[v]);
  851. if (angular_velocity.LengthSq() > 1.0e-6f)
  852. {
  853. Vec3 pos = Vec3(positions[v]);
  854. inRenderer->DrawArrow(com * pos, com * (pos + 0.1f * angular_velocity), Color::sOrange, arrow_size);
  855. }
  856. }
  857. }
  858. // Draw rod orientations
  859. if (inSettings.mDrawOrientations)
  860. for (uint i = 0, n = (uint)mSettings->mSimStrands.size(); i < n; ++i)
  861. if (i >= inSettings.mSimulationStrandBegin && i < inSettings.mSimulationStrandEnd)
  862. {
  863. const HairSettings::SStrand &strand = mSettings->mSimStrands[i];
  864. for (uint32 v = strand.mStartVtx; v < strand.mEndVtx; ++v)
  865. inRenderer->DrawCoordinateSystem(com * Mat44::sRotationTranslation(rotations[v], Vec3(positions[v])), arrow_size);
  866. }
  867. // Draw grid bounds
  868. if (inSettings.mDrawNeutralDensity || inSettings.mDrawGridDensity || inSettings.mDrawGridVelocity)
  869. inRenderer->DrawWireBox(com, mSettings->mSimulationBounds, Color::sGrey);
  870. // Draw neutral density
  871. if (inSettings.mDrawNeutralDensity)
  872. {
  873. Vec3 offset = mSettings->mSimulationBounds.mMin;
  874. Vec3 scale = mSettings->mSimulationBounds.GetSize() / Vec3(mSettings->mGridSize.ToFloat());
  875. float marker_size = 0.5f * scale.ReduceMin();
  876. for (uint32 z = 0; z < mSettings->mGridSize.GetX(); ++z)
  877. for (uint32 y = 0; y < mSettings->mGridSize.GetY(); ++y)
  878. for (uint32 x = 0; x < mSettings->mGridSize.GetZ(); ++x)
  879. {
  880. float density = mSettings->GetNeutralDensity(x, y, z);
  881. JPH_ASSERT(density >= 0.0f);
  882. if (density > 0.0f)
  883. {
  884. Vec3 pos = offset + Vec3(UVec4(x, y, z, 0).ToFloat()) * scale;
  885. inRenderer->DrawMarker(com * pos, Color::sGreenRedGradient(density * mSettings->mDensityScale), marker_size);
  886. }
  887. }
  888. }
  889. // Draw current density
  890. if (inSettings.mDrawGridDensity || inSettings.mDrawGridVelocity)
  891. {
  892. Vec3 offset = mSettings->mSimulationBounds.mMin;
  893. Vec3 scale = mSettings->mSimulationBounds.GetSize() / Vec3(mSettings->mGridSize.ToFloat());
  894. float marker_size = 0.5f * scale.ReduceMin();
  895. for (uint32 z = 0; z < mSettings->mGridSize.GetX(); ++z)
  896. for (uint32 y = 0; y < mSettings->mGridSize.GetY(); ++y)
  897. for (uint32 x = 0; x < mSettings->mGridSize.GetZ(); ++x)
  898. {
  899. const Float4 &velocity_and_density = grid_velocity_and_density[x + y * mSettings->mGridSize.GetX() + z * mSettings->mGridSize.GetX() * mSettings->mGridSize.GetY()];
  900. float density = velocity_and_density.w;
  901. Vec3 velocity = Vec3::sLoadFloat3Unsafe((const Float3 &)velocity_and_density);
  902. if (density > 0.0f)
  903. {
  904. RVec3 pos = com * (offset + Vec3(UVec4(x, y, z, 0).ToFloat()) * scale);
  905. if (inSettings.mDrawGridDensity)
  906. inRenderer->DrawMarker(pos, Color::sGreenRedGradient(density * mSettings->mDensityScale), marker_size);
  907. if (inSettings.mDrawGridVelocity && velocity.LengthSq() > 1.0e-6f)
  908. inRenderer->DrawArrow(pos, pos + com.Multiply3x3(velocity), Color::sYellow, arrow_size);
  909. }
  910. }
  911. }
  912. if (inSettings.mDrawSkinPoints)
  913. for (uint i = 0, n = (uint)mSettings->mSkinPoints.size(); i < n; ++i)
  914. if (i >= inSettings.mSimulationStrandBegin && i < inSettings.mSimulationStrandEnd)
  915. {
  916. const HairSettings::SkinPoint &sp = mSettings->mSkinPoints[i];
  917. const IndexedTriangleNoMaterial &tri = mSettings->mScalpTriangles[sp.mTriangleIndex];
  918. RVec3 v0 = com * Vec3(scalp_vertices[tri.mIdx[0]]);
  919. RVec3 v1 = com * Vec3(scalp_vertices[tri.mIdx[1]]);
  920. RVec3 v2 = com * Vec3(scalp_vertices[tri.mIdx[2]]);
  921. inRenderer->DrawWireTriangle(v0, v1, v2, Color::sYellow);
  922. RVec3 point = Real(sp.mU) * v0 + Real(sp.mV) * v1 + Real(1.0f - sp.mU - sp.mV) * v2;
  923. Vec3 tangent = Vec3(v1 - v0).Normalized();
  924. Vec3 normal = tangent.Cross(Vec3(v2 - v0)).Normalized();
  925. Vec3 binormal = tangent.Cross(normal);
  926. RMat44 basis(Vec4(normal, 0), Vec4(binormal, 0), Vec4(tangent, 0), point);
  927. inRenderer->DrawCoordinateSystem(basis, 0.01f);
  928. }
  929. // Draw initial gravity
  930. if (inSettings.mDrawInitialGravity)
  931. inRenderer->DrawArrow(com.GetTranslation(), com * mSettings->mInitialGravity, Color::sBlue, 0.05f * mSettings->mInitialGravity.Length());
  932. UnlockReadBackBuffers();
  933. }
  934. #endif // JPH_DEBUG_RENDERER
  935. JPH_NAMESPACE_END