#vr #web #graphics #api-bindings

aframe

Rust WASM 的高级Aframe VR绑定

30个发布版本

0.6.2 2024年1月28日
0.6.1 2024年1月28日
0.5.3 2021年10月25日
0.4.0 2021年10月8日
0.1.17 2021年9月29日

#106 in WebAssembly

28 每月下载量

MIT/Apache

240KB
3.5K SLoC

aframe-rs

这是一个为 Rust 编写的 Aframe 库。它仍然相当实验性,很多东西都可能发生变化。我开始写这个是为了好玩,看看我能否在 yew 应用中玩 aframe。它开始变得相当庞大,所以我决定将所有特定的 yew 东西抽象出来,并开始创建一个单独的库。这里还有很多缺失的东西和要完成的事情,但现在已经有的都是可工作的。

设置

初始化

此 crate 包含一个 init 功能,可以启用以允许从异步函数中进行初始化


async fn app_main() -> Result<(), aframe::InitError>
{
    aframe::init_aframe().await?;
    // ... Now you can safely continue
}

您也可以通过将 Aframe 脚本添加到您的 HTML 标题中简单地初始化

<script src="https://aframe.io/releases/1.2.0/aframe.min.js"></script>

使用

您可以使用此 crate 的 Htmlify trait 输出原始 HTML,或者使用 yew-support 功能创建一个 yew 组件(在下面的说明中描述)以输出您的实际 Aframe 场景。

API

场景

实例化场景
scene!

组件

定义新的组件
component_def!

声明定义组件的结构
component_struct!
simple_enum!
complex_enum!

实例化组件结构
component!

有关更多信息以及预定义组件结构,请参阅 component 模块。

自定义几何形状

定义新的自定义几何形状
geometry_def!

尚未实现

  • geometry_struct! 宏用于声明自定义几何形状数据的结构
  • geometry! 宏在实例化自定义几何形状时作为辅助工具

实体 & 原始形状

实例化实体或定义的原始形状
entity!

定义新的原始形状
primitive!

资产

assets!mixin! 宏用于定义一个 Assets 结构。

assets!
mixin!

系统

system_def!

着色器

着色器

Htmlify

Htmlify trait 用于从此 crate 提供的结构中生成 HTML。这已被抽象为单独的 crate

Htmlify

您可以使用它将场景直接放入 DOM 中,使用 web_sys crate,这使得此 crate 即使在没有支持框架的情况下也可以使用

// Say we have some `Scene` structure already constructed:
let body = web_sys::window()?.document()?.body()?;
body.append_with_node_1(scene.as_element()?.as_ref())?;

// Or even simpler:
htmlify::append_to_document_body(&scene);

这是一个使用 wasm-bindgen-test 创建的完全功能的页面的基本示例: 测试示例

系统API

Aframe 的最低级调用定义在 sys 模块中

registerPrimitive
registerComponent
registerSystem
registerShader
registerGeometry
registerElement

yew_support功能

yew_support 功能为这个crate添加了yew支持。其核心是实现了 From<&Scene> for Html 以及一些其他转换到yew的Html类型。

有关示例,请参阅 yew-ext模块页面

正在开发/缺失的功能

  • 事件处理
  • 状态处理
  • 对自定义几何体的高级支持
  • 访问Aframe实用函数
  • 一些组件实现仍然接受字符串,而它们可以接受枚举或更具体的结构

示例

以下是yew中构建场景的完整示例(这也可以作为在yew上下文之外使用 scene! 宏的有效示例)

html!
{
    <Aframe scene = 
    { 
        // Using this contant to clean up some fluff in the code below.
        const CURSOR_COLOR: [(Cow<'static, str>, Cow<'static, str>); 1] = 
            [(Cow::Borrowed("color"), Cow::Borrowed("lightblue"))];
        scene!
        {
            // TODO: Some of these attributes are actually components, they need to be implemented in the library!
            attributes: ("inspector", "true"), ("embedded", "true"), ("cursor", "rayOrigin: mouse"),
                        ("mixin", "intersect_ray"), ("style", "min-height: 50px;"),
            assets: assets!
            {
                // Assume we have a few assets available to use
                Image::new("ramen", "/pics/ramen.png"),
                Image::new("noise", "/pics/noise.bmp"),
                // Create a mixin for shadows to know what to interact with
                mixin!
                {
                    "intersect_ray", 
                    ("raycaster", component!
                    {
                        RayCaster,
                        objects: List(Cow::Borrowed(&[Cow::Borrowed("#ramen-cube, #water")]))
                    })
                }
            },
            children: 
            // The camera rig
            entity!
            {
                attributes: ("id", "rig"),
                components: 
                ("position", component::Position { x: 0.0, y: 0.0, z: 0.0  }),
                ("geometry", component!
                {
                    component::Geometry,
                    primitive: component::GeometryPrimitive::Ring
                    {
                        radius_inner: 0.06,
                        radius_outer: 0.2,
                        segments_theta: 32,
                        segments_phi: 8,
                        theta_start: 0.0,
                        theta_length: 360.0
                    }
                }),
                ("material", component!
                {
                    component::Material,
                    props: component::MaterialProps(Cow::Borrowed(&CURSOR_COLOR)),
                    opacity: 0.8
                }),
                children: 
                    // The camera
                    entity!
                    {
                        attributes: ("id", "camera"), 
                        components: 
                            ("position", component::Position { x: 0.0, y: 1.8, z: 0.0  }),
                            ("camera", component!(component::Camera)),
                            ("look-controls", component!(component::LookControls))
                    }, 
            },
            entity!
            {
                attributes: ("id", "cube-rig"),
                components: 
                ("position", component::Position{x: 0.0, y: 2.5, z: -2.0}),
                ("sound", component!
                {
                    component::Sound,
                    src: Cow::Borrowed("#ambient_music"), 
                    volume: 0.5
                }),
                ("light", component!
                {
                    component::Light,
                    light_type: component::LightType::Point
                    {
                        decay: 1.0,
                        distance: 50.0,
                        shadow: component::OptionalLocalShadow::NoCast{},
                    }, 
                    intensity: 0.0
                }),
                ("animation__mouseenter", component!
                {
                    component::Animation,
                    property: Cow::Borrowed("light.intensity"),
                    to: Cow::Borrowed("1.0"),
                    start_events: component::List(Cow::Borrowed(&[Cow::Borrowed("mouseenter")])),
                    dur: 250
                }),
                ("animation__mouseleave", component!
                {
                    component::Animation,
                    property: Cow::Borrowed("light.intensity"),
                    to: Cow::Borrowed("0.0"),
                    start_events: component::List(Cow::Borrowed(&[Cow::Borrowed("mouseleave")])),
                    dur: 250
                }),
                // This assumes the existence of a primitive registered as "ramen-cube"
                children: entity!
                {
                    primitive: "ramen-cube",
                    attributes: ("id", "ramen-cube"),
                    components: // None
                }
            },
    
            // Ambient light
            entity!
            {
                attributes: ("id", "ambient-light"),
                components: ("light", component!
                {
                    component::Light,
                    light_type: component::LightType::Ambient{},
                    color: color::GREY73,
                    intensity: 0.2
                })
            },
    
            // Directional light
            entity!
            {
                attributes: ("id", "directional-light"),
                components: 
                ("position", component::Position{ x: 0.5, y: 1.0, z: 1.0 }),
                ("light", component!
                {
                    component::Light,
                    light_type: component::LightType::Directional
                    {
                        shadow: component::OptionalDirectionalShadow::Cast
                        {
                            shadow: component!
                            {
                                component::DirectionalShadow
                            }
                        }
                    },
                    color: color::WHITE,
                    intensity: 0.1
                })
            },
            // The sky
            entity!
            {
                primitive: "a-sky",
                attributes: ("id", "sky"),
                components: ("material", component!
                {
                    component::Material, 
                    // This assumes the existence of a shader registered as "strobe"
                    shader: Cow::Borrowed("strobe"),
                    props: component::MaterialProps(Cow::Owned(vec!
                    (
                        (Cow::Borrowed("color"), Cow::Borrowed("black")),
                        (Cow::Borrowed("color2"), Cow::Borrowed("#222222"))
                    )))
                })
            },
            // The ocean
            entity!
            {
                primitive: "a-ocean",
                attributes: ("id", "water"), ("depth", "100"), ("width", "100"), ("amplitude", "0.5"),
                components: ("material", component!
                {
                    component::Material, 
                    // This assumes the existence of a shader registered as "water"
                    shader: Cow::Borrowed("water"),
                    props: component::MaterialProps(Cow::Owned(vec!((Cow::Borrowed("transparent"), Cow::Borrowed("true")))))
                })
            }
        }
    } />
}

依赖项

~11–15MB
~265K SLoC