Skip to content

Instantly share code, notes, and snippets.

@Reputeless
Created October 31, 2023 03:51
Show Gist options
  • Save Reputeless/f3de27e3bd221f13b3dcf3b7e92fa3bf to your computer and use it in GitHub Desktop.
Save Reputeless/f3de27e3bd221f13b3dcf3b7e92fa3bf to your computer and use it in GitHub Desktop.
# include <Siv3D.hpp>
void DrawBillboard(const Vec3& pos, const SizeF& size, const Mesh& mesh, const Texture& texture, const BasicCamera3D& camera)
{
mesh.draw(camera.billboard(pos, size), texture);
}
void DrawBillboard(const Vec3& pos, double size, const Mesh& mesh, const Texture& texture, const BasicCamera3D& camera)
{
DrawBillboard(pos, { size, size }, mesh, texture, camera);
}
void DrawBillboardPoints(const Vec3& pos, const SizeF& size, const BasicCamera3D& camera)
{
const Mat4x4 mat = camera.billboard(pos, size);
const Vec3 p0 = mat.transformPoint(Vec3{ -0.5, 0.5, 0.0 });
const Vec3 p1 = mat.transformPoint(Vec3{ 0.5, 0.5, 0.0 });
const Vec3 p2 = mat.transformPoint(Vec3{ 0.5, -0.5, 0.0 });
const Vec3 p3 = mat.transformPoint(Vec3{ -0.5, -0.5, 0.0 });
Sphere{ p0, 0.08 }.draw(Linear::Palette::Yellow);
Sphere{ p1, 0.12 }.draw(Linear::Palette::Yellow);
Sphere{ p2, 0.16 }.draw(Linear::Palette::Yellow);
Sphere{ p3, 0.2 }.draw(Linear::Palette::Yellow);
}
void DrawBillboardPoints(const Vec3& pos, double size, const BasicCamera3D& camera)
{
DrawBillboardPoints(pos, { size, size }, camera);
}
struct Quad3D
{
std::array<Triangle3D, 2> triangles;
Optional<float> intersects(const Ray& ray) const
{
if (auto d = ray.intersects(triangles[0]))
{
return d;
}
if (const auto d = ray.intersects(triangles[1]))
{
return d;
}
return none;
}
Optional<Float3> intersectsAt(const Ray& ray) const
{
if (auto d = ray.intersectsAt(triangles[0]))
{
return d;
}
if (const auto d = ray.intersectsAt(triangles[1]))
{
return d;
}
return none;
}
};
Quad3D BillboardToQuad(const Vec3& pos, const SizeF& size, const BasicCamera3D& camera)
{
const Mat4x4 mat = camera.billboard(pos, size);
const Vec3 p0 = mat.transformPoint(Vec3{ -0.5, 0.5, 0.0 });
const Vec3 p1 = mat.transformPoint(Vec3{ 0.5, 0.5, 0.0 });
const Vec3 p2 = mat.transformPoint(Vec3{ 0.5, -0.5, 0.0 });
const Vec3 p3 = mat.transformPoint(Vec3{ -0.5, -0.5, 0.0 });
return Quad3D{{
Triangle3D{ p0, p1, p2 },
Triangle3D{ p0, p2, p3 },
}};
}
Quad3D BillboardToQuad(const Vec3& pos, double size, const BasicCamera3D& camera)
{
return BillboardToQuad(pos, { size, size }, camera);
}
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(), 30_deg, Vec3{ 10, 16, -32 } };
// ビルボード表示する板
const Mesh billboard{ MeshData::Billboard() };
const Mesh wideBillboard{ MeshData::Billboard({2, 1}) };
while (System::Update())
{
camera.update(2.0);
Graphics3D::SetCameraTransform(camera);
const Mat4x4 billboardMat = camera.getInvView();
// 3D 描画
{
const ScopedRenderTarget3D target{ renderTexture.clear(backgroundColor) };
Plane{ 64 }.draw(uvChecker);
Box{ -8,2,0,4 }.draw(ColorF{ 0.8, 0.6, 0.4 }.removeSRGBCurve());
Sphere{ 0,2,0,2 }.draw(ColorF{ 0.4, 0.8, 0.6 }.removeSRGBCurve());
Cylinder{ 8, 2, 0, 2, 4 }.draw(ColorF{ 0.6, 0.4, 0.8 }.removeSRGBCurve());
DrawBillboard({ -8, 4, -4 }, 1, billboard, uvChecker, camera);
DrawBillboard({ 0, 4, -4 }, 2, billboard, uvChecker, camera);
DrawBillboard({ 8, 4, 4 }, { 8, 4 }, wideBillboard, uvChecker, camera);
DrawBillboardPoints({ -8, 4, -4 }, 1, camera);
DrawBillboardPoints({ 0, 4, -4 }, 2, camera);
DrawBillboardPoints({ 8, 4, 4 }, { 8, 4 }, camera);
const auto mouseRay = camera.screenToRay(Cursor::PosF());
const auto q0 = BillboardToQuad({ -8, 4, -4 }, 1, camera);
const auto q1 = BillboardToQuad({ 0, 4, -4 }, 2, camera);
const auto q2 = BillboardToQuad({ 8, 4, 4 }, { 8, 4 }, camera);
if (auto pos = q0.intersectsAt(mouseRay))
{
Sphere{ *pos, 0.2 }.draw(Linear::Palette::Red);
}
if (auto pos = q1.intersectsAt(mouseRay))
{
Sphere{ *pos, 0.2 }.draw(Linear::Palette::Red);
}
if (auto pos = q2.intersectsAt(mouseRay))
{
Sphere{ *pos, 0.2 }.draw(Linear::Palette::Red);
}
}
// 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