mirror of
https://github.com/blender/blender-addons.git
synced 2025-07-25 16:05:20 +00:00

Move copyright text to SPDX-FileCopyrightText or set to the Blender Foundation so "make check_licenses" now runs without warnings.
545 lines
21 KiB
Python
Executable File
545 lines
21 KiB
Python
Executable File
# SPDX-FileCopyrightText: 2010-2022 Blender Foundation
|
|
#
|
|
# SPDX-License-Identifier: GPL-2.0-or-later
|
|
|
|
"""Import, export and render to POV engines.
|
|
|
|
These engines can be POV-Ray, Uberpov, HgPovray but others too, since POV is a
|
|
Scene Description Language. The script has been split in as few files as possible and
|
|
metaphorically structured as a train with some boilerplate rendering locomotive,
|
|
followed by its cars each representing a thematic in the 3D field:
|
|
|
|
########################################### RENDERING ###########################################
|
|
|
|
__init__.py :
|
|
Provide script's metadata, Initialize addon preferences, (re)load package modules
|
|
|
|
ui_core.py :
|
|
Set up workspaces and load other ui files for the user to set up all variables
|
|
|
|
render_core.py :
|
|
Define the POV render engines declinations from generic Blender RenderEngine class
|
|
|
|
render_properties.py :
|
|
Initialize properties for render parameters (Blender generic and POV native)
|
|
|
|
render_gui.py :
|
|
Display properties from render_properties.py for user to change them
|
|
|
|
render.py :
|
|
Translate render properties (Blender and POV native) to POV, ini file and CLI
|
|
|
|
__------------------Z__
|
|
_--¨¨] | __ __ _____________||
|
|
_-¨7____/ | | °|° | □□□ □□□ □□□ ||
|
|
(===========|=| | |=============||
|
|
`-,_(@)(@)----------------(@)(@)-'
|
|
############################################# LAYOUT ##############################################
|
|
|
|
scenography_properties.py
|
|
Initialize properties for passing layout (camera/light/environment) parameters to pov
|
|
|
|
scenography_gui.py :
|
|
Display camera/light/environment properties from scenography_properties.py for user to change
|
|
|
|
scenography.py
|
|
Translate camera/light/environment properties to corresponding pov features
|
|
|
|
__------------------Z__ ____________________
|
|
_--¨¨] | __ __ _____________|||____________________|
|
|
_-¨7____/ | | °|° | □□□ □□□ □□□ ||| □□□ □□□ □□□ □□□ □□ |
|
|
(===========|=| | |=============|||====================|
|
|
`-,_(@)(@)----------------(@)(@)-'^-(@)(@)--------(@)(@)'
|
|
############################################### MODEL #############################################
|
|
|
|
model_properties.py :
|
|
Initialize properties for translating Blender geometry objects parameters to pov
|
|
|
|
model_gui.py :
|
|
Display properties from model_properties.py for the user to change them
|
|
|
|
model_all.py :
|
|
Translate to POV the object level data
|
|
|
|
model_poly_topology.py :
|
|
Translate to POV the mesh based geometries
|
|
|
|
model_curve_topology.py :
|
|
Translate to POV the curve based geometries
|
|
|
|
model_meta_topology.py :
|
|
Translate to POV the metaball based geometries
|
|
|
|
model_primitives.py :
|
|
Display some simple POV native primitives in 3D view for input and output
|
|
|
|
model_primitives_topology.py :
|
|
Display some POV native complex or compound primitives in 3D view for input and output
|
|
|
|
__------------------Z__ ____________________ ____________________
|
|
_--¨¨] | __ __ _____________|||____________________|||____________________
|
|
_-¨7____/ | | °|° | □□□ □□□ □□□ ||| □□□ □□□ □□□ □□□ □□ ||| □□□ □□□ □□□ □□□ □□
|
|
(===========|=| | |=============|||====================|||====================
|
|
`-,_(@)(@)----------------(@)(@)-'^-(@)(@)--------(@)(@)-^-(@)(@)--------(@)(@)
|
|
############################################ SHADING #############################################
|
|
|
|
shading_properties.py :
|
|
Initialize properties for translating Blender materials parameters to pov
|
|
|
|
shading_ray_properties.py :
|
|
Initialize properties for translating Blender ray paths relevant material parameters to pov
|
|
|
|
shading_gui.py :
|
|
Display variables from shading_properties.py and shading_ray_properties.py for user to change
|
|
|
|
shading.py
|
|
Translate shading properties to declared textures at the top of a pov file
|
|
|
|
texturing_properties.py :
|
|
Initialize properties for translating Blender materials/world... texture influences to pov
|
|
|
|
texturing_gui.py :
|
|
Display properties from texturing_properties.py available for user to change
|
|
|
|
texturing.py :
|
|
Translate blender pixel based bitmap texture influences into POV
|
|
|
|
texturing_procedural.py :
|
|
Translate blender algorithmic procedural texture influences into POV
|
|
|
|
__------------------Z__ ____________________ ____________________ ________________
|
|
_--¨¨] | __ __ _____________|||____________________|||____________________|||________________
|
|
_-¨7____/ | | °|° | □□□ □□□ □□□ ||| □□□ □□□ □□□ □□□ □□ ||| □□□ □□□ □□□ □□□ □□ ||| □□□ □□□ □□□ □□□
|
|
(===========|=| | |=============|||====================|||====================|||================
|
|
`-,_(@)(@)----------------(@)(@)-'^-(@)(@)--------(@)(@)-^-(@)(@)--------(@)(@)-^-(@)(@)----------
|
|
############################################ VFX/TECH #############################################
|
|
|
|
particles_properties.py :
|
|
Initialize all strands, fx, or particles based objects properties to be translated to POV
|
|
|
|
particles.py :
|
|
Translate to POV the particle based geometries
|
|
|
|
voxel_lib.py :
|
|
Render smoke to *.df3 files using an updated version of Mike Kost's df3.py legacy library
|
|
|
|
nodes_properties.py :
|
|
Define all node items and their respective variables or sockets available to POV node trees
|
|
|
|
nodes.py :
|
|
Translate node trees to the pov file
|
|
|
|
nodes_fn.py :
|
|
Functions toolbox used by nodes.py to translate node trees to the pov file
|
|
|
|
nodes_gui.py :
|
|
Operators and menus to interact with POV specific node trees
|
|
|
|
scripting_properties.py :
|
|
Initialize properties for hand written scene description language fragments (POV native)
|
|
|
|
scripting_gui.py :
|
|
Display properties from scripting_properties.py for user to add his custom POV code
|
|
|
|
scripting.py :
|
|
Insert POV native scene description elements into blender scene or to exported POV file
|
|
|
|
update_files.py :
|
|
Update new variables to values from older API. This file needs an update
|
|
|
|
######################################## PRESETS/TEMPLATES ########################################
|
|
|
|
Along these essential files also coexist a few additional libraries to help make
|
|
Blender stand up to other POV enabled IDEs (povwin, POV for Mac, QTPOV, VSCode, Vim...)
|
|
presets :
|
|
Material (sss)
|
|
apple.py ; chicken.py ; cream.py ; Ketchup.py ; marble.py ;
|
|
potato.py ; skim_milk.py ; skin1.py ; skin2.py ; whole_milk.py
|
|
Radiosity
|
|
01_Debug.py ; 02_Fast.py ; 03_Normal.py ; 04_Two_Bounces.py ;
|
|
05_Final.py ; 06_Outdoor_Low_Quality.py ; 07_Outdoor_High_Quality.py ;
|
|
08_Outdoor(Sun)Light.py ; 09_Indoor_Low_Quality.py ;
|
|
10_Indoor_High_Quality.py ;
|
|
World
|
|
01_Clear_Blue_Sky.py ; 02_Partly_Hazy_Sky.py ; 03_Overcast_Sky.py ;
|
|
04_Cartoony_Sky.py ; 05_Under_Water.py ;
|
|
Light
|
|
01_(4800K)_Direct_Sun.py ;
|
|
02_(5400K)_High_Noon_Sun.py ;
|
|
03_(6000K)_Daylight_Window.py ;
|
|
04_(6000K)_2500W_HMI_(Halogen_Metal_Iodide).py ;
|
|
05_(4000K)_100W_Metal_Halide.py ;
|
|
06_(3200K)_100W_Quartz_Halogen.py ;
|
|
07_(2850K)_100w_Tungsten.py ;
|
|
08_(2600K)_40w_Tungsten.py ;
|
|
09_(5000K)_75W_Full_Spectrum_Fluorescent_T12.py ;
|
|
10_(4300K)_40W_Vintage_Fluorescent_T12.py ;
|
|
11_(5000K)_18W_Standard_Fluorescent_T8 ;
|
|
12_(4200K)_18W_Cool_White_Fluorescent_T8.py ;
|
|
13_(3000K)_18W_Warm_Fluorescent_T8.py ;
|
|
14_(6500K)_54W_Grow_Light_Fluorescent_T5-HO.py ;
|
|
15_(3200K)_40W_Induction_Fluorescent.py ;
|
|
16_(2100K)_150W_High_Pressure_Sodium.py ;
|
|
17_(1700K)_135W_Low_Pressure_Sodium.py ;
|
|
18_(6800K)_175W_Mercury_Vapor.py ;
|
|
19_(5200K)_700W_Carbon_Arc.py ;
|
|
20_(6500K)_15W_LED_Spot.py ;
|
|
21_(2700K)_7W_OLED_Panel.py ;
|
|
22_(30000K)_40W_Black_Light_Fluorescent.py ;
|
|
23_(30000K)_40W_Black_Light_Bulb.py;
|
|
24_(1850K)_Candle.py
|
|
templates:
|
|
abyss.pov ; biscuit.pov ; bsp_Tango.pov ; chess2.pov ;
|
|
cornell.pov ; diffract.pov ; diffuse_back.pov ; float5 ;
|
|
gamma_showcase.pov ; grenadine.pov ; isocacti.pov ;
|
|
mediasky.pov ; patio-radio.pov ; subsurface.pov ; wallstucco.pov
|
|
"""
|
|
|
|
|
|
bl_info = {
|
|
'name': "POV@Ble",
|
|
'author': "Campbell Barton, "
|
|
"Maurice Raybaud, "
|
|
"Leonid Desyatkov, "
|
|
"Bastien Montagne, "
|
|
"Constantin Rahn, "
|
|
"Silvio Falcinelli,"
|
|
"Paco García",
|
|
'version': (0, 1, 3),
|
|
'blender': (3, 2, 0),
|
|
'location': "Render Properties > Render Engine > Persistence of Vision",
|
|
'description': "Persistence of Vision addon for Blender",
|
|
'doc_url': "{BLENDER_MANUAL_URL}/addons/render/povray.html",
|
|
'category': "Render",
|
|
'warning': "Co-maintainers welcome",
|
|
}
|
|
|
|
# Other occasional contributors, more or less in chronological order:
|
|
# Luca Bonavita ; Shane Ambler ; Brendon Murphy ; Doug Hammond ;
|
|
# Thomas Dinges ; Jonathan Smith ; Sebastian Nell ; Philipp Oeser ;
|
|
# Sybren A. Stüvel ; Dalai Felinto ; Sergey Sharybin ; Brecht Van Lommel ;
|
|
# Stephen Leger ; Rune Morling ; Aaron Carlisle ; Ankit Meel ;
|
|
|
|
if "bpy" in locals():
|
|
import importlib
|
|
|
|
importlib.reload(ui_core)
|
|
importlib.reload(nodes_properties)
|
|
importlib.reload(nodes_gui)
|
|
importlib.reload(nodes_fn)
|
|
importlib.reload(nodes)
|
|
importlib.reload(scenography_properties)
|
|
importlib.reload(scenography_gui)
|
|
importlib.reload(scenography)
|
|
importlib.reload(render_properties)
|
|
importlib.reload(render_gui)
|
|
importlib.reload(render_core)
|
|
importlib.reload(render)
|
|
importlib.reload(shading_properties)
|
|
importlib.reload(shading_ray_properties)
|
|
importlib.reload(shading_gui)
|
|
importlib.reload(shading)
|
|
importlib.reload(texturing_procedural)
|
|
importlib.reload(texturing_properties)
|
|
importlib.reload(texturing_gui)
|
|
importlib.reload(texturing)
|
|
importlib.reload(model_properties)
|
|
importlib.reload(model_gui)
|
|
importlib.reload(model_all)
|
|
importlib.reload(model_poly_topology)
|
|
importlib.reload(model_meta_topology)
|
|
importlib.reload(model_curve_topology)
|
|
importlib.reload(model_primitives)
|
|
importlib.reload(model_primitives_topology)
|
|
importlib.reload(particles_properties)
|
|
importlib.reload(particles)
|
|
importlib.reload(scripting_properties)
|
|
importlib.reload(scripting_gui)
|
|
importlib.reload(scripting)
|
|
importlib.reload(update_files)
|
|
|
|
else:
|
|
import bpy
|
|
from bpy.utils import register_class, unregister_class
|
|
|
|
from bpy.props import StringProperty, BoolProperty, EnumProperty
|
|
|
|
from . import (
|
|
ui_core,
|
|
render_properties,
|
|
scenography_properties,
|
|
nodes_properties,
|
|
nodes_gui,
|
|
nodes,
|
|
shading_properties,
|
|
shading_ray_properties,
|
|
texturing_properties,
|
|
model_properties,
|
|
scripting_properties,
|
|
render,
|
|
render_core,
|
|
model_primitives,
|
|
model_primitives_topology,
|
|
particles_properties,
|
|
particles,
|
|
)
|
|
|
|
# ---------------------------------------------------------------- #
|
|
# Auto update.
|
|
# ---------------------------------------------------------------- #
|
|
|
|
|
|
class POV_OT_update_addon(bpy.types.Operator):
|
|
"""Update this addon to the latest version"""
|
|
|
|
bl_idname = "pov.update_addon"
|
|
bl_label = "Update POV addon"
|
|
|
|
def execute(self, context):
|
|
import os
|
|
import shutil
|
|
import tempfile
|
|
import urllib.error
|
|
import urllib.request
|
|
import zipfile
|
|
|
|
def recursive_overwrite(self, src, dest, ignore=None):
|
|
"""Update the script automatically (along with other addons).
|
|
|
|
Arguments:
|
|
src -- path where to update from
|
|
dest -- storing temporary download here
|
|
Keyword Arguments:
|
|
ignore -- leave some directories alone (default: {None})
|
|
|
|
Returns:
|
|
finished flag for operator which is a set()
|
|
"""
|
|
if os.path.isdir(src):
|
|
if not os.path.isdir(dest):
|
|
os.makedirs(dest)
|
|
files = os.listdir(src)
|
|
ignored = ignore(src, files) if ignore is not None else set()
|
|
unignored_files = (fle for fle in files if fle not in ignored)
|
|
for f in unignored_files:
|
|
source = os.path.join(src, f)
|
|
destination = os.path.join(dest, f)
|
|
recursive_overwrite(source, destination, ignore)
|
|
else:
|
|
shutil.copyfile(src, dest)
|
|
|
|
print("-" * 20)
|
|
print("Updating POV addon...")
|
|
|
|
with tempfile.TemporaryDirectory() as temp_dir_path:
|
|
temp_zip_path = os.path.join(temp_dir_path, "master.zip")
|
|
|
|
# Download zip archive of latest addons master branch commit
|
|
# More work needed so we also get files from the shared addons presets /pov folder
|
|
# switch this URL back to the BF hosted one as soon as gitweb snapshot gets fixed
|
|
url = "https://github.com/blender/blender-addons/archive/refs/heads/master.zip"
|
|
try:
|
|
print("Downloading", url)
|
|
|
|
with urllib.request.urlopen(url, timeout=60) as url_handle, open(
|
|
temp_zip_path, "wb"
|
|
) as file_handle:
|
|
file_handle.write(url_handle.read())
|
|
except urllib.error.URLError as err:
|
|
self.report({"ERROR"}, "Could not download: %s" % err)
|
|
|
|
# Extract the zip
|
|
print("Extracting ZIP archive")
|
|
with zipfile.ZipFile(temp_zip_path) as zip_archive:
|
|
pov_addon_pkg = (member for member in zip_archive.namelist() if
|
|
"blender-addons-master/render_povray" in member)
|
|
for member in pov_addon_pkg:
|
|
# Remove the first directory and the filename
|
|
# e.g. blender-addons-master/render_povray/nodes.py
|
|
# becomes render_povray/nodes.py
|
|
target_path = os.path.join(
|
|
temp_dir_path, os.path.join(*member.split("/")[1:-1])
|
|
)
|
|
|
|
filename = os.path.basename(member)
|
|
# Skip directories
|
|
if not filename:
|
|
continue
|
|
|
|
# Create the target directory if necessary
|
|
if not os.path.exists(target_path):
|
|
os.makedirs(target_path)
|
|
|
|
source = zip_archive.open(member)
|
|
target = open(os.path.join(target_path, filename), "wb")
|
|
|
|
with source, target:
|
|
shutil.copyfileobj(source, target)
|
|
print("copying", source, "to", target)
|
|
|
|
extracted_render_povray_path = os.path.join(temp_dir_path, "render_povray")
|
|
|
|
if not os.path.exists(extracted_render_povray_path):
|
|
self.report({"ERROR"}, "Could not extract ZIP archive! Aborting.")
|
|
return {"FINISHED"}
|
|
|
|
# Find the old POV addon files
|
|
render_povray_dir = os.path.abspath(os.path.dirname(__file__)) # Unnecessary abspath?
|
|
print("POV addon addon folder:", render_povray_dir)
|
|
|
|
# TODO: Create backup
|
|
|
|
# Delete old POV addon files
|
|
# (only directories and *.py files, user might have other stuff in there!)
|
|
print("Deleting old POV addon files")
|
|
# remove __init__.py
|
|
os.remove(os.path.join(render_povray_dir, "__init__.py"))
|
|
# remove all folders
|
|
dir_names = 1
|
|
for directory in next(os.walk(render_povray_dir))[dir_names]:
|
|
shutil.rmtree(os.path.join(render_povray_dir, directory))
|
|
|
|
print("Copying new POV addon files")
|
|
# copy new POV addon files
|
|
# copy __init__.py
|
|
shutil.copy2(
|
|
os.path.join(extracted_render_povray_path, "__init__.py"),
|
|
render_povray_dir,
|
|
)
|
|
# copy all folders
|
|
recursive_overwrite(extracted_render_povray_path, render_povray_dir)
|
|
|
|
bpy.ops.preferences.addon_refresh()
|
|
print("POV addon update finished, restart Blender for the changes to take effect.")
|
|
print("-" * 20)
|
|
self.report({"WARNING"}, "Restart Blender!")
|
|
return {"FINISHED"}
|
|
|
|
|
|
# ---------------------------------------------------------------- #
|
|
# Povray Preferences.
|
|
# ---------------------------------------------------------------- #
|
|
|
|
|
|
class PovPreferences(bpy.types.AddonPreferences):
|
|
"""Declare preference variables to set up POV binary."""
|
|
|
|
bl_idname = __name__
|
|
|
|
branch_feature_set_povray: EnumProperty(
|
|
name="Feature Set",
|
|
description="Choose between official (POV-Ray) or (UberPOV) "
|
|
"development branch features to write in the pov file",
|
|
items=(
|
|
("povray", "Official POV-Ray", "", "PLUGIN", 0),
|
|
("uberpov", "Unofficial UberPOV", "", "PLUGIN", 1),
|
|
),
|
|
default="povray",
|
|
)
|
|
|
|
filepath_povray: StringProperty(
|
|
name="Binary Location", description="Path to renderer executable", subtype="FILE_PATH"
|
|
)
|
|
|
|
docpath_povray: StringProperty(
|
|
name="Includes Location", description="Path to Insert Menu files", subtype="FILE_PATH",
|
|
default="",
|
|
)
|
|
|
|
use_sounds: BoolProperty(
|
|
name="Use Sound",
|
|
description="Signaling end of the render process at various"
|
|
"stages can help if you're away from monitor",
|
|
default=False,
|
|
)
|
|
|
|
# TODO: Auto find POV sound directory as it does for binary
|
|
# And implement the three cases, left uncommented for a dummy
|
|
# interface in case some doc screenshots get made for that area
|
|
filepath_complete_sound: StringProperty(
|
|
name="Finish Render Sound",
|
|
description="Path to finished render sound file",
|
|
subtype="FILE_PATH",
|
|
)
|
|
|
|
filepath_parse_error_sound: StringProperty(
|
|
name="Parse Error Sound",
|
|
description="Path to parsing time error sound file",
|
|
subtype="FILE_PATH",
|
|
)
|
|
|
|
filepath_cancel_sound: StringProperty(
|
|
name="Cancel Render Sound",
|
|
description="Path to cancelled or render time error sound file",
|
|
subtype='FILE_PATH',
|
|
)
|
|
|
|
def draw(self, context):
|
|
layout = self.layout
|
|
layout.prop(self, 'branch_feature_set_povray')
|
|
layout.prop(self, 'filepath_povray')
|
|
layout.prop(self, 'docpath_povray')
|
|
layout.prop(self, 'filepath_complete_sound')
|
|
layout.prop(self, 'filepath_parse_error_sound')
|
|
layout.prop(self, 'filepath_cancel_sound')
|
|
layout.prop(self, 'use_sounds', icon='SOUND')
|
|
layout.operator('pov.update_addon', icon='FILE_REFRESH')
|
|
layout.operator("wm.url_open", text="Community",icon='EVENT_F').url = \
|
|
"https://www.facebook.com/povable"
|
|
|
|
|
|
classes = (
|
|
POV_OT_update_addon,
|
|
PovPreferences,
|
|
)
|
|
|
|
|
|
def register():
|
|
for cls in classes:
|
|
register_class(cls)
|
|
|
|
render_properties.register()
|
|
scenography_properties.register()
|
|
shading_properties.register()
|
|
shading_ray_properties.register()
|
|
texturing_properties.register()
|
|
model_properties.register()
|
|
particles_properties.register()
|
|
scripting_properties.register()
|
|
nodes_properties.register()
|
|
nodes_gui.register()
|
|
render.register()
|
|
render_core.register()
|
|
ui_core.register()
|
|
model_primitives_topology.register()
|
|
model_primitives.register()
|
|
|
|
|
|
def unregister():
|
|
model_primitives.unregister()
|
|
model_primitives_topology.unregister()
|
|
ui_core.unregister()
|
|
render_core.unregister()
|
|
render.unregister()
|
|
nodes_gui.unregister()
|
|
nodes_properties.unregister()
|
|
scripting_properties.unregister()
|
|
particles_properties.unregister()
|
|
model_properties.unregister()
|
|
texturing_properties.unregister()
|
|
shading_ray_properties.unregister()
|
|
shading_properties.unregister()
|
|
scenography_properties.unregister()
|
|
render_properties.unregister()
|
|
|
|
for cls in reversed(classes):
|
|
unregister_class(cls)
|
|
|
|
|
|
if __name__ == '__main__':
|
|
register()
|
|
|
|
# ------------8<---------[ BREAKPOINT ]--------------8<----------- # Move this snippet around
|
|
# __import__('code').interact(local=dict(globals(), **locals())) # < and uncomment this line
|
|
# ---------------------------------------------------------------- # to inspect from Terminal
|