Skip to content

Instantly share code, notes, and snippets.

@sakurmoti
Created November 10, 2023 08:00
Show Gist options
  • Save sakurmoti/f70625863149e41264c72eb5435d8b50 to your computer and use it in GitHub Desktop.
Save sakurmoti/f70625863149e41264c72eb5435d8b50 to your computer and use it in GitHub Desktop.
物理挙動の完成
# include <Siv3D.hpp>
struct Physics
{
double mass;
Vec3 pos;
Vec3 vel;
Vec3 force;
OrientedBox obj;
Physics() : mass(0), vel({ 0,0,0 }), force({ 0,0,0 }), obj(OrientedBox{ {0,0,0},{1,1,1} })
{
pos = obj.center;
}
/// @param mass 質量
/// @param vel 速度
/// @param force 力
/// @param obj OrientedBox: {center, size}
Physics(double mass, Vec3 vel, Vec3 force, OrientedBox obj)
: mass(mass), vel(vel), force(force), obj(obj)
{
pos = obj.center;
}
virtual void draw() const
{
//Print << U"Physics: virtual draw";
obj.draw();
}
virtual void draw(const Texture& tex) const
{
obj.draw(tex);
}
virtual void update()
{
double dt = Scene::DeltaTime();
vel += (force / mass) * dt;
pos += vel * dt;
obj.setPos(pos);
}
void stop()
{
vel = Vec3{ 0, 0, 0 };
force = Vec3{ 0, 0, 0 };
}
static Optional<Vec3> getNormal(const Vec3& point, const Physics physics)
{
// pointがphysicsのどの面にあるかを判定
// {0,0,0}を中心としgetCorners()で得られる頂点のうち、インデックスが
// {0,1,2,3}が -Z {4,5,6,7}が +Z
// {0,4,2,6}が -X {1,5,3,7}が +X
// {2,3,6,7}が -Y {0,1,4,5}が +Yの方向
// 角に当たったときの処理は不定
Optional<Vec3> ret;
int indexs[6][4] = {{0,1,2,3}, {4,5,6,7}, {0,4,2,6}, {1,5,3,7}, {2,3,6,7}, {0,1,4,5}};
Array<Vec3> normals = { {0,0,-1}, {0,0,1}, {-1,0,0}, {1,0,0}, {0,-1,0}, {0,1,0} };
Quaternion rot = physics.obj.orientation;
for (int i = 0; i < normals.size(); i++) normals[i] = normals[i] * rot;
std::array<Vec3, 8> corners = physics.obj.getCorners();
double eps = 1e-5;
for (int i = 0; i < 6; i++)
{
Vec3 A = corners[indexs[i][0]];
Vec3 B = corners[indexs[i][1]];
Vec3 C = corners[indexs[i][2]];
Vec3 AB = B - A;
Vec3 AC = C - A;
Vec3 AP = point - A;
// 行列式が0 == 四面体の体積は0 == 点は平面上にある
Mat3x3 mat;
mat._11_12_13 = AB;
mat._21_22_23 = AC;
mat._31_32_33 = AP;
Print << U"mat: " << mat.determinant();
if (Abs(mat.determinant()) < eps) {
ret = normals[i];
Print << U"normal: " << normals[i];
}
}
return ret;
}
void reflect(Physics Wall)
{
// Wallは不動とする
Vec3 v = this->vel;
Ray ray{this->pos, v.normalized()};
Optional<Float3> intersect = ray.intersectsAt(Wall.obj);
if (!intersect) return;
Optional<Vec3> n = getNormal(*intersect, Wall);
if (!n) return;
Vec3 N = *n;
this->vel = v - 2 * Dot(v, N) * N;
Print << U"reflect";
}
};
struct Test : Physics
{
Test () : Physics() {}
Test(double mass, Vec3 vel, Vec3 force, OrientedBox obj)
: Physics(mass, vel, force, obj) {}
void draw() const override
{
}
void update() override
{
Physics::update();
}
};
void Main()
{
//Window::Resize(1280, 720);
const ColorF backgroundColor = ColorF{ 0.4, 0.6, 0.8 }.removeSRGBCurve();
const Texture uvChecker{ U"example/texture/uv.png", TextureDesc::MippedSRGB };
const MSRenderTexture renderTexture{ Scene::Size(), TextureFormat::R8G8B8A8_Unorm_SRGB, HasDepth::Yes };
DebugCamera3D camera{ renderTexture.size(), 120_deg, Vec3{ 0, 2, -5 } };
Physics p1{ 1, {0,0,0}, {0,-9.8,0}, OrientedBox{ {0,4,0}, {1,1,1} } };
Physics p2{ 1, {0,0,0}, {0,0,0}, OrientedBox{ {0,0,0}, {1,1,1}}};
while (System::Update())
{
ClearPrint();
camera.update(2.0);
Graphics3D::SetCameraTransform(camera);
// 3D 描画
{
const ScopedRenderTarget3D target{ renderTexture.clear(backgroundColor) };
{
const ScopedRenderStates3D blend{ BlendState::OpaqueAlphaToCoverage };
/* OrientedBoxの法線ベクトルの取得
OrientedBox box{ {0.5,0.5,0.5}, {1,1,1}, Quaternion::RotateZ(30_deg) };
box.draw();
if (box.intersects(ray))
{
auto raypoint = ray.intersectsAt(box);
Sphere{*raypoint, 0.1}.draw(Palette::Orange);
Print << raypoint;
Optional<Vec3> normal = Physics::getNormal(*raypoint, Physics{ 1, {0,0,0}, {0,0,0}, box });
if (normal) Line3D{ box.center, box.center + *normal }.draw(Palette::Red);
}
Print << box.getCorners();
*/
p1.update();
p2.update();
p1.draw();
p2.draw();
if(p1.obj.intersects(p2.obj)) p1.reflect(p2);
Print << U"IJKL: rotate p2, WSAD: move camera, R: retry";
if (KeyJ.down()) {
p1.pos = { 0,4,0 };
p1.vel = { 0,0,0 };
p2.obj.orientation *= Quaternion::RotateZ(10_deg);
}
if (KeyL.down()) {
p1.pos = { 0,4,0 };
p1.vel = { 0,0,0 };
p2.obj.orientation *= Quaternion::RotateZ(-10_deg);
}
if (KeyI.down()) {
p1.pos = { 0,4,0 };
p1.vel = { 0,0,0 };
p2.obj.orientation *= Quaternion::RotateX(10_deg);
}
if (KeyK.down()) {
p1.pos = { 0,4,0 };
p1.vel = { 0,0,0 };
p2.obj.orientation *= Quaternion::RotateX(-10_deg);
}
if (KeyR.down()) {
p1.pos = { 0,4,0 };
p1.vel = { 0,0,0 };
}
}
}
// 3D シーンを 2D シーンに描画
{
Graphics3D::Flush();
renderTexture.resolve();
Shader::LinearToScreen(renderTexture);
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment