7#include <glm/gtx/component_wise.hpp>
11constexpr float kMinNodeHalfSize = 0.001f;
12constexpr std::size_t kTraversalStackReserve = 512;
13constexpr double kMinRadiationDistanceSq = 0.0001;
15bool containsPosition(
const OctreeNode& node,
const glm::vec3& position) {
16 const glm::vec3 delta = glm::abs(position - node.
center);
25Octant Octree::getOctant(
NodeIndex nodeIdx,
const glm::vec3& pos)
const {
26 const glm::vec3& center = nodes[nodeIdx.
val].center;
28 return Octant{
static_cast<std::uint8_t
>(
31 (pos.z >= center.z ?
Octant::Z_MASK : 0)
35NodeIndex Octree::allocateNode(
const glm::vec3& center,
float halfSize) {
36 nodes.push_back({center, halfSize});
37 return NodeIndex{
static_cast<int>(nodes.size() - 1)};
42 glm::vec3 nodeCenter = node->
center;
45 float childHalfSize = node->
halfSize * 0.5f;
54 node->
bodies.push_back(body);
63 double newMass = node->
totalMass + bodyMass;
71 Octant bOct = Octree::getOctant(nodeIndex, bPos);
74 node = &nodes[nodeIndex.
val];
76 glm::vec3 childCenter = nodeCenter + childHalfSize * glm::vec3(
78 (bOct.val &
Octant::Y_MASK) ? 1.0f : -1.0f,
79 (bOct.val &
Octant::Z_MASK) ? 1.0f : -1.0f
81 NodeIndex childNode = allocateNode(childCenter, childHalfSize);
82 node = &nodes[nodeIndex.
val];
90 const bool hasCoincidentBody = std::any_of(node->
bodies.begin(), node->
bodies.end(),
92 return existing->getPosition(BodyLock::NOLOCK) == bodyPos;
95 if (childHalfSize <= kMinNodeHalfSize || hasCoincidentBody) {
96 node->
bodies.push_back(body);
100 std::vector<Physics::PhysicsBody*> existingBodies = std::move(node->
bodies);
103 insertBody(existing);
113 if (bodies.empty())
return;
114 nodes.reserve(bodies.size() * 2);
119 for (
const auto& body : bodies) {
121 min = glm::min(min, pos);
122 max = glm::max(max, pos);
125 glm::vec3 center = (min + max) * 0.5f;
126 float halfSize = glm::compMax(max - center) + 1.0f;
129 NodeIndex root = allocateNode(center, halfSize);
131 for (
const auto& body : bodies) {
137 if (nodes.empty() || body ==
nullptr) {
138 return glm::vec3(0.0f);
141 glm::vec3 totalForce(0.0f);
145 std::vector<NodeIndex> stack;
146 stack.reserve(kTraversalStackReserve);
149 while (!stack.empty()) {
158 float distSq = glm::dot(dist, dist);
161 const bool nodeContainsBody = containsPosition(node, bodyPos);
166 if (other == body)
continue;
169 float invPairDist = 1.0f / std::sqrt(pairDistSq);
170 float invPairDist3 = invPairDist * invPairDist * invPairDist;
171 double pairForce = (G * bodyMass * other->getMass(
BodyLock::NOLOCK)) * invPairDist3;
172 totalForce +=
static_cast<float>(pairForce) * pairDist;
177 float invDist = 1.0f / sqrt(softeningDistSq);
178 float invDist3 = invDist * invDist * invDist;
180 double force = (G * bodyMass * node.
totalMass) * invDist3;
181 totalForce +=
static_cast<float>(force) * dist;
186 int childOctant = std::countr_zero(childMask);
187 stack.push_back(node.
children[childOctant]);
188 childMask &= (childMask - 1);
196 if (nodes.empty() || body ==
nullptr) {
200 double totalHeat = 0.0;
205 double projectedArea = area * 0.25;
207 std::vector<NodeIndex> stack;
208 stack.reserve(kTraversalStackReserve);
211 while (!stack.empty()) {
219 double distSq =
static_cast<double>(glm::dot(dist, dist));
220 if (distSq < kMinRadiationDistanceSq) distSq = kMinRadiationDistanceSq;
223 const bool nodeContainsBody = containsPosition(node, bodyPos);
227 if (other == body)
continue;
229 double pairDistSq =
static_cast<double>(glm::dot(pairDist, pairDist));
230 if (pairDistSq < kMinRadiationDistanceSq) pairDistSq = kMinRadiationDistanceSq;
232 double otherArea = other->getSurfaceArea();
235 double viewFactorTerm = (projectedArea * otherArea) / (4.0 * glm::pi<double>() * pairDistSq);
236 viewFactorTerm = std::min(viewFactorTerm, projectedArea);
242 double solidAngleFactor = projectedArea / (4.0 * glm::pi<double>() * distSq);
249 int childOctant = std::countr_zero(childMask);
250 stack.push_back(node.
children[childOctant]);
251 childMask &= (childMask - 1);
double computeHeat(Physics::PhysicsBody *body)
void build(const std::vector< Physics::PhysicsBody * > &bodies)
glm::vec3 computeForce(Physics::PhysicsBody *body, double G)
virtual double getMass(BodyLock lock) const
float getSurfaceArea() const
virtual ThermalProperties getThermalProperties(BodyLock lock) const
glm::vec3 getPosition(BodyLock lock) const
constexpr float SOFTENING_SQ
constexpr double STEFAN_BOLTZMANN
double effectiveAbsorptivity(const ThermalProperties &props, double tempK)
double clampTemperature(double tempK)
double effectiveEmissivity(const ThermalProperties &props, double tempK)
double fourthPower(double value)
static NodeIndex rootIndex()
static constexpr std::uint8_t X_MASK
static constexpr std::uint8_t Y_MASK
double totalEffectiveArea
std::vector< Physics::PhysicsBody * > bodies