New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Load full scenes from GLTF files #435

Merged
merged 1 commit into from Oct 21, 2017

Conversation

Projects
None yet
5 participants
@Rhuagh
Member

Rhuagh commented Oct 20, 2017

Only have support for static scenes so far. Need to complete the Animation PR before I can finish loading that.

Also waiting on multiple features in other parts of the engine before I can add full material support, indexed meshes etc.

@torkleyy

This looks fantastic, thank you so much!

Cargo.toml
[workspace]
-members = ["amethyst_assets", "amethyst_audio", "amethyst_config", "amethyst_core", "amethyst_input", "amethyst_renderer", "amethyst_utils"]
+members = ["amethyst_assets", "amethyst_audio", "amethyst_config", "amethyst_core", "amethyst_gltf", "amethyst_input",

This comment has been minimized.

@torkleyy

torkleyy Oct 20, 2017

Member

We should eventually make this a virtual workspace. I think those support kind of implicit members, not sure.

@torkleyy

torkleyy Oct 20, 2017

Member

We should eventually make this a virtual workspace. I think those support kind of implicit members, not sure.

This comment has been minimized.

@Rhuagh

Rhuagh Oct 20, 2017

Member

No idea tbh :)

@Rhuagh

Rhuagh Oct 20, 2017

Member

No idea tbh :)

amethyst_gltf/Cargo.toml
+travis-ci = { repository = "amethyst/amethyst" }
+
+[dependencies]
+amethyst_assets = { path = "../amethyst_assets/" }

This comment has been minimized.

@torkleyy

torkleyy Oct 20, 2017

Member

You need to specify the versions here.

@torkleyy

torkleyy Oct 20, 2017

Member

You need to specify the versions here.

amethyst_gltf/Cargo.toml
+amethyst_assets = { path = "../amethyst_assets/" }
+amethyst_renderer = { path = "../amethyst_renderer/" }
+amethyst_core = { path = "../amethyst_core/" }
+base64 = "*"

This comment has been minimized.

@torkleyy

torkleyy Oct 20, 2017

Member

Please don't use * in library crates

@torkleyy

torkleyy Oct 20, 2017

Member

Please don't use * in library crates

This comment has been minimized.

@Xaeroxe

Xaeroxe Oct 20, 2017

Member

(This actually breaks the cargo upload too)

@Xaeroxe

Xaeroxe Oct 20, 2017

Member

(This actually breaks the cargo upload too)

This comment has been minimized.

@Rhuagh

Rhuagh Oct 20, 2017

Member

Ah. Missed that one, sorry

@Rhuagh

Rhuagh Oct 20, 2017

Member

Ah. Missed that one, sorry

amethyst_gltf/src/format/importer.rs
+ let format = match mime_type {
+ "image/png" => ImageFormat::Png,
+ "image/jpeg" => ImageFormat::Jpeg,
+ _ => unreachable!(),

This comment has been minimized.

@torkleyy

torkleyy Oct 20, 2017

Member

Technically, this could also be e.g. .bmp

@torkleyy

torkleyy Oct 20, 2017

Member

Technically, this could also be e.g. .bmp

This comment has been minimized.

@Rhuagh

Rhuagh Oct 20, 2017

Member

No support in gltf got other than jpg and bmp

@Rhuagh

Rhuagh Oct 20, 2017

Member

No support in gltf got other than jpg and bmp

This comment has been minimized.

@Rhuagh

Rhuagh Oct 20, 2017

Member

Jpg and png I mean ofc

@Rhuagh

Rhuagh Oct 20, 2017

Member

Jpg and png I mean ofc

This comment has been minimized.

@torkleyy

torkleyy Oct 20, 2017

Member

Is that defined by reference or the Rust implementation?

@torkleyy

torkleyy Oct 20, 2017

Member

Is that defined by reference or the Rust implementation?

This comment has been minimized.

@alteous

alteous Oct 20, 2017

The glTF specification allows only JPEG and PNG.

@alteous

alteous Oct 20, 2017

The glTF specification allows only JPEG and PNG.

amethyst_gltf/src/format/importer.rs
+ let format = match ty {
+ "image/png" => ImageFormat::Png,
+ "image/jpeg" => ImageFormat::Jpeg,
+ _ => unreachable!(),

This comment has been minimized.

@torkleyy

torkleyy Oct 20, 2017

Member

Same here.

@torkleyy

torkleyy Oct 20, 2017

Member

Same here.

+/// Gltf scene format, will cause the whole default scene to be loaded from the given file.
+///
+/// Using the `GltfSceneLoaderSystem` a `Handle<GltfSceneAsset>` from this format can be attached
+/// to an entity in ECS, and the system will then load the full scene using the given entity

This comment has been minimized.

@torkleyy

torkleyy Oct 20, 2017

Member

Good idea 👍

@torkleyy

torkleyy Oct 20, 2017

Member

Good idea 👍

This comment has been minimized.

@Rhuagh

Rhuagh Oct 20, 2017

Member

This could probably be replaced by a real prefab system at some point

@Rhuagh

Rhuagh Oct 20, 2017

Member

This could probably be replaced by a real prefab system at some point

This comment has been minimized.

@omni-viral

omni-viral Oct 21, 2017

Member

More like generalized into prefab system

@omni-viral

omni-viral Oct 21, 2017

Member

More like generalized into prefab system

amethyst_gltf/src/format/mod.rs
+ options: GltfSceneOptions,
+ ) -> Result<GltfSceneAsset, BoxedErr> {
+ let gltf = load_gltf(source, &name, options).map_err(|err| BoxedErr::new(err))?;
+ match gltf.default_scene {

This comment has been minimized.

@torkleyy

torkleyy Oct 20, 2017

Member

Should be

if gltf.default_scene.is_some() || gltf.scenes.len() == 1 {
    Ok(gltf)
} else {
    Err(..)
}
@torkleyy

torkleyy Oct 20, 2017

Member

Should be

if gltf.default_scene.is_some() || gltf.scenes.len() == 1 {
    Ok(gltf)
} else {
    Err(..)
}
amethyst_gltf/src/systems.rs
+
+/// A GLTF scene loader, will transform `Handle<GltfSceneAsset>` into full entity hierarchies.
+///
+/// Will also do the asset storage processing for `GltfSceneAsset`.s

This comment has been minimized.

@torkleyy

torkleyy Oct 20, 2017

Member

"GltfSceneAsset.s"

@torkleyy

torkleyy Oct 20, 2017

Member

"GltfSceneAsset.s"

amethyst_gltf/src/systems.rs
+
+impl GltfSceneLoaderSystem {
+ pub fn new() -> Self {
+ Self {}

This comment has been minimized.

@torkleyy

torkleyy Oct 20, 2017

Member

Meh, I don't like this syntax. And I guess we don't need this constructor, do we?

@torkleyy

torkleyy Oct 20, 2017

Member

Meh, I don't like this syntax. And I guess we don't need this constructor, do we?

This comment has been minimized.

@Rhuagh

Rhuagh Oct 20, 2017

Member

Remnant from when it had fields

@Rhuagh

Rhuagh Oct 20, 2017

Member

Remnant from when it had fields

amethyst_gltf/src/systems.rs
+ // TODO: emissive factor
+ // TODO: alpha
+ // TODO: double sided
+ let albedo = match material.base_color.0.handle {

This comment has been minimized.

@torkleyy

torkleyy Oct 20, 2017

Member

I think you could use .cloned().unwrap_or(..)

@torkleyy

torkleyy Oct 20, 2017

Member

I think you could use .cloned().unwrap_or(..)

This comment has been minimized.

@Rhuagh

Rhuagh Oct 20, 2017

Member

Possible, I'll check

@Rhuagh

Rhuagh Oct 20, 2017

Member

Possible, I'll check

@torkleyy

This comment has been minimized.

Show comment
Hide comment
@torkleyy

torkleyy Oct 20, 2017

Member

@alteous This is our gltf integration PR in case you're interested.

Member

torkleyy commented Oct 20, 2017

@alteous This is our gltf integration PR in case you're interested.

+}
+
+// Load a single node, attach all data to the given `node_entity`.
+fn load_node(

This comment has been minimized.

@@ -0,0 +1,328 @@
+use std;

This comment has been minimized.

@alteous

alteous Oct 20, 2017

I hope the burden of writing your own loader wasn't too annoying. It's a compromise between being high-level and not doing 'too much' on behalf of the user.

@alteous

alteous Oct 20, 2017

I hope the burden of writing your own loader wasn't too annoying. It's a compromise between being high-level and not doing 'too much' on behalf of the user.

This comment has been minimized.

@Rhuagh

Rhuagh Oct 20, 2017

Member

No, it was fine, I started with using the importer to get the first implementation in place, then I basically copied the importer code and replaced the file loading parts only.

@Rhuagh

Rhuagh Oct 20, 2017

Member

No, it was fine, I started with using the importer to get the first implementation in place, then I basically copied the importer code and replaced the file loading parts only.

amethyst_gltf/src/format/mod.rs
+}
+
+fn map_mode(mode: gltf::json::mesh::Mode) -> Result<Primitive, GltfError> {
+ use gltf::json::mesh::Mode::*;

This comment has been minimized.

@alteous

alteous Oct 20, 2017

I suggest gltf::mesh::Mode instead. The gltf::json module is deprecated and will be removed in 1.0.

@alteous

alteous Oct 20, 2017

I suggest gltf::mesh::Mode instead. The gltf::json module is deprecated and will be removed in 1.0.

This comment has been minimized.

@Rhuagh

Rhuagh Oct 20, 2017

Member

Oh, I must have missed that, it did feel weird to have to go down to the json stuff.

@Rhuagh

Rhuagh Oct 20, 2017

Member

Oh, I must have missed that, it did feel weird to have to go down to the json stuff.

amethyst_gltf/src/format/mod.rs
+}
+
+impl Format<GltfSceneAsset> for GltfSceneFormat {
+ const NAME: &'static str = "GLTF";

This comment has been minimized.

@alteous

alteous Oct 20, 2017

Also, .glb for binary glTF - not sure if you still distinguish by extension.

@alteous

alteous Oct 20, 2017

Also, .glb for binary glTF - not sure if you still distinguish by extension.

This comment has been minimized.

@Rhuagh

Rhuagh Oct 20, 2017

Member

This is just the name of the format, not related to extension at all.

@Rhuagh

Rhuagh Oct 20, 2017

Member

This is just the name of the format, not related to extension at all.

@torkleyy torkleyy self-requested a review Oct 21, 2017

@torkleyy

Thanks for addressing, got a few other concerns but otherwise it's great!

amethyst_gltf/src/format/importer.rs
+ }
+}
+
+fn import_standard<'a>(

This comment has been minimized.

@torkleyy

torkleyy Oct 21, 2017

Member

Why an explicit lifetime here?

@torkleyy

torkleyy Oct 21, 2017

Member

Why an explicit lifetime here?

This comment has been minimized.

@Rhuagh

Rhuagh Oct 21, 2017

Member

Ah, used to take a reference to something that needed it

@Rhuagh

Rhuagh Oct 21, 2017

Member

Ah, used to take a reference to something that needed it

amethyst_gltf/src/format/importer.rs
+ let gltf = validate_standard(unvalidated)?;
+ let bin = None;
+ let mut buffers = Buffers(vec![]);
+ for buffer in load_external_buffers(source, base_path, &gltf, bin)? {

This comment has been minimized.

@torkleyy

torkleyy Oct 21, 2017

Member

Why are you iterating over a vec just to push the elements to another, intially empty one?

@torkleyy

torkleyy Oct 21, 2017

Member

Why are you iterating over a vec just to push the elements to another, intially empty one?

amethyst_gltf/src/lib.rs
+ pub generate_tex_coords: Option<(f32, f32)>,
+}
+
+impl Default for GltfSceneOptions {

This comment has been minimized.

@torkleyy

torkleyy Oct 21, 2017

Member

Can't we derive this?

@torkleyy

torkleyy Oct 21, 2017

Member

Can't we derive this?

amethyst_gltf/src/systems.rs
+/// A GLTF scene loader, will transform `Handle<GltfSceneAsset>` into full entity hierarchies.
+///
+/// Will also do the asset storage processing for `GltfSceneAsset`.
+pub struct GltfSceneLoaderSystem;

This comment has been minimized.

@torkleyy

torkleyy Oct 21, 2017

Member

Please add a dummy field in case we want to add fields later

@torkleyy

torkleyy Oct 21, 2017

Member

Please add a dummy field in case we want to add fields later

This comment has been minimized.

@Rhuagh

Rhuagh Oct 21, 2017

Member

What is the recommended type for a dummy field?

@Rhuagh

Rhuagh Oct 21, 2017

Member

What is the recommended type for a dummy field?

This comment has been minimized.

@torkleyy

torkleyy Oct 21, 2017

Member

() I guess

@torkleyy

torkleyy Oct 21, 2017

Member

() I guess

amethyst_gltf/src/systems.rs
+ // process new texture handles, cache them in the textures
+ for (material_index, texture_index, handle) in texture_handles {
+ match texture_index {
+ 0 => {

This comment has been minimized.

@torkleyy

torkleyy Oct 21, 2017

Member

Could we at least use constants somewhere, this is a bit magic

@torkleyy

torkleyy Oct 21, 2017

Member

Could we at least use constants somewhere, this is a bit magic

amethyst_gltf/src/systems.rs
+ // Use the default scene if set, otherwise use the first scene.
+ // Note that the format will throw an error if the default scene is not set,
+ // and there are more than one scene in the GLTF, so defaulting to scene 0 is safe
+ let scene_index = match scene_asset.default_scene {

This comment has been minimized.

@torkleyy

torkleyy Oct 21, 2017

Member

Should use unwrap_or

@torkleyy

torkleyy Oct 21, 2017

Member

Should use unwrap_or

amethyst_gltf/src/systems.rs
+ };
+
+ // Load material for the primitive
+ let material = match primitive.material {

This comment has been minimized.

@torkleyy

torkleyy Oct 21, 2017

Member

I think it would be nicer to do this:

let material = primitive
    .material
    .map(|i| (i, scene_asset.materials.get(i)))
    .and_then(|(i, m)| load_material(i, m, ..))
    .unwrap_or_else(|| mat_defaults.0.clone());
@torkleyy

torkleyy Oct 21, 2017

Member

I think it would be nicer to do this:

let material = primitive
    .material
    .map(|i| (i, scene_asset.materials.get(i)))
    .and_then(|(i, m)| load_material(i, m, ..))
    .unwrap_or_else(|| mat_defaults.0.clone());

This comment has been minimized.

@Rhuagh

Rhuagh Oct 21, 2017

Member

Hmm, i need to do unwrap on m in and_then then

@Rhuagh

Rhuagh Oct 21, 2017

Member

Hmm, i need to do unwrap on m in and_then then

This comment has been minimized.

@torkleyy

torkleyy Oct 21, 2017

Member

No?

This comment has been minimized.

@Rhuagh

Rhuagh Oct 21, 2017

Member

If I reverse it it works though.

@Rhuagh

Rhuagh Oct 21, 2017

Member

If I reverse it it works though.

@Rhuagh Rhuagh requested a review from torkleyy Oct 21, 2017

@torkleyy

Looks great!

@omni-viral

Great job @Rhuagh !

@Xaeroxe

I've got a couple organization nits but otherwise this looks awesome! Thanks for your work!

...I'm mostly just glad it wasn't me that had to write this :P Looks like loads of data to manage.

amethyst_gltf/src/format/importer.rs
+where
+ P: AsRef<Path>,
+{
+ import_impl(source, path.as_ref())

This comment has been minimized.

@Xaeroxe

Xaeroxe Oct 21, 2017

Member

You could replace this with the body of import_impl and just add

let path = path.as_ref()

at the top.

@Xaeroxe

Xaeroxe Oct 21, 2017

Member

You could replace this with the body of import_impl and just add

let path = path.as_ref()

at the top.

amethyst_gltf/src/format/importer.rs
+}
+
+fn read_to_end<P: AsRef<Path>>(source: Arc<AssetSource>, path: P) -> Result<Vec<u8>, BoxedErr> {
+ read_to_end_impl(source, path.as_ref())

This comment has been minimized.

@Xaeroxe

Xaeroxe Oct 21, 2017

Member

Same as above.

@Xaeroxe

Xaeroxe Oct 21, 2017

Member

Same as above.

@Xaeroxe

This comment has been minimized.

Show comment
Hide comment
@Xaeroxe

Xaeroxe Oct 21, 2017

Member

bors r+

Member

Xaeroxe commented Oct 21, 2017

bors r+

bors bot added a commit that referenced this pull request Oct 21, 2017

Merge #435
435: feat: Load full scenes from GLTF files r=Xaeroxe a=Rhuagh

Only have support for static scenes so far. Need to complete the Animation PR before I can finish loading that.

Also waiting on multiple features in other parts of the engine before I can add full material support, indexed meshes etc.
@bors

This comment has been minimized.

Show comment
Hide comment

@bors bors bot merged commit 0b738f9 into amethyst:develop Oct 21, 2017

3 checks passed

bors Build succeeded
continuous-integration/appveyor/pr AppVeyor build succeeded
Details
continuous-integration/travis-ci/pr The Travis CI build passed
Details

@Rhuagh Rhuagh deleted the Rhuagh:gltf-format branch Oct 21, 2017

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment