#js #wrapper #3d #scene #camera #babylon

neo-babylon

基于wasm-bindgen的Babylon.js包装器

15次发布

0.2.0 2023年10月24日
0.1.13 2023年9月28日
0.1.12 2023年8月31日
0.1.7 2023年6月29日
0.1.2 2023年5月18日

#411WebAssembly

Download history 1/week @ 2024-05-18 7/week @ 2024-07-06 146/week @ 2024-07-27

每月153 次下载

MIT/Apache

160KB
720

neo-babylon

docs.rs docs Crates.io

Babylon.js在Rust中的WebAssembly包装器。它主要基于https://github.com/richardanaya/babylon.rs的分支,但使用了wasm-bindgen并增加了额外功能。

该项目目前没有提供Babylon.js的所有绑定,但这并非有意为之。请随时提出有关Babylon.js额外功能的issue或pull request。

当前优先级

  • 获取基本GLTF
  • 获取相机
  • 获取某种交互方式

惯用用法

  • 场景包含3D对象
  • 材质决定3D对象的外观
  • 当3D对象下落时,它将从场景中删除

HelloWorld

simple example program showing multiple spheres

use std::{cell::RefCell, rc::Rc};

use js_sys::Math;
use wasm_bindgen::prelude::*;
use neo_babylon::{prelude::*, api};
use web_sys::console;

struct Game {
    scene: Rc<RefCell<Scene>>,
    shapes: Vec<BabylonMesh>,
}

impl Game {
    fn new() -> Self {
        Game {
            scene: api::create_basic_scene("#renderCanvas"),
            shapes: vec![],
        }
    }
}

thread_local! {
    static GAME: RefCell<Game> = RefCell::new(Game::new());
}

#[wasm_bindgen(start)]
pub fn main() {
    console::log_1(&"Starting demo...".into());

    GAME.with(|game| {    

        for i in 0..10 { 
            let sphere = BabylonMesh::create_sphere(&game.borrow().scene.borrow(), format!("sphere_{}", i).as_str(), SphereOptions{ diameter: Some(Math::random() + 0.5), ..Default::default() });
            sphere.set_position(&Vector3::new(
                Math::random() - 0.5,
                Math::random() - 0.5,
                Math::random() - 0.5,
            ));        
            game.borrow_mut().shapes.push(sphere);
        }
    });
}

在此处查看演示 这里 (请确保用鼠标和箭头键 ⬅️ ⬆️ ⬇️ ➡️ 进行操作!)

在140行以内实现Pong

use neo_babylon::{api, prelude::*};
use js_sys::Math;
use wasm_bindgen::JsCast;
use std::cell::RefCell;
use std::{collections::HashSet, rc::Rc};
use wasm_bindgen::prelude::wasm_bindgen;

struct Game {
    scene: Rc<RefCell<Scene>>,
    _camera: ArcRotateCamera,
    _light_1: HemisphericLight,
    _light_2: PointLight,
    ball: BabylonMesh,
    paddle_1: BabylonMesh,
    paddle_2: BabylonMesh,
    paddle_dir: RefCell<f64>,
    ball_dir: Vector3,
    keys: Rc<RefCell<HashSet<u8>>>,
}

impl Default for Game {
    fn default() -> Self {
        // Basic scene setup
        let scene = api::create_scene("#renderCanvas");
        scene.borrow().set_clear_color(Color4::new(0.0, 0.0, 0.0, 1.0));
        let _camera = ArcRotateCamera::default();
        let _light_1 =
            HemisphericLight::new("Light1", Vector3::new(0.0, 0.0, 1.0), &scene.borrow());
        let _light_2 = PointLight::new("Light2", Vector3::new(0.0, 1.0, 0.0), &scene.borrow());

        // Create ball
        let ball = BabylonMesh::create_sphere(
            &scene.borrow(),
            "ball",
            SphereOptions {
                diameter: Some(0.05),
                ..Default::default()
            },
        );

        // Create paddles
        let paddle_mat = StandardMaterial::new("paddle_mat", &scene.borrow());
        paddle_mat.set_diffuse_color(Color3::new(0.1, 0.5, 0.1));
        let paddle_1 = BabylonMesh::create_box(
            &scene.borrow(),
            "paddle_1",
            BoxOptions {
                width: Some(0.5),
                height: Some(0.05),
                depth: Some(0.05),
                ..Default::default()
            },
        );
        paddle_1.set_position(&Vector3::new(0.0, 0.5, 0.0));
        paddle_1.set_material(&paddle_mat);
        let paddle_2 = BabylonMesh::create_box(
            &scene.borrow(),
            "paddle_2",
            BoxOptions {
                width: Some(0.5),
                height: Some(0.05),
                depth: Some(0.05),
                ..Default::default()
            },
        );
        paddle_2.set_position(&Vector3::new(0.0, -0.5, 0.0));
        paddle_2.set_material(&paddle_mat);

        Game {
            scene,
            _camera,
            _light_1,
            _light_2,
            ball,
            paddle_1,
            paddle_2,
            paddle_dir: RefCell::new(0.0),
            ball_dir: Vector3::new(Math::random() - 0.5, -1.0, 0.0),
            keys: Rc::new(RefCell::new(HashSet::<u8>::new())),
        }
    }
}

impl BasicGame for Game {
    fn get_scene(&self) -> Rc<RefCell<Scene>> {
        self.scene.clone()
    }

    fn get_keys(&self) -> Rc<RefCell<HashSet<u8>>> {
        Rc::clone(&self.keys)
    }

    fn update(&self, delta_time: f64) {
        // Get positions
        let p2 = self.paddle_2.position();
        let bp = self.ball.position();

        // Calculate new ball position
        let bp_new = self.ball_dir.unchecked_ref::<Vector3>() * delta_time + bp;

        if bp_new.x() > 0.75 || bp_new.x() < -0.75 {
            self.ball_dir.set_x(-self.ball_dir.x());
        }
        if bp_new.y() > 0.75 || bp_new.y() < -0.75 {
            // Reset ball if outside play area
            bp_new.set_x(0.0);
            bp_new.set_y(0.0);
            self.ball_dir.set(Math::random() - 0.5, -self.ball_dir.y(), 0.0);
        } else if bp_new.y() > 0.45 || (bp_new.y() < -0.45 && bp_new.y() > -0.55 && bp_new.x() <= p2.x() + 0.25 && bp_new.x() >= p2.x() - 0.25) {
            // Hit paddle (top paddle is assumed to always hit)
            self.ball_dir.set_y(-self.ball_dir.y());
            bp_new.set_y(if bp_new.y() > 0.0 { 0.44 } else { -0.44 });
        }

        self.ball.set_position(&bp_new);

        // Move opponent paddle to match ball
        self.paddle_1.set_position_x(bp_new.x());

        // Determine direction based on keys down
        match self.keys.borrow() {
            x if x.contains(&37) => self.paddle_dir.replace(1.0),
            x if x.contains(&39) => self.paddle_dir.replace(-1.0),
            _ => self.paddle_dir.replace(0.0)
        };
        
        // Move paddle if it has velocity
        let p2_x = p2.x() + delta_time * *self.paddle_dir.borrow();
        if p2_x > -0.5 && p2_x < 0.5 {
            self.paddle_2.set_position_x(p2_x);
        }
    }
}

#[wasm_bindgen(start)]
pub fn main() {
    run_basic_game::<Game>();
}

在此处查看演示 这里

其他演示

许可证

该项目受以下任一许可证的约束

任选其一。

贡献

除非你明确声明,否则你提交给此库的任何有意贡献,根据Apache-2.0许可证的定义,将按照上述方式双许可,不附加任何额外条款或条件。

依赖项

~6.5–8.5MB
~170K SLoC