1
$\begingroup$

I want to spawn my own custom primitive objects (in this case a sphere from an underlying cube mesh) and store it as an object in a variable.

I have managed to write a class that creates such objects, but I want to be able to store them inside a variable and then manipulate them using the class's methods. If you're wondering what the end goal is: I want to create a model of the solar system and this class is meant to create planets and stars.

My current code looks like this

import bpy
import time
import numpy

start = time.time()

# Reset scene after each execution
bpy.ops.object.select_all(action='SELECT')
bpy.ops.object.delete(use_global=False, confirm=False)

# Been told this has less wrinkles in the mesh around the poles.
# Hopefully this will make UV unwrapping and texturing easier down the line.

class cube_sphere():
    # r is radius of the sphere
    # R is the distance from the origin (location of the sun)
    def __init__(self,r,R):
        self.r = r
        self.R = R
        # adds the cube and fashions it into a sphere 
        bpy.ops.mesh.primitive_uv_sphere_add(radius=self.r, enter_editmode=False, align='WORLD', location=(0, self.R, 0), scale=(1, 1, 1)) 
        bpy.ops.object.subdivision_set(level=3, relative=False)
        bpy.context.object.modifiers["Subdivision"].levels = 3
        bpy.context.object.modifiers["Subdivision"].render_levels = 3
        bpy.ops.object.modifier_apply(modifier="Subdivision")
        bpy.ops.object.editmode_toggle()
        bpy.ops.transform.tosphere(value=1, mirror=True, use_proportional_edit=False, proportional_edit_falloff='SMOOTH', proportional_size=1, use_proportional_connected=False, use_proportional_projected=False)
        bpy.ops.object.editmode_toggle()
        bpy.ops.object.shade_smooth()


# idk what is being put into variable a, but I'm almost certain it is not an object that inherits from the class that actually defines primitive meshes in blender.
a = cube_sphere(1,0)

end = time.time()
print(end-start)

I've been told that using bpy.ops is very slow since it always comes with a scene update. This is why I time the execution to see how quickly everything is running.

What I'd like to know is how I can store the actual cube object in a variable and then manipulate it by referencing the variable I stored it in. (not actual code)

a = bpy.objects.cube()
a.set_edgelength(2)
a.rotate(0,0,1)

Or in the case of my custom class:

class(bpy.objects.cube):

    def __init__(self,r,R):
        super().__init__() # I think that's how you do it if you specify a parent class in class(parent_class)?
        self.r = r
        self.R = R

    def set_something(self,something):
        self.something = something
        ...

Can this be done and where can I read up on that sort of stuff?

$\endgroup$
1
  • $\begingroup$ search for bmesh to see how this can be done without the bpy.ops. If I get some time later, I'll write up an example. $\endgroup$ Commented Oct 21, 2021 at 19:26

1 Answer 1

1
$\begingroup$
import bpy
from math import pi 


C = bpy.context

bpy.ops.mesh.primitive_cube_add()

#the most recent object added to the scene is the active object. You can assign active object to a variable
cube = C.active_object
#another way to assign object to variable is by its name
cube = C.scene.objects["Cube"]
#another way to assign object to variable is by its index (camera is index 0, light is index 1 of collection)
cube = C.scene.objects[2]



initialFrame = 1
#here I play with some functions that can be performed on the object variable
#set objects values at an initial frame
cube.location = (0, 0, 0)
cube.scale = (1, 1, 1)
cube.rotation_euler = (0, 0, 0)

#keyframe the initial values
cube.keyframe_insert("location", frame= initialFrame)
cube.keyframe_insert("scale", frame = initialFrame)
cube.keyframe_insert("rotation_euler", frame= initialFrame)


finalFrame = 60

#set objects values at an final frame
cube.location = (0, 0, 1)
cube.scale = (2, 2, 2)
cube.rotation_euler = (0, 0, pi/2)

#keyframe the final values
cube.keyframe_insert("location", frame= finalFrame)
cube.keyframe_insert("scale", frame = finalFrame)
cube.keyframe_insert("rotation_euler", frame= finalFrame)

Towards the top of this script I wrote above, I assigned a cube object to a variable in three different ways. I also showed how some of the cubes properties can be changed with the built in functions location, scale, and rotation_euler. I think a.rotation_euler should take care of your desire for something such as "a.rotate(0,0,1)" For "a.set_edgelength" I can't find a built in function that can achieve a specific change in edgelength. I would hope that a.scale does the trick. If not, there are ways to change the objects individual vertices.

$\endgroup$
2
  • $\begingroup$ Thanks. I'm still a bit fuzzy on the way the API actually works but this helped me a lot. I'll probably post my own answer underneath as well that's going to be about how to spawn a meta-object using the bpy.ops commands, hiding it from view, making it referencable by renaming it to something unique and how to then make useable copies of it that can be controlled with the code you wrote. $\endgroup$
    – J.Doe
    Commented Oct 27, 2021 at 12:58
  • $\begingroup$ You're welcome. I'm glad I could help. Seems like a good plan. $\endgroup$ Commented Oct 27, 2021 at 20:02

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .