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

Updated the library to work with bevy 0.7 and rapier 0.13.2 #50

Open
wants to merge 2 commits into
base: master
Choose a base branch
from

Conversation

YourRentIsDue
Copy link

I have tested with my own project. The code compiles and the features all seem to be in working order!

.insert_bundle(bundle)
.insert(RigidBodyPositionSync::Discrete);
//new method of inserting rigid bodies into entities
if body_desc.ccd_enable{
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If possible, could we get rid of this conditional here? I'd rather something like

let initial_body = commands.entity(entity)
    .insert(body_status)

....
if body_desc.ccv_enable {
    initial_body.insert(Ccd::enabled())
}

Copy link
Author

@YourRentIsDue YourRentIsDue May 18, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm pretty sure that'd work, yeah. As I was writing the code I also found out that you can still use bundles, but you can't define them as a variable beforehand. So there's a nicer way to format the inserts. Not that it matters I suppose, since functionaly both methods are the same

@sdfgeoff
Copy link
Owner

Looks pretty good. I'll give it a test this weekend before merging.

@YourRentIsDue
Copy link
Author

I have found an bug! The collider descriptions aren't actually added to rigid bodies, but rather, a new rigid body is created with the collider description. Causing a lot of weird stuff. I will try to fix it and update my fork.

@marko-lazic
Copy link

Please consider updating the examples.

@@ -46,69 +46,64 @@ pub fn body_description_to_builder(
for (body_desc, entity, transform) in body_desc_query.iter() {
commands.entity(entity).remove::<RigidBodyDescription>();

let isometry = Isometry3::from((transform.translation, transform.rotation));

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We can remove Isometry3 from the import list.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is true. I wasn't really worried about code cleanup, just wanted to get it workin.

@@ -46,69 +46,64 @@ pub fn body_description_to_builder(
for (body_desc, entity, transform) in body_desc_query.iter() {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Transform is not used anymore.

@sdfgeoff
Copy link
Owner

sdfgeoff commented May 24, 2022

I'm getting a build error:

error[E0432]: unresolved import `bevy_rapier3d::physics`
 --> examples/scenes/main.rs:4:20
  |
4 | use bevy_rapier3d::physics::{NoUserData, RapierPhysicsPlugin};
  |                    ^^^^^^^ could not find `physics` in `bevy_rapier3d`

I've tried both updating Cargo.lock and updating my rust compiler version.

Any thoughts? Have other people managed to build it?

@YourRentIsDue
Copy link
Author

YourRentIsDue commented May 24, 2022

Have you tried "use bevy_rapier3d::prelude::*"? that was what worked for me. I didn't try building the examples, I only updated the library code.

A friend of mine did try to build it with our game code, it worked fine.

@sdfgeoff
Copy link
Owner

Hmm. Can I get you to also try it with the examples. Even with the fix for the import path (it seems bevy_rapier_3d now does indeed export NoUserData from the prelude), all I get is a black screen.

I'm hesitant to merge it if it means the example doesn't work :)

@YourRentIsDue
Copy link
Author

Yeah, sure, I'll have some spare time tomorrow I'll try to get the examples running

@marko-lazic
Copy link

Lights now have Visibility component. Simply adding "LIGHT" to is_present(obj) in visibility.py fixes the problem.

    @staticmethod
    def is_present(obj):
        return obj.type in [
            "MESH", "LIGHT"
        ]`

@bmarone
Copy link

bmarone commented Nov 8, 2022

@YourRentIsDue, @sdfgeoff I have updated @YourRentIsDue PR in my fork to support bevy 8.1 and rapier 3d 0.18 and have something that still need a little bit more testing and polishing but looks like work good at least with my blender project.

Would you like me to raise a new PR? raise a PR against @YourRentIsDue fork? Please let me know.

Moving fwd I'll certainely help upgrade to bevy 0.9 as soon as I have moved my games to it.

@sdfgeoff
Copy link
Owner

sdfgeoff commented Nov 8, 2022

@bmarone Yeah, feel free to open a new PR against this repo. I'll have a look.

A project has recently come my way that I'm interested in using Bevy for, so I'm also keen to get a 0.9 version of this plugin working.

@bmarone
Copy link

bmarone commented Nov 8, 2022

super! I have noticed a few things that are still exported incorectly from Blender that I'd like to fix, in particularly empties are not working well with the exporter and for a reason I have not looked at yet optional values are not deserialized properly on the rust side. Also I'd would to add some deserialization tests on the rust side and do the same on the python side with the caveat I don't know much about python but that might be my oportunity to learn more about it. @sdfgeoff is there a solid source of knowledge (doc, blog, book..) about developping blender addon I can refer to?

@bmarone
Copy link

bmarone commented Nov 8, 2022

btw thanks for starting this project, at the moment blender_bevy_toolkit is the closest we have to a 3D level editor for Bevy and making it work for 0.8 gave me a ton of flexibility in prototyping my new game I would not have had otherwise.

@sdfgeoff
Copy link
Owner

sdfgeoff commented Nov 9, 2022

@bmarone

Also I'd would to add some deserialization tests on the rust side and do the same on the python side with the caveat I don't know much about python but that might be my oportunity to learn more about it

I'm super keen for tests - particularly on the Rust side. I'd probably just throw some end-to-end serialisation tests (this blend file -> this scene files) for the blender side of things, but have no idea how to test the rust side.

is there a solid source of knowledge (doc, blog, book..) about developping blender addon I can refer to?

There's of course the official API, and it's pretty good with clear writing on all methods and quite a few examples, but it's a bit opaque to get into. I don't know of any good sources of practical knowledge. However I've done a few addons now, so I'll try to dump some knowledge.

If you have questions, ask and I'll answer as best as I'm able.

Operations

Operations tend to reside in bpy.ops, and these are analogous to clicking in the user interface: ie you select vertices (which ones are selected are stored in a context object), and then (eg) run a smooth operation. The operations API is a quick way to automate manual things, and hovering over a button will tell you what operation it triggers. Every button you click in the interface is probably an operation. These aren't so good for plugins because you need to set up the context. This can include which UI panel is selected, if you're in edit mode and a dozen other things you don't generally care about. If you're developing a plugin that a user doesn't interact directly with (eg an exporter like this) try looking for equivalent Data API's

Data/object API;s

Data API's tend to exist in ... bpy.data. They manipulate the underlying representation. For example bpy.data.objects contains all the objects, their transforms, what type of object it is etc. etc. You can manipulate these directly. Most exporters work with these data API's.
The data API's include functions to manipulate the data. For example the bpy.types.Mesh object (eg found via bpy.data.meshes array) has a function calc_tangents to calculate the tangent information. Sounds like it could be an operator, but it's also part of the data API's

Properties and storing data

There's something magic about Blender's file format: it's a self-descriptive database. This means that if you register a custom property into an object in bpy.types.Object, then .... it'll be there when the file is re-opened! How magic is that! No need to bother storing the data yourself, just write it into the most relevant thing (scene, object, render-settings, material, whatever) and let blender do the rest. Of course, there is a small caveat - it only supports bpy.props objects. These are effectively the primitives and include Floats, Vecs, Enum's etc. etc. To avoid littering blender's object namespace, I suggest creating a bpy.types.PropertyGroup to store related properties. In this exporter, I create a PropertyGroup for each component, eg:

# Create a group with a bunch of properties
class ColliderDescriptionProperties(bpy.types.PropertyGroup):
    present: bpy.props.BoolProperty(name="Present", default=False)

    friction: bpy.props.FloatProperty(name="friction", default=0.5)
    ....

# Then on addon startup (inside the register function) we tell blender about this property group:
bpy.utils.register_class(ColliderDescriptionProperties)
bpy.types.Object.rapier_collider_description = bpy.props.PointerProperty(
    type=ColliderDescriptionProperties
)

UI's

The cool thing about properties is that they contain everything needed to create a UI for themselves! So there's no need to set up a fancy UI for each thing you want to adjust, all you have to do is tell blender where to display the property.
Blender's UI is immediate mode, so when you create a panel, you have to provide two methods: poll which tells if if the UI is visible or not, and draw which places all the elements into the UI.

Eg for the point light:

class PointLightPanel(bpy.types.Panel):
    # Defines where to draw the panel:
    bl_idname = "OBJECT_PT_point_light_properties"
    bl_label = "BevyPointLight"
    bl_space_type = "PROPERTIES"
    bl_region_type = "WINDOW"
    bl_context = "physics"

    @classmethod
    def poll(cls, context):
        # Should I render the panel?
        return PointLight.is_present(context.object)

    @staticmethod
    def draw(self, context):
        # What is contained in the panel
        row = self.layout.row()
        row.label(text="Provider of omnidirectional illumination")

        row = self.layout.row()
        row.prop(context.object.data, "color")
        row = self.layout.row()
        row.prop(context.object.data, "energy")
        ....

Because the PointLight object is registered with "Color" being a bpy.props.Color and energy being a bpy.props.Float, blender will render them as a color picker and a numeric selector for you - and keep them in sync across the application.

Want to know a secret? Blender's entire UI is done in python. Don't believe me? Go look in the /usr/share/blender/3.3/scripts/startup/bl_ui folder. If you ever wonder how something in blender's UI is done - go look for where it's defined and see how it's done!

Final Notes

Beyond that, it's just normal python. You can use all of python's inbuilt libraries (eg struct, os, shutil), and pretty much do whatever you like.
The code in this exporter is very meta-programming heavy. I apologise. I dynamically generate python classes etc. etc. to reduce the amount of boilerplate.

After implementing the godot-blender exporter and playcanvas-blender exporter, I decided that it's pretty much always a good idea to create custom properties rather than to try overload blender's properties: ie don't try to fit Rapier around Blender's internal idea of physics. Other than the fact it would be a lot of work, I'd say the same for materials: ideally I'd implement Bevy's PBR materials semi-independent from blender's material system.

Blender's API's are actually even more powerful than I've described here. You can implement rendering engines that draw into the main UI! But while that would be super cool, it's probably also overkill at the moment.


Hopefully that will help give a leg-up. If you have any questions, fire away.

@sdfgeoff
Copy link
Owner

sdfgeoff commented Nov 9, 2022

@bmarone I don't see your 0.8 branch in your fork of this repo. I'd love to take a look and see about getting this repo up to current bevy master. Could you push it up for me?

@OriginLive
Copy link

any news on this? 0.9 is out :(

@sdfgeoff
Copy link
Owner

Recently I investigated using GLTF as the interchange format. You can read about it here:
#52
This looks like a promising approach that removes a lot of complexity from this project and would reduce the required development effort.

However, to make a generic solution (where you can add your own components) would require me to understand how to write a serde deserializer. Know any good documentation on this? The official docs were a bit more complex than I could get my head around.

@YourRentIsDue
Copy link
Author

YourRentIsDue commented Nov 26, 2022 via email

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants