Примеры на Python с использованием Blender Python API

Изучаем Python в среде Blender. По данной ссылке вы найдёте общие Обучающие материалы по Python

Документация и туториалы: https://docs.blender.org/api/current/index.html

Найденные мною видео, которые показывают, как начать программировать в редакторе кода VSCode для Blender. Данное расширение для VSCode позволяет ставить точки останова и отлаживать код в пошаговом режиме.

Содержание:

Найденные мною видео, которые показывают, как начать программировать в редакторе кода VSCode для Blender. Данное расширение для VSCode позволяет ставить точки останова и отлаживать код в пошаговом режиме:

Создаётся кнопка выставляется 3D курсор в центр системы координат:

Показывается, как ставить точки останова, выполнять по шагам и как создавать в VSCode точки останова с условиями:

Чтение файла по нажатию на кнопку

Пример выводит N-панель с кнопкой. При нажатии на кнопку ввыводится содержимое текстового файла в консоль.

text.txt

Hello from a text file.

__init__.py

# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTIBILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.

bl_info = {
    "name" : "text_file",
    "author" : "Ivan Enzhaev (8Observer8)",
    "description" : "",
    "blender" : (2, 81, 0),
    "version" : (0, 0, 1),
    "location" : "View3D",
    "warning" : "",
    "category" : "Generic"
}

import bpy

from . my_op import MyOperator
from . my_panel import MyPanel

classes = (MyOperator, MyPanel)

register, unregister = bpy.utils.register_classes_factory(classes)

my_op.py

import bpy


class MyOperator(bpy.types.Operator):
    bl_idname = "view3d.print_file"
    bl_label = "My Operator"
    bl_description = "Print a file content"

    def execute(self, context):
        f = open("text.txt")
        print(f.read())
        f.close()
        return {'FINISHED'}

my_panel.py

import bpy


class MyPanel(bpy.types.Panel):
    bl_idname = "MyPanel"
    bl_label = "My Panel"
    bl_category = "My Addon"
    bl_space_type = "VIEW_3D"
    bl_region_type = "UI"

    def draw(self, context):
        layout = self.layout

        row = layout.row()
        row.operator('view3d.print_file', text="Print File")

Вариант чтения с помощью "with"

Другой вариант чтения с использованием “with”. Не требует вызов метода close()

Нужно вместо этого кода в примере с чтением по нажанию кнопки:

        # f = open("text.txt")
        # print(f.read())
        # f.close()

Написать этот код:

        with open("text.txt") as fobj:
            print(fobj.read())

Python закроет файл, даже если в блоке кода случится исключение.

Обработка исключения, когда файл не существует

За основу взят пример с чтением по нажатию на кнопку.

Чтобы перехватить исключение, что файл не существует, можно поместить код, выбрасыващий исключение, в блок try:

        try:
            with open("text1.txt") as fobj:
                print(fobj.read())
        except FileNotFoundError:
            print("Failed to open the text1.txt file")

Запись в файл по нажатию на кнопку

За основу взят пример с чтением по нажатию на кнопку.

Пример записывает названия 5 океанов в файл по нажанию на кнопку

        oceans = ["Pacific", "Atlantic", "Indian", "Southern", "Artic"]

        with open("oceans.txt", "w") as f:
            for ocean in oceans:
                f.write(ocean + "\n")

Запись в файл по нажатию на кнопку с аргументом file

За основу взят пример с чтением по нажатию на кнопку.

        oceans = ["Pacific", "Atlantic", "Indian", "Southern", "Artic"]

        with open("oceans.txt", "w") as f:
            for ocean in oceans:
                print(ocean, file=f)

Запись в файл по нажатию на кнопку в режиме добавления

За основу взят пример с чтением по нажатию на кнопку.

Содержимое файла не перезаписывается. Просто добавляем в файл.

        oceans = ["Pacific", "Atlantic", "Indian", "Southern", "Artic"]

        with open("oceans.txt", "w") as f:
            for ocean in oceans:
                print(ocean, file=f)

        with open("oceans.txt", "a") as f:
            print(23*"=", file=f)
            print("These are the 5 oceans.", file=f)

Результат:

Pacific
Atlantic
Indian
Southern
Artic
=======================
These are the 5 oceans.

Создание логотипа Mitsubishi с помощью Blender Python API. Устанавливается плагин, как обычно из архива: mitsubishi_logo_blender_python.zip (6.0 КБ) На N-панели должна появится вкладка с кнопкой “Create Logo”

За основу взят пример из туториала:

Я экспортировал в Collada (.dae) формат. Импортировал в C# OpenGL 3 с помощью XPath. Окно создаётся из консольного проекта с помощью библиотеки OpenTK, которая ставится через NuGet. Порт уроков из learnopengl.com на OpenTK на официальном сайте: https://opentk.net/learn/index.html

Путь загрузки модели: “Assets/Models/Logo.dae”. Модель логотипа в формате Collada (.dae): Logo.zip (979 Байт)

MitsubishiLogoFromDae_OpenTkOpenGL30CSharp

Program.cs

using System;
using OpenTK.Graphics.OpenGL;
using OpenTK.Graphics;
using OpenTK;
using System.Xml;
 
namespace MitsubishiLogoFromDae
{
    class Program
    {
        static void Main(string[] args)
        {
            using (var window = new Window())
            {
                window.Title = "Mitsubishi";
                window.Run();
            }
        }
    }
 
    class Window : GameWindow
    {
        private Matrix4 _projMatrix;
        private Matrix4 _modelMatrix;
        private Matrix4 _mpMatrix;
        private int _uMPMatrixLocation;
        private int _amountOfVertices = 0;
 
        public Window() : base(250, 250, new GraphicsMode(32, 0, 0, 8)) { }
 
        protected override void OnLoad(EventArgs e)
        {
            base.OnLoad(e);
            var vShaderSource =
                @"
                    #version 130
 
                    in vec3 aPosition;
                    uniform mat4 uMPMatrix;
 
                    void main()
                    {
                        gl_Position = uMPMatrix * vec4(aPosition, 1.0);
                    }
                ";
            var fShaderSource =
                @"
                    #version 130
                    precision mediump float;
 
                    out vec4 fragColor;
 
                    void main()
                    {
                        fragColor = vec4(0.0);
                    }
                ";
            var vShader = GL.CreateShader(ShaderType.VertexShader);
            GL.ShaderSource(vShader, vShaderSource);
            GL.CompileShader(vShader);
            var fShader = GL.CreateShader(ShaderType.FragmentShader);
            GL.ShaderSource(fShader, fShaderSource);
            GL.CompileShader(fShader);
            var program = GL.CreateProgram();
            GL.AttachShader(program, vShader);
            GL.AttachShader(program, fShader);
            GL.LinkProgram(program);
            GL.UseProgram(program);
 
            int vbo;
            GL.CreateBuffers(1, out vbo);
 
            float[] positions;
            LoadData("Assets/Models/Logo.dae", out positions);
            _amountOfVertices = positions.Length / 3;
 
            GL.BindBuffer(BufferTarget.ArrayBuffer, vbo);
            GL.BufferData(BufferTarget.ArrayBuffer, sizeof(float) * positions.Length, positions, BufferUsageHint.StaticDraw);
            var aPositionLocation = GL.GetAttribLocation(program, "aPosition");
            GL.VertexAttribPointer(aPositionLocation, 3, VertexAttribPointerType.Float, false, 0, 0);
            GL.EnableVertexAttribArray(aPositionLocation);
 
            _uMPMatrixLocation = GL.GetUniformLocation(program, "uMPMatrix");
 
            GL.ClearColor(1f, 1f, 1f, 1f);
        }
 
        protected override void OnRenderFrame(FrameEventArgs e)
        {
            base.OnRenderFrame(e);
            GL.Clear(ClearBufferMask.ColorBufferBit);
 
            _modelMatrix =
                Matrix4.CreateScale(5f, 5f, 1f) *
                Matrix4.CreateTranslation(0f, 0f, -1f);
            _mpMatrix = _modelMatrix * _projMatrix;
            GL.UniformMatrix4(_uMPMatrixLocation, false, ref _mpMatrix);
            GL.DrawArrays(PrimitiveType.Triangles, 0, _amountOfVertices);
 
            SwapBuffers();
        }
 
        protected override void OnResize(EventArgs e)
        {
            base.OnResize(e);
            GL.Viewport(0, 0, Width, Height);
 
            float aspect = (float)Width / Height;
            float worldWidth = aspect * 20f;
            _projMatrix = Matrix4.CreateOrthographic(worldWidth, 20f, 100f, -100f);
        }
 
        private void LoadData(string path, out float[] vertices)
        {
            XmlDocument xml = new XmlDocument();
            xml.Load(path);
 
            XmlNamespaceManager xnm = new XmlNamespaceManager(xml.NameTable);
            xnm.AddNamespace("a", "http://www.collada.org/2005/11/COLLADASchema");
 
            XmlElement root = xml.DocumentElement;
            XmlNode pNode = root.SelectSingleNode("//a:p", xnm);
            int[] p = Array.ConvertAll(pNode.InnerText.Split(new char[] { ' ' }), int.Parse);
 
            XmlNode posNode = root.SelectSingleNode("//a:float_array[substring(@id, string-length(@id) - string-length('mesh-positions-array') + 1) = 'mesh-positions-array']", xnm);
            float[] positions = Array.ConvertAll(posNode.InnerText.Split(new char[] { ' ' }), float.Parse);
 
            vertices = new float[3 * p.Length / 2];
            int triangleIndex = 0;
            for (int i = 0; i < p.Length; i++)
            {
                if (i % 2 == 0)
                {
                    vertices[triangleIndex++] = positions[p[i] * 3];
                    vertices[triangleIndex++] = positions[p[i] * 3 + 1];
                    vertices[triangleIndex++] = positions[p[i] * 3 + 2];
                }
            }
        }
    }
}