🦀

chip4. 3Dオブジェクト「宝箱」を表示する

2023/08/02に公開

はじめに

2023/08/02時点の内容です。

  • rustc 1.71.0
  • bevy 0.11.0
    bevyは開発初期段階のOSSで、まだまだ破壊的なアップデートが入ります。
    でも、面白いですよ。

前回

chip3. "Hello, world!"の見た目をいじる

よくあるサンプルは公式を見るべし

手抜き。こういうのをやりたい。
https://bevyengine.org/examples/3D Rendering/3d-scene/

bevy0.11に用意されているプリミティブ

自分まったくの素人なので、現在のラインナップが何を基準にそろえたのか謎。
bevy::prelude::shape

名称 2D/3D 説明
Circle 2D XY平面上の円形
Quad 2D 1つの辺で決まるXY平面上の正方形
RegularPolygon 2D 辺の数で決まるXY平面上の正多角形
Plane 3D 1つの辺で決まるXZ平面上の正方形
Cube 3D 1つの辺で決まる立方体
Box 3D 2つの点(x,y,z)で決まる直方体
Cylinder 3D 円柱
Capsule 3D 円柱の上下に半球を持つカプセル型
Icosphere 3D 球体
UVSphere 3D 球体
Torus 3D ドーナツ型

以下の公式サンプルで実物を見られます。
https://bevyengine.org/examples/2D Rendering/2d-shapes/
https://bevyengine.org/examples/3D Rendering/3d-shapes/

3Dオブジェクト「宝箱」を表示する

プリミティブの組み合わせだけでそれっぽく見せるのはなかなか大変。
宝箱‥‥に見える?

chip4
use bevy::{ prelude::*, render::*, render::settings::* };
use std::f32::consts::*;

fn main()
{   //Note:手元の環境だとVulkanのままでは影が描画されなかったので、DX12へ切り替えた。
    let backends = Some ( Backends::DX12 );
    let wgpu_settings = WgpuSettings { backends, ..default() };
    let backend_dx12 = RenderPlugin { wgpu_settings };

    App::new()
        .add_plugins
        (   DefaultPlugins //各種の面倒を見てもらう
                .set( backend_dx12 ) //Note:この行をコメントアウトするとデフォルトになる
        )
        .add_systems
        (   Startup, 
            (   spawn_camera3d_and_light, //カメラを作る
                spawn_3d_lockedchest,     //3Dオブジェクトを作る
            )
        )
        .add_systems
        (   Update,
            (   bevy::window::close_on_esc, //[ESC]キーで終了
            )
        )
        .run();
}

//カメラと光源を作る
fn spawn_camera3d_and_light( mut cmds: Commands )
{   //3Dカメラ
    cmds.spawn( Camera3dBundle::default() )
        .insert
        (   Transform::from_translation( Vec3::new( -1.0, 1.0, 2.0 ) ) //カメラの位置
                .looking_at( Vec3::ZERO, Vec3::Y ) //カメラレンズの向き
        );

    //光源
    cmds.spawn( DirectionalLightBundle::default() )
        .insert
        (   DirectionalLight
            {   illuminance: 15000.0,  //明るさ
                shadows_enabled: true, //影の描画を有効化
                ..default()
            }
        )
        .insert
        (   Transform::from_xyz( 30.0, 100.0, 40.0 ) //光源の位置
                .looking_at( Vec3::ZERO, Vec3::Z )   //光源の向き
        );
}

//3Dオブジェクトを作る
fn spawn_3d_lockedchest
(   mut cmds: Commands,
    mut meshes: ResMut<Assets<Mesh>>,
    mut materials: ResMut<Assets<StandardMaterial>>,
)
{   //地面
    cmds.spawn( PbrBundle::default() )
        .insert( meshes.add( shape::Plane::from_size( 2.0 ).into() ) )
        .insert( Transform::from_translation( Vec3::ZERO ) )
        .insert( materials.add( Color::rgb( 0.5, 0.7, 0.3 ).into() ) );

    //宝箱
    cmds.spawn( PbrBundle::default() )
        .insert( materials.add( Color::NONE.into() ) ) //透明
        .insert( Transform::from_translation( Vec3::new( 0.0, 0.5, 0.0 ) ) )
        .with_children
        (   | cmds |
            {   //本体
                let shape_box = shape::Box::new( 0.7, 0.3, 0.4 );
                cmds.spawn( PbrBundle::default() )
                    .insert( meshes.add( shape_box.into() ) )
                    .insert( Transform::from_translation( Vec3::Y * -0.35 ) )
                    .insert( materials.add( Color::MAROON.into() ) );

                //上蓋
                let shape_cylinder = shape::Cylinder { height: 0.695, radius: 0.195, ..default() };
                cmds.spawn( PbrBundle::default() )
                    .insert( meshes.add( shape_cylinder.into() ) )
                    .insert
                    (   Transform::from_translation( Vec3::Y * -0.2 )
                            .with_rotation( Quat::from_rotation_z( PI * 0.5 ) )
                    )
                    .insert( materials.add( Color::MAROON.into() ) );

                //錠前
                let shape_cube = shape::Cube::new( 0.1 );
                cmds.spawn( PbrBundle::default() )
                    .insert( meshes.add( shape_cube.into() ) )
                    .insert( Transform::from_translation( Vec3::Y * -0.2 + Vec3::Z * 0.17 ) )
                    .insert( materials.add( Color::GRAY.into() ) )
                    .with_children
                    (   | cmds |
                        {   //鍵穴
                            let cylinder = shape::Cylinder { height: 0.11, radius: 0.01, ..default() };
                            cmds.spawn( PbrBundle::default() )
                                .insert( meshes.add( cylinder.into() ) )
                                .insert
                                (   Transform::from_translation( Vec3::Y * 0.02 )
                                        .with_rotation( Quat::from_rotation_x( PI * 0.5 ) )
                                )
                                .insert( materials.add( Color::BLACK.into() ) );

                            let shape_box = shape::Box::new( 0.01, 0.04, 0.11 );
                            cmds.spawn( PbrBundle::default() )
                                .insert( meshes.add( shape_box.into() ) )
                                .insert( Transform::from_translation( Vec3::Y * 0.0 ) )
                                .insert( materials.add( Color::BLACK.into() ) );
                        }
                    );
            }
        );
}

Discussion