Instances with non-shared values - saved in a scene property

Hello all!
I am facing an issues with an add-on I am currently developing.

I want to be able to create several complex objects with a lot of custom properties. For simplicity, my example will be with cube objects and just a few properties. Then I will like to store each cube I create in a scene property called all_cubes.

class Cube(bpy.types.PropertyGroup):
    id = bpy.props.IntProperty()
    x = bpy.props.FloatProperty(name="X")
    y = bpy.props.FloatProperty(name="Y")
    z = bpy.props.FloatProperty(name="Z")

class AllCubes(bpy.types.PropertyGroup):
    cubes: bpy.props.CollectionProperty(type=Cube)

def register():    
    bpy.utils.register_class(Cube)
    bpy.utils.register_class(AllCubes)

    bpy.types.Scene.all_cubes = bpy.props.PointerProperty(type=AllCubes)

1- How do I create instances of Cube, that have different values of x, y, z and not share the values among them.
2- How do I add those instances to all_cubes?

1 Like

I have the same problem! Please someone answer!!!

1 Like

Hello,
for the instancing of the objects you might want to check here:

It avoids copying the mesh data block so that memory footprint should be small. Changing of the location of the object still will be possible as shown in the example.

For working with bpy.props.CollectionProperty you might want to check the code that can be found here:

Maybe you find useful hints there.

1 Like

Hello slartibart!

Thank you so much for the response on this! It was indeed useful!
However, it was not exactly what I was looking for, but let me elaborate a bit.

So, I want to create instances of complex objects that would remain across blender.
Im sharing a small example for simplification.

Here is what I would do in python:

    def _init_(self, bed, sofa):
        self.bed= bed
        self.sofa = sofa
        //...and so on


class House():
    def _init_(self, id, furnitures):
        self.id = id
        self.furnitures= furnitures

class AllHouses():
    def _init_(self):
        self.houses = []

    def add_house(house):
        houses.append(house)

def add_new_house(all_houses, bed, sofa):
    furnitures = Furnitures(bed, sofa)
    house = House(1, furnitures)
    all_houses.add_house(house)

all_houses = AllHouses()
add_new_house(all_houses, <bed_object>, <sofa_object>)

So, translating this to Blender API, Ive got this (please review to check if it is ok):
class Furnitures(bpy.types.PropertyGroup):
    bed: bpy.props.PointerProperty(type=bpy.types.Object)
    sofa: bpy.props.PointerProperty(type=bpy.types.Object)

class House(bpy.types.PropertyGroup):
    id: bpy.props.IntProperty()
    furnitures: bpy.props.PointerProperty(type=Furnitures)

class AllHouses(bpy.types.PropertyGroup):
    houses: bpy.props.CollectionProperty(type=House)

def register():   
    bpy.utils.register_class(Furnitures) 
    bpy.utils.register_class(House)
    bpy.utils.register_class(AllHouses)

    bpy.types.Scene.all_houses = bpy.props.PointerProperty(type=AllHouses)

I want to create a function def add_new_house() that would be called inside an operator that would find in the scene the furnitures and the structure of the house and then add it to the scene variable all_houses.
I know I can not do something like house = House(), and then all_houses.append(house) it raises error. How can I do this in Blender?

And it has me confused that as the variables in the Blender classes are not declared inside an init function, how is it possible that instances of the class could then have different objects as bed, sofa, etc…

Hey Dan80,
not sure if I’ll cover everything from your post in my answer. But I think you are almost there with your code. Just check the “main” section in the code below for getting a feeling how to fill your data structure. The bed and sofa objects I created just for demonstration. Of course, in your case, you might have to iterate over all the objects in your scene to create the different houses and fill them with objects.

I hope that helps a bit.

import bpy

class Furnitures(bpy.types.PropertyGroup):
    bed: bpy.props.PointerProperty(name='bed', type=bpy.types.Object)
    sofa: bpy.props.PointerProperty(name='sofa', type=bpy.types.Object)

class House(bpy.types.PropertyGroup):
    id: bpy.props.IntProperty()
    furnitures: bpy.props.PointerProperty(type=Furnitures)

class AllHouses(bpy.types.PropertyGroup):
    houses: bpy.props.CollectionProperty(type=House)

def register():   
    bpy.utils.register_class(Furnitures) 
    bpy.utils.register_class(House)
    bpy.utils.register_class(AllHouses)

    bpy.types.Scene.all_houses = bpy.props.PointerProperty(type=AllHouses)

def unregister():
    del bpy.types.Scene.all_houses
    bpy.utils.unregister_class(Furnitures)
    bpy.utils.unregister_class(House)
    bpy.utils.unregister_class(AllHouses)

if __name__ == "__main__":
    register()
    
    bpy.ops.mesh.primitive_cube_add(location=(1, 1, 1))
    bed = bpy.context.object
    bed.name = 'bed_with_name'
    bpy.ops.mesh.primitive_cube_add(location=(-1, -1, -1))
    sofa = bpy.context.object
    sofa.name = 'sofa_with_name'
    
    new_house = bpy.context.scene.all_houses.houses.add()
    new_house.id = 100
    new_house.furnitures.bed = bed
    new_house.furnitures.sofa = sofa
    print(new_house)
    print(new_house.furnitures)
    print(new_house.furnitures.bed)
    print(new_house.furnitures.bed.name)

2 Likes

You can error-proof the script a little bit by letting Houses handle the ids

class House(bpy.types.PropertyGroup):
    id: bpy.props.IntProperty()
    furnitures: bpy.props.PointerProperty(type=Furnitures)

class AllHouses(bpy.types.PropertyGroup):
    max_id: bpy.props.IntProperty()
    houses: bpy.props.CollectionProperty(type=House)

    create_house(self, name):
        new_house = self.houses.add()
        new_house.name = name
        new_house.id = self.max_id
        self.max_id += 1
        return new_house

then when you create a house :

house_a = bpy.context.scene.all_houses.create_house(name="House A")
house_b = bpy.context.scene.all_houses.create_house(name="House B")
print(house_a.id)
print(house_b.id)
1 Like