React + Rust + Wasm: Render a 3D Scene
In this article, we will use Bevy game engine in our React application from our Rust WASM library to render a 3D scene. We will build on the previous tutorial available here.
Run a Bevy App using Rust
Last time, we used a setup
function with our Bevy app to draw a 2D image. Now, let's modify our lib.rs
to create another setup
function that will render a 3D scene.
Update the setup function
#[wasm_bindgen]
pub fn run_bevy_app() {
App::new()
.add_plugins(DefaultPlugins)
.add_startup_system(setup_3d) # Defined below
.run();
}
Define setup_3d
fn setup_3d(
mut commands: Commands,
mut meshes: ResMut<Assets<Mesh>>,
mut materials: ResMut<Assets<StandardMaterial>>,
) {
# ...
}
Add a plane
fn setup_3d(
mut commands: Commands,
mut meshes: ResMut<Assets<Mesh>>,
mut materials: ResMut<Assets<StandardMaterial>>,
) {
commands.spawn(PbrBundle {
mesh: meshes.add(Mesh::from(shape::Plane { size: 5.0 })),
material: materials.add(Color::rgb(0.3, 0.5, 0.3).into()),
..default()
});
}
Add a cube
fn setup_3d(
mut commands: Commands,
mut meshes: ResMut<Assets<Mesh>>,
mut materials: ResMut<Assets<StandardMaterial>>,
) {
# ...
commands.spawn(PbrBundle {
mesh: meshes.add(Mesh::from(shape::Cube { size: 1.0 })),
material: materials.add(Color::rgb(0.8, 0.7, 0.6).into()),
transform: Transform::from_xyz(0.0, 0.5, 0.0),
..default()
});
}
Add some light
fn setup_3d(
mut commands: Commands,
mut meshes: ResMut<Assets<Mesh>>,
mut materials: ResMut<Assets<StandardMaterial>>,
) {
# ...
commands.spawn(PointLightBundle {
point_light: PointLight {
intensity: 1500.0,
shadows_enabled: true,
..default()
},
transform: Transform::from_xyz(4.0, 8.0, 4.0),
..default()
});
}
Position the camera
fn setup_3d(
mut commands: Commands,
mut meshes: ResMut<Assets<Mesh>>,
mut materials: ResMut<Assets<StandardMaterial>>,
) {
# ...
commands.spawn(Camera3dBundle {
transform: Transform::from_xyz(-2.0, 2.5, 5.0).looking_at(Vec3::ZERO, Vec3::Y),
..default()
});
}
Build the new wasm library
Let’s run wasm-pack again to build the updated library
wasm-pack build --target web
Call the function from the demo app
Finally, let’s add a button to load the wasm and call run_bevy_app
function from our App.ts
file like so:
// App.ts
import init, { run_bevy_app } from "rust-wasm-lib";
import './App.css';
function App() {
const runBevyApp = async () => {
await init();
run_bevy_app();
};
return (
<div className="App">
<button onClick={runBevyApp}>Run Bevy App</button>
</div>
);
}
export default App;
Now, if you run the updated app and click on Run Bevy App
, you should see a 3d scene :)
If you liked this article, subscribe here to get the complete code and updates for the entire collection: