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
    Dec 16 '20 at 15:34
  • $\begingroup$ @batFINGER is there a way to import a module based on the filename? $\endgroup$
    – sinsedrix
    Dec 16 '20 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
    Dec 17 '20 at 19:13
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
    Dec 18 '20 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$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.