Siv3D AdventCalendar 2017 2 日目の記事です.
概要
本記事では,次期 Siv3D である OpenSiv3D の 3D 機能に向けた,物理演算機能のプロトタイプを紹介します.
# include <Siv3D.hpp>
# include <HamFramework.hpp>
void Main()
{
Physics3DWorld world;
Physics3DBody ground = world.createBox(Vec3(0, -50, 0), Vec3(50, 50, 50), 0.0);
Array<Physics3DBody> bodies;
for (int y = 0; y < 10; y++)
{
for (int z = 0; z < 10; z++)
{
for (int x = 0; x < 10; x++)
{
const Vec3 pos(x, 10 + y, z);
bodies.push_back(world.createBox(pos, Vec3::One * 0.5, 1.0));
}
}
}
while (System::Update())
{
world.update();
ground.draw();
for (const auto& body : bodies)
{
body.draw();
}
}
}
3D 物体の扱いと物理演算
C++で 3D のゲームやアプリケーションなどを開発する際に,3D 物体の扱いには苦労した経験はありませんか.3D の物体同士の相互作用には,面倒な衝突判定・幾何学計算・数値計算を行う必要があります.この面倒さを解決する手段として,3D 物理演算ライブラリが使用される場合があります.3D 物理演算ライブラリとは,3D の形状同士の衝突判定や,物理的な挙動の計算をサポートする機能群であり,Open Dynamics Engine(ODE),Havok Physics,Bullet Physics などが知られています.現在は次期 Siv3D である OpenSiv3D に向けて,短い C++ ソースコードで 3D 物理演算 (Bullet Physics) を利用できる機能を開発しています.本記事では物理演算機能のプロトタイプを紹介します.
- OpenSiv3Dの3D機能に搭載予定で現時点では使用することはできません.
- 本プロトタイプは Siv3D August 2016 で開発しています.
物体の生成
# include <Siv3D.hpp>
# include <HamFramework.hpp>
void Main()
{
Physics3DWorld world;
Physics3DBody ground = world.createBox(Vec3(0, -50, 0), Vec3(50, 50, 50), 0.0);
Physics3DBody body = world.createBox({0.0, 5.0, 0.0}, Vec3::One * 0.5, 1.0);
while (System::Update())
{
world.update();
ground.draw();
body.draw();
}
}
マウスとのインタラクション
# include <Siv3D.hpp>
# include <HamFramework.hpp>
void Main()
{
Physics3DWorld world;
Physics3DBody ground = world.createBox(Vec3(0, -50, 0), Vec3(50, 50, 50), 0.0);
Array<Physics3DBody> bodies;
bodies.push_back(world.createBox(RandomVec3({ -1.0, 1.0 }, { 0.0, 1.0 }, { -1.0, 1.0 }), Vec3::One * 0.5, 1.0));
bodies.push_back(world.createSphere(RandomVec3({ -1.0, 1.0 }, { 0.0, 1.0 }, { -1.0, 1.0 }), 0.5, 1.0));
bodies.push_back(world.createCylinder(RandomVec3({ -1.0, 1.0 }, { 0.0, 1.0 }, { -1.0, 1.0 }), 0.5, 1.0, 1.0));
bodies.push_back(world.createCapsule(RandomVec3({ -1.0, 1.0 }, { 0.0, 1.0 }, { -1.0, 1.0 }), 0.5, 1.0, 1.0));
Physics3DCompoundShape compound;
compound.addShape(Physics3DCapsuleShape(0.3, 2.0));
compound.addShape(Physics3DCapsuleShape(0.3, 2.0), Vec3(0.0, 1.0, 0.0), Quaternion(Vec3(0.0, 0.0, 1.0), Math::HalfPi));
compound.addShape(Physics3DCapsuleShape(0.3, 2.0), Vec3(0.0, -1.0, 0.0), Quaternion(Vec3(1.0, 0.0, 0.0), Math::HalfPi));
bodies.push_back(world.createBody(compound, RandomVec3({ -1.0, 1.0 }, { 0.0, 1.0 }, { -1.0, 1.0 }), 1.0));
Physics3DMousePickManager mousePick;
while (System::Update())
{
mousePick.update(world);
world.update();
ground.draw();
for (const auto& body : bodies)
{
body.draw();
}
mousePick.draw();
}
}
拘束条件
# include <Siv3D.hpp>
# include <HamFramework.hpp>
void Main()
{
Physics3DWorld world;
Physics3DBody ground = world.createBox(Vec3(0, -50, 0), Vec3(50, 50, 50), 0.0);
Array<Physics3DBody> bodies;
Array<Physics3DPointToPointConstraint> constraints;
const double plankWidth = 0.4;
const double plankHeight = 0.2;
const double plankBreadth = 1.0;
const double plankOffset = plankWidth;
const double bridgeWidth = plankWidth * 10.0 + plankOffset*(10.0 - 1.0);
const double bridgeHeight = 5.0;
const double halfBridgeWidth = bridgeWidth*0.5;
const double mass = 1.0;
const int lastBoxIndex = 10 - 1;
for (int i = 0; i < 10; ++i)
{
double t = static_cast<double>(i) / lastBoxIndex;
t = -(t * 2.0 - 1.0) * halfBridgeWidth;
bodies.push_back(world.createBox(Vec3(t, bridgeHeight, 0), Vec3(plankWidth, plankHeight, plankBreadth), (i == 0 || i == lastBoxIndex) ? 0.0 : mass));
}
for (int i = 0; i<10 - 1; ++i)
{
constraints.push_back(world.createPointToPointConstraint(bodies[i], bodies[i + 1], Vec3(-0.5, 0, -0.5), Vec3(0.5, 0, -0.5)));
constraints.push_back(world.createPointToPointConstraint(bodies[i], bodies[i + 1], Vec3(-0.5, 0, 0.5), Vec3(0.5, 0, 0.5)));
}
while (System::Update())
{
if (Input::MouseL.clicked)
{
bodies.push_back(world.createSphere(Vec3(Random(-1.0, 1.0), 10.0 + Random(-1.0, 1.0), Random(-1.0, 1.0)), 0.5, 1.0));
}
world.update();
ground.draw();
for (const auto& body : bodies)
{
body.draw();
}
}
}
応用例
ギア
車
おわりに
本記事では,次期 Siv3D である OpenSiv3D の 3D 機能に向けた,物理演算機能のプロトタイプを紹介しました.本機能により,より多くの 3D ゲームや 3D アプリケーションなどが開発されることを期待しています.