Problem rendering a Sphere with the Debug Lines Example

#1

I have attempted to combine the “debug_lines” and “material” examples to render a sphere in the middle of the coordinate system produced by the first example. My code compiles correctly, yet the sphere itself does not appear. Am I missing something as simple as an adequate source of lighting? Or, does the problem concern a deeper mistake in my code. (e.g., Am I failing to properly store a handle to the sphere in the gen_sphere method?) This project is my first using the amethyst engine; I have only been developing with rust for a period of three weeks. I apologize if my question is redundant.

As I am a new user, I am unable to upload files and instead had to paste my code here.

--------------------------------------- main.rs ----------------------------------

use amethyst::{
    controls::{FlyControlBundle, FlyControlTag},
    core::{
        math::{Point3, Vector3},
        transform::{Transform, TransformBundle},
        Time,
    },
    derive::SystemDesc,
    ecs::{Read, System, SystemData, WorldExt, Write},
    input::{is_close_requested, is_key_down, InputBundle, StringBindings},
    prelude::*,
    renderer::{
        camera::Camera, 
        debug_drawing::{DebugLines, DebugLinesComponent, DebugLinesParams},
        palette::{Srgba, Srgb},
        plugins::{RenderDebugLines, RenderSkybox, RenderToWindow},
        types::DefaultBackend,
        RenderingBundle,
        light::{Light, PointLight}
    },
    utils::application_root_dir,
    winit::VirtualKeyCode,
    window::ScreenDimensions,
};
mod volume_renderer;
#[derive(SystemDesc)]
struct ExampleLinesSystem;
impl<'s> System<'s> for ExampleLinesSystem {
    type SystemData = (
        Write<'s, DebugLines>, // Request DebugLines resource
        Read<'s, Time>,
    );
    fn run(&mut self, (mut debug_lines_resource, time): Self::SystemData) {
        // Drawing debug lines as a resource
        let t = (time.absolute_time_seconds() as f32).cos();
        debug_lines_resource.draw_direction(
            Point3::new(t, 0.0, 0.5),
            Vector3::new(0.0, 0.3, 0.0),
            Srgba::new(0.5, 0.05, 0.65, 1.0),
        );
        debug_lines_resource.draw_line(
            Point3::new(t, 0.0, 0.5),
            Point3::new(0.0, 0.0, 0.2),
            Srgba::new(0.5, 0.05, 0.65, 1.0),
        );
    }
}
struct MainState;
impl SimpleState for MainState {
    fn on_start(&mut self, data: StateData<'_, GameData<'_, '_>>) {
        // Setup debug lines as a resource
        data.world.insert(DebugLines::new());
        // Configure width of lines. Optional step
        data.world.insert(DebugLinesParams { line_width: 2.0 });
        // Setup debug lines as a component and add lines to render axes & grid
        let mut debug_lines_component = DebugLinesComponent::with_capacity(100);
        // X-axis (red)
        debug_lines_component.add_direction(
            Point3::new(0.0, 0.0001, 0.0),
            Vector3::new(0.2, 0.0, 0.0),
            Srgba::new(1.0, 0.0, 0.23, 1.0),
        );
        // Y-axis (yellowish-green)
        debug_lines_component.add_direction(
            Point3::new(0.0, 0.0, 0.0),
            Vector3::new(0.0, 0.2, 0.0),
            Srgba::new(0.5, 0.85, 0.1, 1.0),
        );
        // Z-axis (blue)
        debug_lines_component.add_direction(
            Point3::new(0.0, 0.0001, 0.0),
            Vector3::new(0.0, 0.0, 0.2),
            Srgba::new(0.2, 0.75, 0.93, 1.0),
        );
        let width: u32 = 10;
        let main_color = Srgba::new(0.4, 0.4, 0.4, 1.0);
        // In the following nested for loops, we instantiate the cartesian coordinate system on the
        // x-z plane
        for i in 0..=width {
            let (i, width, depth) = (i as f32, width as f32, width as f32);
            let x_position = Point3::new(i - width / 2.0, 0.0, -depth / 2.0);
            let x_direction = Vector3::new(0.0, 0.0, depth);
            debug_lines_component.add_direction(x_position, x_direction, main_color);
            let z_position = Point3::new(-width / 2.0, 0.0, i - depth / 2.0);
            let z_direction = Vector3::new(width, 0.0, 0.0);
            debug_lines_component.add_direction(z_position, z_direction, main_color);
            // Sub-grid lines
            if (i - width).abs() < 0.0001 {
                for sub in 1..10 {
                    let x_sub_offset = Vector3::new((1.0 / 10.0) * sub as f32, -0.001, 0.0);
                    let z_sub_offset = Vector3::new(0.0, -0.001, (1.0 / 10.0) * sub as f32);
                    debug_lines_component.add_direction(
                        x_position + x_sub_offset,
                        x_direction,
                        Srgba::new(1.0, 1.0, 1.0, 0.5),
                    );
                    debug_lines_component.add_direction(
                        z_position + z_sub_offset,
                        z_direction,
                        Srgba::new(1.0, 1.0, 1.0, 0.5),
                    );
                }
            }
        }
        // Add test sphere 
        volume_renderer::gen_sphere(data.world, 50, 0.0, 0.0, 0.0);
        let mut light1_transform = Transform::default();
        light1_transform.set_translation_xyz(6.0, 6.0, -6.0);
        println!("Create lights");
        let light1: Light = PointLight {
            intensity: 6.0,
            color: Srgb::new(0.8, 0.0, 0.0),
            ..PointLight::default()
        }
        .into();
        data.world
            .create_entity()
            .with(light1)
            .with(light1_transform)
            .build();
        // Debug lines are automatically rendered by including the debug lines
        // rendering plugin
        data.world.register::<DebugLinesComponent>();
        data.world
            .create_entity()
            .with(debug_lines_component)
            .build();
        // Setup camera
        let (camera_width, camera_height) = {
            let dim = data.world.read_resource::<ScreenDimensions>();
            (dim.width(), dim.height())
        };
        println!("width: {} height: {}", camera_width, camera_height);
        let mut local_transform = Transform::default();
        local_transform.set_translation_xyz(0.0, 0.5, 2.0);
        data.world
            .create_entity()
            .with(FlyControlTag)
            .with(Camera::standard_3d(camera_width, camera_height))
            .with(local_transform)
            .build();
   }
    fn handle_event(
        &mut self,
        _: StateData<'_, GameData<'_, '_>>,
        event: StateEvent,
    ) -> SimpleTrans {
        if let StateEvent::Window(event) = event {
            if is_close_requested(&event) || is_key_down(&event, VirtualKeyCode::Escape) {
                Trans::Quit
            } else {
                Trans::None
            }
        } else {
            Trans::None
        }
    }
}
fn main() -> amethyst::Result<()> {
    amethyst::start_logger(Default::default());
    let app_root = application_root_dir()?;
    let display_config_path = app_root.join("src/config/display.ron");
    let key_bindings_path = app_root.join("src/config/input.ron");
    let assets_dir = app_root.join("src/assets/");
    let fly_control_bundle = FlyControlBundle::<StringBindings>::new(
        Some(String::from("move_x")),
        Some(String::from("move_y")),
        Some(String::from("move_z")),
    )
    .with_sensitivity(0.1, 0.1);
    let game_data = GameDataBuilder::default()
        .with_bundle(
            InputBundle::<StringBindings>::new().with_bindings_from_file(&key_bindings_path)?,
        )?
        .with(ExampleLinesSystem, "example_lines_system", &[])
        .with_bundle(fly_control_bundle)?
        .with_bundle(TransformBundle::new().with_dep(&["fly_movement"]))?
        .with_bundle(
            RenderingBundle::<DefaultBackend>::new()
                .with_plugin(RenderToWindow::from_config_path(display_config_path)?)
                .with_plugin(RenderDebugLines::default())
                .with_plugin(RenderSkybox::with_colors(amethyst::renderer::palette::rgb::Rgb::new(0.0, 0.0, 0.25), 
                                                       amethyst::renderer::palette::rgb::Rgb::new(0.0, 0.0, 0.0))),
        )?;
    let mut game = Application::new(assets_dir, MainState, game_data)?;
    game.run();
    Ok(())
}

------------------------------- volume_render.rs ----------------------------------

use amethyst::{
    assets::AssetLoaderSystemData,
    core::{
        ecs::{Builder, WorldExt},
        Transform, TransformBundle,
    },
    ecs::prelude::World,
    renderer::{
        camera::Camera,
        light::{Light, PointLight},
        mtl::{Material, MaterialDefaults},
        palette::{LinSrgba, Srgb},
        plugins::{RenderPbr3D, RenderToWindow},
        rendy::{
            mesh::{Normal, Position, Tangent, TexCoord},
            texture::palette::load_from_linear_rgba,
        },
        shape::Shape,
        types::DefaultBackend,
        Mesh, RenderingBundle, Texture,
    },
    utils::application_root_dir,
    window::ScreenDimensions,
    Application, GameData, GameDataBuilder, SimpleState, StateData,
};
pub fn gen_sphere (world: &mut World, radius: i32, x: f32, y: f32, z: f32) {  
  let mat_defaults = world.read_resource::<MaterialDefaults>().0.clone();
  let mesh = world.exec(|loader: AssetLoaderSystemData<'_, Mesh>| {
             loader.load_from_data(
             Shape::Sphere(radius as usize, radius as usize)
                    .generate::<(Vec<Position>, Vec<Normal>, Vec<Tangent>, Vec<TexCoord>)>(None)
                    .into(),
                  (),
                )
           });
  let albedo = world.exec(|loader: AssetLoaderSystemData<'_, Texture>| {
               loader.load_from_data(
                    load_from_linear_rgba(LinSrgba::new(1.0, 1.0, 1.0, 0.5)).into(),
                    (),
                )
            });
                let mtl = world.exec(
                    |(mtl_loader, tex_loader): (
                        AssetLoaderSystemData<'_, Material>,
                        AssetLoaderSystemData<'_, Texture>,
                    )| {
                        let metallic_roughness = tex_loader.load_from_data(
                            load_from_linear_rgba(LinSrgba::new(1.0, 1.0, 1.0, 1.0))
                                .into(),
                            (),
                        );
                        mtl_loader.load_from_data(
                            Material {
                                albedo: albedo.clone(),
                                metallic_roughness,
                                ..mat_defaults.clone()
                            },
                            (),
                        )
                    },
                );
  let mut pos = Transform::default();
  pos.set_translation_xyz(x, y, z);
  world.create_entity()
                    .with(pos)
                    .with(mesh.clone())
                    .with(mtl)
                    .build();
  println!("[+] Constructing sphere {} {} {} {} {:?} {:?}", x, y, z, radius, mesh, albedo);
}

------------------- Cargo.toml --------------------

[package]
name = ""
version = "0.1.0"
authors = []
edition = "2018"
[features]
default = ["amethyst_rendy/vulkan", "amethyst_rendy/vulkan-x11"]
renderer = ["amethyst_rendy",]
[dependencies]
vulkan = "0.0.1"
amethyst = "0.15.0"
amethyst_rendy = {verison = "0.5.0", optional = true}
nalgebra = "0.21.1"

------------ display.ron --------------------

/*!
    @import /amethyst_window/src/config.rs#DisplayConfig
    DisplayConfig
*/
(
  title: "Debug lines example",
)

--------- input.ron --------------------------

/*!
    @import /amethyst_input/src/bindings.rs#Bindings, StringBindings
    Bindings<StringBindings>
*/
(
    axes: {
        "move_x": Emulated(
            pos: Key(D),
            neg: Key(A),
        ),
        "move_y": Emulated(
            pos: Key(E),
            neg: Key(Q),
        ),
        "move_z": Emulated(
            pos: Key(S),
            neg: Key(W),
        ),
    },
    actions: {
    },
)
(Nathan) #2

Hi @user17347, welcome to the Amethyst forum! Would you mind uploading your code to a public repository on GitHub, and then providing a link to it? It’s a lot easier to interact with this amount of code if folks can easily clone it and poke around in it on their own machines.

I’m guessing from your description that there are no errors that point to why the sphere is not appearing?