Skip to content
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

egui-wgpu on web #1755

Closed
Titaniumtown opened this issue Jun 19, 2022 · 9 comments · Fixed by #2107
Closed

egui-wgpu on web #1755

Titaniumtown opened this issue Jun 19, 2022 · 9 comments · Fixed by #2107
Labels
egui-wgpu web Related to running Egui on the web

Comments

@Titaniumtown
Copy link
Contributor

How could one use the wgpu integration for egui on wasm? I can't find a way to do this. Is this possible?

@Titaniumtown Titaniumtown changed the title WGPU on wasm egui-wgpu on wasm Jun 19, 2022
@emilk
Copy link
Owner

emilk commented Jun 19, 2022

I haven't tried it, but I really would like for it to work.

@expenses claims to be using egui-wgpu for WebGL in #1671 - maybe they have some input?

@expenses
Copy link
Contributor

Yep, but it's currently locked to using webgl and not webgpu:

wgpu = { version = "0.12", features = ["webgl"] }

We'd just need to remove this feature to get it work for both backends

@Titaniumtown
Copy link
Contributor Author

I assume this cannot be done as easily as eframe::start_web... how did you do it exactly?

@felixfaire
Copy link

We are using egui-wgpu successfully on wasm (with the webgl2 backend currently, though i don't think it should be different for webgpu).

We have an existing wgpu context and custom event loop, input events etc (driven by typescript side), i'm not au fait with how eframe does it, but we followed the 'integrations' part of the eframe repo and got it up and running fairly seamlessly. Which bit are you struggling with in particular? @Titaniumtown

@geolehmann
Copy link

geolehmann commented Jun 23, 2022

I managed to create a minimum working example using egui-wgpu with a wgpu backend and wasm32 target, see https://github.com/geolehmann/egui-wgpu_wasm_example (event handling is not yet included), which took me way longer than it should. I had to use my own fork of egui tho with some fixes (I used some code from the fork of @expenses ).

I also found another working example: https://github.com/pierscowburn/egui_wgpu_failure_case, but here still the older egui-wgpu-backend crate is used.

@emilk emilk added web Related to running Egui on the web egui-wgpu labels Aug 20, 2022
@emilk
Copy link
Owner

emilk commented Aug 28, 2022

@geolehmann thanks for that example! I notice that you use winit (and egui-winit) on the web, which is interesting (see #1032).

@metacean
Copy link

metacean commented Aug 31, 2022

I have done my own barebones integration of egui on top of a 'raw' wgpu app originally based on the 'learn wgpu' tutorials. this runs on native and in browser via WASM wth wgpu (no webgl fallback). I also have hooked up basic mouse move and button click events as i required them.

I dont really have a 'releaseable' example app i can publish (and I use camel case which likely makes me an heretic in the wider rust community) but, in case its a helpful to anyone - my renderers state struct has the following added:

guiContext: egui::Context,
guiRenderPass: egui_wgpu::renderer::RenderPass,
guiScreenDescriptor: egui_wgpu::renderer::ScreenDescriptor,
guiInput: egui::RawInput,
guiMousePositionInPoints: egui::Pos2, //cache our mouse position as we need it for events

these are initialised as follows:

let guiContext = egui::Context::default();
let guiRenderPass = egui_wgpu::renderer::RenderPass::new(&device, config.format, 1);
let guiScreenDescriptor = egui_wgpu::renderer::ScreenDescriptor {
            size_in_pixels: [config.width, config.height],
            pixels_per_point: 2.0,
        };
let guiInput = egui::RawInput::default();
let guiMousePositionInPoints = egui::pos2(0.0, 0.0);

and the main part of the rendering looks like:

// at beginning of render function create a second encoder to handle the gui drawing commands
let mut guiEncoder = self
            .device
            .create_command_encoder(&wgpu::CommandEncoderDescriptor {
                label: Some("Gui Encoder"),
            });

{
self.guiContext.begin_frame(self.guiInput.take());

//some code to draw a few widgets - rot is a rotation in radians for the displayed model
egui::Window::new("My Window").show(&self.guiContext, |ui| {
    ui.label("Hello World!");
    if ui.button("A Button").clicked() {
         log::warn!("CLICKED BUTTON");
    };
    ui.add(
        egui::Slider::new(&mut self.rot, 0.0..=6.25)
                        .text("rot")
                        .fixed_decimals(2),
        );
   });

//code needed to render the gui
let guiOutput = self.guiContext.end_frame();
let prims = self.guiContext.tessellate(guiOutput.shapes);
self.guiRenderPass.update_buffers(
                &self.device,
                &self.queue,
                &prims[..],
                &self.guiScreenDescriptor,
            );
for (id, image_delta) in &guiOutput.textures_delta.set {
                self.guiRenderPass
                    .update_texture(&self.device, &self.queue, *id, image_delta);
            }
self.guiRenderPass.execute(
                &mut guiEncoder,
                &view,
                &prims[..],
                &self.guiScreenDescriptor,
                None,
            );
}

self.queue.submit(iter::once(guiEncoder.finish()));
output.present();

example of input gathering from the existing winit handlers is:

WindowEvent::CursorMoved {
                device_id,
                position,
                modifiers,
                ..
            } => {
                //log::warn!("CURSOR {:#?} {:#?}", position.x, position.y);
                let pos = egui::pos2(
                    position.x as f32 / self.guiScreenDescriptor.pixels_per_point,
                    position.y as f32 / self.guiScreenDescriptor.pixels_per_point,
                );
                self.guiMousePositionInPoints = pos;
                let pointerEvent = egui::Event::PointerMoved(pos);
                self.guiInput.events.push(pointerEvent);
                true
            }

I am a bit of a rust newbie (Most of my experience in this sort of thing is with raw Vulkan and C++) so have just followed my nose as to how to make this work, but this produces a usable gui overlaid on top of my existing 3d rendered output. If anyone else wants to try the same approach i'm happy to provide more detail

@emilk emilk changed the title egui-wgpu on wasm egui-wgpu on web Sep 5, 2022
@emilk
Copy link
Owner

emilk commented Sep 7, 2022

@metacean please use backticks for code

like this

@luiswirth
Copy link
Contributor

I would be willing to provide an example, as I've got my own egui + winit + wgpu integration working on wasm!

But I would like to first await some responses to #2022 and #2023 :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
egui-wgpu web Related to running Egui on the web
Projects
None yet
Development

Successfully merging a pull request may close this issue.

7 participants