1
$\begingroup$

I'm scripting my own mesh class but don't manage to access to it.

import bpy
from math import sqrt
from mathutils import Vector
import bmesh

class Triangle(bpy.types.Mesh):
    bl_idname = "Triangle"

    def __init__(self, origin, depth=1):
        Mesh.__init__(name="Triangle.001")
        self.origin = origin
        self.depth = depth

        bm = bmesh.new()

        bm.verts.ensure_lookup_table()
        v1 = Vector((- sqrt(3)/2, -.5, 0))
        v2 = Vector((0, 1, 0))
        v3 = Vector((sqrt(3)/2, -.5, 0))

        bmv1 = bm.verts.new(v1)
        bmv2 = bm.verts.new(v2)
        bmv3 = bm.verts.new(v3)

        bm.edges.new([bmv1, bmv2])
        bm.edges.new([bmv2, bmv3])
        bm.edges.new([bmv3, bmv1])
        bm.faces.new([bmv1, bmv2, bmv3])

        bm.to_mesh(self)
        bm.free()

When I try to instanciate it, it is unknown:

>>> steeve = Triangle()

Traceback (most recent call last): File "<blender_console>", line 1, in NameError: name 'Triangle' is not defined

Blender says, I'm not meant to register this class:

ValueError: register_class(...): expected a subclass of a registerable RNA type (Mesh does not support registration)

How can I access this class into console?

EDIT

My script is imported like this:

import bpy
import os

filename = os.path.join("C:\\yMAK\\triangle", "triangle.py")
exec(compile(open(filename).read(), filename, 'exec'))
$\endgroup$
3
  • 1
    $\begingroup$ If that is in a text block named "Text" then in console foo = D.texts["Text"].as_module() to emulate importing script as module named foo. Can then steeve = foo.Triangle() ... however will find what you are attempting will fail as blender doesn't create objects by instancing python classes.. $\endgroup$
    – batFINGER
    Commented Dec 16, 2020 at 15:34
  • $\begingroup$ @batFINGER is there a way to import a module based on the filename? $\endgroup$
    – sinsedrix
    Commented Dec 16, 2020 at 18:10
  • $\begingroup$ Import as you would any python module. Comment above was regarding using a class defined in text editor in the python console. To create a mesh in blender use bpy.data.meshes.new("Foo") ... not like attempted in question code. It does not work that way. $\endgroup$
    – batFINGER
    Commented Dec 17, 2020 at 19:13

2 Answers 2

2
$\begingroup$

Alternatively

If we wish to make a special mesh class based on bpy.types.Mesh

import bpy


class Triangle(bpy.types.Mesh):
    def __init__(self, verts):
        self.is_triangle = True
        pass
    def __new__(cls, verts):
        me = bpy.data.meshes.new("Tri")
        # why bother with bmesh for a tri?
        me.from_pydata(verts, [], ((0, 1, 2),))
        return bpy.types.Mesh.__new__(Triangle, me)

# test
from math import sqrt
root = sqrt(3) / 2
context = bpy.context    
tri = Triangle(
   (
        (-root, -.5, 0),
        (0, 1, 0),
        (root, -.5, 0),
    )
)       


print(tri)
print(tri.is_triangle)
print(tri.vertices)
ob = bpy.data.objects.new("Tri", tri)
context.collection.objects.link(ob)

output

<bpy_struct, Mesh("Tri.012") at 0x7fd4057b6c08>
True
<bpy_collection[0], MeshVertices>

as well as triangle object linked to context collection.

$\endgroup$
1
  • $\begingroup$ thanks, my real object is a bit more complex than a simple triangle so I'm more a ease with bmesh. would you tell me in my answer, if all lines are needed (ensure_lookup_table, mesh.validate)? is there a great difference between object_utils.object_data_add and objects.link? $\endgroup$
    – sinsedrix
    Commented Dec 18, 2020 at 18:10
1
$\begingroup$

According to @batFINGER advices and many readings, I refactored my code.

First the import part with an append to path needed to load local modules:

import os import sys import bpy

filepath = bpy.data.filepath
directory = os.path.dirname(filepath)
print(directory)

# needed to load local modules
if not directory in sys.path:
    sys.path.append(directory)

script_path = os.path.join(directory, "triangle.py")
exec(compile(open(script_path).read(), script_path, 'exec'))

Then as it's not possible to instanciate a mesh explicitly, i made it an attribute of my Triangle class:

import bpy
from math import sqrt
from mathutils import Vector
import bmesh

class Triangle():
    bl_idname = "Triangle"

    def __init__(self, origin, depth=1):
        self.mesh = bpy.data.meshes.new(name="Triangle.001")
        self.origin = origin
        self.depth = depth

        bm = bmesh.new()

        # needed ?
        bm.verts.ensure_lookup_table()

        v1 = Vector((- sqrt(3)/2, -.5, 0))
        v2 = Vector((0, 1, 0))
        v3 = Vector((sqrt(3)/2, -.5, 0))

        bmv1 = bm.verts.new(v1)
        bmv2 = bm.verts.new(v2)
        bmv3 = bm.verts.new(v3)

        bm.edges.new([bmv1, bmv2])
        bm.edges.new([bmv2, bmv3])
        bm.edges.new([bmv3, bmv1])
        bm.faces.new([bmv1, bmv2, bmv3])

        bm.to_mesh(self.mesh)
        bm.free()

Finaly, I can add the expected mesh to the scene:

steeve = Triangle()

object_utils.object_data_add(context, steeve.mesh, operator=self)
# needed ?
steeve.mesh.validate(verbose=True)

I'm not sure it's the best way to develop Blender scripts, but it works.

$\endgroup$

You must log in to answer this question.

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