void CollisionSolver::UpdateDiagnostics(const Simplex& simplex, const D3DXVECTOR3& furthestPoint) { if(m_engine->diagnostic()->AllowDiagnostics(Diagnostic::COLLISION)) { const float radius = 0.1f; const float normalLength = 1.5f; D3DXVECTOR3 origin(0.0, 0.0, 0.0); m_engine->diagnostic()->UpdateSphere(Diagnostic::COLLISION, "OriginPoint", Diagnostic::WHITE, origin, radius); m_engine->diagnostic()->UpdateSphere(Diagnostic::COLLISION, "FurthestPoint", Diagnostic::MAGENTA, furthestPoint, radius); const auto& borders = simplex.GetBorderEdges(); for(unsigned int i = 0; i < borders.size(); ++i) { m_engine->diagnostic()->UpdateLine(Diagnostic::COLLISION, "BorderEdge" + StringCast(i), Diagnostic::RED, simplex.GetPoint(borders[i].indices[0]), simplex.GetPoint(borders[i].indices[1])); } const auto& faces = simplex.GetFaces(); for(unsigned int i = 0; i < faces.size(); ++i) { if(faces[i].alive) { std::string id = StringCast(i); const Face& face = faces[i]; const D3DXVECTOR3 center = simplex.GetFaceCenter(i); const D3DXVECTOR3& normal = face.normal * normalLength; const D3DXVECTOR3& pointA = simplex.GetPoint(face.indices[0]); const D3DXVECTOR3& pointB = simplex.GetPoint(face.indices[1]); const D3DXVECTOR3& pointC = simplex.GetPoint(face.indices[2]); m_engine->diagnostic()->UpdateSphere(Diagnostic::COLLISION, "sCenter" + id, Diagnostic::BLUE, center, radius); m_engine->diagnostic()->UpdateLine(Diagnostic::COLLISION, "sNormal" + id, Diagnostic::BLUE, center, center + normal); m_engine->diagnostic()->UpdateLine(Diagnostic::COLLISION, "sLine1" + id, Diagnostic::YELLOW, pointA, pointB); m_engine->diagnostic()->UpdateLine(Diagnostic::COLLISION, "sLine2" + id, Diagnostic::YELLOW, pointA, pointC); m_engine->diagnostic()->UpdateLine(Diagnostic::COLLISION, "sLine3" + id, Diagnostic::YELLOW, pointC, pointB); } } } }
void CollisionMesh::DrawDiagnostics() { if(m_draw && m_geometry && m_engine->diagnostic()->AllowDiagnostics(Diagnostic::MESH)) { // Render world vertices const std::string id = StringCast(this); const float vertexRadius = 0.1f; const auto& vertices = GetVertices(); for(unsigned int i = 0; i < vertices.size(); ++i) { m_engine->diagnostic()->UpdateSphere(Diagnostic::MESH, "0" + StringCast(i) + id, Diagnostic::RED, vertices[i], vertexRadius); } // Render face normals m_geometry->UpdateDiagnostics(*m_engine->diagnostic(), m_world.GetMatrix()); // Render OABB for diagnostic mesh auto getPointColor = [=](int index) -> Diagnostic::Colour { return index == MINBOUND || index == MAXBOUND ? Diagnostic::BLUE : Diagnostic::MAGENTA; }; const float radius = 0.2f; std::string corner; for(unsigned int i = 0; i < CORNERS/2; ++i) { corner = StringCast(i); m_engine->diagnostic()->UpdateSphere(Diagnostic::MESH, "CornerA" + corner + id, getPointColor(i), m_oabb[i], radius); m_engine->diagnostic()->UpdateSphere(Diagnostic::MESH, "CornerB" + corner + id, getPointColor(i+4), m_oabb[i+4], radius); m_engine->diagnostic()->UpdateLine(Diagnostic::MESH, "LineA" + corner + id, Diagnostic::MAGENTA, m_oabb[i], m_oabb[i+1 >= 4 ? 0 : i+1]); m_engine->diagnostic()->UpdateLine(Diagnostic::MESH, "LineB" + corner + id, Diagnostic::MAGENTA, m_oabb[i+4], m_oabb[i+5 >= CORNERS ? 4 : i+5]); m_engine->diagnostic()->UpdateLine(Diagnostic::MESH, "LineC" + corner + id, Diagnostic::MAGENTA, m_oabb[i], m_oabb[i+4]); } // Render radius of diagnostic mesh in wireframe m_engine->diagnostic()->UpdateSphere(Diagnostic::MESH, "Radius" + id, Diagnostic::WHITE, GetPosition(), GetRadius()); } }
int Octree::RenderPartition(const std::unique_ptr<Partition>& partition) { int nodeCount = 0; // Render all children of this partition const auto& children = partition->GetChildren(); for(const std::unique_ptr<Partition>& child : children) { nodeCount += RenderPartition(child); } // Only render the root children and onwards if they have nodes if(partition->GetLevel() > 0 && partition->HasNodes()) { const float size = partition->GetSize(); const D3DXVECTOR3 minBounds = partition->GetMinBounds(); std::array<D3DXVECTOR3, CUBE_POINTS> corners = { // top four corners minBounds, minBounds + D3DXVECTOR3(size, 0, 0), minBounds + D3DXVECTOR3(size, -size, 0), minBounds + D3DXVECTOR3(0, -size, 0), // bottom four corners minBounds + D3DXVECTOR3(0, 0, size), minBounds + D3DXVECTOR3(size, 0, size), minBounds + D3DXVECTOR3(size, -size, size), minBounds + D3DXVECTOR3(0, -size, size) }; const std::string& id = partition->GetID(); auto colour = partition->GetColor(); for(int i = 0, j = SQUARE_POINTS; i < SQUARE_POINTS; ++i, ++j) { m_engine->diagnostic()->UpdateLine(Diagnostic::OCTREE, id + StringCast(i) + "1", colour, corners[i], corners[i+1 >= SQUARE_POINTS ? 0 : i+1]); m_engine->diagnostic()->UpdateLine(Diagnostic::OCTREE, id + StringCast(i) + "2", colour, corners[j], corners[j+1 >= CUBE_POINTS ? SQUARE_POINTS : j+1]); m_engine->diagnostic()->UpdateLine(Diagnostic::OCTREE, id + StringCast(i) + "3", colour, corners[i], corners[j]); } } return nodeCount + static_cast<int>(partition->GetNodes().size()); }
void Scene::PreCollisionUpdate(bool pressed, const D3DXVECTOR2& direction, const Matrix& world, const Matrix& invProjection, float deltatime) { if(m_engine->diagnostic()->AllowDiagnostics(Diagnostic::MESH)) { m_engine->diagnostic()->UpdateText(Diagnostic::MESH, "QueueFront", Diagnostic::WHITE, StringCast(m_open.empty() ? 0 : m_open.front())); m_engine->diagnostic()->UpdateText(Diagnostic::MESH, "QueueSize", Diagnostic::WHITE, StringCast(m_open.size())); m_engine->diagnostic()->UpdateText(Diagnostic::MESH, "SelectedMesh", Diagnostic::WHITE, StringCast(m_selectedMesh)); if(m_diagnosticMesh != NO_INDEX) { const auto& mesh = m_meshes[m_diagnosticMesh]; if(mesh->IsVisible()) { const auto& collision = m_meshes[m_diagnosticMesh]->GetCollisionMesh(); const Partition* partition = collision.GetPartition(); const D3DXVECTOR3& velocity = collision.GetVelocity(); const D3DXVECTOR3 scale = collision.GetLocalScale(); m_manipulator->UpdateDiagnostics(m_meshes[m_diagnosticMesh]); m_engine->diagnostic()->UpdateText(Diagnostic::MESH, "PartitionID", Diagnostic::WHITE, partition ? partition->GetID() : "None", true); m_engine->diagnostic()->UpdateText(Diagnostic::MESH, "Velocity", Diagnostic::WHITE, StringCast(velocity.x) + " " + StringCast(velocity.y) + " " + StringCast(velocity.z), true); m_engine->diagnostic()->UpdateText(Diagnostic::MESH, "LocalScale", Diagnostic::WHITE, StringCast(scale.x) + " " + StringCast(scale.y) + " " + StringCast(scale.z), true); } } } if(m_selectedMesh != NO_INDEX) { m_manipulator->UpdateState(m_meshes[m_selectedMesh], direction, world, invProjection, pressed, deltatime); } std::for_each(m_meshes.begin(), m_meshes.end(), [deltatime](const MeshPtr& mesh) { if(mesh->IsVisible()) { mesh->Animate(deltatime); } }); }
void Geometry::UpdateDiagnostics(Diagnostic& renderer, const D3DXMATRIX& world) { if(renderer.AllowDiagnostics(Diagnostic::MESH)) { std::string id = StringCast(this); const auto& faces = GetFaces(); const float normalsize = 0.6f; for(unsigned int i = 0; i < faces.size(); ++i) { D3DXVECTOR3 center, normal; D3DXVec3TransformCoord(¢er, &faces[i].center, &world); D3DXVec3TransformNormal(&normal, &faces[i].normal, &world); D3DXVec3Normalize(&normal, &normal); renderer.UpdateLine(Diagnostic::MESH, "FaceNormal" + StringCast(i) + id, Diagnostic::CYAN, center, center + (normal * normalsize)); } } }
void Timer::UpdateTimer() { QueryPerformanceCounter(&m_timer); double currentTime = static_cast<double>(m_timer.QuadPart); double deltatime = (currentTime - m_previousTime) / m_frequency; m_deltaTimeCounter += deltatime; if (m_deltaTimeCounter >= 1.0) //one second has passed { m_deltaTimeCounter = 0.0; m_fps = m_fpsCounter; m_fpsCounter = 0; } m_deltaTime = max(deltatime, DT_MINIMUM); m_deltaTime = min(m_deltaTime, DT_MAXIMUM); if(m_engine->diagnostic()->AllowDiagnostics(Diagnostic::TEXT)) { m_engine->diagnostic()->UpdateText(Diagnostic::TEXT, "FramePerSec", Diagnostic::WHITE, StringCast(m_fps)); m_engine->diagnostic()->UpdateText(Diagnostic::TEXT, "DeltaTime", Diagnostic::WHITE, StringCast(deltatime)); m_engine->diagnostic()->UpdateText(Diagnostic::TEXT, "CappedDeltaTime", Diagnostic::WHITE, StringCast(m_deltaTime)); if(m_forceDeltatime) { m_engine->diagnostic()->UpdateText(Diagnostic::TEXT, "ForcedDeltaTime", Diagnostic::YELLOW, StringCast(m_forcedDeltatime), true); } } ++m_fpsCounter; //increment frame counter m_previousTime = currentTime; }
void Picking::SolvePicking() { if(Diagnostic::AllowText()) { Diagnostic::UpdateText("DistanceToPick", Diagnostic::WHITE, StringCast(m_distanceToMesh == FLT_MAX ? 0.0f : m_distanceToMesh)); } if(m_mesh) { m_mesh->OnPickMesh(); } }
void Diagnostic::UpdateText(const std::string& id, Diagnostic::Colour color, bool increaseCounter) { if(sm_diag->m_textmap.find(id) == sm_diag->m_textmap.end()) { sm_diag->m_textmap.insert(TextMap::value_type(id,DiagText())); sm_diag->m_textmap[id].counter = 0; } else if(increaseCounter) { ++sm_diag->m_textmap[id].counter; } sm_diag->m_textmap[id].color = sm_diag->m_colourmap[color]; sm_diag->m_textmap[id].text = id + ": " + StringCast(sm_diag->m_textmap[id].counter); }
void Particle::UpdateDiagnostics(Diagnostic& renderer) { if(renderer.AllowDiagnostics(Diagnostic::TEXT)) { renderer.UpdateText(Diagnostic::TEXT, "Particle Delta", Diagnostic::WHITE, StringCast(m_positionDelta.y));; renderer.UpdateText(Diagnostic::TEXT, "Particle Collision", Diagnostic::WHITE, std::string( (m_collision->IsCollidingWith(Geometry::NONE) ? "NONE " : "")) + (m_collision->IsCollidingWith(Geometry::SPHERE) ? "SPHERE " : "") + (m_collision->IsCollidingWith(Geometry::BOX) ? "BOX " : "") + (m_collision->IsCollidingWith(Geometry::CYLINDER) ? "CYLINDER " : "")); } }
void Octree::RenderDiagnostics() { if(m_engine->diagnostic()->AllowDiagnostics(Diagnostic::OCTREE)) { int nodeCount = static_cast<int>(m_octree->GetNodes().size()); const auto& children = m_octree->GetChildren(); for(const std::unique_ptr<Partition>& child : children) { nodeCount += RenderPartition(child); } m_engine->diagnostic()->UpdateText(Diagnostic::OCTREE, "NodeCount", Diagnostic::WHITE, StringCast(nodeCount)); } }
void Manipulator::UpdateDiagnostics(const MeshPtr selectedMesh) { const float length = 5.0f; const auto position = selectedMesh->Position(); m_engine->diagnostic()->UpdateText(Diagnostic::MESH, "SelectedTool", Diagnostic::WHITE, GetDescription(m_selectedTool)); m_engine->diagnostic()->UpdateText(Diagnostic::MESH, "SelectedAxis", Diagnostic::WHITE, GetDescription(m_selectedAxis)); m_engine->diagnostic()->UpdateText(Diagnostic::MESH, "AnimationPoints", Diagnostic::WHITE, StringCast(selectedMesh->GetAnimationPoints().size())); m_engine->diagnostic()->UpdateLine(Diagnostic::MESH, "MeshXaxis", Diagnostic::YELLOW, position, position + (selectedMesh->Right() * length)); m_engine->diagnostic()->UpdateLine(Diagnostic::MESH, "MeshYaxis", Diagnostic::RED, position, position + (selectedMesh->Up() * length)); m_engine->diagnostic()->UpdateLine(Diagnostic::MESH, "MeshZaxis", Diagnostic::GREEN, position, position + (selectedMesh->Forward() * length)); }
void Manipulator::UpdateState(Manipulator::MeshPtr mesh, const D3DXVECTOR2& direction, const Matrix& world, const Matrix& invProjection, bool pressed, float deltatime) { if(m_selectedTool == NONE) { return; } // Ensure the tool axis are aligned with the mesh axis std::for_each(m_tools[m_selectedTool]->axis.begin(), m_tools[m_selectedTool]->axis.end(), [&mesh](const MeshPtr& axis) { axis->SetRotationMatrix(mesh->GetRotationMatrix()); }); if(pressed) { if(m_selectedAxis != NO_AXIS && D3DXVec2Length(&direction) > 0.0f) { D3DXVECTOR3 axis; switch(m_selectedAxis) { case X_AXIS: axis = mesh->Right(); break; case Y_AXIS: axis = mesh->Up(); break; case Z_AXIS: axis = mesh->Forward(); break; } D3DXVECTOR3 mouseDirection(direction.x, direction.y, CAMERA_NEAR); mouseDirection.x *= -1.0f; // Transform the screen space mouse direction into global 3D coordinates // Camera world matrix is the inverse view matrix D3DXVec3TransformNormal(&mouseDirection, &mouseDirection, &invProjection.GetMatrix()); D3DXVec3TransformNormal(&mouseDirection, &mouseDirection, &world.GetMatrix()); D3DXVec3Normalize(&mouseDirection, &mouseDirection); D3DXVec3Normalize(&axis, &axis); const float dot = D3DXVec3Dot(&axis, &mouseDirection); const float angle = RadToDeg(std::acos(dot)); const float speed = fabs(dot) * (angle > 90.0f ? -1.0f : 1.0f) * deltatime; if(m_engine->diagnostic()->AllowDiagnostics(Diagnostic::MESH)) { m_engine->diagnostic()->UpdateLine(Diagnostic::MESH, "MouseDirection3D", Diagnostic::WHITE, mesh->Position(), mesh->Position() + mouseDirection * 20.0f); m_engine->diagnostic()->UpdateText(Diagnostic::MESH, "MovementDot", Diagnostic::WHITE, StringCast(dot)); m_engine->diagnostic()->UpdateText(Diagnostic::MESH, "MovementAngle", Diagnostic::WHITE, StringCast(angle)); } switch(m_selectedTool) { case ROTATE: RotateMesh(mesh, speed * ROTATION_SPEED); break; case MOVE: mesh->ResetAnimation(); TranslateMesh(mesh, speed * TRANSLATION_SPEED); break; case SCALE: ScaleMesh(mesh, speed * SCALE_SPEED); break; case ANIMATE: AnimateMesh(mesh, speed * TRANSLATION_SPEED); break; } } } if(m_selectedTool == ANIMATE) { if(mesh->GetAnimationPoints().empty() || (!pressed && m_saveAnimation)) { m_saveAnimation = false; mesh->SavePosition(); } } }