Formatting and fixes
* Moved: some existing functions into new separate files to improve code readability (detailed in __init__.py docstring) * Remove: max_intersections deprecated in pov 3.8 * Add: Validate utf-8 characters with specific API function at session's first script init * Add : Icons to some text fields and inviting labels * Change default camera normal perturbation value to non zero since its use is first driven by a boolean toggle * Change: lists (vectors and indices) are now exported in one line by default for better manual scene overview and debugging * Change: a couple of tooltips corrections * Change : renamed many variables and functions to snake_case according to recommanded style guides * Fix : Heightfield primitive (forward slashes were expected for displacement texture path) * Fix : Text nippet insertion operator * Fix : added console print tip to check executable path on failure to process * Fix : tweaked finished render say command for Linux * Fix : interface of some shader nodes broken since 2.8 api changes * Fix : export hair particles
This commit is contained in:
parent
051d4f7d59
commit
fad5186bb6
|
@ -9,8 +9,8 @@ lampdata = bpy.context.object.data
|
|||
lampdata.shape = 'SQUARE'
|
||||
lampdata.size = 30000000#0.02
|
||||
#lampdata.size_y = 0.02
|
||||
lampdata.shadow_ray_samples_x = 2
|
||||
#lampdata.shadow_ray_samples_y = 3
|
||||
lampdata.pov.shadow_ray_samples_x = 2
|
||||
#lampdata.pov.shadow_ray_samples_y = 3
|
||||
lampdata.color = (1.0, 1.0, 1.0)
|
||||
lampdata.energy = 1.094316#91193 #lux
|
||||
lampdata.distance =695699968
|
||||
|
|
|
@ -6,8 +6,8 @@ lampdata = bpy.context.object.data
|
|||
|
||||
lampdata.size = 1.2
|
||||
lampdata.size_y = 2.10
|
||||
lampdata.shadow_ray_samples_x = 2
|
||||
lampdata.shadow_ray_samples_y = 3
|
||||
lampdata.pov.shadow_ray_samples_x = 2
|
||||
lampdata.pov.shadow_ray_samples_y = 3
|
||||
lampdata.color = (1.0, 1.0, 1.0)
|
||||
lampdata.energy = 1.094316#91193 #lux
|
||||
lampdata.distance = 1.0
|
||||
|
|
|
@ -6,8 +6,8 @@ lampdata = bpy.context.object.data
|
|||
|
||||
lampdata.size = 0.038
|
||||
lampdata.size_y = 2.40284
|
||||
lampdata.shadow_ray_samples_x = 1
|
||||
lampdata.shadow_ray_samples_y = 2
|
||||
lampdata.pov.shadow_ray_samples_x = 1
|
||||
lampdata.pov.shadow_ray_samples_y = 2
|
||||
lampdata.color = (1.0, 0.95686274766922, 0.9490200281143188)
|
||||
lampdata.energy = 4.45304#4775lm/21.446(=lux)*0.004(distance) *2 for distance is the point of half strength 6200lm?
|
||||
lampdata.distance = 1.0 #dist values multiplied by 10 for area lights for same power as bulb/spot/...
|
||||
|
|
|
@ -6,8 +6,8 @@ lampdata = bpy.context.object.data
|
|||
|
||||
lampdata.size = 0.038
|
||||
lampdata.size_y = 1.2192
|
||||
lampdata.shadow_ray_samples_x = 1
|
||||
lampdata.shadow_ray_samples_y = 2
|
||||
lampdata.pov.shadow_ray_samples_x = 1
|
||||
lampdata.pov.shadow_ray_samples_y = 2
|
||||
lampdata.color = (0.901, 1.0, 0.979)
|
||||
lampdata.energy = 2.14492#2300lm/21.446(=lux)*0.004*2.5(distance) *2 for distance is the point of half strength
|
||||
lampdata.distance = 1.0 #dist values multiplied by 10 for area lights for same power as bulb/spot/...
|
||||
|
|
|
@ -6,8 +6,8 @@ lampdata = bpy.context.object.data
|
|||
|
||||
lampdata.size = 0.026
|
||||
lampdata.size_y = 0.59
|
||||
lampdata.shadow_ray_samples_x = 1
|
||||
lampdata.shadow_ray_samples_y = 2
|
||||
lampdata.pov.shadow_ray_samples_x = 1
|
||||
lampdata.pov.shadow_ray_samples_y = 2
|
||||
lampdata.color = (0.95686274766922, 1.0, 0.9803921580314636)
|
||||
lampdata.energy = 1.25898#1350lm/21.446(=lux)*0.004*2.5(distance) *2 for distance is the point of half strength
|
||||
lampdata.distance = 1.0 #dist values multiplied by 10 for area lights for same power as bulb/spot/...
|
||||
|
|
|
@ -7,8 +7,8 @@ lampdata = bpy.context.object.data
|
|||
|
||||
lampdata.size = 0.026
|
||||
lampdata.size_y = 0.59
|
||||
lampdata.shadow_ray_samples_x = 1
|
||||
lampdata.shadow_ray_samples_y = 2
|
||||
lampdata.pov.shadow_ray_samples_x = 1
|
||||
lampdata.pov.shadow_ray_samples_y = 2
|
||||
lampdata.color = (0.8313725590705872, 0.9215686321258545, 1.0)
|
||||
lampdata.energy = 1.25898#1350lm/21.446(=lux)*0.004*2.5(distance) *2 for distance is the point of half strength
|
||||
lampdata.distance = 1.0 #dist values multiplied by 10 for area lights for same power as bulb/spot/...
|
||||
|
|
|
@ -7,8 +7,8 @@ lampdata = bpy.context.object.data
|
|||
|
||||
lampdata.size = 0.026
|
||||
lampdata.size_y = 0.59
|
||||
lampdata.shadow_ray_samples_x = 1
|
||||
lampdata.shadow_ray_samples_y = 2
|
||||
lampdata.pov.shadow_ray_samples_x = 1
|
||||
lampdata.pov.shadow_ray_samples_y = 2
|
||||
lampdata.color = (1.0, 0.95686274766922, 0.8980392217636108)
|
||||
lampdata.energy = 1.25898#1350lm/21.446(=lux)*0.004*2.5(distance) *2 for distance is the point of half strength
|
||||
lampdata.distance = 1.0 #dist values multiplied by 10 for area lights for same power as bulb/spot/...
|
||||
|
|
|
@ -6,8 +6,8 @@ lampdata = bpy.context.object.data
|
|||
|
||||
lampdata.size = 0.016
|
||||
lampdata.size_y = 1.149
|
||||
lampdata.shadow_ray_samples_x = 1
|
||||
lampdata.shadow_ray_samples_y = 2
|
||||
lampdata.pov.shadow_ray_samples_x = 1
|
||||
lampdata.pov.shadow_ray_samples_y = 2
|
||||
lampdata.color = (1.0, 0.83, 0.986274528503418)
|
||||
lampdata.energy = 4.66287 #0.93257#4.66287#5000lm/21.446(=lux)*0.004*2.5(distance) *2 for distance is the point of half strength
|
||||
lampdata.distance = 0.1 #dist values multiplied by 10 for area lights for same power as bulb/spot/...
|
||||
|
|
|
@ -7,8 +7,8 @@ lampdata = bpy.context.object.data
|
|||
|
||||
lampdata.size = 0.033
|
||||
lampdata.size_y = 0.133
|
||||
lampdata.shadow_ray_samples_x = 2
|
||||
lampdata.shadow_ray_samples_y = 2
|
||||
lampdata.pov.shadow_ray_samples_x = 2
|
||||
lampdata.pov.shadow_ray_samples_y = 2
|
||||
lampdata.color = (1.0, 0.8292156958580017, 0.6966666865348816)
|
||||
lampdata.energy = 0.83932#900lm/21.446(=lux)*0.004*2.5(distance) *2 for distance is the point of half strength
|
||||
lampdata.distance = 1.18 #dist values multiplied by 10 for area lights for same power as bulb/spot/...
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,307 @@
|
|||
# ##### BEGIN GPL LICENSE BLOCK #####
|
||||
#
|
||||
# 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 2
|
||||
# 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
|
||||
# MERCHANTABILITY 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, write to the Free Software Foundation,
|
||||
# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
#
|
||||
# ##### END GPL LICENSE BLOCK #####
|
||||
|
||||
# <pep8 compliant>
|
||||
|
||||
"""User interface imports and preferences for the addon."""
|
||||
|
||||
# import addon_utils
|
||||
# from time import sleep
|
||||
import bpy
|
||||
|
||||
|
||||
from bpy.app.handlers import persistent
|
||||
|
||||
# from bpy.utils import register_class, unregister_class
|
||||
# from bpy.types import (
|
||||
# Operator,
|
||||
# Menu,
|
||||
# UIList,
|
||||
# Panel,
|
||||
# Brush,
|
||||
# Material,
|
||||
# Light,
|
||||
# World,
|
||||
# ParticleSettings,
|
||||
# FreestyleLineStyle,
|
||||
# )
|
||||
|
||||
# from bl_operators.presets import AddPresetBase
|
||||
|
||||
from . import (
|
||||
render_gui,
|
||||
scenography_gui,
|
||||
object_gui,
|
||||
shading_gui,
|
||||
texturing_gui,
|
||||
shading_nodes, # for POV specific nodes
|
||||
scripting_gui,
|
||||
)
|
||||
|
||||
|
||||
############# POV-Centric WORKSPACE #############
|
||||
@persistent
|
||||
def povCentricWorkspace(dummy):
|
||||
"""Set up a POV centric Workspace if addon was activated and saved as default renderer.
|
||||
|
||||
This would bring a ’_RestrictData’ error because UI needs to be fully loaded before
|
||||
workspace changes so registering this function in bpy.app.handlers is needed.
|
||||
By default handlers are freed when loading new files, but here we want the handler
|
||||
to stay running across multiple files as part of this add-on. That is why the
|
||||
bpy.app.handlers.persistent decorator is used (@persistent) above.
|
||||
"""
|
||||
# Scripting workspace may have been altered from factory though, so should
|
||||
# we put all within a Try... Except AttributeErrors ? Any better solution ?
|
||||
# Should it simply not run when opening existing file? be a preferences operator to create
|
||||
# Moray like workspace
|
||||
if 'Scripting' in bpy.data.workspaces:
|
||||
|
||||
wsp = bpy.data.workspaces.get('Scripting')
|
||||
context = bpy.context
|
||||
if context.scene.render.engine == 'POVRAY_RENDER' and wsp is not None:
|
||||
bpy.ops.workspace.duplicate({'workspace': wsp})
|
||||
bpy.data.workspaces['Scripting.001'].name = 'POV'
|
||||
# Already done it would seem, but explicitly make this workspace the active one
|
||||
context.window.workspace = bpy.data.workspaces['POV']
|
||||
pov_screen = bpy.data.workspaces['POV'].screens[0]
|
||||
pov_workspace = pov_screen.areas
|
||||
pov_window = context.window
|
||||
try:
|
||||
# Already outliners but invert both types
|
||||
pov_workspace[1].spaces[0].display_mode = 'LIBRARIES'
|
||||
pov_workspace[3].spaces[0].display_mode = 'VIEW_LAYER'
|
||||
except AttributeError:
|
||||
# But not necessarily outliners in existing blend files
|
||||
pass
|
||||
override = bpy.context.copy()
|
||||
|
||||
for area in pov_workspace:
|
||||
if area.type == 'VIEW_3D':
|
||||
for region in [r for r in area.regions if r.type == 'WINDOW']:
|
||||
for space in area.spaces:
|
||||
if space.type == 'VIEW_3D':
|
||||
# override['screen'] = pov_screen
|
||||
override['area'] = area
|
||||
override['region'] = region
|
||||
# bpy.data.workspaces['POV'].screens[0].areas[6].spaces[0].width = 333 # Read only,
|
||||
# how do we set ?
|
||||
# This has a glitch:
|
||||
# bpy.ops.screen.area_move(override, x=(area.x + area.width), y=(area.y + 5), delta=100)
|
||||
# bpy.ops.screen.area_move(override, x=(area.x + 5), y=area.y, delta=-100)
|
||||
|
||||
bpy.ops.screen.space_type_set_or_cycle(
|
||||
override, space_type='TEXT_EDITOR'
|
||||
)
|
||||
space.show_region_ui = True
|
||||
# bpy.ops.screen.region_scale(override)
|
||||
# bpy.ops.screen.region_scale()
|
||||
break
|
||||
|
||||
elif area.type == 'CONSOLE':
|
||||
for region in [r for r in area.regions if r.type == 'WINDOW']:
|
||||
for space in area.spaces:
|
||||
if space.type == 'CONSOLE':
|
||||
override['screen'] = pov_screen
|
||||
override['window'] = pov_window
|
||||
override['area'] = area
|
||||
override['region'] = region
|
||||
|
||||
area_x = area.x + (area.width / 2)
|
||||
area_y = area.y + area.height
|
||||
bpy.ops.screen.space_type_set_or_cycle(override, space_type='INFO')
|
||||
try:
|
||||
if area == pov_workspace[6] and bpy.ops.screen.area_move.poll(
|
||||
override
|
||||
):
|
||||
# bpy.ops.screen.area_move(override, x = area_x, y = area_y, delta = -300)
|
||||
pass
|
||||
# pov_window.cursor_warp(area_x, area_y-300) # Is manual move emulation necessary
|
||||
# despite the delta?
|
||||
except IndexError:
|
||||
# Not necessarily so many areas in existing blend files
|
||||
pass
|
||||
|
||||
break
|
||||
|
||||
elif area.type == 'INFO':
|
||||
for region in [r for r in area.regions if r.type == 'WINDOW']:
|
||||
for space in area.spaces:
|
||||
if space.type == 'INFO':
|
||||
# override['screen'] = pov_screen
|
||||
override['area'] = area
|
||||
override['region'] = region
|
||||
bpy.ops.screen.space_type_set_or_cycle(
|
||||
override, space_type='CONSOLE'
|
||||
)
|
||||
|
||||
break
|
||||
|
||||
elif area.type == 'TEXT_EDITOR':
|
||||
for region in [r for r in area.regions if r.type == 'WINDOW']:
|
||||
for space in area.spaces:
|
||||
if space.type == 'TEXT_EDITOR':
|
||||
# override['screen'] = pov_screen
|
||||
override['area'] = area
|
||||
override['region'] = region
|
||||
# bpy.ops.screen.space_type_set_or_cycle(space_type='VIEW_3D')
|
||||
# space.type = 'VIEW_3D'
|
||||
bpy.ops.screen.space_type_set_or_cycle(
|
||||
override, space_type='VIEW_3D'
|
||||
)
|
||||
|
||||
# bpy.ops.screen.area_join(override, cursor=(area.x, area.y + area.height))
|
||||
|
||||
break
|
||||
|
||||
if area.type == 'VIEW_3D':
|
||||
for region in [r for r in area.regions if r.type == 'WINDOW']:
|
||||
for space in area.spaces:
|
||||
if space.type == 'VIEW_3D':
|
||||
# override['screen'] = pov_screen
|
||||
override['area'] = area
|
||||
override['region'] = region
|
||||
bpy.ops.screen.region_quadview(override)
|
||||
space.region_3d.view_perspective = 'CAMERA'
|
||||
# bpy.ops.screen.space_type_set_or_cycle(override, space_type = 'TEXT_EDITOR')
|
||||
# bpy.ops.screen.region_quadview(override)
|
||||
|
||||
elif area.type == 'OUTLINER':
|
||||
for region in [
|
||||
r for r in area.regions if r.type == 'HEADER' and (r.y - area.y)
|
||||
]:
|
||||
for space in area.spaces:
|
||||
if space.display_mode == 'LIBRARIES':
|
||||
override['area'] = area
|
||||
override['region'] = region
|
||||
override['window'] = pov_window
|
||||
bpy.ops.screen.region_flip(override)
|
||||
|
||||
bpy.data.workspaces.update()
|
||||
|
||||
'''
|
||||
for window in bpy.context.window_manager.windows:
|
||||
for area in [a for a in window.screen.areas if a.type == 'VIEW_3D']:
|
||||
for region in [r for r in area.regions if r.type == 'WINDOW']:
|
||||
context_override = {
|
||||
'window': window,
|
||||
'screen': window.screen,
|
||||
'area': area,
|
||||
'region': region,
|
||||
'space_data': area.spaces.active,
|
||||
'scene': bpy.context.scene
|
||||
}
|
||||
bpy.ops.view3d.camera_to_view(context_override)
|
||||
'''
|
||||
|
||||
else:
|
||||
print(
|
||||
"\nPOV centric workspace available if you set render option\n"
|
||||
"and save it in default file with CTRL+U"
|
||||
)
|
||||
|
||||
else:
|
||||
print(
|
||||
"\nThe factory 'Scripting' workspace is needed before POV centric "
|
||||
"\nworkspace may activate when POV is set as your default renderer"
|
||||
)
|
||||
####################################UTF-8###################################
|
||||
# Check and fix all strings in current .blend file to be valid UTF-8 Unicode
|
||||
# sometimes needed for old, 2.4x / 2.6x area files
|
||||
bpy.ops.wm.blend_strings_utf8_validate()
|
||||
|
||||
|
||||
def check_material(mat):
|
||||
"""Allow use of material properties buttons rather than nodes."""
|
||||
if mat is not None:
|
||||
if mat.use_nodes:
|
||||
if not mat.node_tree: # FORMERLY : #mat.active_node_material is not None:
|
||||
return True
|
||||
return False
|
||||
return True
|
||||
return False
|
||||
|
||||
|
||||
def simple_material(mat):
|
||||
"""Test if a material uses nodes."""
|
||||
if (mat is not None) and (not mat.use_nodes):
|
||||
return True
|
||||
return False
|
||||
|
||||
|
||||
def pov_context_tex_datablock(context):
|
||||
"""Recreate texture context type as deprecated in blender 2.8."""
|
||||
idblock = context.brush
|
||||
if idblock and context.scene.texture_context == 'OTHER':
|
||||
return idblock
|
||||
|
||||
# idblock = bpy.context.active_object.active_material
|
||||
idblock = context.view_layer.objects.active.active_material
|
||||
if idblock and context.scene.texture_context == 'MATERIAL':
|
||||
return idblock
|
||||
|
||||
idblock = context.scene.world
|
||||
if idblock and context.scene.texture_context == 'WORLD':
|
||||
return idblock
|
||||
|
||||
idblock = context.light
|
||||
if idblock and context.scene.texture_context == 'LIGHT':
|
||||
return idblock
|
||||
|
||||
if context.particle_system and context.scene.texture_context == 'PARTICLES':
|
||||
idblock = context.particle_system.settings
|
||||
|
||||
return idblock
|
||||
|
||||
idblock = context.line_style
|
||||
if idblock and context.scene.texture_context == 'LINESTYLE':
|
||||
return idblock
|
||||
|
||||
|
||||
# class TextureTypePanel(TextureButtonsPanel):
|
||||
|
||||
# @classmethod
|
||||
# def poll(cls, context):
|
||||
# tex = context.texture
|
||||
# engine = context.scene.render.engine
|
||||
# return tex and ((tex.type == cls.tex_type and not tex.use_nodes) and (engine in cls.COMPAT_ENGINES))
|
||||
|
||||
|
||||
def register():
|
||||
render_gui.register()
|
||||
scenography_gui.register()
|
||||
object_gui.register()
|
||||
shading_gui.register()
|
||||
texturing_gui.register()
|
||||
shading_nodes.register()
|
||||
scripting_gui.register()
|
||||
|
||||
if not povCentricWorkspace in bpy.app.handlers.load_post:
|
||||
bpy.app.handlers.load_post.append(povCentricWorkspace)
|
||||
|
||||
|
||||
def unregister():
|
||||
if povCentricWorkspace in bpy.app.handlers.load_post:
|
||||
bpy.app.handlers.load_post.remove(povCentricWorkspace)
|
||||
|
||||
scripting_gui.unregister()
|
||||
shading_nodes.unregister()
|
||||
texturing_gui.unregister()
|
||||
shading_gui.unregister()
|
||||
object_gui.unregister()
|
||||
scenography_gui.unregister()
|
||||
render_gui.register()
|
|
@ -52,18 +52,19 @@ import sys
|
|||
|
||||
# -+-+-+- Start df3 Class -+-+-+-
|
||||
|
||||
|
||||
class df3:
|
||||
__version__ = '0.2'
|
||||
|
||||
__arraytype__ = 'f'
|
||||
|
||||
__struct4byte__ = '>I'
|
||||
__struct2byte__ = '>H'
|
||||
__struct4byte__ = '>I'
|
||||
__struct2byte__ = '>H'
|
||||
__struct2byte3__ = '>HHH'
|
||||
__struct1byte__ = '>B'
|
||||
__array4byte__ = 'I'
|
||||
__array2byte__ = 'H'
|
||||
__array1byte__ = 'B'
|
||||
__struct1byte__ = '>B'
|
||||
__array4byte__ = 'I'
|
||||
__array2byte__ = 'H'
|
||||
__array1byte__ = 'B'
|
||||
|
||||
def __init__(self, x=1, y=1, z=1):
|
||||
self.maxX = x
|
||||
|
@ -73,7 +74,7 @@ class df3:
|
|||
|
||||
def clone(self, indf3):
|
||||
self.voxel = array.array(self.__arraytype__)
|
||||
for i in range(indf3.sizeX()*indf3.sizeY()*indf3.sizeZ()):
|
||||
for i in range(indf3.sizeX() * indf3.sizeY() * indf3.sizeZ()):
|
||||
self.voxel[i] = indf3.voxel[i]
|
||||
return self
|
||||
|
||||
|
@ -98,35 +99,41 @@ class df3:
|
|||
#### Voxel Access Functions
|
||||
|
||||
def get(self, x, y, z):
|
||||
return self.voxel[self.__voxa__(x,y,z)]
|
||||
return self.voxel[self.__voxa__(x, y, z)]
|
||||
|
||||
def getB(self, x, y, z):
|
||||
if (x > self.sizeX() or x < 0): return 0
|
||||
if (y > self.sizeX() or y < 0): return 0
|
||||
if (z > self.sizeX() or z < 0): return 0
|
||||
if x > self.sizeX() or x < 0:
|
||||
return 0
|
||||
if y > self.sizeX() or y < 0:
|
||||
return 0
|
||||
if z > self.sizeX() or z < 0:
|
||||
return 0
|
||||
|
||||
return self.voxel[self.__voxa__(x,y,z)]
|
||||
return self.voxel[self.__voxa__(x, y, z)]
|
||||
|
||||
def set(self, x, y, z, val):
|
||||
self.voxel[self.__voxa__(x,y,z)] = val
|
||||
self.voxel[self.__voxa__(x, y, z)] = val
|
||||
|
||||
def setB(self, x, y, z, val):
|
||||
if (x > self.sizeX() or x < 0): return
|
||||
if (y > self.sizeX() or y < 0): return
|
||||
if (z > self.sizeX() or z < 0): return
|
||||
if x > self.sizeX() or x < 0:
|
||||
return
|
||||
if y > self.sizeX() or y < 0:
|
||||
return
|
||||
if z > self.sizeX() or z < 0:
|
||||
return
|
||||
|
||||
self.voxel[self.__voxa__(x,y,z)] = val
|
||||
self.voxel[self.__voxa__(x, y, z)] = val
|
||||
|
||||
#### Scalar Functions
|
||||
|
||||
def mult(self, val):
|
||||
for i in range(self.sizeX()*self.sizeY()*self.sizeZ()):
|
||||
for i in range(self.sizeX() * self.sizeY() * self.sizeZ()):
|
||||
self.voxel[i] = self.voxel[i] * val
|
||||
|
||||
return self
|
||||
|
||||
def add(self, val):
|
||||
for i in range(self.sizeX()*self.sizeY()*self.sizeZ()):
|
||||
for i in range(self.sizeX() * self.sizeY() * self.sizeZ()):
|
||||
self.voxel[i] = self.voxel[i] + val
|
||||
|
||||
return self
|
||||
|
@ -134,8 +141,8 @@ class df3:
|
|||
def max(self):
|
||||
tmp = self.voxel[0]
|
||||
|
||||
for i in range(self.sizeX()*self.sizeY()*self.sizeZ()):
|
||||
if (self.voxel[i] > tmp):
|
||||
for i in range(self.sizeX() * self.sizeY() * self.sizeZ()):
|
||||
if self.voxel[i] > tmp:
|
||||
tmp = self.voxel[i]
|
||||
|
||||
return tmp
|
||||
|
@ -143,8 +150,8 @@ class df3:
|
|||
def min(self):
|
||||
tmp = self.voxel[0]
|
||||
|
||||
for i in range(self.sizeX()*self.sizeY()*self.sizeZ()):
|
||||
if (self.voxel[i] < tmp):
|
||||
for i in range(self.sizeX() * self.sizeY() * self.sizeZ()):
|
||||
if self.voxel[i] < tmp:
|
||||
tmp = self.voxel[i]
|
||||
|
||||
return tmp
|
||||
|
@ -152,30 +159,31 @@ class df3:
|
|||
#### Vector Functions
|
||||
|
||||
def compare(self, indf3):
|
||||
if (self.__samesize__(indf3) == 0): return 0
|
||||
if self.__samesize__(indf3) == 0:
|
||||
return 0
|
||||
|
||||
if (self.voxel == indf3.voxel):
|
||||
if self.voxel == indf3.voxel:
|
||||
return 1
|
||||
|
||||
return 0
|
||||
|
||||
def multV(self, indf3):
|
||||
if (self.__samesize__(indf3) == 0):
|
||||
if self.__samesize__(indf3) == 0:
|
||||
print("Cannot multiply voxels - not same size")
|
||||
return
|
||||
|
||||
for i in range(self.sizeX()*self.sizeY()*self.sizeZ()):
|
||||
self.voxel[i] = self.voxel[i]*indf3.voxel[i]
|
||||
for i in range(self.sizeX() * self.sizeY() * self.sizeZ()):
|
||||
self.voxel[i] = self.voxel[i] * indf3.voxel[i]
|
||||
|
||||
return self
|
||||
|
||||
def addV(self, indf3):
|
||||
if (self.__samesize__(indf3) == 0):
|
||||
if self.__samesize__(indf3) == 0:
|
||||
print("Cannot add voxels - not same size")
|
||||
return
|
||||
|
||||
for i in range(self.sizeX()*self.sizeY()*self.sizeZ()):
|
||||
self.voxel[i] = self.voxel[i]+indf3.voxel[i]
|
||||
for i in range(self.sizeX() * self.sizeY() * self.sizeZ()):
|
||||
self.voxel[i] = self.voxel[i] + indf3.voxel[i]
|
||||
|
||||
return self
|
||||
|
||||
|
@ -183,31 +191,31 @@ class df3:
|
|||
fx = filt.sizeX()
|
||||
fy = filt.sizeY()
|
||||
fz = filt.sizeZ()
|
||||
if (fx % 2 != 1):
|
||||
if fx % 2 != 1:
|
||||
print("Incompatible filter - must be odd number of X")
|
||||
return self
|
||||
if (fy % 2 != 1):
|
||||
if fy % 2 != 1:
|
||||
print("Incompatible filter - must be odd number of Y")
|
||||
return self
|
||||
if (fz % 2 != 1):
|
||||
if fz % 2 != 1:
|
||||
print("Incompatible filter - must be odd number of Z")
|
||||
return self
|
||||
|
||||
fdx = (fx-1)/2
|
||||
fdy = (fy-1)/2
|
||||
fdz = (fz-1)/2
|
||||
flen = fx*fy*fz
|
||||
fdx = (fx - 1) / 2
|
||||
fdy = (fy - 1) / 2
|
||||
fdz = (fz - 1) / 2
|
||||
flen = fx * fy * fz
|
||||
|
||||
newV = self.__create__(self.sizeX(), self.sizeY(), self.sizeZ());
|
||||
newV = self.__create__(self.sizeX(), self.sizeY(), self.sizeZ())
|
||||
|
||||
for x in range(self.sizeX()):
|
||||
for y in range(self.sizeY()):
|
||||
for z in range(self.sizeZ()):
|
||||
rip = self.__rip__(x-fdx, x+fdx, y-fdy, y+fdy, z-fdz, z+fdz)
|
||||
rip = self.__rip__(x - fdx, x + fdx, y - fdy, y + fdy, z - fdz, z + fdz)
|
||||
tmp = 0.0
|
||||
for i in range(flen):
|
||||
tmp += rip[i]*filt.voxel[i]
|
||||
newV[self.__voxa__(x,y,z)] = tmp
|
||||
tmp += rip[i] * filt.voxel[i]
|
||||
newV[self.__voxa__(x, y, z)] = tmp
|
||||
|
||||
self.voxel = newV
|
||||
|
||||
|
@ -221,64 +229,67 @@ class df3:
|
|||
z = self.sizeZ()
|
||||
|
||||
try:
|
||||
f = open(file, 'wb');
|
||||
f = open(file, 'wb')
|
||||
except:
|
||||
print("Could not open " + file + " for write");
|
||||
print("Could not open " + file + " for write")
|
||||
return
|
||||
|
||||
f.write(struct.pack(self.__struct2byte3__, x, y, z));
|
||||
f.write(struct.pack(self.__struct2byte3__, x, y, z))
|
||||
|
||||
tmp = self.__toInteger__(pow(2,depth)-1, rescale)
|
||||
tmp = self.__toInteger__(pow(2, depth) - 1, rescale)
|
||||
|
||||
if (depth > 16): # 32-bit
|
||||
for i in range( x*y*z ):
|
||||
if depth > 16: # 32-bit
|
||||
for i in range(x * y * z):
|
||||
f.write(struct.pack(self.__struct4byte__, tmp[i]))
|
||||
elif (depth > 8): # 16-bit
|
||||
for i in range( x*y*z ):
|
||||
elif depth > 8: # 16-bit
|
||||
for i in range(x * y * z):
|
||||
f.write(struct.pack(self.__struct2byte__, tmp[i]))
|
||||
else:
|
||||
for i in range( x*y*z ):
|
||||
for i in range(x * y * z):
|
||||
f.write(struct.pack(self.__struct1byte__, tmp[i]))
|
||||
|
||||
def importDF3(self, file, scale=1):
|
||||
try:
|
||||
f = open(file, 'rb');
|
||||
f = open(file, 'rb')
|
||||
size = os.stat(file)[stat.ST_SIZE]
|
||||
|
||||
except:
|
||||
print("Could not open " + file + " for read");
|
||||
print("Could not open " + file + " for read")
|
||||
return []
|
||||
|
||||
(x, y, z) = struct.unpack(self.__struct2byte3__, f.read(6) )
|
||||
(x, y, z) = struct.unpack(self.__struct2byte3__, f.read(6))
|
||||
|
||||
self.voxel = self.__create__(x, y, z)
|
||||
self.maxX = x
|
||||
self.maxY = y
|
||||
self.maxZ = z
|
||||
|
||||
size = size-6
|
||||
if (size == x*y*z): format = 8
|
||||
elif (size == 2*x*y*z): format = 16
|
||||
elif (size == 4*x*y*z): format = 32
|
||||
size = size - 6
|
||||
if size == x * y * z:
|
||||
format = 8
|
||||
elif size == 2 * x * y * z:
|
||||
format = 16
|
||||
elif size == 4 * x * y * z:
|
||||
format = 32
|
||||
|
||||
if (format == 32):
|
||||
for i in range(x*y*z):
|
||||
self.voxel[i] = float(struct.unpack(self.__struct4byte__, f.read(4) )[0])
|
||||
elif (format == 16):
|
||||
for i in range(x*y*z):
|
||||
self.voxel[i] = float(struct.unpack(self.__struct2byte__, f.read(2) )[0])
|
||||
elif (format == 8):
|
||||
for i in range(x*y*z):
|
||||
self.voxel[i] = float(struct.unpack(self.__struct1byte__, f.read(1) )[0])
|
||||
if format == 32:
|
||||
for i in range(x * y * z):
|
||||
self.voxel[i] = float(struct.unpack(self.__struct4byte__, f.read(4))[0])
|
||||
elif format == 16:
|
||||
for i in range(x * y * z):
|
||||
self.voxel[i] = float(struct.unpack(self.__struct2byte__, f.read(2))[0])
|
||||
elif format == 8:
|
||||
for i in range(x * y * z):
|
||||
self.voxel[i] = float(struct.unpack(self.__struct1byte__, f.read(1))[0])
|
||||
|
||||
return self
|
||||
|
||||
#### Local classes not intended for user use
|
||||
|
||||
def __rip__(self, minX, maxX, minY, maxY, minZ, maxZ):
|
||||
sizeX = maxX-minX+1
|
||||
sizeY = maxY-minY+1
|
||||
sizeZ = maxZ-minZ+1
|
||||
sizeX = maxX - minX + 1
|
||||
sizeY = maxY - minY + 1
|
||||
sizeZ = maxZ - minZ + 1
|
||||
|
||||
tmpV = self.__create__(sizeX, sizeY, sizeZ)
|
||||
|
||||
|
@ -286,95 +297,99 @@ class df3:
|
|||
for y in range(sizeY):
|
||||
for z in range(sizeZ):
|
||||
# Check X
|
||||
if ((minX + x) < 0):
|
||||
tmpV[(z*sizeZ+y)*sizeY+x] = 0.0
|
||||
elif ((minX + x) > self.sizeX()-1):
|
||||
tmpV[(z*sizeZ+y)*sizeY+x] = 0.0
|
||||
if (minX + x) < 0:
|
||||
tmpV[(z * sizeZ + y) * sizeY + x] = 0.0
|
||||
elif (minX + x) > self.sizeX() - 1:
|
||||
tmpV[(z * sizeZ + y) * sizeY + x] = 0.0
|
||||
# Check Y
|
||||
elif ((minY + y) < 0):
|
||||
tmpV[(z*sizeZ+y)*sizeY+x] = 0.0
|
||||
elif ((minY + y) > self.sizeY()-1):
|
||||
tmpV[(z*sizeZ+y)*sizeY+x] = 0.0
|
||||
elif (minY + y) < 0:
|
||||
tmpV[(z * sizeZ + y) * sizeY + x] = 0.0
|
||||
elif (minY + y) > self.sizeY() - 1:
|
||||
tmpV[(z * sizeZ + y) * sizeY + x] = 0.0
|
||||
# Check Z
|
||||
elif ((minZ + z) < 0):
|
||||
tmpV[(z*sizeZ+y)*sizeY+x] = 0.0
|
||||
elif ((minZ + z) > self.sizeZ()-1):
|
||||
tmpV[(z*sizeZ+y)*sizeY+x] = 0.0
|
||||
elif (minZ + z) < 0:
|
||||
tmpV[(z * sizeZ + y) * sizeY + x] = 0.0
|
||||
elif (minZ + z) > self.sizeZ() - 1:
|
||||
tmpV[(z * sizeZ + y) * sizeY + x] = 0.0
|
||||
else:
|
||||
tmpV[(z*sizeZ+y)*sizeY+x] = self.get(minX+x,minY+y,minZ+z)
|
||||
tmpV[(z * sizeZ + y) * sizeY + x] = self.get(minX + x, minY + y, minZ + z)
|
||||
|
||||
return tmpV
|
||||
|
||||
def __samesize__(self, indf3):
|
||||
if (self.sizeX() != indf3.sizeX()): return 0
|
||||
if (self.sizeY() != indf3.sizeY()): return 0
|
||||
if (self.sizeZ() != indf3.sizeZ()): return 0
|
||||
if self.sizeX() != indf3.sizeX():
|
||||
return 0
|
||||
if self.sizeY() != indf3.sizeY():
|
||||
return 0
|
||||
if self.sizeZ() != indf3.sizeZ():
|
||||
return 0
|
||||
return 1
|
||||
|
||||
def __voxa__(self, x, y, z):
|
||||
return ((z*self.sizeY()+y)*self.sizeX()+x)
|
||||
return (z * self.sizeY() + y) * self.sizeX() + x
|
||||
|
||||
def __create__(self, x, y, z, atype='0', init=1):
|
||||
if (atype == '0'):
|
||||
if atype == '0':
|
||||
tmp = self.__arraytype__
|
||||
else:
|
||||
tmp = atype
|
||||
|
||||
if (init == 1):
|
||||
if tmp in ('f','d'):
|
||||
voxel = array.array(tmp, [0.0 for i in range(x*y*z)])
|
||||
if init == 1:
|
||||
if tmp in ('f', 'd'):
|
||||
voxel = array.array(tmp, [0.0 for i in range(x * y * z)])
|
||||
else:
|
||||
voxel = array.array(tmp, [0 for i in range(x*y*z)])
|
||||
voxel = array.array(tmp, [0 for i in range(x * y * z)])
|
||||
else:
|
||||
voxel = array.array(tmp)
|
||||
|
||||
return voxel
|
||||
|
||||
def __toInteger__(self, scale, rescale=1):
|
||||
if (scale < pow(2,8)): # 8-bit
|
||||
if scale < pow(2, 8): # 8-bit
|
||||
tmp = self.__create__(self.sizeX(), self.sizeY(), self.sizeZ(), self.__array1byte__)
|
||||
elif (scale < pow(2,16)): # 16-bit
|
||||
elif scale < pow(2, 16): # 16-bit
|
||||
tmp = self.__create__(self.sizeX(), self.sizeY(), self.sizeZ(), self.__array2byte__)
|
||||
else: # 32-bit
|
||||
else: # 32-bit
|
||||
tmp = self.__create__(self.sizeX(), self.sizeY(), self.sizeZ(), self.__array4byte__)
|
||||
|
||||
maxVal = self.max()
|
||||
|
||||
print(scale)
|
||||
|
||||
for i in range(self.sizeX()*self.sizeY()*self.sizeZ()):
|
||||
if (rescale == 1):
|
||||
tmp[i] = max(0,int(round(scale*self.voxel[i]/maxVal)))
|
||||
for i in range(self.sizeX() * self.sizeY() * self.sizeZ()):
|
||||
if rescale == 1:
|
||||
tmp[i] = max(0, int(round(scale * self.voxel[i] / maxVal)))
|
||||
else:
|
||||
tmp[i] = max(0,min(scale,int(round(self.voxel[i]))))
|
||||
tmp[i] = max(0, min(scale, int(round(self.voxel[i]))))
|
||||
|
||||
return tmp
|
||||
|
||||
|
||||
# -=-=-=- End df3 Class -=-=-=-
|
||||
##########DEFAULT EXAMPLES
|
||||
# if __name__ == '__main__':
|
||||
# localX = 80
|
||||
# localY = 90
|
||||
# localZ = 100
|
||||
## Generate an output
|
||||
# temp = df3(localX, localY, localZ)
|
||||
# localX = 80
|
||||
# localY = 90
|
||||
# localZ = 100
|
||||
## Generate an output
|
||||
# temp = df3(localX, localY, localZ)
|
||||
|
||||
# for i in range(localX):
|
||||
# for j in range(localY):
|
||||
# for k in range(localZ):
|
||||
# if (i >= (localX/2)):
|
||||
# temp.set(i, j, k, 1.0)
|
||||
# for i in range(localX):
|
||||
# for j in range(localY):
|
||||
# for k in range(localZ):
|
||||
# if (i >= (localX/2)):
|
||||
# temp.set(i, j, k, 1.0)
|
||||
|
||||
# temp.exportDF3('temp.df3', 16)
|
||||
# temp.exportDF3('temp.df3', 16)
|
||||
###############################################################################
|
||||
## Import
|
||||
# temp2 = df3().importDF3('temp.df3')
|
||||
# temp2.mult(1/temp2.max())
|
||||
## Import
|
||||
# temp2 = df3().importDF3('temp.df3')
|
||||
# temp2.mult(1/temp2.max())
|
||||
|
||||
## Compare
|
||||
# print(temp2.size())
|
||||
## Compare
|
||||
# print(temp2.size())
|
||||
|
||||
# if (temp.compare(temp2) == 0): print("DF3's Do Not Match")
|
||||
# if (temp.compare(temp2) == 0): print("DF3's Do Not Match")
|
||||
|
||||
###############################################################################
|
||||
# ChangeLog
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,974 @@
|
|||
# ***** BEGIN GPL LICENSE BLOCK *****
|
||||
#
|
||||
# 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 2
|
||||
# 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
|
||||
# MERCHANTABILITY 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, write to the Free Software Foundation,
|
||||
# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
#
|
||||
# #**** END GPL LICENSE BLOCK #****
|
||||
|
||||
# <pep8 compliant>
|
||||
|
||||
"""Translate to POV the control point compounded geometries like polygon
|
||||
|
||||
meshes or curve based shapes.
|
||||
"""
|
||||
|
||||
import bpy
|
||||
|
||||
from .shading import write_object_material
|
||||
|
||||
################################ LOFT, ETC.
|
||||
def export_curves(ob, string_strip_hyphen, global_matrix, tab_write):
|
||||
"""write all curves based POV primitives to exported file """
|
||||
name_orig = "OB" + ob.name
|
||||
dataname_orig = "DATA" + ob.data.name
|
||||
|
||||
name = string_strip_hyphen(bpy.path.clean_name(name_orig))
|
||||
dataname = string_strip_hyphen(bpy.path.clean_name(dataname_orig))
|
||||
|
||||
matrix = global_matrix @ ob.matrix_world
|
||||
bezier_sweep = False
|
||||
if ob.pov.curveshape == 'sphere_sweep':
|
||||
# inlined spheresweep macro, which itself calls Shapes.inc:
|
||||
file.write(' #include "shapes.inc"\n')
|
||||
|
||||
file.write(
|
||||
' #macro Shape_Bezierpoints_Sphere_Sweep(_merge_shape, _resolution, _points_array, _radius_array)\n'
|
||||
)
|
||||
file.write(' //input adjusting and inspection\n')
|
||||
file.write(' #if(_resolution <= 1)\n')
|
||||
file.write(' #local res = 1;\n')
|
||||
file.write(' #else\n')
|
||||
file.write(' #local res = int(_resolution);\n')
|
||||
file.write(' #end\n')
|
||||
file.write(' #if(dimensions(_points_array) != 1 | dimensions(_radius_array) != 1)\n')
|
||||
file.write(' #error ""\n')
|
||||
file.write(
|
||||
' #elseif(div(dimension_size(_points_array,1),4) - dimension_size(_points_array,1)/4 != 0)\n'
|
||||
)
|
||||
file.write(' #error ""\n')
|
||||
file.write(
|
||||
' #elseif(dimension_size(_points_array,1) != dimension_size(_radius_array,1))\n'
|
||||
)
|
||||
file.write(' #error ""\n')
|
||||
file.write(' #else\n')
|
||||
file.write(' #local n_of_seg = div(dimension_size(_points_array,1), 4);\n')
|
||||
file.write(' #local ctrl_pts_array = array[n_of_seg]\n')
|
||||
file.write(' #local ctrl_rs_array = array[n_of_seg]\n')
|
||||
file.write(' #for(i, 0, n_of_seg-1)\n')
|
||||
file.write(
|
||||
' #local ctrl_pts_array[i] = array[4] {_points_array[4*i], _points_array[4*i+1], _points_array[4*i+2], _points_array[4*i+3]}\n'
|
||||
)
|
||||
file.write(
|
||||
' #local ctrl_rs_array[i] = array[4] {abs(_radius_array[4*i]), abs(_radius_array[4*i+1]), abs(_radius_array[4*i+2]), abs(_radius_array[4*i+3])}\n'
|
||||
)
|
||||
file.write(' #end\n')
|
||||
file.write(' #end\n')
|
||||
|
||||
file.write(' //drawing\n')
|
||||
file.write(' #local mockup1 =\n')
|
||||
file.write(' #if(_merge_shape) merge{ #else union{ #end\n')
|
||||
file.write(' #for(i, 0, n_of_seg-1)\n')
|
||||
file.write(' #local has_head = true;\n')
|
||||
file.write(' #if(i = 0)\n')
|
||||
file.write(
|
||||
' #if(vlength(ctrl_pts_array[i][0]-ctrl_pts_array[n_of_seg-1][3]) = 0 & ctrl_rs_array[i][0]-ctrl_rs_array[n_of_seg-1][3] <= 0)\n'
|
||||
)
|
||||
file.write(' #local has_head = false;\n')
|
||||
file.write(' #end\n')
|
||||
file.write(' #else\n')
|
||||
file.write(
|
||||
' #if(vlength(ctrl_pts_array[i][0]-ctrl_pts_array[i-1][3]) = 0 & ctrl_rs_array[i][0]-ctrl_rs_array[i-1][3] <= 0)\n'
|
||||
)
|
||||
file.write(' #local has_head = false;\n')
|
||||
file.write(' #end\n')
|
||||
file.write(' #end\n')
|
||||
file.write(' #if(has_head = true)\n')
|
||||
file.write(' sphere{\n')
|
||||
file.write(' ctrl_pts_array[i][0], ctrl_rs_array[i][0]\n')
|
||||
file.write(' }\n')
|
||||
file.write(' #end\n')
|
||||
file.write(' #local para_t = (1/2)/res;\n')
|
||||
file.write(
|
||||
' #local this_point = ctrl_pts_array[i][0]*pow(1-para_t,3) + ctrl_pts_array[i][1]*3*pow(1-para_t,2)*para_t + ctrl_pts_array[i][2]*3*(1-para_t)*pow(para_t,2) + ctrl_pts_array[i][3]*pow(para_t,3);\n'
|
||||
)
|
||||
file.write(
|
||||
' #local this_radius = ctrl_rs_array[i][0]*pow(1-para_t,3) + ctrl_rs_array[i][1]*3*pow(1-para_t,2)*para_t + ctrl_rs_array[i][2]*3*(1-para_t)*pow(para_t,2) + ctrl_rs_array[i][3]*pow(para_t,3);\n'
|
||||
)
|
||||
file.write(
|
||||
' #if(vlength(this_point-ctrl_pts_array[i][0]) > abs(this_radius-ctrl_rs_array[i][0]))\n'
|
||||
)
|
||||
file.write(' object{\n')
|
||||
file.write(
|
||||
' Connect_Spheres(ctrl_pts_array[i][0], ctrl_rs_array[i][0], this_point, this_radius)\n'
|
||||
)
|
||||
file.write(' }\n')
|
||||
file.write(' #end\n')
|
||||
file.write(' sphere{\n')
|
||||
file.write(' this_point, this_radius\n')
|
||||
file.write(' }\n')
|
||||
file.write(' #for(j, 1, res-1)\n')
|
||||
file.write(' #local last_point = this_point;\n')
|
||||
file.write(' #local last_radius = this_radius;\n')
|
||||
file.write(' #local para_t = (1/2+j)/res;\n')
|
||||
file.write(
|
||||
' #local this_point = ctrl_pts_array[i][0]*pow(1-para_t,3) + ctrl_pts_array[i][1]*3*pow(1-para_t,2)*para_t + ctrl_pts_array[i][2]*3*(1-para_t)*pow(para_t,2) + ctrl_pts_array[i][3]*pow(para_t,3);\n'
|
||||
)
|
||||
file.write(
|
||||
' #local this_radius = ctrl_rs_array[i][0]*pow(1-para_t,3) + ctrl_rs_array[i][1]*3*pow(1-para_t,2)*para_t + ctrl_rs_array[i][2]*3*(1-para_t)*pow(para_t,2) + ctrl_rs_array[i][3]*pow(para_t,3);\n'
|
||||
)
|
||||
file.write(
|
||||
' #if(vlength(this_point-last_point) > abs(this_radius-last_radius))\n'
|
||||
)
|
||||
file.write(' object{\n')
|
||||
file.write(
|
||||
' Connect_Spheres(last_point, last_radius, this_point, this_radius)\n'
|
||||
)
|
||||
file.write(' }\n')
|
||||
file.write(' #end\n')
|
||||
file.write(' sphere{\n')
|
||||
file.write(' this_point, this_radius\n')
|
||||
file.write(' }\n')
|
||||
file.write(' #end\n')
|
||||
file.write(' #local last_point = this_point;\n')
|
||||
file.write(' #local last_radius = this_radius;\n')
|
||||
file.write(' #local this_point = ctrl_pts_array[i][3];\n')
|
||||
file.write(' #local this_radius = ctrl_rs_array[i][3];\n')
|
||||
file.write(
|
||||
' #if(vlength(this_point-last_point) > abs(this_radius-last_radius))\n'
|
||||
)
|
||||
file.write(' object{\n')
|
||||
file.write(
|
||||
' Connect_Spheres(last_point, last_radius, this_point, this_radius)\n'
|
||||
)
|
||||
file.write(' }\n')
|
||||
file.write(' #end\n')
|
||||
file.write(' sphere{\n')
|
||||
file.write(' this_point, this_radius\n')
|
||||
file.write(' }\n')
|
||||
file.write(' #end\n')
|
||||
file.write(' }\n')
|
||||
file.write(' mockup1\n')
|
||||
file.write(' #end\n')
|
||||
|
||||
for spl in ob.data.splines:
|
||||
if spl.type == "BEZIER":
|
||||
bezier_sweep = True
|
||||
if ob.pov.curveshape in {'loft', 'birail'}:
|
||||
n = 0
|
||||
for spline in ob.data.splines:
|
||||
n += 1
|
||||
tab_write('#declare %s%s=spline {\n' % (dataname, n))
|
||||
tab_write('cubic_spline\n')
|
||||
lp = len(spline.points)
|
||||
delta = 1 / (lp)
|
||||
d = -delta
|
||||
point = spline.points[lp - 1]
|
||||
x, y, z, w = point.co[:]
|
||||
tab_write('%.6f, <%.6f,%.6f,%.6f>\n' % (d, x, y, z))
|
||||
d += delta
|
||||
for point in spline.points:
|
||||
x, y, z, w = point.co[:]
|
||||
tab_write('%.6f, <%.6f,%.6f,%.6f>\n' % (d, x, y, z))
|
||||
d += delta
|
||||
for i in range(2):
|
||||
point = spline.points[i]
|
||||
x, y, z, w = point.co[:]
|
||||
tab_write('%.6f, <%.6f,%.6f,%.6f>\n' % (d, x, y, z))
|
||||
d += delta
|
||||
tab_write('}\n')
|
||||
if ob.pov.curveshape in {'loft'}:
|
||||
n = len(ob.data.splines)
|
||||
tab_write('#declare %s = array[%s]{\n' % (dataname, (n + 3)))
|
||||
tab_write('spline{%s%s},\n' % (dataname, n))
|
||||
for i in range(n):
|
||||
tab_write('spline{%s%s},\n' % (dataname, (i + 1)))
|
||||
tab_write('spline{%s1},\n' % (dataname))
|
||||
tab_write('spline{%s2}\n' % (dataname))
|
||||
tab_write('}\n')
|
||||
# Use some of the Meshmaker.inc macro, here inlined
|
||||
file.write('#macro CheckFileName(FileName)\n')
|
||||
file.write(' #local Len=strlen(FileName);\n')
|
||||
file.write(' #if(Len>0)\n')
|
||||
file.write(' #if(file_exists(FileName))\n')
|
||||
file.write(' #if(Len>=4)\n')
|
||||
file.write(' #local Ext=strlwr(substr(FileName,Len-3,4))\n')
|
||||
file.write(
|
||||
' #if (strcmp(Ext,".obj")=0 | strcmp(Ext,".pcm")=0 | strcmp(Ext,".arr")=0)\n'
|
||||
)
|
||||
file.write(' #local Return=99;\n')
|
||||
file.write(' #else\n')
|
||||
file.write(' #local Return=0;\n')
|
||||
file.write(' #end\n')
|
||||
file.write(' #else\n')
|
||||
file.write(' #local Return=0;\n')
|
||||
file.write(' #end\n')
|
||||
file.write(' #else\n')
|
||||
file.write(' #if(Len>=4)\n')
|
||||
file.write(' #local Ext=strlwr(substr(FileName,Len-3,4))\n')
|
||||
file.write(
|
||||
' #if (strcmp(Ext,".obj")=0 | strcmp(Ext,".pcm")=0 | strcmp(Ext,".arr")=0)\n'
|
||||
)
|
||||
file.write(' #if (strcmp(Ext,".obj")=0)\n')
|
||||
file.write(' #local Return=2;\n')
|
||||
file.write(' #end\n')
|
||||
file.write(' #if (strcmp(Ext,".pcm")=0)\n')
|
||||
file.write(' #local Return=3;\n')
|
||||
file.write(' #end\n')
|
||||
file.write(' #if (strcmp(Ext,".arr")=0)\n')
|
||||
file.write(' #local Return=4;\n')
|
||||
file.write(' #end\n')
|
||||
file.write(' #else\n')
|
||||
file.write(' #local Return=1;\n')
|
||||
file.write(' #end\n')
|
||||
file.write(' #else\n')
|
||||
file.write(' #local Return=1;\n')
|
||||
file.write(' #end\n')
|
||||
file.write(' #end\n')
|
||||
file.write(' #else\n')
|
||||
file.write(' #local Return=1;\n')
|
||||
file.write(' #end\n')
|
||||
file.write(' (Return)\n')
|
||||
file.write('#end\n')
|
||||
|
||||
file.write('#macro BuildSpline(Arr, SplType)\n')
|
||||
file.write(' #local Ds=dimension_size(Arr,1);\n')
|
||||
file.write(' #local Asc=asc(strupr(SplType));\n')
|
||||
file.write(' #if(Asc!=67 & Asc!=76 & Asc!=81) \n')
|
||||
file.write(' #local Asc=76;\n')
|
||||
file.write(
|
||||
' #debug "\nWrong spline type defined (C/c/L/l/N/n/Q/q), using default linear_spline\\n"\n'
|
||||
)
|
||||
file.write(' #end\n')
|
||||
file.write(' spline {\n')
|
||||
file.write(' #switch (Asc)\n')
|
||||
file.write(' #case (67) //C cubic_spline\n')
|
||||
file.write(' cubic_spline\n')
|
||||
file.write(' #break\n')
|
||||
file.write(' #case (76) //L linear_spline\n')
|
||||
file.write(' linear_spline\n')
|
||||
file.write(' #break\n')
|
||||
file.write(' #case (78) //N linear_spline\n')
|
||||
file.write(' natural_spline\n')
|
||||
file.write(' #break\n')
|
||||
file.write(' #case (81) //Q Quadratic_spline\n')
|
||||
file.write(' quadratic_spline\n')
|
||||
file.write(' #break\n')
|
||||
file.write(' #end\n')
|
||||
file.write(' #local Add=1/((Ds-2)-1);\n')
|
||||
file.write(' #local J=0-Add;\n')
|
||||
file.write(' #local I=0;\n')
|
||||
file.write(' #while (I<Ds)\n')
|
||||
file.write(' J\n')
|
||||
file.write(' Arr[I]\n')
|
||||
file.write(' #local I=I+1;\n')
|
||||
file.write(' #local J=J+Add;\n')
|
||||
file.write(' #end\n')
|
||||
file.write(' }\n')
|
||||
file.write('#end\n')
|
||||
|
||||
file.write('#macro BuildWriteMesh2(VecArr, NormArr, UVArr, U, V, FileName)\n')
|
||||
# suppressed some file checking from original macro because no more separate files
|
||||
file.write(' #local Write=0;\n')
|
||||
file.write(' #debug concat("\\n\\n Building mesh2: \\n - vertex_vectors\\n")\n')
|
||||
file.write(' #local NumVertices=dimension_size(VecArr,1);\n')
|
||||
file.write(' #switch (Write)\n')
|
||||
file.write(' #case(1)\n')
|
||||
file.write(' #write(\n')
|
||||
file.write(' MeshFile,\n')
|
||||
file.write(' " vertex_vectors {\\n",\n')
|
||||
file.write(' " ", str(NumVertices,0,0),"\\n "\n')
|
||||
file.write(' )\n')
|
||||
file.write(' #break\n')
|
||||
file.write(' #case(2)\n')
|
||||
file.write(' #write(\n')
|
||||
file.write(' MeshFile,\n')
|
||||
file.write(' "# Vertices: ",str(NumVertices,0,0),"\\n"\n')
|
||||
file.write(' )\n')
|
||||
file.write(' #break\n')
|
||||
file.write(' #case(3)\n')
|
||||
file.write(' #write(\n')
|
||||
file.write(' MeshFile,\n')
|
||||
file.write(' str(2*NumVertices,0,0),",\\n"\n')
|
||||
file.write(' )\n')
|
||||
file.write(' #break\n')
|
||||
file.write(' #case(4)\n')
|
||||
file.write(' #write(\n')
|
||||
file.write(' MeshFile,\n')
|
||||
file.write(' "#declare VertexVectors= array[",str(NumVertices,0,0),"] {\\n "\n')
|
||||
file.write(' )\n')
|
||||
file.write(' #break\n')
|
||||
file.write(' #end\n')
|
||||
file.write(' mesh2 {\n')
|
||||
file.write(' vertex_vectors {\n')
|
||||
file.write(' NumVertices\n')
|
||||
file.write(' #local I=0;\n')
|
||||
file.write(' #while (I<NumVertices)\n')
|
||||
file.write(' VecArr[I]\n')
|
||||
file.write(' #switch(Write)\n')
|
||||
file.write(' #case(1)\n')
|
||||
file.write(' #write(MeshFile, VecArr[I])\n')
|
||||
file.write(' #break\n')
|
||||
file.write(' #case(2)\n')
|
||||
file.write(' #write(\n')
|
||||
file.write(' MeshFile,\n')
|
||||
file.write(
|
||||
' "v ", VecArr[I].x," ", VecArr[I].y," ", VecArr[I].z,"\\n"\n'
|
||||
)
|
||||
file.write(' )\n')
|
||||
file.write(' #break\n')
|
||||
file.write(' #case(3)\n')
|
||||
file.write(' #write(\n')
|
||||
file.write(' MeshFile,\n')
|
||||
file.write(' VecArr[I].x,",", VecArr[I].y,",", VecArr[I].z,",\\n"\n')
|
||||
file.write(' )\n')
|
||||
file.write(' #break\n')
|
||||
file.write(' #case(4)\n')
|
||||
file.write(' #write(MeshFile, VecArr[I])\n')
|
||||
file.write(' #break\n')
|
||||
file.write(' #end\n')
|
||||
file.write(' #local I=I+1;\n')
|
||||
file.write(' #if(Write=1 | Write=4)\n')
|
||||
file.write(' #if(mod(I,3)=0)\n')
|
||||
file.write(' #write(MeshFile,"\\n ")\n')
|
||||
file.write(' #end\n')
|
||||
file.write(' #end \n')
|
||||
file.write(' #end\n')
|
||||
file.write(' #switch(Write)\n')
|
||||
file.write(' #case(1)\n')
|
||||
file.write(' #write(MeshFile,"\\n }\\n")\n')
|
||||
file.write(' #break\n')
|
||||
file.write(' #case(2)\n')
|
||||
file.write(' #write(MeshFile,"\\n")\n')
|
||||
file.write(' #break\n')
|
||||
file.write(' #case(3)\n')
|
||||
file.write(' // do nothing\n')
|
||||
file.write(' #break\n')
|
||||
file.write(' #case(4) \n')
|
||||
file.write(' #write(MeshFile,"\\n}\\n")\n')
|
||||
file.write(' #break\n')
|
||||
file.write(' #end\n')
|
||||
file.write(' }\n')
|
||||
|
||||
file.write(' #debug concat(" - normal_vectors\\n") \n')
|
||||
file.write(' #local NumVertices=dimension_size(NormArr,1);\n')
|
||||
file.write(' #switch(Write)\n')
|
||||
file.write(' #case(1)\n')
|
||||
file.write(' #write(\n')
|
||||
file.write(' MeshFile,\n')
|
||||
file.write(' " normal_vectors {\\n",\n')
|
||||
file.write(' " ", str(NumVertices,0,0),"\\n "\n')
|
||||
file.write(' )\n')
|
||||
file.write(' #break\n')
|
||||
file.write(' #case(2)\n')
|
||||
file.write(' #write(\n')
|
||||
file.write(' MeshFile,\n')
|
||||
file.write(' "# Normals: ",str(NumVertices,0,0),"\\n"\n')
|
||||
file.write(' )\n')
|
||||
file.write(' #break\n')
|
||||
file.write(' #case(3)\n')
|
||||
file.write(' // do nothing\n')
|
||||
file.write(' #break\n')
|
||||
file.write(' #case(4)\n')
|
||||
file.write(' #write(\n')
|
||||
file.write(' MeshFile,\n')
|
||||
file.write(
|
||||
' "#declare NormalVectors= array[",str(NumVertices,0,0),"] {\\n "\n'
|
||||
)
|
||||
file.write(' )\n')
|
||||
file.write(' #break\n')
|
||||
file.write(' #end\n')
|
||||
file.write(' normal_vectors {\n')
|
||||
file.write(' NumVertices\n')
|
||||
file.write(' #local I=0;\n')
|
||||
file.write(' #while (I<NumVertices)\n')
|
||||
file.write(' NormArr[I]\n')
|
||||
file.write(' #switch(Write)\n')
|
||||
file.write(' #case(1)\n')
|
||||
file.write(' #write(MeshFile NormArr[I])\n')
|
||||
file.write(' #break\n')
|
||||
file.write(' #case(2)\n')
|
||||
file.write(' #write(\n')
|
||||
file.write(' MeshFile,\n')
|
||||
file.write(
|
||||
' "vn ", NormArr[I].x," ", NormArr[I].y," ", NormArr[I].z,"\\n"\n'
|
||||
)
|
||||
file.write(' )\n')
|
||||
file.write(' #break\n')
|
||||
file.write(' #case(3)\n')
|
||||
file.write(' #write(\n')
|
||||
file.write(' MeshFile,\n')
|
||||
file.write(' NormArr[I].x,",", NormArr[I].y,",", NormArr[I].z,",\\n"\n')
|
||||
file.write(' )\n')
|
||||
file.write(' #break\n')
|
||||
file.write(' #case(4)\n')
|
||||
file.write(' #write(MeshFile NormArr[I])\n')
|
||||
file.write(' #break\n')
|
||||
file.write(' #end\n')
|
||||
file.write(' #local I=I+1;\n')
|
||||
file.write(' #if(Write=1 | Write=4) \n')
|
||||
file.write(' #if(mod(I,3)=0)\n')
|
||||
file.write(' #write(MeshFile,"\\n ")\n')
|
||||
file.write(' #end\n')
|
||||
file.write(' #end\n')
|
||||
file.write(' #end\n')
|
||||
file.write(' #switch(Write)\n')
|
||||
file.write(' #case(1)\n')
|
||||
file.write(' #write(MeshFile,"\\n }\\n")\n')
|
||||
file.write(' #break\n')
|
||||
file.write(' #case(2)\n')
|
||||
file.write(' #write(MeshFile,"\\n")\n')
|
||||
file.write(' #break\n')
|
||||
file.write(' #case(3)\n')
|
||||
file.write(' //do nothing\n')
|
||||
file.write(' #break\n')
|
||||
file.write(' #case(4)\n')
|
||||
file.write(' #write(MeshFile,"\\n}\\n")\n')
|
||||
file.write(' #break\n')
|
||||
file.write(' #end\n')
|
||||
file.write(' }\n')
|
||||
|
||||
file.write(' #debug concat(" - uv_vectors\\n") \n')
|
||||
file.write(' #local NumVertices=dimension_size(UVArr,1);\n')
|
||||
file.write(' #switch(Write)\n')
|
||||
file.write(' #case(1)\n')
|
||||
file.write(' #write(\n')
|
||||
file.write(' MeshFile, \n')
|
||||
file.write(' " uv_vectors {\\n",\n')
|
||||
file.write(' " ", str(NumVertices,0,0),"\\n "\n')
|
||||
file.write(' )\n')
|
||||
file.write(' #break\n')
|
||||
file.write(' #case(2)\n')
|
||||
file.write(' #write(\n')
|
||||
file.write(' MeshFile,\n')
|
||||
file.write(' "# UV-vectors: ",str(NumVertices,0,0),"\\n"\n')
|
||||
file.write(' )\n')
|
||||
file.write(' #break\n')
|
||||
file.write(' #case(3)\n')
|
||||
file.write(' // do nothing, *.pcm does not support uv-vectors\n')
|
||||
file.write(' #break\n')
|
||||
file.write(' #case(4)\n')
|
||||
file.write(' #write(\n')
|
||||
file.write(' MeshFile,\n')
|
||||
file.write(' "#declare UVVectors= array[",str(NumVertices,0,0),"] {\\n "\n')
|
||||
file.write(' )\n')
|
||||
file.write(' #break\n')
|
||||
file.write(' #end\n')
|
||||
file.write(' uv_vectors {\n')
|
||||
file.write(' NumVertices\n')
|
||||
file.write(' #local I=0;\n')
|
||||
file.write(' #while (I<NumVertices)\n')
|
||||
file.write(' UVArr[I]\n')
|
||||
file.write(' #switch(Write)\n')
|
||||
file.write(' #case(1)\n')
|
||||
file.write(' #write(MeshFile UVArr[I])\n')
|
||||
file.write(' #break\n')
|
||||
file.write(' #case(2)\n')
|
||||
file.write(' #write(\n')
|
||||
file.write(' MeshFile,\n')
|
||||
file.write(' "vt ", UVArr[I].u," ", UVArr[I].v,"\\n"\n')
|
||||
file.write(' )\n')
|
||||
file.write(' #break\n')
|
||||
file.write(' #case(3)\n')
|
||||
file.write(' //do nothing\n')
|
||||
file.write(' #break\n')
|
||||
file.write(' #case(4)\n')
|
||||
file.write(' #write(MeshFile UVArr[I])\n')
|
||||
file.write(' #break\n')
|
||||
file.write(' #end\n')
|
||||
file.write(' #local I=I+1; \n')
|
||||
file.write(' #if(Write=1 | Write=4)\n')
|
||||
file.write(' #if(mod(I,3)=0)\n')
|
||||
file.write(' #write(MeshFile,"\\n ")\n')
|
||||
file.write(' #end \n')
|
||||
file.write(' #end\n')
|
||||
file.write(' #end \n')
|
||||
file.write(' #switch(Write)\n')
|
||||
file.write(' #case(1)\n')
|
||||
file.write(' #write(MeshFile,"\\n }\\n")\n')
|
||||
file.write(' #break\n')
|
||||
file.write(' #case(2)\n')
|
||||
file.write(' #write(MeshFile,"\\n")\n')
|
||||
file.write(' #break\n')
|
||||
file.write(' #case(3)\n')
|
||||
file.write(' //do nothing\n')
|
||||
file.write(' #break\n')
|
||||
file.write(' #case(4)\n')
|
||||
file.write(' #write(MeshFile,"\\n}\\n")\n')
|
||||
file.write(' #break\n')
|
||||
file.write(' #end\n')
|
||||
file.write(' }\n')
|
||||
file.write('\n')
|
||||
file.write(' #debug concat(" - face_indices\\n") \n')
|
||||
file.write(' #declare NumFaces=U*V*2;\n')
|
||||
file.write(' #switch(Write)\n')
|
||||
file.write(' #case(1)\n')
|
||||
file.write(' #write(\n')
|
||||
file.write(' MeshFile,\n')
|
||||
file.write(' " face_indices {\\n"\n')
|
||||
file.write(' " ", str(NumFaces,0,0),"\\n "\n')
|
||||
file.write(' )\n')
|
||||
file.write(' #break\n')
|
||||
file.write(' #case(2)\n')
|
||||
file.write(' #write (\n')
|
||||
file.write(' MeshFile,\n')
|
||||
file.write(' "# faces: ",str(NumFaces,0,0),"\\n"\n')
|
||||
file.write(' )\n')
|
||||
file.write(' #break\n')
|
||||
file.write(' #case(3)\n')
|
||||
file.write(' #write (\n')
|
||||
file.write(' MeshFile,\n')
|
||||
file.write(' "0,",str(NumFaces,0,0),",\\n"\n')
|
||||
file.write(' )\n')
|
||||
file.write(' #break\n')
|
||||
file.write(' #case(4)\n')
|
||||
file.write(' #write(\n')
|
||||
file.write(' MeshFile,\n')
|
||||
file.write(' "#declare FaceIndices= array[",str(NumFaces,0,0),"] {\\n "\n')
|
||||
file.write(' )\n')
|
||||
file.write(' #break\n')
|
||||
file.write(' #end\n')
|
||||
file.write(' face_indices {\n')
|
||||
file.write(' NumFaces\n')
|
||||
file.write(' #local I=0;\n')
|
||||
file.write(' #local H=0;\n')
|
||||
file.write(' #local NumVertices=dimension_size(VecArr,1);\n')
|
||||
file.write(' #while (I<V)\n')
|
||||
file.write(' #local J=0;\n')
|
||||
file.write(' #while (J<U)\n')
|
||||
file.write(' #local Ind=(I*U)+I+J;\n')
|
||||
file.write(' <Ind, Ind+1, Ind+U+2>, <Ind, Ind+U+1, Ind+U+2>\n')
|
||||
file.write(' #switch(Write)\n')
|
||||
file.write(' #case(1)\n')
|
||||
file.write(' #write(\n')
|
||||
file.write(' MeshFile,\n')
|
||||
file.write(' <Ind, Ind+1, Ind+U+2>, <Ind, Ind+U+1, Ind+U+2>\n')
|
||||
file.write(' )\n')
|
||||
file.write(' #break\n')
|
||||
file.write(' #case(2)\n')
|
||||
file.write(' #write(\n')
|
||||
file.write(' MeshFile,\n')
|
||||
file.write(
|
||||
' "f ",Ind+1,"/",Ind+1,"/",Ind+1," ",Ind+1+1,"/",Ind+1+1,"/",Ind+1+1," ",Ind+U+2+1,"/",Ind+U+2+1,"/",Ind+U+2+1,"\\n",\n'
|
||||
)
|
||||
file.write(
|
||||
' "f ",Ind+U+1+1,"/",Ind+U+1+1,"/",Ind+U+1+1," ",Ind+1,"/",Ind+1,"/",Ind+1," ",Ind+U+2+1,"/",Ind+U+2+1,"/",Ind+U+2+1,"\\n"\n'
|
||||
)
|
||||
file.write(' )\n')
|
||||
file.write(' #break\n')
|
||||
file.write(' #case(3)\n')
|
||||
file.write(' #write(\n')
|
||||
file.write(' MeshFile,\n')
|
||||
file.write(
|
||||
' Ind,",",Ind+NumVertices,",",Ind+1,",",Ind+1+NumVertices,",",Ind+U+2,",",Ind+U+2+NumVertices,",\\n"\n'
|
||||
)
|
||||
file.write(
|
||||
' Ind+U+1,",",Ind+U+1+NumVertices,",",Ind,",",Ind+NumVertices,",",Ind+U+2,",",Ind+U+2+NumVertices,",\\n"\n'
|
||||
)
|
||||
file.write(' )\n')
|
||||
file.write(' #break\n')
|
||||
file.write(' #case(4)\n')
|
||||
file.write(' #write(\n')
|
||||
file.write(' MeshFile,\n')
|
||||
file.write(' <Ind, Ind+1, Ind+U+2>, <Ind, Ind+U+1, Ind+U+2>\n')
|
||||
file.write(' )\n')
|
||||
file.write(' #break\n')
|
||||
file.write(' #end\n')
|
||||
file.write(' #local J=J+1;\n')
|
||||
file.write(' #local H=H+1;\n')
|
||||
file.write(' #if(Write=1 | Write=4)\n')
|
||||
file.write(' #if(mod(H,3)=0)\n')
|
||||
file.write(' #write(MeshFile,"\\n ")\n')
|
||||
file.write(' #end \n')
|
||||
file.write(' #end\n')
|
||||
file.write(' #end\n')
|
||||
file.write(' #local I=I+1;\n')
|
||||
file.write(' #end\n')
|
||||
file.write(' }\n')
|
||||
file.write(' #switch(Write)\n')
|
||||
file.write(' #case(1)\n')
|
||||
file.write(' #write(MeshFile, "\\n }\\n}")\n')
|
||||
file.write(' #fclose MeshFile\n')
|
||||
file.write(' #debug concat(" Done writing\\n")\n')
|
||||
file.write(' #break\n')
|
||||
file.write(' #case(2)\n')
|
||||
file.write(' #fclose MeshFile\n')
|
||||
file.write(' #debug concat(" Done writing\\n")\n')
|
||||
file.write(' #break\n')
|
||||
file.write(' #case(3)\n')
|
||||
file.write(' #fclose MeshFile\n')
|
||||
file.write(' #debug concat(" Done writing\\n")\n')
|
||||
file.write(' #break\n')
|
||||
file.write(' #case(4)\n')
|
||||
file.write(' #write(MeshFile, "\\n}\\n}")\n')
|
||||
file.write(' #fclose MeshFile\n')
|
||||
file.write(' #debug concat(" Done writing\\n")\n')
|
||||
file.write(' #break\n')
|
||||
file.write(' #end\n')
|
||||
file.write(' }\n')
|
||||
file.write('#end\n')
|
||||
|
||||
file.write('#macro MSM(SplineArray, SplRes, Interp_type, InterpRes, FileName)\n')
|
||||
file.write(' #declare Build=CheckFileName(FileName);\n')
|
||||
file.write(' #if(Build=0)\n')
|
||||
file.write(' #debug concat("\\n Parsing mesh2 from file: ", FileName, "\\n")\n')
|
||||
file.write(' #include FileName\n')
|
||||
file.write(' object{Surface}\n')
|
||||
file.write(' #else\n')
|
||||
file.write(' #local NumVertices=(SplRes+1)*(InterpRes+1);\n')
|
||||
file.write(' #local NumFaces=SplRes*InterpRes*2;\n')
|
||||
file.write(
|
||||
' #debug concat("\\n Calculating ",str(NumVertices,0,0)," vertices for ", str(NumFaces,0,0)," triangles\\n\\n")\n'
|
||||
)
|
||||
file.write(' #local VecArr=array[NumVertices]\n')
|
||||
file.write(' #local NormArr=array[NumVertices]\n')
|
||||
file.write(' #local UVArr=array[NumVertices]\n')
|
||||
file.write(' #local N=dimension_size(SplineArray,1);\n')
|
||||
file.write(' #local TempSplArr0=array[N];\n')
|
||||
file.write(' #local TempSplArr1=array[N];\n')
|
||||
file.write(' #local TempSplArr2=array[N];\n')
|
||||
file.write(' #local PosStep=1/SplRes;\n')
|
||||
file.write(' #local InterpStep=1/InterpRes;\n')
|
||||
file.write(' #local Count=0;\n')
|
||||
file.write(' #local Pos=0;\n')
|
||||
file.write(' #while(Pos<=1)\n')
|
||||
file.write(' #local I=0;\n')
|
||||
file.write(' #if (Pos=0)\n')
|
||||
file.write(' #while (I<N)\n')
|
||||
file.write(' #local Spl=spline{SplineArray[I]}\n')
|
||||
file.write(' #local TempSplArr0[I]=<0,0,0>+Spl(Pos);\n')
|
||||
file.write(' #local TempSplArr1[I]=<0,0,0>+Spl(Pos+PosStep);\n')
|
||||
file.write(' #local TempSplArr2[I]=<0,0,0>+Spl(Pos-PosStep);\n')
|
||||
file.write(' #local I=I+1;\n')
|
||||
file.write(' #end\n')
|
||||
file.write(' #local S0=BuildSpline(TempSplArr0, Interp_type)\n')
|
||||
file.write(' #local S1=BuildSpline(TempSplArr1, Interp_type)\n')
|
||||
file.write(' #local S2=BuildSpline(TempSplArr2, Interp_type)\n')
|
||||
file.write(' #else\n')
|
||||
file.write(' #while (I<N)\n')
|
||||
file.write(' #local Spl=spline{SplineArray[I]}\n')
|
||||
file.write(' #local TempSplArr1[I]=<0,0,0>+Spl(Pos+PosStep);\n')
|
||||
file.write(' #local I=I+1;\n')
|
||||
file.write(' #end\n')
|
||||
file.write(' #local S1=BuildSpline(TempSplArr1, Interp_type)\n')
|
||||
file.write(' #end\n')
|
||||
file.write(' #local J=0;\n')
|
||||
file.write(' #while (J<=1)\n')
|
||||
file.write(' #local P0=<0,0,0>+S0(J);\n')
|
||||
file.write(' #local P1=<0,0,0>+S1(J);\n')
|
||||
file.write(' #local P2=<0,0,0>+S2(J);\n')
|
||||
file.write(' #local P3=<0,0,0>+S0(J+InterpStep);\n')
|
||||
file.write(' #local P4=<0,0,0>+S0(J-InterpStep);\n')
|
||||
file.write(' #local B1=P4-P0;\n')
|
||||
file.write(' #local B2=P2-P0;\n')
|
||||
file.write(' #local B3=P3-P0;\n')
|
||||
file.write(' #local B4=P1-P0;\n')
|
||||
file.write(' #local N1=vcross(B1,B2);\n')
|
||||
file.write(' #local N2=vcross(B2,B3);\n')
|
||||
file.write(' #local N3=vcross(B3,B4);\n')
|
||||
file.write(' #local N4=vcross(B4,B1);\n')
|
||||
file.write(' #local Norm=vnormalize((N1+N2+N3+N4));\n')
|
||||
file.write(' #local VecArr[Count]=P0;\n')
|
||||
file.write(' #local NormArr[Count]=Norm;\n')
|
||||
file.write(' #local UVArr[Count]=<J,Pos>;\n')
|
||||
file.write(' #local J=J+InterpStep;\n')
|
||||
file.write(' #local Count=Count+1;\n')
|
||||
file.write(' #end\n')
|
||||
file.write(' #local S2=spline{S0}\n')
|
||||
file.write(' #local S0=spline{S1}\n')
|
||||
file.write(
|
||||
' #debug concat("\\r Done ", str(Count,0,0)," vertices : ", str(100*Count/NumVertices,0,2)," %")\n'
|
||||
)
|
||||
file.write(' #local Pos=Pos+PosStep;\n')
|
||||
file.write(' #end\n')
|
||||
file.write(' BuildWriteMesh2(VecArr, NormArr, UVArr, InterpRes, SplRes, "")\n')
|
||||
file.write(' #end\n')
|
||||
file.write('#end\n\n')
|
||||
|
||||
file.write('#macro Coons(Spl1, Spl2, Spl3, Spl4, Iter_U, Iter_V, FileName)\n')
|
||||
file.write(' #declare Build=CheckFileName(FileName);\n')
|
||||
file.write(' #if(Build=0)\n')
|
||||
file.write(' #debug concat("\\n Parsing mesh2 from file: ", FileName, "\\n")\n')
|
||||
file.write(' #include FileName\n')
|
||||
file.write(' object{Surface}\n')
|
||||
file.write(' #else\n')
|
||||
file.write(' #local NumVertices=(Iter_U+1)*(Iter_V+1);\n')
|
||||
file.write(' #local NumFaces=Iter_U*Iter_V*2;\n')
|
||||
file.write(
|
||||
' #debug concat("\\n Calculating ", str(NumVertices,0,0), " vertices for ",str(NumFaces,0,0), " triangles\\n\\n")\n'
|
||||
)
|
||||
file.write(' #declare VecArr=array[NumVertices] \n')
|
||||
file.write(' #declare NormArr=array[NumVertices] \n')
|
||||
file.write(' #local UVArr=array[NumVertices] \n')
|
||||
file.write(' #local Spl1_0=Spl1(0);\n')
|
||||
file.write(' #local Spl2_0=Spl2(0);\n')
|
||||
file.write(' #local Spl3_0=Spl3(0);\n')
|
||||
file.write(' #local Spl4_0=Spl4(0);\n')
|
||||
file.write(' #local UStep=1/Iter_U;\n')
|
||||
file.write(' #local VStep=1/Iter_V;\n')
|
||||
file.write(' #local Count=0;\n')
|
||||
file.write(' #local I=0;\n')
|
||||
file.write(' #while (I<=1)\n')
|
||||
file.write(' #local Im=1-I;\n')
|
||||
file.write(' #local J=0;\n')
|
||||
file.write(' #while (J<=1)\n')
|
||||
file.write(' #local Jm=1-J;\n')
|
||||
file.write(
|
||||
' #local C0=Im*Jm*(Spl1_0)+Im*J*(Spl2_0)+I*J*(Spl3_0)+I*Jm*(Spl4_0);\n'
|
||||
)
|
||||
file.write(' #local P0=LInterpolate(I, Spl1(J), Spl3(Jm)) + \n')
|
||||
file.write(' LInterpolate(Jm, Spl2(I), Spl4(Im))-C0;\n')
|
||||
file.write(' #declare VecArr[Count]=P0;\n')
|
||||
file.write(' #local UVArr[Count]=<J,I>;\n')
|
||||
file.write(' #local J=J+UStep;\n')
|
||||
file.write(' #local Count=Count+1;\n')
|
||||
file.write(' #end\n')
|
||||
file.write(' #debug concat(\n')
|
||||
file.write(' "\r Done ", str(Count,0,0)," vertices : ",\n')
|
||||
file.write(' str(100*Count/NumVertices,0,2)," %"\n')
|
||||
file.write(' )\n')
|
||||
file.write(' #local I=I+VStep;\n')
|
||||
file.write(' #end\n')
|
||||
file.write(' #debug "\r Normals "\n')
|
||||
file.write(' #local Count=0;\n')
|
||||
file.write(' #local I=0;\n')
|
||||
file.write(' #while (I<=Iter_V)\n')
|
||||
file.write(' #local J=0;\n')
|
||||
file.write(' #while (J<=Iter_U)\n')
|
||||
file.write(' #local Ind=(I*Iter_U)+I+J;\n')
|
||||
file.write(' #local P0=VecArr[Ind];\n')
|
||||
file.write(' #if(J=0)\n')
|
||||
file.write(' #local P1=P0+(P0-VecArr[Ind+1]);\n')
|
||||
file.write(' #else\n')
|
||||
file.write(' #local P1=VecArr[Ind-1];\n')
|
||||
file.write(' #end\n')
|
||||
file.write(' #if (J=Iter_U)\n')
|
||||
file.write(' #local P2=P0+(P0-VecArr[Ind-1]);\n')
|
||||
file.write(' #else\n')
|
||||
file.write(' #local P2=VecArr[Ind+1];\n')
|
||||
file.write(' #end\n')
|
||||
file.write(' #if (I=0)\n')
|
||||
file.write(' #local P3=P0+(P0-VecArr[Ind+Iter_U+1]);\n')
|
||||
file.write(' #else\n')
|
||||
file.write(' #local P3=VecArr[Ind-Iter_U-1];\n')
|
||||
file.write(' #end\n')
|
||||
file.write(' #if (I=Iter_V)\n')
|
||||
file.write(' #local P4=P0+(P0-VecArr[Ind-Iter_U-1]);\n')
|
||||
file.write(' #else\n')
|
||||
file.write(' #local P4=VecArr[Ind+Iter_U+1];\n')
|
||||
file.write(' #end\n')
|
||||
file.write(' #local B1=P4-P0;\n')
|
||||
file.write(' #local B2=P2-P0;\n')
|
||||
file.write(' #local B3=P3-P0;\n')
|
||||
file.write(' #local B4=P1-P0;\n')
|
||||
file.write(' #local N1=vcross(B1,B2);\n')
|
||||
file.write(' #local N2=vcross(B2,B3);\n')
|
||||
file.write(' #local N3=vcross(B3,B4);\n')
|
||||
file.write(' #local N4=vcross(B4,B1);\n')
|
||||
file.write(' #local Norm=vnormalize((N1+N2+N3+N4));\n')
|
||||
file.write(' #declare NormArr[Count]=Norm;\n')
|
||||
file.write(' #local J=J+1;\n')
|
||||
file.write(' #local Count=Count+1;\n')
|
||||
file.write(' #end\n')
|
||||
file.write(
|
||||
' #debug concat("\r Done ", str(Count,0,0)," normals : ",str(100*Count/NumVertices,0,2), " %")\n'
|
||||
)
|
||||
file.write(' #local I=I+1;\n')
|
||||
file.write(' #end\n')
|
||||
file.write(' BuildWriteMesh2(VecArr, NormArr, UVArr, Iter_U, Iter_V, FileName)\n')
|
||||
file.write(' #end\n')
|
||||
file.write('#end\n\n')
|
||||
# Empty curves
|
||||
if len(ob.data.splines) == 0:
|
||||
tab_write("\n//dummy sphere to represent empty curve location\n")
|
||||
tab_write("#declare %s =\n" % dataname)
|
||||
tab_write(
|
||||
"sphere {<%.6g, %.6g, %.6g>,0 pigment{rgbt 1} no_image no_reflection no_radiosity photons{pass_through collect off} hollow}\n\n"
|
||||
% (ob.location.x, ob.location.y, ob.location.z)
|
||||
) # ob.name > povdataname)
|
||||
# And non empty curves
|
||||
else:
|
||||
if not bezier_sweep:
|
||||
tab_write("#declare %s =\n" % dataname)
|
||||
if ob.pov.curveshape == 'sphere_sweep' and not bezier_sweep:
|
||||
tab_write("union {\n")
|
||||
for spl in ob.data.splines:
|
||||
if spl.type != "BEZIER":
|
||||
spl_type = "linear"
|
||||
if spl.type == "NURBS":
|
||||
spl_type = "cubic"
|
||||
points = spl.points
|
||||
num_points = len(points)
|
||||
if spl.use_cyclic_u:
|
||||
num_points += 3
|
||||
|
||||
tab_write("sphere_sweep { %s_spline %s,\n" % (spl_type, num_points))
|
||||
if spl.use_cyclic_u:
|
||||
pt1 = points[len(points) - 1]
|
||||
wpt1 = pt1.co
|
||||
tab_write(
|
||||
"<%.4g,%.4g,%.4g>,%.4g\n"
|
||||
% (wpt1[0], wpt1[1], wpt1[2], pt1.radius * ob.data.bevel_depth)
|
||||
)
|
||||
for pt in points:
|
||||
wpt = pt.co
|
||||
tab_write(
|
||||
"<%.4g,%.4g,%.4g>,%.4g\n"
|
||||
% (wpt[0], wpt[1], wpt[2], pt.radius * ob.data.bevel_depth)
|
||||
)
|
||||
if spl.use_cyclic_u:
|
||||
for i in range(0, 2):
|
||||
end_pt = points[i]
|
||||
wpt = end_pt.co
|
||||
tab_write(
|
||||
"<%.4g,%.4g,%.4g>,%.4g\n"
|
||||
% (wpt[0], wpt[1], wpt[2], end_pt.radius * ob.data.bevel_depth)
|
||||
)
|
||||
|
||||
tab_write("}\n")
|
||||
# below not used yet?
|
||||
if ob.pov.curveshape == 'sor':
|
||||
for spl in ob.data.splines:
|
||||
if spl.type in {'POLY', 'NURBS'}:
|
||||
points = spl.points
|
||||
num_points = len(points)
|
||||
tab_write("sor { %s,\n" % num_points)
|
||||
for pt in points:
|
||||
wpt = pt.co
|
||||
tab_write("<%.4g,%.4g>\n" % (wpt[0], wpt[1]))
|
||||
else:
|
||||
tab_write("box { 0,0\n")
|
||||
if ob.pov.curveshape in {'lathe', 'prism'}:
|
||||
spl = ob.data.splines[0]
|
||||
if spl.type == "BEZIER":
|
||||
points = spl.bezier_points
|
||||
len_cur = len(points) - 1
|
||||
len_pts = len_cur * 4
|
||||
ifprism = ''
|
||||
if ob.pov.curveshape in {'prism'}:
|
||||
height = ob.data.extrude
|
||||
ifprism = '-%s, %s,' % (height, height)
|
||||
len_cur += 1
|
||||
len_pts += 4
|
||||
tab_write("%s { bezier_spline %s %s,\n" % (ob.pov.curveshape, ifprism, len_pts))
|
||||
for i in range(0, len_cur):
|
||||
p1 = points[i].co
|
||||
pR = points[i].handle_right
|
||||
end = i + 1
|
||||
if i == len_cur - 1 and ob.pov.curveshape in {'prism'}:
|
||||
end = 0
|
||||
pL = points[end].handle_left
|
||||
p2 = points[end].co
|
||||
line = "<%.4g,%.4g>" % (p1[0], p1[1])
|
||||
line += "<%.4g,%.4g>" % (pR[0], pR[1])
|
||||
line += "<%.4g,%.4g>" % (pL[0], pL[1])
|
||||
line += "<%.4g,%.4g>" % (p2[0], p2[1])
|
||||
tab_write("%s\n" % line)
|
||||
else:
|
||||
points = spl.points
|
||||
len_cur = len(points)
|
||||
len_pts = len_cur
|
||||
ifprism = ''
|
||||
if ob.pov.curveshape in {'prism'}:
|
||||
height = ob.data.extrude
|
||||
ifprism = '-%s, %s,' % (height, height)
|
||||
len_pts += 3
|
||||
spl_type = 'quadratic'
|
||||
if spl.type == 'POLY':
|
||||
spl_type = 'linear'
|
||||
tab_write(
|
||||
"%s { %s_spline %s %s,\n" % (ob.pov.curveshape, spl_type, ifprism, len_pts)
|
||||
)
|
||||
if ob.pov.curveshape in {'prism'}:
|
||||
pt = points[len(points) - 1]
|
||||
wpt = pt.co
|
||||
tab_write("<%.4g,%.4g>\n" % (wpt[0], wpt[1]))
|
||||
for pt in points:
|
||||
wpt = pt.co
|
||||
tab_write("<%.4g,%.4g>\n" % (wpt[0], wpt[1]))
|
||||
if ob.pov.curveshape in {'prism'}:
|
||||
for i in range(2):
|
||||
pt = points[i]
|
||||
wpt = pt.co
|
||||
tab_write("<%.4g,%.4g>\n" % (wpt[0], wpt[1]))
|
||||
if bezier_sweep:
|
||||
for p in range(len(ob.data.splines)):
|
||||
br = []
|
||||
depth = ob.data.bevel_depth
|
||||
spl = ob.data.splines[p]
|
||||
points = spl.bezier_points
|
||||
len_cur = len(points) - 1
|
||||
num_points = len_cur * 4
|
||||
if spl.use_cyclic_u:
|
||||
len_cur += 1
|
||||
num_points += 4
|
||||
tab_write("#declare %s_points_%s = array[%s]{\n" % (dataname, p, num_points))
|
||||
for i in range(len_cur):
|
||||
p1 = points[i].co
|
||||
pR = points[i].handle_right
|
||||
end = i + 1
|
||||
if spl.use_cyclic_u and i == (len_cur - 1):
|
||||
end = 0
|
||||
pL = points[end].handle_left
|
||||
p2 = points[end].co
|
||||
r3 = points[end].radius * depth
|
||||
r0 = points[i].radius * depth
|
||||
r1 = 2 / 3 * r0 + 1 / 3 * r3
|
||||
r2 = 1 / 3 * r0 + 2 / 3 * r3
|
||||
br.append((r0, r1, r2, r3))
|
||||
line = "<%.4g,%.4g,%.4f>" % (p1[0], p1[1], p1[2])
|
||||
line += "<%.4g,%.4g,%.4f>" % (pR[0], pR[1], pR[2])
|
||||
line += "<%.4g,%.4g,%.4f>" % (pL[0], pL[1], pL[2])
|
||||
line += "<%.4g,%.4g,%.4f>" % (p2[0], p2[1], p2[2])
|
||||
tab_write("%s\n" % line)
|
||||
tab_write("}\n")
|
||||
tab_write("#declare %s_radii_%s = array[%s]{\n" % (dataname, p, len(br) * 4))
|
||||
for rad_tuple in br:
|
||||
tab_write(
|
||||
'%.4f,%.4f,%.4f,%.4f\n'
|
||||
% (rad_tuple[0], rad_tuple[1], rad_tuple[2], rad_tuple[3])
|
||||
)
|
||||
tab_write("}\n")
|
||||
if len(ob.data.splines) == 1:
|
||||
tab_write('#declare %s = object{\n' % dataname)
|
||||
tab_write(
|
||||
' Shape_Bezierpoints_Sphere_Sweep(yes,%s, %s_points_%s, %s_radii_%s) \n'
|
||||
% (ob.data.resolution_u, dataname, p, dataname, p)
|
||||
)
|
||||
else:
|
||||
tab_write('#declare %s = union{\n' % dataname)
|
||||
for p in range(len(ob.data.splines)):
|
||||
tab_write(
|
||||
' object{Shape_Bezierpoints_Sphere_Sweep(yes,%s, %s_points_%s, %s_radii_%s)} \n'
|
||||
% (ob.data.resolution_u, dataname, p, dataname, p)
|
||||
)
|
||||
# tab_write('#include "bezier_spheresweep.inc"\n') #now inlined
|
||||
# tab_write('#declare %s = object{Shape_Bezierpoints_Sphere_Sweep(yes,%s, %s_bezier_points, %.4f) \n'%(dataname,ob.data.resolution_u,dataname,ob.data.bevel_depth))
|
||||
if ob.pov.curveshape in {'loft'}:
|
||||
tab_write('object {MSM(%s,%s,"c",%s,"")\n' % (dataname, ob.pov.res_u, ob.pov.res_v))
|
||||
if ob.pov.curveshape in {'birail'}:
|
||||
splines = '%s1,%s2,%s3,%s4' % (dataname, dataname, dataname, dataname)
|
||||
tab_write('object {Coons(%s, %s, %s, "")\n' % (splines, ob.pov.res_u, ob.pov.res_v))
|
||||
pov_mat_name = "Default_texture"
|
||||
if ob.active_material:
|
||||
# pov_mat_name = string_strip_hyphen(bpy.path.clean_name(ob.active_material.name))
|
||||
try:
|
||||
material = ob.active_material
|
||||
write_object_material(material, ob, tab_write)
|
||||
except IndexError:
|
||||
print(ob.data)
|
||||
# tab_write("texture {%s}\n"%pov_mat_name)
|
||||
if ob.pov.curveshape in {'prism'}:
|
||||
tab_write("rotate <90,0,0>\n")
|
||||
tab_write("scale y*-1\n")
|
||||
tab_write("}\n")
|
|
@ -0,0 +1,731 @@
|
|||
# ##### BEGIN GPL LICENSE BLOCK #####
|
||||
#
|
||||
# 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 2
|
||||
# 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
|
||||
# MERCHANTABILITY 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, write to the Free Software Foundation,
|
||||
# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
#
|
||||
# ##### END GPL LICENSE BLOCK #####
|
||||
|
||||
# <pep8 compliant>
|
||||
"""User interface for the POV tools"""
|
||||
|
||||
import bpy
|
||||
|
||||
from bpy.utils import register_class, unregister_class
|
||||
from bpy.types import (
|
||||
# Operator,
|
||||
Menu,
|
||||
Panel,
|
||||
)
|
||||
|
||||
|
||||
# Example of wrapping every class 'as is'
|
||||
from bl_ui import properties_data_modifier
|
||||
|
||||
for member in dir(properties_data_modifier):
|
||||
subclass = getattr(properties_data_modifier, member)
|
||||
try:
|
||||
subclass.COMPAT_ENGINES.add('POVRAY_RENDER')
|
||||
except BaseException as e:
|
||||
print(e.__doc__)
|
||||
print('An exception occurred: {}'.format(e))
|
||||
del properties_data_modifier
|
||||
|
||||
|
||||
from bl_ui import properties_data_mesh
|
||||
|
||||
# These panels are kept
|
||||
properties_data_mesh.DATA_PT_custom_props_mesh.COMPAT_ENGINES.add('POVRAY_RENDER')
|
||||
properties_data_mesh.DATA_PT_context_mesh.COMPAT_ENGINES.add('POVRAY_RENDER')
|
||||
|
||||
## make some native panels contextual to some object variable
|
||||
## by recreating custom panels inheriting their properties
|
||||
|
||||
|
||||
from .scripting_gui import VIEW_MT_POV_import
|
||||
|
||||
|
||||
class ModifierButtonsPanel:
|
||||
"""Use this class to define buttons from the modifier tab of
|
||||
properties window."""
|
||||
|
||||
bl_space_type = 'PROPERTIES'
|
||||
bl_region_type = 'WINDOW'
|
||||
bl_context = "modifier"
|
||||
# COMPAT_ENGINES must be defined in each subclass, external engines can add themselves here
|
||||
|
||||
@classmethod
|
||||
def poll(cls, context):
|
||||
mods = context.object.modifiers
|
||||
rd = context.scene.render
|
||||
return mods and (rd.engine in cls.COMPAT_ENGINES)
|
||||
|
||||
|
||||
class ObjectButtonsPanel:
|
||||
"""Use this class to define buttons from the object tab of
|
||||
properties window."""
|
||||
|
||||
bl_space_type = 'PROPERTIES'
|
||||
bl_region_type = 'WINDOW'
|
||||
bl_context = "object"
|
||||
# COMPAT_ENGINES must be defined in each subclass, external engines can add themselves here
|
||||
|
||||
@classmethod
|
||||
def poll(cls, context):
|
||||
obj = context.object
|
||||
rd = context.scene.render
|
||||
return obj and (rd.engine in cls.COMPAT_ENGINES)
|
||||
|
||||
|
||||
class PovDataButtonsPanel(properties_data_mesh.MeshButtonsPanel):
|
||||
"""Use this class to define buttons from the edit data tab of
|
||||
properties window."""
|
||||
|
||||
COMPAT_ENGINES = {'POVRAY_RENDER'}
|
||||
POV_OBJECT_TYPES = {
|
||||
'PLANE',
|
||||
'BOX',
|
||||
'SPHERE',
|
||||
'CYLINDER',
|
||||
'CONE',
|
||||
'TORUS',
|
||||
'BLOB',
|
||||
'ISOSURFACE',
|
||||
'SUPERELLIPSOID',
|
||||
'SUPERTORUS',
|
||||
'HEIGHT_FIELD',
|
||||
'PARAMETRIC',
|
||||
'POLYCIRCLE',
|
||||
}
|
||||
|
||||
@classmethod
|
||||
def poll(cls, context):
|
||||
engine = context.scene.render.engine
|
||||
obj = context.object
|
||||
# We use our parent class poll func too, avoids to re-define too much things...
|
||||
return (
|
||||
super(PovDataButtonsPanel, cls).poll(context)
|
||||
and obj
|
||||
and obj.pov.object_as not in cls.POV_OBJECT_TYPES
|
||||
)
|
||||
|
||||
|
||||
# We cannot inherit from RNA classes (like e.g. properties_data_mesh.DATA_PT_vertex_groups).
|
||||
# Complex py/bpy/rna interactions (with metaclass and all) simply do not allow it to work.
|
||||
# So we simply have to explicitly copy here the interesting bits. ;)
|
||||
class DATA_PT_POV_normals(PovDataButtonsPanel, Panel):
|
||||
bl_label = properties_data_mesh.DATA_PT_normals.bl_label
|
||||
|
||||
draw = properties_data_mesh.DATA_PT_normals.draw
|
||||
|
||||
|
||||
class DATA_PT_POV_texture_space(PovDataButtonsPanel, Panel):
|
||||
bl_label = properties_data_mesh.DATA_PT_texture_space.bl_label
|
||||
bl_options = properties_data_mesh.DATA_PT_texture_space.bl_options
|
||||
|
||||
draw = properties_data_mesh.DATA_PT_texture_space.draw
|
||||
|
||||
|
||||
class DATA_PT_POV_vertex_groups(PovDataButtonsPanel, Panel):
|
||||
bl_label = properties_data_mesh.DATA_PT_vertex_groups.bl_label
|
||||
|
||||
draw = properties_data_mesh.DATA_PT_vertex_groups.draw
|
||||
|
||||
|
||||
class DATA_PT_POV_shape_keys(PovDataButtonsPanel, Panel):
|
||||
bl_label = properties_data_mesh.DATA_PT_shape_keys.bl_label
|
||||
|
||||
draw = properties_data_mesh.DATA_PT_shape_keys.draw
|
||||
|
||||
|
||||
class DATA_PT_POV_uv_texture(PovDataButtonsPanel, Panel):
|
||||
bl_label = properties_data_mesh.DATA_PT_uv_texture.bl_label
|
||||
|
||||
draw = properties_data_mesh.DATA_PT_uv_texture.draw
|
||||
|
||||
|
||||
class DATA_PT_POV_vertex_colors(PovDataButtonsPanel, Panel):
|
||||
bl_label = properties_data_mesh.DATA_PT_vertex_colors.bl_label
|
||||
|
||||
draw = properties_data_mesh.DATA_PT_vertex_colors.draw
|
||||
|
||||
|
||||
class DATA_PT_POV_customdata(PovDataButtonsPanel, Panel):
|
||||
bl_label = properties_data_mesh.DATA_PT_customdata.bl_label
|
||||
bl_options = properties_data_mesh.DATA_PT_customdata.bl_options
|
||||
draw = properties_data_mesh.DATA_PT_customdata.draw
|
||||
|
||||
|
||||
del properties_data_mesh
|
||||
|
||||
|
||||
class MODIFIERS_PT_POV_modifiers(ModifierButtonsPanel, Panel):
|
||||
"""Use this class to define pov modifier buttons. (For booleans)"""
|
||||
|
||||
bl_label = "POV-Ray"
|
||||
COMPAT_ENGINES = {'POVRAY_RENDER'}
|
||||
|
||||
# def draw_header(self, context):
|
||||
# scene = context.scene
|
||||
# self.layout.prop(scene.pov, "boolean_mod", text="")
|
||||
|
||||
def draw(self, context):
|
||||
# scene = context.scene
|
||||
layout = self.layout
|
||||
ob = context.object
|
||||
mod = ob.modifiers
|
||||
col = layout.column()
|
||||
# Find Boolean Modifiers for displaying CSG option
|
||||
onceCSG = 0
|
||||
for mod in ob.modifiers:
|
||||
if onceCSG == 0:
|
||||
if mod:
|
||||
if mod.type == 'BOOLEAN':
|
||||
col.prop(ob.pov, "boolean_mod")
|
||||
onceCSG = 1
|
||||
|
||||
if ob.pov.boolean_mod == "POV":
|
||||
split = layout.split()
|
||||
col = layout.column()
|
||||
# Inside Vector for CSG
|
||||
col.prop(ob.pov, "inside_vector")
|
||||
|
||||
|
||||
class OBJECT_PT_POV_obj_parameters(ObjectButtonsPanel, Panel):
|
||||
"""Use this class to define pov specific object level options buttons."""
|
||||
|
||||
bl_label = "POV"
|
||||
COMPAT_ENGINES = {'POVRAY_RENDER'}
|
||||
|
||||
@classmethod
|
||||
def poll(cls, context):
|
||||
|
||||
engine = context.scene.render.engine
|
||||
return engine in cls.COMPAT_ENGINES
|
||||
|
||||
def draw(self, context):
|
||||
layout = self.layout
|
||||
|
||||
obj = context.object
|
||||
|
||||
split = layout.split()
|
||||
|
||||
col = split.column(align=True)
|
||||
|
||||
col.label(text="Radiosity:")
|
||||
col.prop(obj.pov, "importance_value", text="Importance")
|
||||
col.label(text="Photons:")
|
||||
col.prop(obj.pov, "collect_photons", text="Receive Photon Caustics")
|
||||
if obj.pov.collect_photons:
|
||||
col.prop(obj.pov, "spacing_multiplier", text="Photons Spacing Multiplier")
|
||||
|
||||
split = layout.split()
|
||||
|
||||
col = split.column()
|
||||
col.prop(obj.pov, "hollow")
|
||||
col.prop(obj.pov, "double_illuminate")
|
||||
|
||||
if obj.type == 'META' or obj.pov.curveshape == 'lathe':
|
||||
# if obj.pov.curveshape == 'sor'
|
||||
col.prop(obj.pov, "sturm")
|
||||
col.prop(obj.pov, "no_shadow")
|
||||
col.prop(obj.pov, "no_image")
|
||||
col.prop(obj.pov, "no_reflection")
|
||||
col.prop(obj.pov, "no_radiosity")
|
||||
col.prop(obj.pov, "inverse")
|
||||
col.prop(obj.pov, "hierarchy")
|
||||
# col.prop(obj.pov,"boundorclip",text="Bound / Clip")
|
||||
# if obj.pov.boundorclip != "none":
|
||||
# col.prop_search(obj.pov,"boundorclipob",context.blend_data,"objects",text="Object")
|
||||
# text = "Clipped by"
|
||||
# if obj.pov.boundorclip == "clipped_by":
|
||||
# text = "Bounded by"
|
||||
# col.prop(obj.pov,"addboundorclip",text=text)
|
||||
|
||||
|
||||
class OBJECT_PT_POV_obj_sphere(PovDataButtonsPanel, Panel):
|
||||
"""Use this class to define pov sphere primitive parameters buttons."""
|
||||
|
||||
bl_label = "POV Sphere"
|
||||
COMPAT_ENGINES = {'POVRAY_RENDER'}
|
||||
# bl_options = {'HIDE_HEADER'}
|
||||
@classmethod
|
||||
def poll(cls, context):
|
||||
engine = context.scene.render.engine
|
||||
obj = context.object
|
||||
return obj and obj.pov.object_as == 'SPHERE' and (engine in cls.COMPAT_ENGINES)
|
||||
|
||||
def draw(self, context):
|
||||
layout = self.layout
|
||||
|
||||
obj = context.object
|
||||
|
||||
col = layout.column()
|
||||
|
||||
if obj.pov.object_as == 'SPHERE':
|
||||
if not obj.pov.unlock_parameters:
|
||||
col.prop(
|
||||
obj.pov, "unlock_parameters", text="Exported parameters below", icon='LOCKED'
|
||||
)
|
||||
col.label(text="Sphere radius: " + str(obj.pov.sphere_radius))
|
||||
|
||||
else:
|
||||
col.prop(
|
||||
obj.pov, "unlock_parameters", text="Edit exported parameters", icon='UNLOCKED'
|
||||
)
|
||||
col.label(text="3D view proxy may get out of synch")
|
||||
col.active = obj.pov.unlock_parameters
|
||||
|
||||
layout.operator("pov.sphere_update", text="Update", icon="SHADING_RENDERED")
|
||||
|
||||
# col.label(text="Parameters:")
|
||||
col.prop(obj.pov, "sphere_radius", text="Radius of Sphere")
|
||||
|
||||
|
||||
class OBJECT_PT_POV_obj_cylinder(PovDataButtonsPanel, Panel):
|
||||
"""Use this class to define pov cylinder primitive parameters buttons."""
|
||||
|
||||
bl_label = "POV Cylinder"
|
||||
COMPAT_ENGINES = {'POVRAY_RENDER'}
|
||||
# bl_options = {'HIDE_HEADER'}
|
||||
@classmethod
|
||||
def poll(cls, context):
|
||||
engine = context.scene.render.engine
|
||||
obj = context.object
|
||||
return obj and obj.pov.object_as == 'CYLINDER' and (engine in cls.COMPAT_ENGINES)
|
||||
|
||||
def draw(self, context):
|
||||
layout = self.layout
|
||||
|
||||
obj = context.object
|
||||
|
||||
col = layout.column()
|
||||
|
||||
if obj.pov.object_as == 'CYLINDER':
|
||||
if not obj.pov.unlock_parameters:
|
||||
col.prop(
|
||||
obj.pov, "unlock_parameters", text="Exported parameters below", icon='LOCKED'
|
||||
)
|
||||
col.label(text="Cylinder radius: " + str(obj.pov.cylinder_radius))
|
||||
col.label(text="Cylinder cap location: " + str(obj.pov.cylinder_location_cap))
|
||||
|
||||
else:
|
||||
col.prop(
|
||||
obj.pov, "unlock_parameters", text="Edit exported parameters", icon='UNLOCKED'
|
||||
)
|
||||
col.label(text="3D view proxy may get out of synch")
|
||||
col.active = obj.pov.unlock_parameters
|
||||
|
||||
layout.operator("pov.cylinder_update", text="Update", icon="MESH_CYLINDER")
|
||||
|
||||
# col.label(text="Parameters:")
|
||||
col.prop(obj.pov, "cylinder_radius")
|
||||
col.prop(obj.pov, "cylinder_location_cap")
|
||||
|
||||
|
||||
class OBJECT_PT_POV_obj_cone(PovDataButtonsPanel, Panel):
|
||||
"""Use this class to define pov cone primitive parameters buttons."""
|
||||
|
||||
bl_label = "POV Cone"
|
||||
COMPAT_ENGINES = {'POVRAY_RENDER'}
|
||||
# bl_options = {'HIDE_HEADER'}
|
||||
@classmethod
|
||||
def poll(cls, context):
|
||||
engine = context.scene.render.engine
|
||||
obj = context.object
|
||||
return obj and obj.pov.object_as == 'CONE' and (engine in cls.COMPAT_ENGINES)
|
||||
|
||||
def draw(self, context):
|
||||
layout = self.layout
|
||||
|
||||
obj = context.object
|
||||
|
||||
col = layout.column()
|
||||
|
||||
if obj.pov.object_as == 'CONE':
|
||||
if not obj.pov.unlock_parameters:
|
||||
col.prop(
|
||||
obj.pov, "unlock_parameters", text="Exported parameters below", icon='LOCKED'
|
||||
)
|
||||
col.label(text="Cone base radius: " + str(obj.pov.cone_base_radius))
|
||||
col.label(text="Cone cap radius: " + str(obj.pov.cone_cap_radius))
|
||||
col.label(text="Cone proxy segments: " + str(obj.pov.cone_segments))
|
||||
col.label(text="Cone height: " + str(obj.pov.cone_height))
|
||||
else:
|
||||
col.prop(
|
||||
obj.pov, "unlock_parameters", text="Edit exported parameters", icon='UNLOCKED'
|
||||
)
|
||||
col.label(text="3D view proxy may get out of synch")
|
||||
col.active = obj.pov.unlock_parameters
|
||||
|
||||
layout.operator("pov.cone_update", text="Update", icon="MESH_CONE")
|
||||
|
||||
# col.label(text="Parameters:")
|
||||
col.prop(obj.pov, "cone_base_radius", text="Radius of Cone Base")
|
||||
col.prop(obj.pov, "cone_cap_radius", text="Radius of Cone Cap")
|
||||
col.prop(obj.pov, "cone_segments", text="Segmentation of Cone proxy")
|
||||
col.prop(obj.pov, "cone_height", text="Height of the cone")
|
||||
|
||||
|
||||
class OBJECT_PT_POV_obj_superellipsoid(PovDataButtonsPanel, Panel):
|
||||
"""Use this class to define pov superellipsoid primitive parameters buttons."""
|
||||
|
||||
bl_label = "POV Superquadric ellipsoid"
|
||||
COMPAT_ENGINES = {'POVRAY_RENDER'}
|
||||
# bl_options = {'HIDE_HEADER'}
|
||||
@classmethod
|
||||
def poll(cls, context):
|
||||
engine = context.scene.render.engine
|
||||
obj = context.object
|
||||
return obj and obj.pov.object_as == 'SUPERELLIPSOID' and (engine in cls.COMPAT_ENGINES)
|
||||
|
||||
def draw(self, context):
|
||||
layout = self.layout
|
||||
|
||||
obj = context.object
|
||||
|
||||
col = layout.column()
|
||||
|
||||
if obj.pov.object_as == 'SUPERELLIPSOID':
|
||||
if not obj.pov.unlock_parameters:
|
||||
col.prop(
|
||||
obj.pov, "unlock_parameters", text="Exported parameters below", icon='LOCKED'
|
||||
)
|
||||
col.label(text="Radial segmentation: " + str(obj.pov.se_u))
|
||||
col.label(text="Lateral segmentation: " + str(obj.pov.se_v))
|
||||
col.label(text="Ring shape: " + str(obj.pov.se_n1))
|
||||
col.label(text="Cross-section shape: " + str(obj.pov.se_n2))
|
||||
col.label(text="Fill up and down: " + str(obj.pov.se_edit))
|
||||
else:
|
||||
col.prop(
|
||||
obj.pov, "unlock_parameters", text="Edit exported parameters", icon='UNLOCKED'
|
||||
)
|
||||
col.label(text="3D view proxy may get out of synch")
|
||||
col.active = obj.pov.unlock_parameters
|
||||
|
||||
layout.operator("pov.superellipsoid_update", text="Update", icon="MOD_SUBSURF")
|
||||
|
||||
# col.label(text="Parameters:")
|
||||
col.prop(obj.pov, "se_u")
|
||||
col.prop(obj.pov, "se_v")
|
||||
col.prop(obj.pov, "se_n1")
|
||||
col.prop(obj.pov, "se_n2")
|
||||
col.prop(obj.pov, "se_edit")
|
||||
|
||||
|
||||
class OBJECT_PT_POV_obj_torus(PovDataButtonsPanel, Panel):
|
||||
"""Use this class to define pov torus primitive parameters buttons."""
|
||||
|
||||
bl_label = "POV Torus"
|
||||
COMPAT_ENGINES = {'POVRAY_RENDER'}
|
||||
# bl_options = {'HIDE_HEADER'}
|
||||
@classmethod
|
||||
def poll(cls, context):
|
||||
engine = context.scene.render.engine
|
||||
obj = context.object
|
||||
return obj and obj.pov.object_as == 'TORUS' and (engine in cls.COMPAT_ENGINES)
|
||||
|
||||
def draw(self, context):
|
||||
layout = self.layout
|
||||
|
||||
obj = context.object
|
||||
|
||||
col = layout.column()
|
||||
|
||||
if obj.pov.object_as == 'TORUS':
|
||||
if not obj.pov.unlock_parameters:
|
||||
col.prop(
|
||||
obj.pov, "unlock_parameters", text="Exported parameters below", icon='LOCKED'
|
||||
)
|
||||
col.label(text="Torus major radius: " + str(obj.pov.torus_major_radius))
|
||||
col.label(text="Torus minor radius: " + str(obj.pov.torus_minor_radius))
|
||||
col.label(text="Torus major segments: " + str(obj.pov.torus_major_segments))
|
||||
col.label(text="Torus minor segments: " + str(obj.pov.torus_minor_segments))
|
||||
else:
|
||||
col.prop(
|
||||
obj.pov, "unlock_parameters", text="Edit exported parameters", icon='UNLOCKED'
|
||||
)
|
||||
col.label(text="3D view proxy may get out of synch")
|
||||
col.active = obj.pov.unlock_parameters
|
||||
|
||||
layout.operator("pov.torus_update", text="Update", icon="MESH_TORUS")
|
||||
|
||||
# col.label(text="Parameters:")
|
||||
col.prop(obj.pov, "torus_major_radius")
|
||||
col.prop(obj.pov, "torus_minor_radius")
|
||||
col.prop(obj.pov, "torus_major_segments")
|
||||
col.prop(obj.pov, "torus_minor_segments")
|
||||
|
||||
|
||||
class OBJECT_PT_POV_obj_supertorus(PovDataButtonsPanel, Panel):
|
||||
"""Use this class to define pov supertorus primitive parameters buttons."""
|
||||
|
||||
bl_label = "POV SuperTorus"
|
||||
COMPAT_ENGINES = {'POVRAY_RENDER'}
|
||||
# bl_options = {'HIDE_HEADER'}
|
||||
@classmethod
|
||||
def poll(cls, context):
|
||||
engine = context.scene.render.engine
|
||||
obj = context.object
|
||||
return obj and obj.pov.object_as == 'SUPERTORUS' and (engine in cls.COMPAT_ENGINES)
|
||||
|
||||
def draw(self, context):
|
||||
layout = self.layout
|
||||
|
||||
obj = context.object
|
||||
|
||||
col = layout.column()
|
||||
|
||||
if obj.pov.object_as == 'SUPERTORUS':
|
||||
if not obj.pov.unlock_parameters:
|
||||
col.prop(
|
||||
obj.pov, "unlock_parameters", text="Exported parameters below", icon='LOCKED'
|
||||
)
|
||||
col.label(text="SuperTorus major radius: " + str(obj.pov.st_major_radius))
|
||||
col.label(text="SuperTorus minor radius: " + str(obj.pov.st_minor_radius))
|
||||
col.label(text="SuperTorus major segments: " + str(obj.pov.st_u))
|
||||
col.label(text="SuperTorus minor segments: " + str(obj.pov.st_v))
|
||||
|
||||
col.label(text="SuperTorus Ring Manipulator: " + str(obj.pov.st_ring))
|
||||
col.label(text="SuperTorus Cross Manipulator: " + str(obj.pov.st_cross))
|
||||
col.label(text="SuperTorus Internal And External radii: " + str(obj.pov.st_ie))
|
||||
|
||||
col.label(text="SuperTorus accuracy: " + str(obj.pov.st_accuracy))
|
||||
col.label(text="SuperTorus max gradient: " + str(obj.pov.st_max_gradient))
|
||||
|
||||
else:
|
||||
col.prop(
|
||||
obj.pov, "unlock_parameters", text="Edit exported parameters", icon='UNLOCKED'
|
||||
)
|
||||
col.label(text="3D view proxy may get out of synch")
|
||||
col.active = obj.pov.unlock_parameters
|
||||
|
||||
layout.operator("pov.supertorus_update", text="Update", icon="MESH_TORUS")
|
||||
|
||||
# col.label(text="Parameters:")
|
||||
col.prop(obj.pov, "st_major_radius")
|
||||
col.prop(obj.pov, "st_minor_radius")
|
||||
col.prop(obj.pov, "st_u")
|
||||
col.prop(obj.pov, "st_v")
|
||||
col.prop(obj.pov, "st_ring")
|
||||
col.prop(obj.pov, "st_cross")
|
||||
col.prop(obj.pov, "st_ie")
|
||||
# col.prop(obj.pov, "st_edit") #?
|
||||
col.prop(obj.pov, "st_accuracy")
|
||||
col.prop(obj.pov, "st_max_gradient")
|
||||
|
||||
|
||||
class OBJECT_PT_POV_obj_parametric(PovDataButtonsPanel, Panel):
|
||||
"""Use this class to define pov parametric surface primitive parameters buttons."""
|
||||
|
||||
bl_label = "POV Parametric surface"
|
||||
COMPAT_ENGINES = {'POVRAY_RENDER'}
|
||||
# bl_options = {'HIDE_HEADER'}
|
||||
@classmethod
|
||||
def poll(cls, context):
|
||||
engine = context.scene.render.engine
|
||||
obj = context.object
|
||||
return obj and obj.pov.object_as == 'PARAMETRIC' and (engine in cls.COMPAT_ENGINES)
|
||||
|
||||
def draw(self, context):
|
||||
layout = self.layout
|
||||
|
||||
obj = context.object
|
||||
|
||||
col = layout.column()
|
||||
|
||||
if obj.pov.object_as == 'PARAMETRIC':
|
||||
if not obj.pov.unlock_parameters:
|
||||
col.prop(
|
||||
obj.pov, "unlock_parameters", text="Exported parameters below", icon='LOCKED'
|
||||
)
|
||||
col.label(text="Minimum U: " + str(obj.pov.u_min))
|
||||
col.label(text="Minimum V: " + str(obj.pov.v_min))
|
||||
col.label(text="Maximum U: " + str(obj.pov.u_max))
|
||||
col.label(text="Minimum V: " + str(obj.pov.v_min))
|
||||
col.label(text="X Function: " + str(obj.pov.x_eq))
|
||||
col.label(text="Y Function: " + str(obj.pov.y_eq))
|
||||
col.label(text="Z Function: " + str(obj.pov.x_eq))
|
||||
|
||||
else:
|
||||
col.prop(
|
||||
obj.pov, "unlock_parameters", text="Edit exported parameters", icon='UNLOCKED'
|
||||
)
|
||||
col.label(text="3D view proxy may get out of synch")
|
||||
col.active = obj.pov.unlock_parameters
|
||||
|
||||
layout.operator("pov.parametric_update", text="Update", icon="SCRIPTPLUGINS")
|
||||
|
||||
col.prop(obj.pov, "u_min", text="Minimum U")
|
||||
col.prop(obj.pov, "v_min", text="Minimum V")
|
||||
col.prop(obj.pov, "u_max", text="Maximum U")
|
||||
col.prop(obj.pov, "v_max", text="Minimum V")
|
||||
col.prop(obj.pov, "x_eq", text="X Function")
|
||||
col.prop(obj.pov, "y_eq", text="Y Function")
|
||||
col.prop(obj.pov, "z_eq", text="Z Function")
|
||||
|
||||
|
||||
class OBJECT_PT_povray_replacement_text(ObjectButtonsPanel, Panel):
|
||||
"""Use this class to define pov object replacement field."""
|
||||
|
||||
bl_label = "Custom POV Code"
|
||||
COMPAT_ENGINES = {'POVRAY_RENDER'}
|
||||
|
||||
def draw(self, context):
|
||||
layout = self.layout
|
||||
|
||||
obj = context.object
|
||||
|
||||
col = layout.column()
|
||||
col.label(text="Replace properties with:")
|
||||
col.prop(obj.pov, "replacement_text", text="")
|
||||
|
||||
|
||||
###############################################################################
|
||||
# Add Povray Objects
|
||||
###############################################################################
|
||||
def check_add_mesh_extra_objects():
|
||||
"""Test if Add mesh extra objects addon is activated
|
||||
|
||||
This addon is currently used to generate the proxy for POV parametric
|
||||
surface which is almost the same priciple as its Math xyz surface
|
||||
"""
|
||||
if "add_mesh_extra_objects" in bpy.context.preferences.addons.keys():
|
||||
return True
|
||||
return False
|
||||
|
||||
|
||||
def menu_func_add(self, context):
|
||||
"""Append the POV primitives submenu to blender add objects menu"""
|
||||
engine = context.scene.render.engine
|
||||
if engine == 'POVRAY_RENDER':
|
||||
self.layout.menu("VIEW_MT_POV_primitives_add", icon="PLUGIN")
|
||||
|
||||
|
||||
class VIEW_MT_POV_primitives_add(Menu):
|
||||
"""Define the primitives menu with presets"""
|
||||
|
||||
bl_idname = "VIEW_MT_POV_primitives_add"
|
||||
bl_label = "Povray"
|
||||
COMPAT_ENGINES = {'POVRAY_RENDER'}
|
||||
|
||||
@classmethod
|
||||
def poll(cls, context):
|
||||
engine = context.scene.render.engine
|
||||
return engine == 'POVRAY_RENDER'
|
||||
|
||||
def draw(self, context):
|
||||
layout = self.layout
|
||||
layout.operator_context = 'INVOKE_REGION_WIN'
|
||||
layout.menu(VIEW_MT_POV_Basic_Shapes.bl_idname, text="Primitives", icon="GROUP")
|
||||
layout.menu(VIEW_MT_POV_import.bl_idname, text="Import", icon="IMPORT")
|
||||
|
||||
|
||||
class VIEW_MT_POV_Basic_Shapes(Menu):
|
||||
"""Use this class to sort simple primitives menu entries."""
|
||||
|
||||
bl_idname = "POVRAY_MT_basic_shape_tools"
|
||||
bl_label = "Basic_shapes"
|
||||
|
||||
def draw(self, context):
|
||||
layout = self.layout
|
||||
layout.operator_context = 'INVOKE_REGION_WIN'
|
||||
layout.operator("pov.addplane", text="Infinite Plane", icon='MESH_PLANE')
|
||||
layout.operator("pov.addbox", text="Box", icon='MESH_CUBE')
|
||||
layout.operator("pov.addsphere", text="Sphere", icon='SHADING_RENDERED')
|
||||
layout.operator("pov.addcylinder", text="Cylinder", icon="MESH_CYLINDER")
|
||||
layout.operator("pov.cone_add", text="Cone", icon="MESH_CONE")
|
||||
layout.operator("pov.addtorus", text="Torus", icon='MESH_TORUS')
|
||||
layout.separator()
|
||||
layout.operator("pov.addrainbow", text="Rainbow", icon="COLOR")
|
||||
layout.operator("pov.addlathe", text="Lathe", icon='MOD_SCREW')
|
||||
layout.operator("pov.addprism", text="Prism", icon='MOD_SOLIDIFY')
|
||||
layout.operator("pov.addsuperellipsoid", text="Superquadric Ellipsoid", icon='MOD_SUBSURF')
|
||||
layout.operator("pov.addheightfield", text="Height Field", icon="RNDCURVE")
|
||||
layout.operator("pov.addspheresweep", text="Sphere Sweep", icon='FORCE_CURVE')
|
||||
layout.separator()
|
||||
layout.operator("pov.addblobsphere", text="Blob Sphere", icon='META_DATA')
|
||||
layout.separator()
|
||||
layout.label(text="Isosurfaces")
|
||||
layout.operator("pov.addisosurfacebox", text="Isosurface Box", icon="META_CUBE")
|
||||
layout.operator("pov.addisosurfacesphere", text="Isosurface Sphere", icon="META_BALL")
|
||||
layout.operator("pov.addsupertorus", text="Supertorus", icon="SURFACE_NTORUS")
|
||||
layout.separator()
|
||||
layout.label(text="Macro based")
|
||||
layout.operator(
|
||||
"pov.addpolygontocircle", text="Polygon To Circle Blending", icon="MOD_CAST"
|
||||
)
|
||||
layout.operator("pov.addloft", text="Loft", icon="SURFACE_NSURFACE")
|
||||
layout.separator()
|
||||
# Warning if the Add Advanced Objects addon containing
|
||||
# Add mesh extra objects is not enabled
|
||||
if not check_add_mesh_extra_objects():
|
||||
# col = box.column()
|
||||
layout.label(text="Please enable Add Mesh: Extra Objects addon", icon="INFO")
|
||||
# layout.separator()
|
||||
layout.operator(
|
||||
"preferences.addon_show",
|
||||
text="Go to Add Mesh: Extra Objects addon",
|
||||
icon="PREFERENCES",
|
||||
).module = "add_mesh_extra_objects"
|
||||
|
||||
# layout.separator()
|
||||
return
|
||||
layout.operator("pov.addparametric", text="Parametric", icon='SCRIPTPLUGINS')
|
||||
|
||||
|
||||
classes = (
|
||||
# ObjectButtonsPanel,
|
||||
# PovDataButtonsPanel,
|
||||
DATA_PT_POV_normals,
|
||||
DATA_PT_POV_texture_space,
|
||||
DATA_PT_POV_vertex_groups,
|
||||
DATA_PT_POV_shape_keys,
|
||||
DATA_PT_POV_uv_texture,
|
||||
DATA_PT_POV_vertex_colors,
|
||||
DATA_PT_POV_customdata,
|
||||
MODIFIERS_PT_POV_modifiers,
|
||||
OBJECT_PT_POV_obj_parameters,
|
||||
OBJECT_PT_POV_obj_sphere,
|
||||
OBJECT_PT_POV_obj_cylinder,
|
||||
OBJECT_PT_POV_obj_cone,
|
||||
OBJECT_PT_POV_obj_superellipsoid,
|
||||
OBJECT_PT_POV_obj_torus,
|
||||
OBJECT_PT_POV_obj_supertorus,
|
||||
OBJECT_PT_POV_obj_parametric,
|
||||
OBJECT_PT_povray_replacement_text,
|
||||
VIEW_MT_POV_primitives_add,
|
||||
VIEW_MT_POV_Basic_Shapes,
|
||||
)
|
||||
|
||||
|
||||
def register():
|
||||
# from bpy.utils import register_class
|
||||
|
||||
for cls in classes:
|
||||
register_class(cls)
|
||||
|
||||
bpy.types.VIEW3D_MT_add.prepend(menu_func_add)
|
||||
|
||||
# was used for parametric objects but made the other addon unreachable on
|
||||
# unregister for other tools to use created a user action call instead
|
||||
# addon_utils.enable("add_mesh_extra_objects", default_set=False, persistent=True)
|
||||
|
||||
|
||||
def unregister():
|
||||
# addon_utils.disable("add_mesh_extra_objects", default_set=False)
|
||||
|
||||
bpy.types.VIEW3D_MT_add.remove(menu_func_add)
|
||||
|
||||
for cls in reversed(classes):
|
||||
unregister_class(cls)
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,255 @@
|
|||
# ##### BEGIN GPL LICENSE BLOCK #####
|
||||
#
|
||||
# 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 2
|
||||
# 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
|
||||
# MERCHANTABILITY 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, write to the Free Software Foundation,
|
||||
# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
#
|
||||
# ##### END GPL LICENSE BLOCK #####
|
||||
|
||||
# <pep8 compliant>
|
||||
"""Get some Blender particle objects translated to POV."""
|
||||
|
||||
import bpy
|
||||
|
||||
|
||||
def export_hair(file, ob, p_sys, global_matrix, write_matrix):
|
||||
"""Get Blender path particles (hair strands) objects translated to POV sphere_sweep unions."""
|
||||
# tstart = time.time()
|
||||
textured_hair = 0
|
||||
if ob.material_slots[p_sys.settings.material - 1].material and ob.active_material is not None:
|
||||
pmaterial = ob.material_slots[p_sys.settings.material - 1].material
|
||||
# XXX Todo: replace by pov_(Particles?)_texture_slot
|
||||
for th in pmaterial.pov_texture_slots:
|
||||
povtex = th.texture # slot.name
|
||||
tex = bpy.data.textures[povtex]
|
||||
|
||||
if th and th.use:
|
||||
if (tex.type == 'IMAGE' and tex.image) or tex.type != 'IMAGE':
|
||||
if th.use_map_color_diffuse:
|
||||
textured_hair = 1
|
||||
if pmaterial.strand.use_blender_units:
|
||||
strand_start = pmaterial.strand.root_size
|
||||
strand_end = pmaterial.strand.tip_size
|
||||
strand_shape = pmaterial.strand.shape
|
||||
else: # Blender unit conversion
|
||||
strand_start = pmaterial.strand.root_size / 200.0
|
||||
strand_end = pmaterial.strand.tip_size / 200.0
|
||||
strand_shape = pmaterial.strand.shape
|
||||
else:
|
||||
pmaterial = "default" # No material assigned in blender, use default one
|
||||
strand_start = 0.01
|
||||
strand_end = 0.01
|
||||
strand_shape = 0.0
|
||||
# Set the number of particles to render count rather than 3d view display
|
||||
# p_sys.set_resolution(scene, ob, 'RENDER') # DEPRECATED
|
||||
# When you render, the entire dependency graph will be
|
||||
# evaluated at render resolution, including the particles.
|
||||
# In the viewport it will be at viewport resolution.
|
||||
# So there is no need fo render engines to use this function anymore,
|
||||
# it's automatic now.
|
||||
steps = p_sys.settings.display_step
|
||||
steps = 2 ** steps # or + 1 # Formerly : len(particle.hair_keys)
|
||||
|
||||
total_number_of_strands = p_sys.settings.count + p_sys.settings.rendered_child_count
|
||||
# hairCounter = 0
|
||||
file.write('#declare HairArray = array[%i] {\n' % total_number_of_strands)
|
||||
for pindex in range(0, total_number_of_strands):
|
||||
|
||||
# if particle.is_exist and particle.is_visible:
|
||||
# hairCounter += 1
|
||||
# controlPointCounter = 0
|
||||
# Each hair is represented as a separate sphere_sweep in POV-Ray.
|
||||
|
||||
file.write('sphere_sweep{')
|
||||
if p_sys.settings.use_hair_bspline:
|
||||
file.write('b_spline ')
|
||||
file.write(
|
||||
'%i,\n' % (steps + 2)
|
||||
) # +2 because the first point needs tripling to be more than a handle in POV
|
||||
else:
|
||||
file.write('linear_spline ')
|
||||
file.write('%i,\n' % (steps))
|
||||
# changing world coordinates to object local coordinates by
|
||||
# multiplying with inverted matrix
|
||||
init_coord = ob.matrix_world.inverted() @ (p_sys.co_hair(ob, particle_no=pindex, step=0))
|
||||
if (
|
||||
ob.material_slots[p_sys.settings.material - 1].material
|
||||
and ob.active_material is not None
|
||||
):
|
||||
pmaterial = ob.material_slots[p_sys.settings.material - 1].material
|
||||
for th in pmaterial.pov_texture_slots:
|
||||
if th and th.use and th.use_map_color_diffuse:
|
||||
povtex = th.texture # slot.name
|
||||
tex = bpy.data.textures[povtex]
|
||||
# treat POV textures as bitmaps
|
||||
if (
|
||||
tex.type == 'IMAGE'
|
||||
and tex.image
|
||||
and th.texture_coords == 'UV'
|
||||
and ob.data.uv_textures is not None
|
||||
):
|
||||
# or (
|
||||
# tex.pov.tex_pattern_type != 'emulator'
|
||||
# and th.texture_coords == 'UV'
|
||||
# and ob.data.uv_textures is not None
|
||||
# ):
|
||||
image = tex.image
|
||||
image_width = image.size[0]
|
||||
image_height = image.size[1]
|
||||
image_pixels = image.pixels[:]
|
||||
uv_co = p_sys.uv_on_emitter(mod, p_sys.particles[pindex], pindex, 0)
|
||||
x_co = round(uv_co[0] * (image_width - 1))
|
||||
y_co = round(uv_co[1] * (image_height - 1))
|
||||
pixelnumber = (image_width * y_co) + x_co
|
||||
r = image_pixels[pixelnumber * 4]
|
||||
g = image_pixels[pixelnumber * 4 + 1]
|
||||
b = image_pixels[pixelnumber * 4 + 2]
|
||||
a = image_pixels[pixelnumber * 4 + 3]
|
||||
init_color = (r, g, b, a)
|
||||
else:
|
||||
# only overwrite variable for each competing texture for now
|
||||
init_color = tex.evaluate((init_coord[0], init_coord[1], init_coord[2]))
|
||||
for step in range(0, steps):
|
||||
coord = ob.matrix_world.inverted() @ (p_sys.co_hair(ob, particle_no=pindex, step=step))
|
||||
# for controlPoint in particle.hair_keys:
|
||||
if p_sys.settings.clump_factor != 0:
|
||||
hair_strand_diameter = p_sys.settings.clump_factor / 200.0 * random.uniform(0.5, 1)
|
||||
elif step == 0:
|
||||
hair_strand_diameter = strand_start
|
||||
else:
|
||||
hair_strand_diameter += (strand_end - strand_start) / (
|
||||
p_sys.settings.display_step + 1
|
||||
) # XXX +1 or not? # XXX use strand_shape in formula
|
||||
if step == 0 and p_sys.settings.use_hair_bspline:
|
||||
# Write three times the first point to compensate pov Bezier handling
|
||||
file.write(
|
||||
'<%.6g,%.6g,%.6g>,%.7g,\n'
|
||||
% (coord[0], coord[1], coord[2], abs(hair_strand_diameter))
|
||||
)
|
||||
file.write(
|
||||
'<%.6g,%.6g,%.6g>,%.7g,\n'
|
||||
% (coord[0], coord[1], coord[2], abs(hair_strand_diameter))
|
||||
)
|
||||
# Useless because particle location is the tip, not the root:
|
||||
# file.write(
|
||||
# '<%.6g,%.6g,%.6g>,%.7g'
|
||||
# % (
|
||||
# particle.location[0],
|
||||
# particle.location[1],
|
||||
# particle.location[2],
|
||||
# abs(hair_strand_diameter)
|
||||
# )
|
||||
# )
|
||||
# file.write(',\n')
|
||||
# controlPointCounter += 1
|
||||
# total_number_of_strands += len(p_sys.particles)# len(particle.hair_keys)
|
||||
|
||||
# Each control point is written out, along with the radius of the
|
||||
# hair at that point.
|
||||
file.write(
|
||||
'<%.6g,%.6g,%.6g>,%.7g' % (coord[0], coord[1], coord[2], abs(hair_strand_diameter))
|
||||
)
|
||||
|
||||
# All coordinates except the last need a following comma.
|
||||
|
||||
if step != steps - 1:
|
||||
file.write(',\n')
|
||||
else:
|
||||
if textured_hair:
|
||||
# Write pigment and alpha (between Pov and Blender,
|
||||
# alpha 0 and 1 are reversed)
|
||||
file.write(
|
||||
'\npigment{ color srgbf < %.3g, %.3g, %.3g, %.3g> }\n'
|
||||
% (init_color[0], init_color[1], init_color[2], 1.0 - init_color[3])
|
||||
)
|
||||
# End the sphere_sweep declaration for this hair
|
||||
file.write('}\n')
|
||||
|
||||
# All but the final sphere_sweep (each array element) needs a terminating comma.
|
||||
if pindex != total_number_of_strands:
|
||||
file.write(',\n')
|
||||
else:
|
||||
file.write('\n')
|
||||
|
||||
# End the array declaration.
|
||||
|
||||
file.write('}\n')
|
||||
file.write('\n')
|
||||
|
||||
if not textured_hair:
|
||||
# Pick up the hair material diffuse color and create a default POV-Ray hair texture.
|
||||
|
||||
file.write('#ifndef (HairTexture)\n')
|
||||
file.write(' #declare HairTexture = texture {\n')
|
||||
file.write(
|
||||
' pigment {srgbt <%s,%s,%s,%s>}\n'
|
||||
% (
|
||||
pmaterial.diffuse_color[0],
|
||||
pmaterial.diffuse_color[1],
|
||||
pmaterial.diffuse_color[2],
|
||||
(pmaterial.strand.width_fade + 0.05),
|
||||
)
|
||||
)
|
||||
file.write(' }\n')
|
||||
file.write('#end\n')
|
||||
file.write('\n')
|
||||
|
||||
# Dynamically create a union of the hairstrands (or a subset of them).
|
||||
# By default use every hairstrand, commented line is for hand tweaking test renders.
|
||||
file.write('//Increasing HairStep divides the amount of hair for test renders.\n')
|
||||
file.write('#ifndef(HairStep) #declare HairStep = 1; #end\n')
|
||||
file.write('union{\n')
|
||||
file.write(' #local I = 0;\n')
|
||||
file.write(' #while (I < %i)\n' % total_number_of_strands)
|
||||
file.write(' object {HairArray[I]')
|
||||
if not textured_hair:
|
||||
file.write(' texture{HairTexture}\n')
|
||||
else:
|
||||
file.write('\n')
|
||||
# Translucency of the hair:
|
||||
file.write(' hollow\n')
|
||||
file.write(' double_illuminate\n')
|
||||
file.write(' interior {\n')
|
||||
file.write(' ior 1.45\n')
|
||||
file.write(' media {\n')
|
||||
file.write(' scattering { 1, 10*<0.73, 0.35, 0.15> /*extinction 0*/ }\n')
|
||||
file.write(' absorption 10/<0.83, 0.75, 0.15>\n')
|
||||
file.write(' samples 1\n')
|
||||
file.write(' method 2\n')
|
||||
file.write(' density {cylindrical\n')
|
||||
file.write(' color_map {\n')
|
||||
file.write(' [0.0 rgb <0.83, 0.45, 0.35>]\n')
|
||||
file.write(' [0.5 rgb <0.8, 0.8, 0.4>]\n')
|
||||
file.write(' [1.0 rgb <1,1,1>]\n')
|
||||
file.write(' }\n')
|
||||
file.write(' }\n')
|
||||
file.write(' }\n')
|
||||
file.write(' }\n')
|
||||
file.write(' }\n')
|
||||
|
||||
file.write(' #local I = I + HairStep;\n')
|
||||
file.write(' #end\n')
|
||||
|
||||
write_matrix(global_matrix @ ob.matrix_world)
|
||||
|
||||
file.write('}')
|
||||
print('Totals hairstrands written: %i' % total_number_of_strands)
|
||||
print('Number of tufts (particle systems)', len(ob.particle_systems))
|
||||
|
||||
# Set back the displayed number of particles to preview count
|
||||
# p_sys.set_resolution(scene, ob, 'PREVIEW') #DEPRECATED
|
||||
# When you render, the entire dependency graph will be
|
||||
# evaluated at render resolution, including the particles.
|
||||
# In the viewport it will be at viewport resolution.
|
||||
# So there is no need fo render engines to use this function anymore,
|
||||
# it's automatic now.
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,670 @@
|
|||
# ##### BEGIN GPL LICENSE BLOCK #####
|
||||
#
|
||||
# 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 2
|
||||
# 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
|
||||
# MERCHANTABILITY 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, write to the Free Software Foundation,
|
||||
# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
#
|
||||
# ##### END GPL LICENSE BLOCK #####
|
||||
|
||||
# <pep8 compliant>
|
||||
"""Declare object level properties controllable in UI and translated to POV"""
|
||||
import bpy
|
||||
from bpy.utils import register_class, unregister_class
|
||||
from bpy.types import PropertyGroup
|
||||
from bpy.props import (
|
||||
BoolProperty,
|
||||
IntProperty,
|
||||
FloatProperty,
|
||||
FloatVectorProperty,
|
||||
StringProperty,
|
||||
EnumProperty,
|
||||
PointerProperty,
|
||||
)
|
||||
|
||||
|
||||
###############################################################################
|
||||
# Object POV properties.
|
||||
###############################################################################
|
||||
|
||||
|
||||
class RenderPovSettingsObject(PropertyGroup):
|
||||
"""Declare object and primitives level properties controllable in UI and translated to POV."""
|
||||
|
||||
# Pov inside_vector used for CSG
|
||||
inside_vector: FloatVectorProperty(
|
||||
name="CSG Inside Vector",
|
||||
description="Direction to shoot CSG inside test rays at",
|
||||
precision=4,
|
||||
step=0.01,
|
||||
min=0,
|
||||
soft_max=1,
|
||||
default=(0.001, 0.001, 0.5),
|
||||
options={"ANIMATABLE"},
|
||||
subtype="XYZ",
|
||||
)
|
||||
|
||||
# Importance sampling
|
||||
importance_value: FloatProperty(
|
||||
name="Radiosity Importance",
|
||||
description="Priority value relative to other objects for sampling radiosity rays. "
|
||||
"Increase to get more radiosity rays at comparatively small yet "
|
||||
"bright objects",
|
||||
min=0.01,
|
||||
max=1.00,
|
||||
default=0.50,
|
||||
)
|
||||
|
||||
# Collect photons
|
||||
collect_photons: BoolProperty(
|
||||
name="Receive Photon Caustics",
|
||||
description="Enable object to collect photons from other objects caustics. Turn "
|
||||
"off for objects that don't really need to receive caustics (e.g. objects"
|
||||
" that generate caustics often don't need to show any on themselves)",
|
||||
default=True,
|
||||
)
|
||||
|
||||
# Photons spacing_multiplier
|
||||
spacing_multiplier: FloatProperty(
|
||||
name="Photons Spacing Multiplier",
|
||||
description="Multiplier value relative to global spacing of photons. "
|
||||
"Decrease by half to get 4x more photons at surface of "
|
||||
"this object (or 8x media photons than specified in the globals",
|
||||
min=0.01,
|
||||
max=1.00,
|
||||
default=1.00,
|
||||
)
|
||||
|
||||
##################################CustomPOV Code############################
|
||||
# Only DUMMIES below for now:
|
||||
replacement_text: StringProperty(
|
||||
name="Declared name:",
|
||||
description="Type the declared name in custom POV code or an external .inc "
|
||||
"it points at. Any POV shape expected e.g: isosurface {}",
|
||||
default="",
|
||||
)
|
||||
|
||||
#############POV specific object properties.############################
|
||||
object_as: StringProperty(maxlen=1024)
|
||||
|
||||
imported_loc: FloatVectorProperty(
|
||||
name="Imported Pov location", precision=6, default=(0.0, 0.0, 0.0)
|
||||
)
|
||||
|
||||
imported_loc_cap: FloatVectorProperty(
|
||||
name="Imported Pov location", precision=6, default=(0.0, 0.0, 2.0)
|
||||
)
|
||||
|
||||
unlock_parameters: BoolProperty(name="Lock", default=False)
|
||||
|
||||
# not in UI yet but used for sor (lathe) / prism... pov primitives
|
||||
curveshape: EnumProperty(
|
||||
name="Povray Shape Type",
|
||||
items=(
|
||||
("birail", "Birail", ""),
|
||||
("cairo", "Cairo", ""),
|
||||
("lathe", "Lathe", ""),
|
||||
("loft", "Loft", ""),
|
||||
("prism", "Prism", ""),
|
||||
("sphere_sweep", "Sphere Sweep", ""),
|
||||
),
|
||||
default="sphere_sweep",
|
||||
)
|
||||
|
||||
mesh_write_as: EnumProperty(
|
||||
name="Mesh Write As",
|
||||
items=(("blobgrid", "Blob Grid", ""), ("grid", "Grid", ""), ("mesh", "Mesh", "")),
|
||||
default="mesh",
|
||||
)
|
||||
|
||||
object_ior: FloatProperty(name="IOR", description="IOR", min=1.0, max=10.0, default=1.0)
|
||||
|
||||
# shape_as_light = StringProperty(name="Light",maxlen=1024)
|
||||
# fake_caustics_power = FloatProperty(
|
||||
# name="Power", description="Fake caustics power",
|
||||
# min=0.0, max=10.0,default=0.0)
|
||||
# target = BoolProperty(name="Target",description="",default=False)
|
||||
# target_value = FloatProperty(
|
||||
# name="Value", description="",
|
||||
# min=0.0, max=1.0,default=1.0)
|
||||
# refraction = BoolProperty(name="Refraction",description="",default=False)
|
||||
# dispersion = BoolProperty(name="Dispersion",description="",default=False)
|
||||
# dispersion_value = FloatProperty(
|
||||
# name="Dispersion", description="Good values are 1.01 to 1.1. ",
|
||||
# min=1.0, max=1.2,default=1.01)
|
||||
# dispersion_samples = IntProperty(name="Samples",min=2, max=100,default=7)
|
||||
# reflection = BoolProperty(name="Reflection",description="",default=False)
|
||||
# pass_through = BoolProperty(name="Pass through",description="",default=False)
|
||||
no_shadow: BoolProperty(name="No Shadow", default=False)
|
||||
|
||||
no_image: BoolProperty(name="No Image", default=False)
|
||||
|
||||
no_reflection: BoolProperty(name="No Reflection", default=False)
|
||||
|
||||
no_radiosity: BoolProperty(name="No Radiosity", default=False)
|
||||
|
||||
inverse: BoolProperty(name="Inverse", default=False)
|
||||
|
||||
sturm: BoolProperty(name="Sturm", default=False)
|
||||
|
||||
double_illuminate: BoolProperty(name="Double Illuminate", default=False)
|
||||
|
||||
hierarchy: BoolProperty(name="Hierarchy", default=False)
|
||||
|
||||
hollow: BoolProperty(name="Hollow", default=False)
|
||||
|
||||
boundorclip: EnumProperty(
|
||||
name="Boundorclip",
|
||||
items=(
|
||||
("none", "None", ""),
|
||||
("bounded_by", "Bounded_by", ""),
|
||||
("clipped_by", "Clipped_by", ""),
|
||||
),
|
||||
default="none",
|
||||
)
|
||||
|
||||
boundorclipob: StringProperty(maxlen=1024)
|
||||
|
||||
addboundorclip: BoolProperty(description="", default=False)
|
||||
|
||||
blob_threshold: FloatProperty(name="Threshold", min=0.00, max=10.0, default=0.6)
|
||||
|
||||
blob_strength: FloatProperty(name="Strength", min=-10.00, max=10.0, default=1.00)
|
||||
|
||||
res_u: IntProperty(name="U", min=100, max=1000, default=500)
|
||||
|
||||
res_v: IntProperty(name="V", min=100, max=1000, default=500)
|
||||
|
||||
contained_by: EnumProperty(
|
||||
name="Contained by", items=(("box", "Box", ""), ("sphere", "Sphere", "")), default="box"
|
||||
)
|
||||
|
||||
container_scale: FloatProperty(name="Container Scale", min=0.0, max=10.0, default=1.00)
|
||||
|
||||
threshold: FloatProperty(name="Threshold", min=0.0, max=10.0, default=0.00)
|
||||
|
||||
accuracy: FloatProperty(name="Accuracy", min=0.0001, max=0.1, default=0.001)
|
||||
|
||||
max_gradient: FloatProperty(name="Max Gradient", min=0.0, max=100.0, default=5.0)
|
||||
|
||||
all_intersections: BoolProperty(name="All Intersections", default=False)
|
||||
|
||||
max_trace: IntProperty(name="Max Trace", min=1, max=100, default=1)
|
||||
|
||||
###########Cylinder
|
||||
def prop_update_cylinder(self, context):
|
||||
"""Update POV cylinder primitive parameters not only at creation but anytime they are changed in UI."""
|
||||
if bpy.ops.pov.cylinder_update.poll():
|
||||
bpy.ops.pov.cylinder_update()
|
||||
|
||||
cylinder_radius: FloatProperty(
|
||||
name="Cylinder R", min=0.00, max=10.0, default=0.04, update=prop_update_cylinder
|
||||
)
|
||||
|
||||
cylinder_location_cap: FloatVectorProperty(
|
||||
name="Cylinder Cap Location",
|
||||
subtype="TRANSLATION",
|
||||
description="The position of the 'other' end of the cylinder (relative to object location)",
|
||||
default=(0.0, 0.0, 2.0),
|
||||
update=prop_update_cylinder,
|
||||
)
|
||||
|
||||
imported_cyl_loc: FloatVectorProperty(
|
||||
name="Imported Pov location", precision=6, default=(0.0, 0.0, 0.0)
|
||||
)
|
||||
|
||||
imported_cyl_loc_cap: FloatVectorProperty(
|
||||
name="Imported Pov location", precision=6, default=(0.0, 0.0, 2.0)
|
||||
)
|
||||
|
||||
###########Sphere
|
||||
def prop_update_sphere(self, context):
|
||||
|
||||
"""Update POV sphere primitive parameters not only at creation but anytime they are changed in UI."""
|
||||
|
||||
bpy.ops.pov.sphere_update()
|
||||
|
||||
sphere_radius: FloatProperty(
|
||||
name="Sphere radius", min=0.00, max=10.0, default=0.5, update=prop_update_sphere
|
||||
)
|
||||
|
||||
###########Cone
|
||||
def prop_update_cone(self, context):
|
||||
|
||||
"""Update POV cone primitive parameters not only at creation but anytime they are changed in UI."""
|
||||
|
||||
bpy.ops.pov.cone_update()
|
||||
|
||||
cone_base_radius: FloatProperty(
|
||||
name="Base radius",
|
||||
description="The first radius of the cone",
|
||||
default=1.0,
|
||||
min=0.01,
|
||||
max=100.0,
|
||||
update=prop_update_cone,
|
||||
)
|
||||
|
||||
cone_cap_radius: FloatProperty(
|
||||
name="Cap radius",
|
||||
description="The second radius of the cone",
|
||||
default=0.3,
|
||||
min=0.0,
|
||||
max=100.0,
|
||||
update=prop_update_cone,
|
||||
)
|
||||
|
||||
cone_segments: IntProperty(
|
||||
name="Segments",
|
||||
description="Radial segmentation of proxy mesh",
|
||||
default=16,
|
||||
min=3,
|
||||
max=265,
|
||||
update=prop_update_cone,
|
||||
)
|
||||
|
||||
cone_height: FloatProperty(
|
||||
name="Height",
|
||||
description="Height of the cone",
|
||||
default=2.0,
|
||||
min=0.01,
|
||||
max=100.0,
|
||||
update=prop_update_cone,
|
||||
)
|
||||
|
||||
cone_base_z: FloatProperty()
|
||||
|
||||
cone_cap_z: FloatProperty()
|
||||
|
||||
###########Parametric
|
||||
def prop_update_parametric(self, context):
|
||||
|
||||
"""Update POV parametric surface primitive parameters not only at creation but anytime they are changed in UI."""
|
||||
|
||||
bpy.ops.pov.parametric_update()
|
||||
|
||||
u_min: FloatProperty(name="U Min", description="", default=0.0, update=prop_update_parametric)
|
||||
|
||||
v_min: FloatProperty(name="V Min", description="", default=0.0, update=prop_update_parametric)
|
||||
|
||||
u_max: FloatProperty(name="U Max", description="", default=6.28, update=prop_update_parametric)
|
||||
|
||||
v_max: FloatProperty(name="V Max", description="", default=12.57, update=prop_update_parametric)
|
||||
|
||||
x_eq: StringProperty(
|
||||
maxlen=1024, default="cos(v)*(1+cos(u))*sin(v/8)", update=prop_update_parametric
|
||||
)
|
||||
|
||||
y_eq: StringProperty(
|
||||
maxlen=1024, default="sin(u)*sin(v/8)+cos(v/8)*1.5", update=prop_update_parametric
|
||||
)
|
||||
|
||||
z_eq: StringProperty(
|
||||
maxlen=1024, default="sin(v)*(1+cos(u))*sin(v/8)", update=prop_update_parametric
|
||||
)
|
||||
|
||||
###########Torus
|
||||
|
||||
def prop_update_torus(self, context):
|
||||
|
||||
"""Update POV torus primitive parameters not only at creation but anytime they are changed in UI."""
|
||||
|
||||
bpy.ops.pov.torus_update()
|
||||
|
||||
torus_major_segments: IntProperty(
|
||||
name="Segments",
|
||||
description="Radial segmentation of proxy mesh",
|
||||
default=48,
|
||||
min=3,
|
||||
max=720,
|
||||
update=prop_update_torus,
|
||||
)
|
||||
|
||||
torus_minor_segments: IntProperty(
|
||||
name="Segments",
|
||||
description="Cross-section segmentation of proxy mesh",
|
||||
default=12,
|
||||
min=3,
|
||||
max=720,
|
||||
update=prop_update_torus,
|
||||
)
|
||||
|
||||
torus_major_radius: FloatProperty(
|
||||
name="Major radius",
|
||||
description="Major radius",
|
||||
min=0.00,
|
||||
max=100.00,
|
||||
default=1.0,
|
||||
update=prop_update_torus,
|
||||
)
|
||||
|
||||
torus_minor_radius: FloatProperty(
|
||||
name="Minor radius",
|
||||
description="Minor radius",
|
||||
min=0.00,
|
||||
max=100.00,
|
||||
default=0.25,
|
||||
update=prop_update_torus,
|
||||
)
|
||||
|
||||
###########Rainbow
|
||||
arc_angle: FloatProperty(
|
||||
name="Arc angle",
|
||||
description="The angle of the raynbow arc in degrees",
|
||||
default=360,
|
||||
min=0.01,
|
||||
max=360.0,
|
||||
)
|
||||
|
||||
falloff_angle: FloatProperty(
|
||||
name="Falloff angle",
|
||||
description="The angle after which rainbow dissolves into background",
|
||||
default=360,
|
||||
min=0.0,
|
||||
max=360,
|
||||
)
|
||||
|
||||
###########HeightFields
|
||||
|
||||
quality: IntProperty(name="Quality", description="", default=100, min=1, max=100)
|
||||
|
||||
hf_filename: StringProperty(maxlen=1024)
|
||||
|
||||
hf_gamma: FloatProperty(name="Gamma", description="Gamma", min=0.0001, max=20.0, default=1.0)
|
||||
|
||||
hf_premultiplied: BoolProperty(name="Premultiplied", description="Premultiplied", default=True)
|
||||
|
||||
hf_smooth: BoolProperty(name="Smooth", description="Smooth", default=False)
|
||||
|
||||
hf_water: FloatProperty(
|
||||
name="Water Level", description="Wather Level", min=0.00, max=1.00, default=0.0
|
||||
)
|
||||
|
||||
hf_hierarchy: BoolProperty(name="Hierarchy", description="Height field hierarchy", default=True)
|
||||
|
||||
##############Superellipsoid
|
||||
def prop_update_superellipsoid(self, context):
|
||||
|
||||
"""Update POV superellipsoid primitive parameters not only at creation but anytime they are changed in UI."""
|
||||
|
||||
bpy.ops.pov.superellipsoid_update()
|
||||
|
||||
se_param1: FloatProperty(name="Parameter 1", description="", min=0.00, max=10.0, default=0.04)
|
||||
|
||||
se_param2: FloatProperty(name="Parameter 2", description="", min=0.00, max=10.0, default=0.04)
|
||||
|
||||
se_u: IntProperty(
|
||||
name="U-segments",
|
||||
description="radial segmentation",
|
||||
default=20,
|
||||
min=4,
|
||||
max=265,
|
||||
update=prop_update_superellipsoid,
|
||||
)
|
||||
|
||||
se_v: IntProperty(
|
||||
name="V-segments",
|
||||
description="lateral segmentation",
|
||||
default=20,
|
||||
min=4,
|
||||
max=265,
|
||||
update=prop_update_superellipsoid,
|
||||
)
|
||||
|
||||
se_n1: FloatProperty(
|
||||
name="Ring manipulator",
|
||||
description="Manipulates the shape of the Ring",
|
||||
default=1.0,
|
||||
min=0.01,
|
||||
max=100.0,
|
||||
update=prop_update_superellipsoid,
|
||||
)
|
||||
|
||||
se_n2: FloatProperty(
|
||||
name="Cross manipulator",
|
||||
description="Manipulates the shape of the cross-section",
|
||||
default=1.0,
|
||||
min=0.01,
|
||||
max=100.0,
|
||||
update=prop_update_superellipsoid,
|
||||
)
|
||||
|
||||
se_edit: EnumProperty(
|
||||
items=[("NOTHING", "Nothing", ""), ("NGONS", "N-Gons", ""), ("TRIANGLES", "Triangles", "")],
|
||||
name="Fill up and down",
|
||||
description="",
|
||||
default="TRIANGLES",
|
||||
update=prop_update_superellipsoid,
|
||||
)
|
||||
|
||||
#############Used for loft but also Superellipsoid, etc.
|
||||
curveshape: EnumProperty(
|
||||
name="Povray Shape Type",
|
||||
items=(
|
||||
("birail", "Birail", ""),
|
||||
("cairo", "Cairo", ""),
|
||||
("lathe", "Lathe", ""),
|
||||
("loft", "Loft", ""),
|
||||
("prism", "Prism", ""),
|
||||
("sphere_sweep", "Sphere Sweep", ""),
|
||||
("sor", "Surface of Revolution", ""),
|
||||
),
|
||||
default="sphere_sweep",
|
||||
)
|
||||
|
||||
#############Supertorus
|
||||
def prop_update_supertorus(self, context):
|
||||
|
||||
"""Update POV supertorus primitive parameters not only at creation but anytime they are changed in UI."""
|
||||
|
||||
bpy.ops.pov.supertorus_update()
|
||||
|
||||
st_major_radius: FloatProperty(
|
||||
name="Major radius",
|
||||
description="Major radius",
|
||||
min=0.00,
|
||||
max=100.00,
|
||||
default=1.0,
|
||||
update=prop_update_supertorus,
|
||||
)
|
||||
|
||||
st_minor_radius: FloatProperty(
|
||||
name="Minor radius",
|
||||
description="Minor radius",
|
||||
min=0.00,
|
||||
max=100.00,
|
||||
default=0.25,
|
||||
update=prop_update_supertorus,
|
||||
)
|
||||
|
||||
st_ring: FloatProperty(
|
||||
name="Ring",
|
||||
description="Ring manipulator",
|
||||
min=0.0001,
|
||||
max=100.00,
|
||||
default=1.00,
|
||||
update=prop_update_supertorus,
|
||||
)
|
||||
|
||||
st_cross: FloatProperty(
|
||||
name="Cross",
|
||||
description="Cross manipulator",
|
||||
min=0.0001,
|
||||
max=100.00,
|
||||
default=1.00,
|
||||
update=prop_update_supertorus,
|
||||
)
|
||||
|
||||
st_accuracy: FloatProperty(
|
||||
name="Accuracy", description="Supertorus accuracy", min=0.00001, max=1.00, default=0.001
|
||||
)
|
||||
|
||||
st_max_gradient: FloatProperty(
|
||||
name="Gradient",
|
||||
description="Max gradient",
|
||||
min=0.0001,
|
||||
max=100.00,
|
||||
default=10.00,
|
||||
update=prop_update_supertorus,
|
||||
)
|
||||
|
||||
st_R: FloatProperty(
|
||||
name="big radius",
|
||||
description="The radius inside the tube",
|
||||
default=1.0,
|
||||
min=0.01,
|
||||
max=100.0,
|
||||
update=prop_update_supertorus,
|
||||
)
|
||||
|
||||
st_r: FloatProperty(
|
||||
name="small radius",
|
||||
description="The radius of the tube",
|
||||
default=0.3,
|
||||
min=0.01,
|
||||
max=100.0,
|
||||
update=prop_update_supertorus,
|
||||
)
|
||||
|
||||
st_u: IntProperty(
|
||||
name="U-segments",
|
||||
description="radial segmentation",
|
||||
default=16,
|
||||
min=3,
|
||||
max=265,
|
||||
update=prop_update_supertorus,
|
||||
)
|
||||
|
||||
st_v: IntProperty(
|
||||
name="V-segments",
|
||||
description="lateral segmentation",
|
||||
default=8,
|
||||
min=3,
|
||||
max=265,
|
||||
update=prop_update_supertorus,
|
||||
)
|
||||
|
||||
st_n1: FloatProperty(
|
||||
name="Ring manipulator",
|
||||
description="Manipulates the shape of the Ring",
|
||||
default=1.0,
|
||||
min=0.01,
|
||||
max=100.0,
|
||||
update=prop_update_supertorus,
|
||||
)
|
||||
|
||||
st_n2: FloatProperty(
|
||||
name="Cross manipulator",
|
||||
description="Manipulates the shape of the cross-section",
|
||||
default=1.0,
|
||||
min=0.01,
|
||||
max=100.0,
|
||||
update=prop_update_supertorus,
|
||||
)
|
||||
|
||||
st_ie: BoolProperty(
|
||||
name="Use Int.+Ext. radii",
|
||||
description="Use internal and external radii",
|
||||
default=False,
|
||||
update=prop_update_supertorus,
|
||||
)
|
||||
|
||||
st_edit: BoolProperty(
|
||||
name="", description="", default=False, options={"HIDDEN"}, update=prop_update_supertorus
|
||||
)
|
||||
|
||||
########################Loft
|
||||
loft_n: IntProperty(
|
||||
name="Segments", description="Vertical segments", default=16, min=3, max=720
|
||||
)
|
||||
|
||||
loft_rings_bottom: IntProperty(
|
||||
name="Bottom", description="Bottom rings", default=5, min=2, max=100
|
||||
)
|
||||
|
||||
loft_rings_side: IntProperty(name="Side", description="Side rings", default=10, min=2, max=100)
|
||||
|
||||
loft_thick: FloatProperty(
|
||||
name="Thickness",
|
||||
description="Manipulates the shape of the Ring",
|
||||
default=0.3,
|
||||
min=0.01,
|
||||
max=1.0,
|
||||
)
|
||||
|
||||
loft_r: FloatProperty(name="Radius", description="Radius", default=1, min=0.01, max=10)
|
||||
|
||||
loft_height: FloatProperty(
|
||||
name="Height",
|
||||
description="Manipulates the shape of the Ring",
|
||||
default=2,
|
||||
min=0.01,
|
||||
max=10.0,
|
||||
)
|
||||
|
||||
###################Prism
|
||||
prism_n: IntProperty(name="Sides", description="Number of sides", default=5, min=3, max=720)
|
||||
|
||||
prism_r: FloatProperty(name="Radius", description="Radius", default=1.0)
|
||||
|
||||
##################Isosurface
|
||||
iso_function_text: StringProperty(
|
||||
name="Function Text", maxlen=1024
|
||||
) # ,update=iso_props_update_callback)
|
||||
|
||||
##################PolygonToCircle
|
||||
polytocircle_resolution: IntProperty(
|
||||
name="Resolution", description="", default=3, min=0, max=256
|
||||
)
|
||||
|
||||
polytocircle_ngon: IntProperty(name="NGon", description="", min=3, max=64, default=5)
|
||||
|
||||
polytocircle_ngonR: FloatProperty(name="NGon Radius", description="", default=0.3)
|
||||
|
||||
polytocircle_circleR: FloatProperty(name="Circle Radius", description="", default=1.0)
|
||||
|
||||
###############################################################################
|
||||
# Modifiers POV properties.
|
||||
###############################################################################
|
||||
# class RenderPovSettingsModifier(PropertyGroup):
|
||||
boolean_mod: EnumProperty(
|
||||
name="Operation",
|
||||
description="Choose the type of calculation for Boolean modifier",
|
||||
items=(
|
||||
("BMESH", "Use the BMesh Boolean Solver", ""),
|
||||
("CARVE", "Use the Carve Boolean Solver", ""),
|
||||
("POV", "Use POV Constructive Solid Geometry", ""),
|
||||
),
|
||||
default="BMESH",
|
||||
)
|
||||
|
||||
#################Avogadro
|
||||
# filename_ext = ".png"
|
||||
|
||||
# filter_glob = StringProperty(
|
||||
# default="*.exr;*.gif;*.hdr;*.iff;*.jpeg;*.jpg;*.pgm;*.png;*.pot;*.ppm;*.sys;*.tga;*.tiff;*.EXR;*.GIF;*.HDR;*.IFF;*.JPEG;*.JPG;*.PGM;*.PNG;*.POT;*.PPM;*.SYS;*.TGA;*.TIFF",
|
||||
# options={'HIDDEN'},
|
||||
# )
|
||||
|
||||
|
||||
classes = (RenderPovSettingsObject,)
|
||||
|
||||
|
||||
def register():
|
||||
for cls in classes:
|
||||
register_class(cls)
|
||||
bpy.types.Object.pov = PointerProperty(type=RenderPovSettingsObject)
|
||||
|
||||
|
||||
def unregister():
|
||||
del bpy.types.Object.pov
|
||||
for cls in reversed(classes):
|
||||
unregister_class(cls)
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,562 @@
|
|||
# ##### BEGIN GPL LICENSE BLOCK #####
|
||||
#
|
||||
# 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 2
|
||||
# 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
|
||||
# MERCHANTABILITY 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, write to the Free Software Foundation,
|
||||
# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
#
|
||||
# ##### END GPL LICENSE BLOCK #####
|
||||
|
||||
# <pep8 compliant>
|
||||
|
||||
"""User interface for rendering parameters"""
|
||||
|
||||
import bpy
|
||||
from sys import platform # really import here, as in render.py?
|
||||
|
||||
# Or todo: handle this more crossplatform using QTpovray for Linux for instance
|
||||
# from os.path import isfile
|
||||
from bl_operators.presets import AddPresetBase
|
||||
from bpy.utils import register_class, unregister_class
|
||||
from bpy.props import EnumProperty
|
||||
from bpy.types import Operator, Menu, Panel
|
||||
|
||||
|
||||
# Example of wrapping every class 'as is'
|
||||
from bl_ui import properties_output
|
||||
|
||||
for member in dir(properties_output):
|
||||
subclass = getattr(properties_output, member)
|
||||
try:
|
||||
subclass.COMPAT_ENGINES.add('POVRAY_RENDER')
|
||||
except BaseException as e:
|
||||
print(e.__doc__)
|
||||
print('An exception occurred: {}'.format(e))
|
||||
pass
|
||||
del properties_output
|
||||
|
||||
from bl_ui import properties_freestyle
|
||||
|
||||
for member in dir(properties_freestyle):
|
||||
subclass = getattr(properties_freestyle, member)
|
||||
try:
|
||||
if not (subclass.bl_space_type == 'PROPERTIES' and subclass.bl_context == "render"):
|
||||
subclass.COMPAT_ENGINES.add('POVRAY_RENDER')
|
||||
# subclass.bl_parent_id = "RENDER_PT_POV_filter"
|
||||
except BaseException as e:
|
||||
print(e.__doc__)
|
||||
print('An exception occurred: {}'.format(e))
|
||||
pass
|
||||
del properties_freestyle
|
||||
|
||||
from bl_ui import properties_view_layer
|
||||
|
||||
for member in dir(properties_view_layer):
|
||||
subclass = getattr(properties_view_layer, member)
|
||||
try:
|
||||
subclass.COMPAT_ENGINES.add('POVRAY_RENDER')
|
||||
except BaseException as e:
|
||||
print(e.__doc__)
|
||||
print('An exception occurred: {}'.format(e))
|
||||
pass
|
||||
del properties_view_layer
|
||||
|
||||
# Use some of the existing buttons.
|
||||
from bl_ui import properties_render
|
||||
|
||||
# DEPRECATED#properties_render.RENDER_PT_render.COMPAT_ENGINES.add('POVRAY_RENDER')
|
||||
# DEPRECATED#properties_render.RENDER_PT_dimensions.COMPAT_ENGINES.add('POVRAY_RENDER')
|
||||
# properties_render.RENDER_PT_antialiasing.COMPAT_ENGINES.add('POVRAY_RENDER')
|
||||
# TORECREATE##DEPRECATED#properties_render.RENDER_PT_shading.COMPAT_ENGINES.add('POVRAY_RENDER')
|
||||
# DEPRECATED#properties_render.RENDER_PT_output.COMPAT_ENGINES.add('POVRAY_RENDER')
|
||||
del properties_render
|
||||
|
||||
|
||||
def check_render_freestyle_svg():
|
||||
"""Test if Freestyle SVG Exporter addon is activated
|
||||
|
||||
This addon is currently used to generate the SVG lines file
|
||||
when Freestyle is enabled alongside POV
|
||||
"""
|
||||
if "render_freestyle_svg" in bpy.context.preferences.addons.keys():
|
||||
return True
|
||||
return False
|
||||
|
||||
|
||||
class RenderButtonsPanel:
|
||||
"""Use this class to define buttons from the render tab of
|
||||
properties window."""
|
||||
|
||||
bl_space_type = 'PROPERTIES'
|
||||
bl_region_type = 'WINDOW'
|
||||
bl_context = "render"
|
||||
COMPAT_ENGINES = {'POVRAY_RENDER'}
|
||||
|
||||
@classmethod
|
||||
def poll(cls, context):
|
||||
rd = context.scene.render
|
||||
return rd.engine in cls.COMPAT_ENGINES
|
||||
|
||||
|
||||
class RENDER_PT_POV_export_settings(RenderButtonsPanel, Panel):
|
||||
"""Use this class to define pov ini settingss buttons."""
|
||||
|
||||
bl_options = {'DEFAULT_CLOSED'}
|
||||
bl_label = "Auto Start"
|
||||
COMPAT_ENGINES = {'POVRAY_RENDER'}
|
||||
|
||||
def draw_header(self, context):
|
||||
scene = context.scene
|
||||
if scene.pov.tempfiles_enable:
|
||||
self.layout.prop(scene.pov, "tempfiles_enable", text="", icon='AUTO')
|
||||
else:
|
||||
self.layout.prop(scene.pov, "tempfiles_enable", text="", icon='CONSOLE')
|
||||
|
||||
def draw(self, context):
|
||||
|
||||
layout = self.layout
|
||||
|
||||
scene = context.scene
|
||||
|
||||
layout.active = scene.pov.max_trace_level != 0
|
||||
split = layout.split()
|
||||
|
||||
col = split.column()
|
||||
col.label(text="Command line options:")
|
||||
col.prop(scene.pov, "command_line_switches", text="", icon='RIGHTARROW')
|
||||
split = layout.split()
|
||||
|
||||
# layout.active = not scene.pov.tempfiles_enable
|
||||
if not scene.pov.tempfiles_enable:
|
||||
split.prop(scene.pov, "deletefiles_enable", text="Delete files")
|
||||
split.prop(scene.pov, "pov_editor", text="POV Editor")
|
||||
|
||||
col = layout.column()
|
||||
col.prop(scene.pov, "scene_name", text="Name")
|
||||
col.prop(scene.pov, "scene_path", text="Path to files")
|
||||
# col.prop(scene.pov, "scene_path", text="Path to POV-file")
|
||||
# col.prop(scene.pov, "renderimage_path", text="Path to image")
|
||||
|
||||
split = layout.split()
|
||||
split.prop(scene.pov, "indentation_character", text="Indent")
|
||||
if scene.pov.indentation_character == 'SPACE':
|
||||
split.prop(scene.pov, "indentation_spaces", text="Spaces")
|
||||
|
||||
row = layout.row()
|
||||
row.prop(scene.pov, "comments_enable", text="Comments")
|
||||
row.prop(scene.pov, "list_lf_enable", text="Line breaks in lists")
|
||||
|
||||
|
||||
class RENDER_PT_POV_render_settings(RenderButtonsPanel, Panel):
|
||||
"""Use this class to define pov render settings buttons."""
|
||||
|
||||
bl_label = "Global Settings"
|
||||
bl_icon = 'SETTINGS'
|
||||
bl_options = {'DEFAULT_CLOSED'}
|
||||
COMPAT_ENGINES = {'POVRAY_RENDER'}
|
||||
|
||||
def draw_header(self, context):
|
||||
scene = context.scene
|
||||
if scene.pov.global_settings_advanced:
|
||||
self.layout.prop(scene.pov, "global_settings_advanced", text="", icon='SETTINGS')
|
||||
else:
|
||||
self.layout.prop(scene.pov, "global_settings_advanced", text="", icon='PREFERENCES')
|
||||
|
||||
def draw(self, context):
|
||||
layout = self.layout
|
||||
|
||||
scene = context.scene
|
||||
# rd = context.scene.render
|
||||
# layout.active = (scene.pov.max_trace_level != 0)
|
||||
|
||||
if not platform.startswith('win'):
|
||||
layout.prop(scene.pov, "sdl_window_enable", text="POV-Ray SDL Window")
|
||||
|
||||
col = layout.column()
|
||||
col.label(text="Main Path Tracing:")
|
||||
col.prop(scene.pov, "max_trace_level", text="Ray Depth")
|
||||
align = True
|
||||
layout.active = scene.pov.global_settings_advanced
|
||||
row = layout.row(align=align)
|
||||
row.prop(scene.pov, "adc_bailout")
|
||||
row = layout.row(align=align)
|
||||
row.prop(scene.pov, "ambient_light")
|
||||
row = layout.row(align=align)
|
||||
row.prop(scene.pov, "irid_wavelength")
|
||||
row = layout.row(align=align)
|
||||
row.prop(scene.pov, "number_of_waves")
|
||||
row = layout.row(align=align)
|
||||
row.prop(scene.pov, "noise_generator")
|
||||
|
||||
split = layout.split()
|
||||
split.label(text="Shading:")
|
||||
split = layout.split()
|
||||
|
||||
row = split.row(align=align)
|
||||
row.prop(scene.pov, "use_shadows")
|
||||
row.prop(scene.pov, "alpha_mode")
|
||||
|
||||
|
||||
class RENDER_PT_POV_photons(RenderButtonsPanel, Panel):
|
||||
"""Use this class to define pov photons buttons."""
|
||||
|
||||
bl_label = "Photons"
|
||||
bl_options = {'DEFAULT_CLOSED'}
|
||||
COMPAT_ENGINES = {'POVRAY_RENDER'}
|
||||
|
||||
# def draw_header(self, context):
|
||||
# self.layout.label(icon='SETTINGS')
|
||||
|
||||
def draw_header(self, context):
|
||||
scene = context.scene
|
||||
if scene.pov.photon_enable:
|
||||
self.layout.prop(scene.pov, "photon_enable", text="", icon='PMARKER_ACT')
|
||||
else:
|
||||
self.layout.prop(scene.pov, "photon_enable", text="", icon='PMARKER')
|
||||
|
||||
def draw(self, context):
|
||||
scene = context.scene
|
||||
layout = self.layout
|
||||
layout.active = scene.pov.photon_enable
|
||||
col = layout.column()
|
||||
# col.label(text="Global Photons:")
|
||||
col.prop(scene.pov, "photon_max_trace_level", text="Photon Depth")
|
||||
|
||||
split = layout.split()
|
||||
|
||||
col = split.column()
|
||||
col.prop(scene.pov, "photon_spacing", text="Spacing")
|
||||
col.prop(scene.pov, "photon_gather_min")
|
||||
|
||||
col = split.column()
|
||||
col.prop(scene.pov, "photon_adc_bailout", text="Photon ADC")
|
||||
col.prop(scene.pov, "photon_gather_max")
|
||||
|
||||
box = layout.box()
|
||||
box.label(text='Photon Map File:')
|
||||
row = box.row()
|
||||
row.prop(scene.pov, "photon_map_file_save_load", expand=True)
|
||||
if scene.pov.photon_map_file_save_load in {'save'}:
|
||||
box.prop(scene.pov, "photon_map_dir")
|
||||
box.prop(scene.pov, "photon_map_filename")
|
||||
if scene.pov.photon_map_file_save_load in {'load'}:
|
||||
box.prop(scene.pov, "photon_map_file")
|
||||
# end main photons
|
||||
|
||||
|
||||
class RENDER_PT_POV_antialias(RenderButtonsPanel, Panel):
|
||||
"""Use this class to define pov antialiasing buttons."""
|
||||
|
||||
bl_label = "Anti-Aliasing"
|
||||
bl_options = {'DEFAULT_CLOSED'}
|
||||
COMPAT_ENGINES = {'POVRAY_RENDER'}
|
||||
|
||||
def draw_header(self, context):
|
||||
prefs = bpy.context.preferences.addons[__package__].preferences
|
||||
scene = context.scene
|
||||
if prefs.branch_feature_set_povray != 'uberpov' and scene.pov.antialias_method == '2':
|
||||
self.layout.prop(scene.pov, "antialias_enable", text="", icon='ERROR')
|
||||
elif scene.pov.antialias_enable:
|
||||
self.layout.prop(scene.pov, "antialias_enable", text="", icon='ANTIALIASED')
|
||||
else:
|
||||
self.layout.prop(scene.pov, "antialias_enable", text="", icon='ALIASED')
|
||||
|
||||
def draw(self, context):
|
||||
prefs = bpy.context.preferences.addons[__package__].preferences
|
||||
layout = self.layout
|
||||
scene = context.scene
|
||||
|
||||
layout.active = scene.pov.antialias_enable
|
||||
|
||||
row = layout.row()
|
||||
row.prop(scene.pov, "antialias_method", text="")
|
||||
|
||||
if prefs.branch_feature_set_povray != 'uberpov' and scene.pov.antialias_method == '2':
|
||||
col = layout.column()
|
||||
col.alignment = 'CENTER'
|
||||
col.label(text="Stochastic Anti Aliasing is")
|
||||
col.label(text="Only Available with UberPOV")
|
||||
col.label(text="Feature Set in User Preferences.")
|
||||
col.label(text="Using Type 2 (recursive) instead")
|
||||
else:
|
||||
row.prop(scene.pov, "jitter_enable", text="Jitter")
|
||||
|
||||
split = layout.split()
|
||||
col = split.column()
|
||||
col.prop(scene.pov, "antialias_depth", text="AA Depth")
|
||||
sub = split.column()
|
||||
sub.prop(scene.pov, "jitter_amount", text="Jitter Amount")
|
||||
if scene.pov.jitter_enable:
|
||||
sub.enabled = True
|
||||
else:
|
||||
sub.enabled = False
|
||||
|
||||
row = layout.row()
|
||||
row.prop(scene.pov, "antialias_threshold", text="AA Threshold")
|
||||
row.prop(scene.pov, "antialias_gamma", text="AA Gamma")
|
||||
|
||||
if prefs.branch_feature_set_povray == 'uberpov':
|
||||
row = layout.row()
|
||||
row.prop(scene.pov, "antialias_confidence", text="AA Confidence")
|
||||
if scene.pov.antialias_method == '2':
|
||||
row.enabled = True
|
||||
else:
|
||||
row.enabled = False
|
||||
|
||||
|
||||
class RENDER_PT_POV_radiosity(RenderButtonsPanel, Panel):
|
||||
"""Use this class to define pov radiosity buttons."""
|
||||
|
||||
bl_label = "Diffuse Radiosity"
|
||||
bl_options = {'DEFAULT_CLOSED'}
|
||||
COMPAT_ENGINES = {'POVRAY_RENDER'}
|
||||
|
||||
def draw_header(self, context):
|
||||
scene = context.scene
|
||||
if scene.pov.radio_enable:
|
||||
self.layout.prop(scene.pov, "radio_enable", text="", icon='OUTLINER_OB_LIGHTPROBE')
|
||||
else:
|
||||
self.layout.prop(scene.pov, "radio_enable", text="", icon='LIGHTPROBE_CUBEMAP')
|
||||
|
||||
def draw(self, context):
|
||||
layout = self.layout
|
||||
|
||||
scene = context.scene
|
||||
|
||||
layout.active = scene.pov.radio_enable
|
||||
|
||||
split = layout.split()
|
||||
|
||||
col = split.column()
|
||||
col.prop(scene.pov, "radio_count", text="Rays")
|
||||
col.prop(scene.pov, "radio_recursion_limit", text="Recursions")
|
||||
|
||||
split.prop(scene.pov, "radio_error_bound", text="Error Bound")
|
||||
|
||||
layout.prop(scene.pov, "radio_display_advanced")
|
||||
|
||||
if scene.pov.radio_display_advanced:
|
||||
split = layout.split()
|
||||
|
||||
col = split.column()
|
||||
col.prop(scene.pov, "radio_adc_bailout", slider=True)
|
||||
col.prop(scene.pov, "radio_minimum_reuse", text="Min Reuse")
|
||||
col.prop(scene.pov, "radio_gray_threshold", slider=True)
|
||||
col.prop(scene.pov, "radio_pretrace_start", slider=True)
|
||||
col.prop(scene.pov, "radio_low_error_factor", slider=True)
|
||||
|
||||
col = split.column()
|
||||
col.prop(scene.pov, "radio_brightness")
|
||||
col.prop(scene.pov, "radio_maximum_reuse", text="Max Reuse")
|
||||
col.prop(scene.pov, "radio_nearest_count")
|
||||
col.prop(scene.pov, "radio_pretrace_end", slider=True)
|
||||
|
||||
col = layout.column()
|
||||
col.label(text="Estimation Influence:")
|
||||
col.prop(scene.pov, "radio_always_sample")
|
||||
col.prop(scene.pov, "radio_normal")
|
||||
col.prop(scene.pov, "radio_media")
|
||||
col.prop(scene.pov, "radio_subsurface")
|
||||
|
||||
|
||||
class POV_RADIOSITY_MT_presets(Menu):
|
||||
"""Use this class to define pov radiosity presets menu."""
|
||||
|
||||
bl_label = "Radiosity Presets"
|
||||
preset_subdir = "pov/radiosity"
|
||||
preset_operator = "script.execute_preset"
|
||||
draw = bpy.types.Menu.draw_preset
|
||||
|
||||
|
||||
class RENDER_OT_POV_radiosity_add_preset(AddPresetBase, Operator):
|
||||
"""Use this class to define pov radiosity add presets button"""
|
||||
|
||||
'''Add a Radiosity Preset'''
|
||||
bl_idname = "scene.radiosity_preset_add"
|
||||
bl_label = "Add Radiosity Preset"
|
||||
preset_menu = "POV_RADIOSITY_MT_presets"
|
||||
|
||||
# variable used for all preset values
|
||||
preset_defines = ["scene = bpy.context.scene"]
|
||||
|
||||
# properties to store in the preset
|
||||
preset_values = [
|
||||
"scene.pov.radio_display_advanced",
|
||||
"scene.pov.radio_adc_bailout",
|
||||
"scene.pov.radio_always_sample",
|
||||
"scene.pov.radio_brightness",
|
||||
"scene.pov.radio_count",
|
||||
"scene.pov.radio_error_bound",
|
||||
"scene.pov.radio_gray_threshold",
|
||||
"scene.pov.radio_low_error_factor",
|
||||
"scene.pov.radio_media",
|
||||
"scene.pov.radio_subsurface",
|
||||
"scene.pov.radio_minimum_reuse",
|
||||
"scene.pov.radio_maximum_reuse",
|
||||
"scene.pov.radio_nearest_count",
|
||||
"scene.pov.radio_normal",
|
||||
"scene.pov.radio_recursion_limit",
|
||||
"scene.pov.radio_pretrace_start",
|
||||
"scene.pov.radio_pretrace_end",
|
||||
]
|
||||
|
||||
# where to store the preset
|
||||
preset_subdir = "pov/radiosity"
|
||||
|
||||
|
||||
# Draw into an existing panel
|
||||
def rad_panel_func(self, context):
|
||||
"""Display radiosity presets rolldown menu"""
|
||||
layout = self.layout
|
||||
|
||||
row = layout.row(align=True)
|
||||
row.menu(POV_RADIOSITY_MT_presets.__name__, text=POV_RADIOSITY_MT_presets.bl_label)
|
||||
row.operator(RENDER_OT_POV_radiosity_add_preset.bl_idname, text="", icon='ADD')
|
||||
row.operator(
|
||||
RENDER_OT_POV_radiosity_add_preset.bl_idname, text="", icon='REMOVE'
|
||||
).remove_active = True
|
||||
|
||||
|
||||
###############################################################################
|
||||
# Freestyle
|
||||
###############################################################################
|
||||
# import addon_utils
|
||||
# addon_utils.paths()[0]
|
||||
# addon_utils.modules()
|
||||
# mod.bl_info['name'] == 'Freestyle SVG Exporter':
|
||||
bpy.utils.script_paths("addons")
|
||||
# render_freestyle_svg = os.path.join(bpy.utils.script_paths("addons"), "render_freestyle_svg.py")
|
||||
|
||||
render_freestyle_svg = bpy.context.preferences.addons.get('render_freestyle_svg')
|
||||
# mpath=addon_utils.paths()[0].render_freestyle_svg
|
||||
# import mpath
|
||||
# from mpath import render_freestyle_svg #= addon_utils.modules(['Freestyle SVG Exporter'])
|
||||
# from scripts\\addons import render_freestyle_svg
|
||||
if check_render_freestyle_svg():
|
||||
'''
|
||||
snippetsWIP
|
||||
import myscript
|
||||
import importlib
|
||||
|
||||
importlib.reload(myscript)
|
||||
myscript.main()
|
||||
'''
|
||||
for member in dir(render_freestyle_svg):
|
||||
subclass = getattr(render_freestyle_svg, member)
|
||||
try:
|
||||
subclass.COMPAT_ENGINES.add('POVRAY_RENDER')
|
||||
if subclass.bl_idname == "RENDER_PT_SVGExporterPanel":
|
||||
subclass.bl_parent_id = "RENDER_PT_POV_filter"
|
||||
subclass.bl_options = {'HIDE_HEADER'}
|
||||
# subclass.bl_order = 11
|
||||
print(subclass.bl_info)
|
||||
except BaseException as e:
|
||||
print(e.__doc__)
|
||||
print('An exception occurred: {}'.format(e))
|
||||
pass
|
||||
|
||||
# del render_freestyle_svg.RENDER_PT_SVGExporterPanel.bl_parent_id
|
||||
|
||||
|
||||
class RENDER_PT_POV_filter(RenderButtonsPanel, Panel):
|
||||
"""Use this class to invoke stuff like Freestyle UI."""
|
||||
|
||||
bl_label = "Freestyle"
|
||||
bl_options = {'DEFAULT_CLOSED'}
|
||||
COMPAT_ENGINES = {'POVRAY_RENDER'}
|
||||
|
||||
@classmethod
|
||||
def poll(cls, context):
|
||||
with_freestyle = bpy.app.build_options.freestyle
|
||||
engine = context.scene.render.engine
|
||||
return with_freestyle and engine == 'POVRAY_RENDER'
|
||||
|
||||
def draw_header(self, context):
|
||||
|
||||
# scene = context.scene
|
||||
rd = context.scene.render
|
||||
layout = self.layout
|
||||
|
||||
if rd.use_freestyle:
|
||||
layout.prop(rd, "use_freestyle", text="", icon='LINE_DATA')
|
||||
|
||||
else:
|
||||
layout.prop(rd, "use_freestyle", text="", icon='OUTLINER_OB_IMAGE')
|
||||
|
||||
def draw(self, context):
|
||||
rd = context.scene.render
|
||||
layout = self.layout
|
||||
layout.active = rd.use_freestyle
|
||||
layout.use_property_split = True
|
||||
layout.use_property_decorate = False # No animation.
|
||||
flow = layout.grid_flow(
|
||||
row_major=True, columns=0, even_columns=True, even_rows=False, align=True
|
||||
)
|
||||
|
||||
flow.prop(rd, "line_thickness_mode", expand=True)
|
||||
|
||||
if rd.line_thickness_mode == 'ABSOLUTE':
|
||||
flow.prop(rd, "line_thickness")
|
||||
|
||||
# Warning if the Freestyle SVG Exporter addon is not enabled
|
||||
if not check_render_freestyle_svg():
|
||||
# col = box.column()
|
||||
layout.label(text="Please enable Freestyle SVG Exporter addon", icon="INFO")
|
||||
# layout.separator()
|
||||
layout.operator(
|
||||
"preferences.addon_show",
|
||||
text="Go to Render: Freestyle SVG Exporter addon",
|
||||
icon="PREFERENCES",
|
||||
).module = "render_freestyle_svg"
|
||||
|
||||
|
||||
##class RENDER_PT_povray_baking(RenderButtonsPanel, Panel):
|
||||
## bl_label = "Baking"
|
||||
## COMPAT_ENGINES = {'POVRAY_RENDER'}
|
||||
##
|
||||
## def draw_header(self, context):
|
||||
## scene = context.scene
|
||||
##
|
||||
## self.layout.prop(scene.pov, "baking_enable", text="")
|
||||
##
|
||||
## def draw(self, context):
|
||||
## layout = self.layout
|
||||
##
|
||||
## scene = context.scene
|
||||
## rd = scene.render
|
||||
##
|
||||
## layout.active = scene.pov.baking_enable
|
||||
|
||||
|
||||
classes = (
|
||||
RENDER_PT_POV_export_settings,
|
||||
RENDER_PT_POV_render_settings,
|
||||
RENDER_PT_POV_photons,
|
||||
RENDER_PT_POV_antialias,
|
||||
RENDER_PT_POV_radiosity,
|
||||
RENDER_PT_POV_filter,
|
||||
# RENDER_PT_povray_baking,
|
||||
POV_RADIOSITY_MT_presets,
|
||||
RENDER_OT_POV_radiosity_add_preset,
|
||||
)
|
||||
|
||||
|
||||
def register():
|
||||
for cls in classes:
|
||||
register_class(cls)
|
||||
bpy.types.RENDER_PT_POV_radiosity.prepend(rad_panel_func)
|
||||
|
||||
|
||||
def unregister():
|
||||
bpy.types.RENDER_PT_POV_radiosity.remove(rad_panel_func)
|
||||
for cls in reversed(classes):
|
||||
unregister_class(cls)
|
|
@ -0,0 +1,687 @@
|
|||
# ##### BEGIN GPL LICENSE BLOCK #####
|
||||
#
|
||||
# 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 2
|
||||
# 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
|
||||
# MERCHANTABILITY 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, write to the Free Software Foundation,
|
||||
# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
#
|
||||
# ##### END GPL LICENSE BLOCK #####
|
||||
|
||||
# <pep8 compliant>
|
||||
"""Declare rendering properties controllable in UI"""
|
||||
|
||||
import bpy
|
||||
from bpy.utils import register_class, unregister_class
|
||||
from bpy.types import PropertyGroup
|
||||
from bpy.props import (
|
||||
BoolProperty,
|
||||
IntProperty,
|
||||
FloatProperty,
|
||||
FloatVectorProperty,
|
||||
StringProperty,
|
||||
EnumProperty,
|
||||
PointerProperty,
|
||||
)
|
||||
|
||||
###############################################################################
|
||||
# Scene POV properties.
|
||||
###############################################################################
|
||||
class RenderPovSettingsScene(PropertyGroup):
|
||||
|
||||
"""Declare scene level properties controllable in UI and translated to POV"""
|
||||
|
||||
# Linux SDL-window enable
|
||||
sdl_window_enable: BoolProperty(
|
||||
name="Enable SDL window", description="Enable the SDL window in Linux OS", default=True
|
||||
)
|
||||
# File Options
|
||||
text_block: StringProperty(
|
||||
name="Text Scene Name",
|
||||
description="Name of POV scene to use. "
|
||||
"Set when clicking Run to render current text only",
|
||||
maxlen=1024,
|
||||
)
|
||||
tempfiles_enable: BoolProperty(
|
||||
name="Enable Tempfiles",
|
||||
description="Enable the OS-Tempfiles. Otherwise set the path where to save the files",
|
||||
default=True,
|
||||
)
|
||||
pov_editor: BoolProperty(
|
||||
name="POV editor",
|
||||
description="Don't Close POV editor after rendering (Overridden by /EXIT command)",
|
||||
default=False,
|
||||
)
|
||||
deletefiles_enable: BoolProperty(
|
||||
name="Delete files",
|
||||
description="Delete files after rendering. Doesn't work with the image",
|
||||
default=True,
|
||||
)
|
||||
scene_name: StringProperty(
|
||||
name="Scene Name",
|
||||
description="Name of POV scene to create. Empty name will use "
|
||||
"the name of the blend file",
|
||||
maxlen=1024,
|
||||
)
|
||||
scene_path: StringProperty(
|
||||
name="Export scene path",
|
||||
# Bug in POV-Ray RC3
|
||||
# description="Path to directory where the exported scene "
|
||||
# "(POV and INI) is created",
|
||||
description="Path to directory where the files are created",
|
||||
maxlen=1024,
|
||||
subtype="DIR_PATH",
|
||||
)
|
||||
renderimage_path: StringProperty(
|
||||
name="Rendered image path",
|
||||
description="Full path to directory where the rendered image is saved",
|
||||
maxlen=1024,
|
||||
subtype="DIR_PATH",
|
||||
)
|
||||
list_lf_enable: BoolProperty(
|
||||
name="LF in lists",
|
||||
description="Enable line breaks in lists (vectors and indices). "
|
||||
"Disabled: lists are exported in one line",
|
||||
default=False,
|
||||
)
|
||||
|
||||
# Not a real pov option, just to know if we should write
|
||||
radio_enable: BoolProperty(
|
||||
name="Enable Radiosity", description="Enable POV radiosity calculation", default=True
|
||||
)
|
||||
|
||||
radio_display_advanced: BoolProperty(
|
||||
name="Advanced Options", description="Show advanced options", default=False
|
||||
)
|
||||
|
||||
media_enable: BoolProperty(
|
||||
name="Enable Media", description="Enable POV atmospheric media", default=False
|
||||
)
|
||||
|
||||
media_samples: IntProperty(
|
||||
name="Samples",
|
||||
description="Number of samples taken from camera to first object "
|
||||
"encountered along ray path for media calculation",
|
||||
min=1,
|
||||
max=100,
|
||||
default=35,
|
||||
)
|
||||
|
||||
media_scattering_type: EnumProperty(
|
||||
name="Scattering Type",
|
||||
description="Scattering model",
|
||||
items=(
|
||||
(
|
||||
"1",
|
||||
"1 Isotropic",
|
||||
"The simplest form of scattering because it is independent of direction.",
|
||||
),
|
||||
(
|
||||
"2",
|
||||
"2 Mie haze ",
|
||||
"For relatively small particles such as "
|
||||
"minuscule water droplets of fog, cloud "
|
||||
"particles, and particles responsible "
|
||||
"for the polluted sky. In this model the"
|
||||
" scattering is extremely directional in"
|
||||
" the forward direction i.e. the amount "
|
||||
"of scattered light is largest when the "
|
||||
"incident light is anti-parallel to the "
|
||||
"viewing direction (the light goes "
|
||||
"directly to the viewer). It is smallest"
|
||||
" when the incident light is parallel to"
|
||||
" the viewing direction. ",
|
||||
),
|
||||
("3", "3 Mie murky", "Like haze but much more directional"),
|
||||
(
|
||||
"4",
|
||||
"4 Rayleigh",
|
||||
"For extremely small particles such as "
|
||||
"molecules of the air. The amount of "
|
||||
"scattered light depends on the incident"
|
||||
" light angle. It is largest when the "
|
||||
"incident light is parallel or "
|
||||
"anti-parallel to the viewing direction "
|
||||
"and smallest when the incident light is "
|
||||
"perpendicular to viewing direction.",
|
||||
),
|
||||
(
|
||||
"5",
|
||||
"5 Henyey-Greenstein",
|
||||
"The default eccentricity value "
|
||||
"of zero defines isotropic "
|
||||
"scattering while positive "
|
||||
"values lead to scattering in "
|
||||
"the direction of the light and "
|
||||
"negative values lead to "
|
||||
"scattering in the opposite "
|
||||
"direction of the light. Larger "
|
||||
"values of e (or smaller values "
|
||||
"in the negative case) increase "
|
||||
"the directional property of the"
|
||||
" scattering.",
|
||||
),
|
||||
),
|
||||
default="1",
|
||||
)
|
||||
|
||||
media_diffusion_scale: FloatProperty(
|
||||
name="Scale",
|
||||
description="Scale factor of Media Diffusion Color",
|
||||
precision=6,
|
||||
step=0.00000001,
|
||||
min=0.000000001,
|
||||
max=1.0,
|
||||
default=(1.0),
|
||||
)
|
||||
|
||||
media_diffusion_color: FloatVectorProperty(
|
||||
name="Media Diffusion Color",
|
||||
description="The atmospheric media color",
|
||||
precision=4,
|
||||
step=0.01,
|
||||
min=0,
|
||||
soft_max=1,
|
||||
default=(0.001, 0.001, 0.001),
|
||||
options={"ANIMATABLE"},
|
||||
subtype="COLOR",
|
||||
)
|
||||
|
||||
media_absorption_scale: FloatProperty(
|
||||
name="Scale",
|
||||
description="Scale factor of Media Absorption Color. "
|
||||
"use 1/depth of media volume in meters",
|
||||
precision=6,
|
||||
step=0.000001,
|
||||
min=0.000000001,
|
||||
max=1.0,
|
||||
default=(0.00002),
|
||||
)
|
||||
|
||||
media_absorption_color: FloatVectorProperty(
|
||||
name="Media Absorption Color",
|
||||
description="The atmospheric media absorption color",
|
||||
precision=4,
|
||||
step=0.01,
|
||||
min=0,
|
||||
soft_max=1,
|
||||
default=(0.0, 0.0, 0.0),
|
||||
options={"ANIMATABLE"},
|
||||
subtype="COLOR",
|
||||
)
|
||||
|
||||
media_eccentricity: FloatProperty(
|
||||
name="Media Eccenticity Factor",
|
||||
description="Positive values lead"
|
||||
" to scattering in the direction of the light and negative "
|
||||
"values lead to scattering in the opposite direction of the "
|
||||
"light. Larger values of e (or smaller values in the negative"
|
||||
" case) increase the directional property of the scattering",
|
||||
precision=2,
|
||||
step=0.01,
|
||||
min=-1.0,
|
||||
max=1.0,
|
||||
default=(0.0),
|
||||
options={"ANIMATABLE"},
|
||||
)
|
||||
|
||||
baking_enable: BoolProperty(
|
||||
name="Enable Baking", description="Enable POV texture baking", default=False
|
||||
)
|
||||
|
||||
indentation_character: EnumProperty(
|
||||
name="Indentation",
|
||||
description="Select the indentation type",
|
||||
items=(
|
||||
("NONE", "None", "No indentation"),
|
||||
("TAB", "Tabs", "Indentation with tabs"),
|
||||
("SPACE", "Spaces", "Indentation with spaces"),
|
||||
),
|
||||
default="SPACE",
|
||||
)
|
||||
|
||||
indentation_spaces: IntProperty(
|
||||
name="Quantity of spaces",
|
||||
description="The number of spaces for indentation",
|
||||
min=1,
|
||||
max=10,
|
||||
default=4,
|
||||
)
|
||||
|
||||
comments_enable: BoolProperty(
|
||||
name="Enable Comments", description="Add comments to pov file", default=True
|
||||
)
|
||||
|
||||
# Real pov options
|
||||
command_line_switches: StringProperty(
|
||||
name="Command Line Switches",
|
||||
description="Command line switches consist of a + (plus) or - "
|
||||
"(minus) sign, followed by one or more alphabetic "
|
||||
"characters and possibly a numeric value",
|
||||
maxlen=500,
|
||||
)
|
||||
|
||||
antialias_enable: BoolProperty(
|
||||
name="Anti-Alias", description="Enable Anti-Aliasing", default=True
|
||||
)
|
||||
|
||||
antialias_method: EnumProperty(
|
||||
name="Method",
|
||||
description="AA-sampling method. Type 1 is an adaptive, "
|
||||
"non-recursive, super-sampling (as in the plain old render "
|
||||
"bigger and scale down trick. Type 2 is a slightly "
|
||||
"more efficient adaptive and recursive super-sampling. "
|
||||
"Type 3 is a stochastic halton based super-sampling method so "
|
||||
"rather artifact free and sampling rays so depth of field can "
|
||||
"use them at no additional cost, as do area lights and "
|
||||
"subsurface scattering materials, making it the best "
|
||||
"quality / time trade-off in complex scenes",
|
||||
items=(
|
||||
("0", "non-recursive AA", "Type 1 Sampling in POV"),
|
||||
("1", "recursive AA", "Type 2 Sampling in POV"),
|
||||
("2", "stochastic AA", "Type 3 Sampling in POV"),
|
||||
),
|
||||
default="1",
|
||||
)
|
||||
|
||||
antialias_confidence: FloatProperty(
|
||||
name="Antialias Confidence",
|
||||
description="how surely the computed color "
|
||||
"of a given pixel is indeed"
|
||||
"within the threshold error margin",
|
||||
min=0.0001,
|
||||
max=1.0000,
|
||||
default=0.9900,
|
||||
precision=4,
|
||||
)
|
||||
|
||||
antialias_depth: IntProperty(
|
||||
name="Antialias Depth", description="Depth of pixel for sampling", min=1, max=9, default=2
|
||||
)
|
||||
|
||||
antialias_threshold: FloatProperty(
|
||||
name="Antialias Threshold",
|
||||
description="Tolerance for sub-pixels",
|
||||
min=0.0,
|
||||
max=1.0,
|
||||
soft_min=0.05,
|
||||
soft_max=0.5,
|
||||
default=0.03,
|
||||
)
|
||||
|
||||
jitter_enable: BoolProperty(
|
||||
name="Jitter",
|
||||
description="Enable Jittering. Adds noise into the sampling "
|
||||
"process (it should be avoided to use jitter in "
|
||||
"animation)",
|
||||
default=False,
|
||||
)
|
||||
|
||||
jitter_amount: FloatProperty(
|
||||
name="Jitter Amount",
|
||||
description="Amount of jittering",
|
||||
min=0.0,
|
||||
max=1.0,
|
||||
soft_min=0.01,
|
||||
soft_max=1.0,
|
||||
default=1.0,
|
||||
)
|
||||
|
||||
antialias_gamma: FloatProperty(
|
||||
name="Antialias Gamma",
|
||||
description="POV-Ray compares gamma-adjusted values for super "
|
||||
"sampling. Antialias Gamma sets the Gamma before "
|
||||
"comparison",
|
||||
min=0.0,
|
||||
max=5.0,
|
||||
soft_min=0.01,
|
||||
soft_max=2.5,
|
||||
default=2.5,
|
||||
)
|
||||
|
||||
alpha_mode: EnumProperty(
|
||||
name="Alpha",
|
||||
description="Representation of alpha information in the RGBA pixels",
|
||||
items=(
|
||||
("SKY", "Sky", "Transparent pixels are filled with sky color"),
|
||||
(
|
||||
"TRANSPARENT",
|
||||
"Transparent",
|
||||
"Transparent, World background is transparent with premultiplied alpha",
|
||||
),
|
||||
),
|
||||
default="SKY",
|
||||
)
|
||||
|
||||
use_shadows: BoolProperty(
|
||||
name="Shadows", description="Calculate shadows while rendering", default=True
|
||||
)
|
||||
|
||||
max_trace_level: IntProperty(
|
||||
name="Max Trace Level",
|
||||
description="Number of reflections/refractions allowed on ray " "path",
|
||||
min=1,
|
||||
max=256,
|
||||
default=5,
|
||||
)
|
||||
|
||||
adc_bailout_enable: BoolProperty(name="Enable", description="", default=False)
|
||||
|
||||
adc_bailout: FloatProperty(
|
||||
name="ADC Bailout",
|
||||
description="Adaptive Depth Control (ADC) to stop computing additional"
|
||||
"reflected or refracted rays when their contribution is insignificant."
|
||||
"The default value is 1/255, or approximately 0.0039, since a change "
|
||||
"smaller than that could not be visible in a 24 bit image. Generally "
|
||||
"this value is fine and should be left alone."
|
||||
"Setting adc_bailout to 0 will disable ADC, relying completely on "
|
||||
"max_trace_level to set an upper limit on the number of rays spawned. ",
|
||||
min=0.0,
|
||||
max=1000.0,
|
||||
default=0.00392156862745,
|
||||
precision=3,
|
||||
)
|
||||
|
||||
ambient_light_enable: BoolProperty(name="Enable", description="", default=False)
|
||||
|
||||
ambient_light: FloatVectorProperty(
|
||||
name="Ambient Light",
|
||||
description="Ambient light is used to simulate the effect of inter-diffuse reflection",
|
||||
precision=4,
|
||||
step=0.01,
|
||||
min=0,
|
||||
soft_max=1,
|
||||
default=(1, 1, 1),
|
||||
options={"ANIMATABLE"},
|
||||
subtype="COLOR",
|
||||
)
|
||||
global_settings_advanced: BoolProperty(name="Advanced", description="", default=False)
|
||||
|
||||
irid_wavelength_enable: BoolProperty(name="Enable", description="", default=False)
|
||||
|
||||
irid_wavelength: FloatVectorProperty(
|
||||
name="Irid Wavelength",
|
||||
description=(
|
||||
"Iridescence calculations depend upon the dominant "
|
||||
"wavelengths of the primary colors of red, green and blue light"
|
||||
),
|
||||
precision=4,
|
||||
step=0.01,
|
||||
min=0,
|
||||
soft_max=1,
|
||||
default=(0.25, 0.18, 0.14),
|
||||
options={"ANIMATABLE"},
|
||||
subtype="COLOR",
|
||||
)
|
||||
|
||||
number_of_waves_enable: BoolProperty(name="Enable", description="", default=False)
|
||||
|
||||
number_of_waves: IntProperty(
|
||||
name="Number Waves",
|
||||
description=(
|
||||
"The waves and ripples patterns are generated by summing a series of waves, "
|
||||
"each with a slightly different center and size"
|
||||
),
|
||||
min=1,
|
||||
max=10,
|
||||
default=1000,
|
||||
)
|
||||
|
||||
noise_generator_enable: BoolProperty(name="Enable", description="", default=False)
|
||||
|
||||
noise_generator: IntProperty(
|
||||
name="Noise Generator",
|
||||
description="There are three noise generators implemented",
|
||||
min=1,
|
||||
max=3,
|
||||
default=2,
|
||||
)
|
||||
|
||||
########################### PHOTONS #######################################
|
||||
photon_enable: BoolProperty(name="Photons", description="Enable global photons", default=False)
|
||||
|
||||
photon_enable_count: BoolProperty(
|
||||
name="Spacing / Count", description="Enable count photons", default=False
|
||||
)
|
||||
|
||||
photon_count: IntProperty(
|
||||
name="Count", description="Photons count", min=1, max=100000000, default=20000
|
||||
)
|
||||
|
||||
photon_spacing: FloatProperty(
|
||||
name="Spacing",
|
||||
description="Average distance between photons on surfaces. half "
|
||||
"this get four times as many surface photons",
|
||||
min=0.001,
|
||||
max=1.000,
|
||||
soft_min=0.001,
|
||||
soft_max=1.000,
|
||||
precision=3,
|
||||
default=0.005,
|
||||
)
|
||||
|
||||
photon_max_trace_level: IntProperty(
|
||||
name="Max Trace Level",
|
||||
description="Number of reflections/refractions allowed on ray " "path",
|
||||
min=1,
|
||||
max=256,
|
||||
default=5,
|
||||
)
|
||||
|
||||
photon_adc_bailout: FloatProperty(
|
||||
name="ADC Bailout",
|
||||
description="The adc_bailout for photons. Use adc_bailout = "
|
||||
"0.01 / brightest_ambient_object for good results",
|
||||
min=0.0,
|
||||
max=1000.0,
|
||||
soft_min=0.0,
|
||||
soft_max=1.0,
|
||||
precision=3,
|
||||
default=0.1,
|
||||
)
|
||||
|
||||
photon_gather_min: IntProperty(
|
||||
name="Gather Min",
|
||||
description="Minimum number of photons gathered" "for each point",
|
||||
min=1,
|
||||
max=256,
|
||||
default=20,
|
||||
)
|
||||
|
||||
photon_gather_max: IntProperty(
|
||||
name="Gather Max",
|
||||
description="Maximum number of photons gathered for each point",
|
||||
min=1,
|
||||
max=256,
|
||||
default=100,
|
||||
)
|
||||
|
||||
photon_map_file_save_load: EnumProperty(
|
||||
name="Operation",
|
||||
description="Load or Save photon map file",
|
||||
items=(("NONE", "None", ""), ("save", "Save", ""), ("load", "Load", "")),
|
||||
default="NONE",
|
||||
)
|
||||
|
||||
photon_map_filename: StringProperty(name="Filename", description="", maxlen=1024)
|
||||
|
||||
photon_map_dir: StringProperty(
|
||||
name="Directory", description="", maxlen=1024, subtype="DIR_PATH"
|
||||
)
|
||||
|
||||
photon_map_file: StringProperty(name="File", description="", maxlen=1024, subtype="FILE_PATH")
|
||||
|
||||
#########RADIOSITY########
|
||||
radio_adc_bailout: FloatProperty(
|
||||
name="ADC Bailout",
|
||||
description="The adc_bailout for radiosity rays. Use "
|
||||
"adc_bailout = 0.01 / brightest_ambient_object for good results",
|
||||
min=0.0,
|
||||
max=1000.0,
|
||||
soft_min=0.0,
|
||||
soft_max=1.0,
|
||||
default=0.0039,
|
||||
precision=4,
|
||||
)
|
||||
|
||||
radio_always_sample: BoolProperty(
|
||||
name="Always Sample",
|
||||
description="Only use the data from the pretrace step and not gather "
|
||||
"any new samples during the final radiosity pass",
|
||||
default=False,
|
||||
)
|
||||
|
||||
radio_brightness: FloatProperty(
|
||||
name="Brightness",
|
||||
description="Amount objects are brightened before being returned "
|
||||
"upwards to the rest of the system",
|
||||
min=0.0,
|
||||
max=1000.0,
|
||||
soft_min=0.0,
|
||||
soft_max=10.0,
|
||||
default=1.0,
|
||||
)
|
||||
|
||||
radio_count: IntProperty(
|
||||
name="Ray Count",
|
||||
description="Number of rays for each new radiosity value to be calculated "
|
||||
"(halton sequence over 1600)",
|
||||
min=1,
|
||||
max=10000,
|
||||
soft_max=1600,
|
||||
default=35,
|
||||
)
|
||||
|
||||
radio_error_bound: FloatProperty(
|
||||
name="Error Bound",
|
||||
description="One of the two main speed/quality tuning values, "
|
||||
"lower values are more accurate",
|
||||
min=0.0,
|
||||
max=1000.0,
|
||||
soft_min=0.1,
|
||||
soft_max=10.0,
|
||||
default=10.0,
|
||||
)
|
||||
|
||||
radio_gray_threshold: FloatProperty(
|
||||
name="Gray Threshold",
|
||||
description="One of the two main speed/quality tuning values, "
|
||||
"lower values are more accurate",
|
||||
min=0.0,
|
||||
max=1.0,
|
||||
soft_min=0,
|
||||
soft_max=1,
|
||||
default=0.0,
|
||||
)
|
||||
|
||||
radio_low_error_factor: FloatProperty(
|
||||
name="Low Error Factor",
|
||||
description="Just enough samples is slightly blotchy. Low error changes error "
|
||||
"tolerance for less critical last refining pass",
|
||||
min=0.000001,
|
||||
max=1.0,
|
||||
soft_min=0.000001,
|
||||
soft_max=1.0,
|
||||
default=0.5,
|
||||
)
|
||||
|
||||
radio_media: BoolProperty(
|
||||
name="Media", description="Radiosity estimation can be affected by media", default=True
|
||||
)
|
||||
|
||||
radio_subsurface: BoolProperty(
|
||||
name="Subsurface",
|
||||
description="Radiosity estimation can be affected by Subsurface Light Transport",
|
||||
default=False,
|
||||
)
|
||||
|
||||
radio_minimum_reuse: FloatProperty(
|
||||
name="Minimum Reuse",
|
||||
description="Fraction of the screen width which sets the minimum radius of reuse "
|
||||
"for each sample point (At values higher than 2% expect errors)",
|
||||
min=0.0,
|
||||
max=1.0,
|
||||
soft_min=0.1,
|
||||
soft_max=0.1,
|
||||
default=0.015,
|
||||
precision=3,
|
||||
)
|
||||
|
||||
radio_maximum_reuse: FloatProperty(
|
||||
name="Maximum Reuse",
|
||||
description="The maximum reuse parameter works in conjunction with, and is similar to that of minimum reuse, "
|
||||
"the only difference being that it is an upper bound rather than a lower one",
|
||||
min=0.0,
|
||||
max=1.0,
|
||||
default=0.2,
|
||||
precision=3,
|
||||
)
|
||||
|
||||
radio_nearest_count: IntProperty(
|
||||
name="Nearest Count",
|
||||
description="Number of old ambient values blended together to "
|
||||
"create a new interpolated value",
|
||||
min=1,
|
||||
max=20,
|
||||
default=1,
|
||||
)
|
||||
|
||||
radio_normal: BoolProperty(
|
||||
name="Normals", description="Radiosity estimation can be affected by normals", default=False
|
||||
)
|
||||
|
||||
radio_recursion_limit: IntProperty(
|
||||
name="Recursion Limit",
|
||||
description="how many recursion levels are used to calculate "
|
||||
"the diffuse inter-reflection",
|
||||
min=1,
|
||||
max=20,
|
||||
default=1,
|
||||
)
|
||||
|
||||
radio_pretrace_start: FloatProperty(
|
||||
name="Pretrace Start",
|
||||
description="Fraction of the screen width which sets the size of the "
|
||||
"blocks in the mosaic preview first pass",
|
||||
min=0.005,
|
||||
max=1.00,
|
||||
soft_min=0.02,
|
||||
soft_max=1.0,
|
||||
default=0.04,
|
||||
)
|
||||
# XXX TODO set automatically to pretrace_end = 8 / max (image_width, image_height)
|
||||
# for non advanced mode
|
||||
radio_pretrace_end: FloatProperty(
|
||||
name="Pretrace End",
|
||||
description="Fraction of the screen width which sets the size of the blocks "
|
||||
"in the mosaic preview last pass",
|
||||
min=0.000925,
|
||||
max=1.00,
|
||||
soft_min=0.01,
|
||||
soft_max=1.00,
|
||||
default=0.004,
|
||||
precision=3,
|
||||
)
|
||||
|
||||
|
||||
classes = (RenderPovSettingsScene,)
|
||||
|
||||
|
||||
def register():
|
||||
for cls in classes:
|
||||
register_class(cls)
|
||||
bpy.types.Scene.pov = PointerProperty(type=RenderPovSettingsScene)
|
||||
|
||||
|
||||
def unregister():
|
||||
del bpy.types.Scene.pov
|
||||
for cls in reversed(classes):
|
||||
unregister_class(cls)
|
|
@ -0,0 +1,847 @@
|
|||
# ***** BEGIN GPL LICENSE BLOCK *****
|
||||
#
|
||||
# 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 2
|
||||
# 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
|
||||
# MERCHANTABILITY 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, write to the Free Software Foundation,
|
||||
# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
#
|
||||
# #**** END GPL LICENSE BLOCK #****
|
||||
|
||||
# <pep8 compliant>
|
||||
|
||||
"""With respect to camera frame and optics distortions, also export environment
|
||||
|
||||
with world, sky, atmospheric effects such as rainbows or smoke """
|
||||
|
||||
import bpy
|
||||
from bpy.utils import register_class, unregister_class
|
||||
import os
|
||||
from imghdr import what # imghdr is a python lib to identify image file types
|
||||
from math import atan, pi, sqrt, degrees
|
||||
from . import df3_library # for smoke rendering
|
||||
from .object_primitives import write_object_modifiers
|
||||
|
||||
##############find image texture # used for export_world
|
||||
def image_format(imgF):
|
||||
"""Identify input image filetypes to transmit to POV."""
|
||||
# First use the below explicit extensions to identify image file prospects
|
||||
ext = {
|
||||
'JPG': "jpeg",
|
||||
'JPEG': "jpeg",
|
||||
'GIF': "gif",
|
||||
'TGA': "tga",
|
||||
'IFF': "iff",
|
||||
'PPM': "ppm",
|
||||
'PNG': "png",
|
||||
'SYS': "sys",
|
||||
'TIFF': "tiff",
|
||||
'TIF': "tiff",
|
||||
'EXR': "exr",
|
||||
'HDR': "hdr",
|
||||
}.get(os.path.splitext(imgF)[-1].upper(), "")
|
||||
# Then, use imghdr to really identify the filetype as it can be different
|
||||
if not ext:
|
||||
# maybe add a check for if path exists here?
|
||||
print(" WARNING: texture image has no extension") # too verbose
|
||||
|
||||
ext = what(imgF) # imghdr is a python lib to identify image file types
|
||||
return ext
|
||||
|
||||
|
||||
def img_map(ts):
|
||||
"""Translate mapping type from Blender UI to POV syntax and return that string."""
|
||||
image_map = ""
|
||||
texdata = bpy.data.textures[ts.texture]
|
||||
if ts.mapping == 'FLAT':
|
||||
image_map = "map_type 0 "
|
||||
elif ts.mapping == 'SPHERE':
|
||||
image_map = "map_type 1 "
|
||||
elif ts.mapping == 'TUBE':
|
||||
image_map = "map_type 2 "
|
||||
|
||||
## map_type 3 and 4 in development (?) (ENV in pov 3.8)
|
||||
## for POV-Ray, currently they just seem to default back to Flat (type 0)
|
||||
# elif ts.mapping=="?":
|
||||
# image_map = " map_type 3 "
|
||||
# elif ts.mapping=="?":
|
||||
# image_map = " map_type 4 "
|
||||
if ts.use_interpolation: # Available if image sampling class reactivated?
|
||||
image_map += " interpolate 2 "
|
||||
if texdata.extension == 'CLIP':
|
||||
image_map += " once "
|
||||
# image_map += "}"
|
||||
# if ts.mapping=='CUBE':
|
||||
# image_map+= "warp { cubic } rotate <-90,0,180>"
|
||||
# no direct cube type mapping. Though this should work in POV 3.7
|
||||
# it doesn't give that good results(best suited to environment maps?)
|
||||
# if image_map == "":
|
||||
# print(" No texture image found ")
|
||||
return image_map
|
||||
|
||||
|
||||
def img_map_transforms(ts):
|
||||
"""Translate mapping transformations from Blender UI to POV syntax and return that string."""
|
||||
# XXX TODO: unchecked textures give error of variable referenced before assignment XXX
|
||||
# POV-Ray "scale" is not a number of repetitions factor, but ,its
|
||||
# inverse, a standard scale factor.
|
||||
# 0.5 Offset is needed relatively to scale because center of the
|
||||
# scale is 0.5,0.5 in blender and 0,0 in POV
|
||||
# Strange that the translation factor for scale is not the same as for
|
||||
# translate.
|
||||
# TODO: verify both matches with other blender renderers / internal in previous versions.
|
||||
image_map_transforms = ""
|
||||
image_map_transforms = "scale <%.4g,%.4g,%.4g> translate <%.4g,%.4g,%.4g>" % (
|
||||
ts.scale[0],
|
||||
ts.scale[1],
|
||||
ts.scale[2],
|
||||
ts.offset[0],
|
||||
ts.offset[1],
|
||||
ts.offset[2],
|
||||
)
|
||||
# image_map_transforms = (" translate <-0.5,-0.5,0.0> scale <%.4g,%.4g,%.4g> translate <%.4g,%.4g,%.4g>" % \
|
||||
# ( 1.0 / ts.scale.x,
|
||||
# 1.0 / ts.scale.y,
|
||||
# 1.0 / ts.scale.z,
|
||||
# (0.5 / ts.scale.x) + ts.offset.x,
|
||||
# (0.5 / ts.scale.y) + ts.offset.y,
|
||||
# ts.offset.z))
|
||||
# image_map_transforms = (
|
||||
# "translate <-0.5,-0.5,0> "
|
||||
# "scale <-1,-1,1> * <%.4g,%.4g,%.4g> "
|
||||
# "translate <0.5,0.5,0> + <%.4g,%.4g,%.4g>" % \
|
||||
# (1.0 / ts.scale.x,
|
||||
# 1.0 / ts.scale.y,
|
||||
# 1.0 / ts.scale.z,
|
||||
# ts.offset.x,
|
||||
# ts.offset.y,
|
||||
# ts.offset.z)
|
||||
# )
|
||||
return image_map_transforms
|
||||
|
||||
|
||||
def img_map_bg(wts):
|
||||
"""Translate world mapping from Blender UI to POV syntax and return that string."""
|
||||
tex = bpy.data.textures[wts.texture]
|
||||
image_mapBG = ""
|
||||
# texture_coords refers to the mapping of world textures:
|
||||
if wts.texture_coords == 'VIEW' or wts.texture_coords == 'GLOBAL':
|
||||
image_mapBG = " map_type 0 "
|
||||
elif wts.texture_coords == 'ANGMAP':
|
||||
image_mapBG = " map_type 1 "
|
||||
elif wts.texture_coords == 'TUBE':
|
||||
image_mapBG = " map_type 2 "
|
||||
|
||||
if tex.use_interpolation:
|
||||
image_mapBG += " interpolate 2 "
|
||||
if tex.extension == 'CLIP':
|
||||
image_mapBG += " once "
|
||||
# image_mapBG += "}"
|
||||
# if wts.mapping == 'CUBE':
|
||||
# image_mapBG += "warp { cubic } rotate <-90,0,180>"
|
||||
# no direct cube type mapping. Though this should work in POV 3.7
|
||||
# it doesn't give that good results(best suited to environment maps?)
|
||||
# if image_mapBG == "":
|
||||
# print(" No background texture image found ")
|
||||
return image_mapBG
|
||||
|
||||
|
||||
def path_image(image):
|
||||
"""Conform a path string to POV syntax to avoid POV errors."""
|
||||
return bpy.path.abspath(image.filepath, library=image.library).replace("\\", "/")
|
||||
# .replace("\\","/") to get only forward slashes as it's what POV prefers,
|
||||
# even on windows
|
||||
|
||||
|
||||
# end find image texture
|
||||
# -----------------------------------------------------------------------------
|
||||
|
||||
|
||||
def export_camera(scene, global_matrix, render, tab_write):
|
||||
"""Translate camera from Blender UI to POV syntax and write to exported file."""
|
||||
camera = scene.camera
|
||||
|
||||
# DH disabled for now, this isn't the correct context
|
||||
active_object = None # bpy.context.active_object # does not always work MR
|
||||
matrix = global_matrix @ camera.matrix_world
|
||||
focal_point = camera.data.dof.focus_distance
|
||||
|
||||
# compute resolution
|
||||
q_size = render.resolution_x / render.resolution_y
|
||||
tab_write("#declare camLocation = <%.6f, %.6f, %.6f>;\n" % matrix.translation[:])
|
||||
tab_write(
|
||||
"#declare camLookAt = <%.6f, %.6f, %.6f>;\n"
|
||||
% tuple([degrees(e) for e in matrix.to_3x3().to_euler()])
|
||||
)
|
||||
|
||||
tab_write("camera {\n")
|
||||
if scene.pov.baking_enable and active_object and active_object.type == 'MESH':
|
||||
tab_write("mesh_camera{ 1 3\n") # distribution 3 is what we want here
|
||||
tab_write("mesh{%s}\n" % active_object.name)
|
||||
tab_write("}\n")
|
||||
tab_write("location <0,0,.01>")
|
||||
tab_write("direction <0,0,-1>")
|
||||
|
||||
else:
|
||||
if camera.data.type == 'ORTHO':
|
||||
# todo: track when SensorHeightRatio was added to see if needed (not used)
|
||||
sensor_height_ratio = (
|
||||
render.resolution_x * camera.data.ortho_scale / render.resolution_y
|
||||
)
|
||||
tab_write("orthographic\n")
|
||||
# Blender angle is radian so should be converted to degrees:
|
||||
# % (camera.data.angle * (180.0 / pi) )
|
||||
# but actually argument is not compulsory after angle in pov ortho mode
|
||||
tab_write("angle\n")
|
||||
tab_write("right <%6f, 0, 0>\n" % -camera.data.ortho_scale)
|
||||
tab_write("location <0, 0, 0>\n")
|
||||
tab_write("look_at <0, 0, -1>\n")
|
||||
tab_write("up <0, %6f, 0>\n" % (camera.data.ortho_scale / q_size))
|
||||
|
||||
elif camera.data.type == 'PANO':
|
||||
tab_write("panoramic\n")
|
||||
tab_write("location <0, 0, 0>\n")
|
||||
tab_write("look_at <0, 0, -1>\n")
|
||||
tab_write("right <%s, 0, 0>\n" % -q_size)
|
||||
tab_write("up <0, 1, 0>\n")
|
||||
tab_write("angle %f\n" % (360.0 * atan(16.0 / camera.data.lens) / pi))
|
||||
elif camera.data.type == 'PERSP':
|
||||
# Standard camera otherwise would be default in pov
|
||||
tab_write("location <0, 0, 0>\n")
|
||||
tab_write("look_at <0, 0, -1>\n")
|
||||
tab_write("right <%s, 0, 0>\n" % -q_size)
|
||||
tab_write("up <0, 1, 0>\n")
|
||||
tab_write(
|
||||
"angle %f\n"
|
||||
% (2 * atan(camera.data.sensor_width / 2 / camera.data.lens) * 180.0 / pi)
|
||||
)
|
||||
|
||||
tab_write(
|
||||
"rotate <%.6f, %.6f, %.6f>\n" % tuple([degrees(e) for e in matrix.to_3x3().to_euler()])
|
||||
)
|
||||
tab_write("translate <%.6f, %.6f, %.6f>\n" % matrix.translation[:])
|
||||
if camera.data.dof.use_dof and (focal_point != 0 or camera.data.dof.focus_object):
|
||||
tab_write("aperture %.3g\n" % (1 / (camera.data.dof.aperture_fstop * 10000) * 1000))
|
||||
tab_write(
|
||||
"blur_samples %d %d\n"
|
||||
% (camera.data.pov.dof_samples_min, camera.data.pov.dof_samples_max)
|
||||
)
|
||||
tab_write("variance 1/%d\n" % camera.data.pov.dof_variance)
|
||||
tab_write("confidence %.3g\n" % camera.data.pov.dof_confidence)
|
||||
if camera.data.dof.focus_object:
|
||||
focal_ob = scene.objects[camera.data.dof.focus_object.name]
|
||||
matrix_blur = global_matrix @ focal_ob.matrix_world
|
||||
tab_write("focal_point <%.4f,%.4f,%.4f>\n" % matrix_blur.translation[:])
|
||||
else:
|
||||
tab_write("focal_point <0, 0, %f>\n" % focal_point)
|
||||
if camera.data.pov.normal_enable:
|
||||
tab_write(
|
||||
"normal {%s %.4f turbulence %.4f scale %.4f}\n"
|
||||
% (
|
||||
camera.data.pov.normal_patterns,
|
||||
camera.data.pov.cam_normal,
|
||||
camera.data.pov.turbulence,
|
||||
camera.data.pov.scale,
|
||||
)
|
||||
)
|
||||
tab_write("}\n")
|
||||
|
||||
|
||||
exported_lights_count = 0
|
||||
|
||||
|
||||
def export_lights(lamps, file, scene, global_matrix, write_matrix, tab_write):
|
||||
"""Translate lights from Blender UI to POV syntax and write to exported file."""
|
||||
|
||||
# Incremented after each lamp export to declare its target
|
||||
# currently used for Fresnel diffuse shader as their slope vector:
|
||||
global exported_lights_count
|
||||
exported_lights_count = 0
|
||||
# Get all lamps
|
||||
for ob in lamps:
|
||||
lamp = ob.data
|
||||
|
||||
matrix = global_matrix @ ob.matrix_world
|
||||
|
||||
# Color is no longer modified by energy
|
||||
# any way to directly get bpy_prop_array as tuple?
|
||||
color = tuple(lamp.color)
|
||||
|
||||
tab_write("light_source {\n")
|
||||
tab_write("< 0,0,0 >\n")
|
||||
tab_write("color srgb<%.3g, %.3g, %.3g>\n" % color)
|
||||
|
||||
if lamp.type == 'POINT':
|
||||
pass
|
||||
elif lamp.type == 'SPOT':
|
||||
tab_write("spotlight\n")
|
||||
|
||||
# Falloff is the main radius from the centre line
|
||||
tab_write("falloff %.2f\n" % (degrees(lamp.spot_size) / 2.0)) # 1 TO 179 FOR BOTH
|
||||
tab_write("radius %.6f\n" % ((degrees(lamp.spot_size) / 2.0) * (1.0 - lamp.spot_blend)))
|
||||
|
||||
# Blender does not have a tightness equivalent, 0 is most like blender default.
|
||||
tab_write("tightness 0\n") # 0:10f
|
||||
|
||||
tab_write("point_at <0, 0, -1>\n")
|
||||
if lamp.pov.use_halo:
|
||||
tab_write("looks_like{\n")
|
||||
tab_write("sphere{<0,0,0>,%.6f\n" % lamp.distance)
|
||||
tab_write("hollow\n")
|
||||
tab_write("material{\n")
|
||||
tab_write("texture{\n")
|
||||
tab_write("pigment{rgbf<1,1,1,%.4f>}\n" % (lamp.pov.halo_intensity * 5.0))
|
||||
tab_write("}\n")
|
||||
tab_write("interior{\n")
|
||||
tab_write("media{\n")
|
||||
tab_write("emission 1\n")
|
||||
tab_write("scattering {1, 0.5}\n")
|
||||
tab_write("density{\n")
|
||||
tab_write("spherical\n")
|
||||
tab_write("color_map{\n")
|
||||
tab_write("[0.0 rgb <0,0,0>]\n")
|
||||
tab_write("[0.5 rgb <1,1,1>]\n")
|
||||
tab_write("[1.0 rgb <1,1,1>]\n")
|
||||
tab_write("}\n")
|
||||
tab_write("}\n")
|
||||
tab_write("}\n")
|
||||
tab_write("}\n")
|
||||
tab_write("}\n")
|
||||
tab_write("}\n")
|
||||
tab_write("}\n")
|
||||
elif lamp.type == 'SUN':
|
||||
tab_write("parallel\n")
|
||||
tab_write("point_at <0, 0, -1>\n") # *must* be after 'parallel'
|
||||
|
||||
elif lamp.type == 'AREA':
|
||||
tab_write("fade_distance %.6f\n" % (lamp.distance / 2.0))
|
||||
# Area lights have no falloff type, so always use blenders lamp quad equivalent
|
||||
# for those?
|
||||
tab_write("fade_power %d\n" % 2)
|
||||
size_x = lamp.size
|
||||
samples_x = lamp.pov.shadow_ray_samples_x
|
||||
if lamp.shape == 'SQUARE':
|
||||
size_y = size_x
|
||||
samples_y = samples_x
|
||||
else:
|
||||
size_y = lamp.size_y
|
||||
samples_y = lamp.pov.shadow_ray_samples_y
|
||||
|
||||
tab_write(
|
||||
"area_light <%.6f,0,0>,<0,%.6f,0> %d, %d\n" % (size_x, size_y, samples_x, samples_y)
|
||||
)
|
||||
tab_write("area_illumination\n")
|
||||
if lamp.pov.shadow_ray_sample_method == 'CONSTANT_JITTERED':
|
||||
if lamp.pov.use_jitter:
|
||||
tab_write("jitter\n")
|
||||
else:
|
||||
tab_write("adaptive 1\n")
|
||||
tab_write("jitter\n")
|
||||
|
||||
# No shadow checked either at global or light level:
|
||||
if not scene.pov.use_shadows or (lamp.pov.shadow_method == 'NOSHADOW'):
|
||||
tab_write("shadowless\n")
|
||||
|
||||
# Sun shouldn't be attenuated. Area lights have no falloff attribute so they
|
||||
# are put to type 2 attenuation a little higher above.
|
||||
if lamp.type not in {'SUN', 'AREA'}:
|
||||
if lamp.falloff_type == 'INVERSE_SQUARE':
|
||||
tab_write("fade_distance %.6f\n" % (sqrt(lamp.distance / 2.0)))
|
||||
tab_write("fade_power %d\n" % 2) # Use blenders lamp quad equivalent
|
||||
elif lamp.falloff_type == 'INVERSE_LINEAR':
|
||||
tab_write("fade_distance %.6f\n" % (lamp.distance / 2.0))
|
||||
tab_write("fade_power %d\n" % 1) # Use blenders lamp linear
|
||||
elif lamp.falloff_type == 'CONSTANT':
|
||||
tab_write("fade_distance %.6f\n" % (lamp.distance / 2.0))
|
||||
tab_write("fade_power %d\n" % 3)
|
||||
# Use blenders lamp constant equivalent no attenuation.
|
||||
# Using Custom curve for fade power 3 for now.
|
||||
elif lamp.falloff_type == 'CUSTOM_CURVE':
|
||||
tab_write("fade_power %d\n" % 4)
|
||||
|
||||
write_matrix(matrix)
|
||||
|
||||
tab_write("}\n")
|
||||
|
||||
exported_lights_count += 1
|
||||
|
||||
# v(A,B) rotates vector A about origin by vector B.
|
||||
file.write(
|
||||
"#declare lampTarget%s= vrotate(<%.4g,%.4g,%.4g>,<%.4g,%.4g,%.4g>);\n"
|
||||
% (
|
||||
exported_lights_count,
|
||||
-(ob.location.x),
|
||||
-(ob.location.y),
|
||||
-(ob.location.z),
|
||||
ob.rotation_euler.x,
|
||||
ob.rotation_euler.y,
|
||||
ob.rotation_euler.z,
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
def export_world(world, scene, global_matrix, tab_write):
|
||||
"""write world as POV backgrounbd and sky_sphere to exported file """
|
||||
render = scene.pov
|
||||
camera = scene.camera
|
||||
matrix = global_matrix @ camera.matrix_world # view dependant for later use
|
||||
if not world:
|
||||
return
|
||||
#############Maurice####################################
|
||||
# These lines added to get sky gradient (visible with PNG output)
|
||||
if world:
|
||||
# For simple flat background:
|
||||
if not world.pov.use_sky_blend:
|
||||
# Non fully transparent background could premultiply alpha and avoid anti-aliasing
|
||||
# display issue:
|
||||
if render.alpha_mode == 'TRANSPARENT':
|
||||
tab_write(
|
||||
"background {rgbt<%.3g, %.3g, %.3g, 0.75>}\n" % (world.pov.horizon_color[:])
|
||||
)
|
||||
# Currently using no alpha with Sky option:
|
||||
elif render.alpha_mode == 'SKY':
|
||||
tab_write("background {rgbt<%.3g, %.3g, %.3g, 0>}\n" % (world.pov.horizon_color[:]))
|
||||
# StraightAlpha:
|
||||
# XXX Does not exists anymore
|
||||
# else:
|
||||
# tab_write("background {rgbt<%.3g, %.3g, %.3g, 1>}\n" % (world.pov.horizon_color[:]))
|
||||
|
||||
world_tex_count = 0
|
||||
# For Background image textures
|
||||
for t in world.pov_texture_slots: # risk to write several sky_spheres but maybe ok.
|
||||
if t:
|
||||
tex = bpy.data.textures[t.texture]
|
||||
if tex.type is not None:
|
||||
world_tex_count += 1
|
||||
# XXX No enable checkbox for world textures yet (report it?)
|
||||
# if t and tex.type == 'IMAGE' and t.use:
|
||||
if tex.type == 'IMAGE':
|
||||
image_filename = path_image(tex.image)
|
||||
if tex.image.filepath != image_filename:
|
||||
tex.image.filepath = image_filename
|
||||
if image_filename != "" and t.use_map_blend:
|
||||
textures_blend = image_filename
|
||||
# colvalue = t.default_value
|
||||
t_blend = t
|
||||
|
||||
# Commented below was an idea to make the Background image oriented as camera
|
||||
# taken here:
|
||||
# http://news.pov.org/pov.newusers/thread/%3Cweb.4a5cddf4e9c9822ba2f93e20@news.pov.org%3E/
|
||||
# Replace 4/3 by the ratio of each image found by some custom or existing
|
||||
# function
|
||||
# mapping_blend = (" translate <%.4g,%.4g,%.4g> rotate z*degrees" \
|
||||
# "(atan((camLocation - camLookAt).x/(camLocation - " \
|
||||
# "camLookAt).y)) rotate x*degrees(atan((camLocation - " \
|
||||
# "camLookAt).y/(camLocation - camLookAt).z)) rotate y*" \
|
||||
# "degrees(atan((camLocation - camLookAt).z/(camLocation - " \
|
||||
# "camLookAt).x)) scale <%.4g,%.4g,%.4g>b" % \
|
||||
# (t_blend.offset.x / 10 , t_blend.offset.y / 10 ,
|
||||
# t_blend.offset.z / 10, t_blend.scale.x ,
|
||||
# t_blend.scale.y , t_blend.scale.z))
|
||||
# using camera rotation valuesdirectly from blender seems much easier
|
||||
if t_blend.texture_coords == 'ANGMAP':
|
||||
mapping_blend = ""
|
||||
else:
|
||||
# POV-Ray "scale" is not a number of repetitions factor, but its
|
||||
# inverse, a standard scale factor.
|
||||
# 0.5 Offset is needed relatively to scale because center of the
|
||||
# UV scale is 0.5,0.5 in blender and 0,0 in POV
|
||||
# Further Scale by 2 and translate by -1 are
|
||||
# required for the sky_sphere not to repeat
|
||||
|
||||
mapping_blend = (
|
||||
"scale 2 scale <%.4g,%.4g,%.4g> translate -1 "
|
||||
"translate <%.4g,%.4g,%.4g> rotate<0,0,0> "
|
||||
% (
|
||||
(1.0 / t_blend.scale.x),
|
||||
(1.0 / t_blend.scale.y),
|
||||
(1.0 / t_blend.scale.z),
|
||||
0.5 - (0.5 / t_blend.scale.x) - t_blend.offset.x,
|
||||
0.5 - (0.5 / t_blend.scale.y) - t_blend.offset.y,
|
||||
t_blend.offset.z,
|
||||
)
|
||||
)
|
||||
|
||||
# The initial position and rotation of the pov camera is probably creating
|
||||
# the rotation offset should look into it someday but at least background
|
||||
# won't rotate with the camera now.
|
||||
# Putting the map on a plane would not introduce the skysphere distortion and
|
||||
# allow for better image scale matching but also some waay to chose depth and
|
||||
# size of the plane relative to camera.
|
||||
tab_write("sky_sphere {\n")
|
||||
tab_write("pigment {\n")
|
||||
tab_write(
|
||||
"image_map{%s \"%s\" %s}\n"
|
||||
% (image_format(textures_blend), textures_blend, img_map_bg(t_blend))
|
||||
)
|
||||
tab_write("}\n")
|
||||
tab_write("%s\n" % (mapping_blend))
|
||||
# The following layered pigment opacifies to black over the texture for
|
||||
# transmit below 1 or otherwise adds to itself
|
||||
tab_write("pigment {rgb 0 transmit %s}\n" % (tex.intensity))
|
||||
tab_write("}\n")
|
||||
# tab_write("scale 2\n")
|
||||
# tab_write("translate -1\n")
|
||||
|
||||
# For only Background gradient
|
||||
|
||||
if world_tex_count == 0:
|
||||
if world.pov.use_sky_blend:
|
||||
tab_write("sky_sphere {\n")
|
||||
tab_write("pigment {\n")
|
||||
# maybe Should follow the advice of POV doc about replacing gradient
|
||||
# for skysphere..5.5
|
||||
tab_write("gradient y\n")
|
||||
tab_write("color_map {\n")
|
||||
# XXX Does not exists anymore
|
||||
# if render.alpha_mode == 'STRAIGHT':
|
||||
# tab_write("[0.0 rgbt<%.3g, %.3g, %.3g, 1>]\n" % (world.pov.horizon_color[:]))
|
||||
# tab_write("[1.0 rgbt<%.3g, %.3g, %.3g, 1>]\n" % (world.pov.zenith_color[:]))
|
||||
if render.alpha_mode == 'TRANSPARENT':
|
||||
tab_write("[0.0 rgbt<%.3g, %.3g, %.3g, 0.99>]\n" % (world.pov.horizon_color[:]))
|
||||
# aa premult not solved with transmit 1
|
||||
tab_write("[1.0 rgbt<%.3g, %.3g, %.3g, 0.99>]\n" % (world.pov.zenith_color[:]))
|
||||
else:
|
||||
tab_write("[0.0 rgbt<%.3g, %.3g, %.3g, 0>]\n" % (world.pov.horizon_color[:]))
|
||||
tab_write("[1.0 rgbt<%.3g, %.3g, %.3g, 0>]\n" % (world.pov.zenith_color[:]))
|
||||
tab_write("}\n")
|
||||
tab_write("}\n")
|
||||
tab_write("}\n")
|
||||
# Sky_sphere alpha (transmit) is not translating into image alpha the same
|
||||
# way as 'background'
|
||||
|
||||
# if world.pov.light_settings.use_indirect_light:
|
||||
# scene.pov.radio_enable=1
|
||||
|
||||
# Maybe change the above to a function copyInternalRenderer settings when
|
||||
# user pushes a button, then:
|
||||
# scene.pov.radio_enable = world.pov.light_settings.use_indirect_light
|
||||
# and other such translations but maybe this would not be allowed either?
|
||||
|
||||
###############################################################
|
||||
|
||||
mist = world.mist_settings
|
||||
|
||||
if mist.use_mist:
|
||||
tab_write("fog {\n")
|
||||
if mist.falloff == 'LINEAR':
|
||||
tab_write("distance %.6f\n" % ((mist.start + mist.depth) * 0.368))
|
||||
elif mist.falloff == 'QUADRATIC': # n**2 or squrt(n)?
|
||||
tab_write("distance %.6f\n" % ((mist.start + mist.depth) ** 2 * 0.368))
|
||||
elif mist.falloff == 'INVERSE_QUADRATIC': # n**2 or squrt(n)?
|
||||
tab_write("distance %.6f\n" % ((mist.start + mist.depth) ** 2 * 0.368))
|
||||
tab_write(
|
||||
"color rgbt<%.3g, %.3g, %.3g, %.3g>\n"
|
||||
% (*world.pov.horizon_color, 1.0 - mist.intensity)
|
||||
)
|
||||
# tab_write("fog_offset %.6f\n" % mist.start) #create a pov property to prepend
|
||||
# tab_write("fog_alt %.6f\n" % mist.height) #XXX right?
|
||||
# tab_write("turbulence 0.2\n")
|
||||
# tab_write("turb_depth 0.3\n")
|
||||
tab_write("fog_type 1\n") # type2 for height
|
||||
tab_write("}\n")
|
||||
if scene.pov.media_enable:
|
||||
tab_write("media {\n")
|
||||
tab_write(
|
||||
"scattering { %d, rgb %.12f*<%.4g, %.4g, %.4g>\n"
|
||||
% (
|
||||
int(scene.pov.media_scattering_type),
|
||||
(scene.pov.media_diffusion_scale),
|
||||
*(scene.pov.media_diffusion_color[:]),
|
||||
)
|
||||
)
|
||||
if scene.pov.media_scattering_type == '5':
|
||||
tab_write("eccentricity %.3g\n" % scene.pov.media_eccentricity)
|
||||
tab_write("}\n")
|
||||
tab_write(
|
||||
"absorption %.12f*<%.4g, %.4g, %.4g>\n"
|
||||
% (scene.pov.media_absorption_scale, *(scene.pov.media_absorption_color[:]))
|
||||
)
|
||||
tab_write("\n")
|
||||
tab_write("samples %.d\n" % scene.pov.media_samples)
|
||||
tab_write("}\n")
|
||||
|
||||
|
||||
####################################################################################################
|
||||
def export_rainbows(rainbows, file, scene, global_matrix, write_matrix, tab_write):
|
||||
"""write all POV rainbows primitives to exported file """
|
||||
for ob in rainbows:
|
||||
povdataname = ob.data.name # enough? XXX not used nor matrix fn?
|
||||
angle = degrees(ob.data.spot_size / 2.5) # radians in blender (2
|
||||
width = ob.data.spot_blend * 10
|
||||
distance = ob.data.shadow_buffer_clip_start
|
||||
# eps=0.0000001
|
||||
# angle = br/(cr+eps) * 10 #eps is small epsilon variable to avoid dividing by zero
|
||||
# width = ob.dimensions[2] #now let's say width of rainbow is the actual proxy height
|
||||
# formerly:
|
||||
# cz-bz # let's say width of the rainbow is height of the cone (interfacing choice
|
||||
|
||||
# v(A,B) rotates vector A about origin by vector B.
|
||||
# and avoid a 0 length vector by adding 1
|
||||
|
||||
# file.write("#declare %s_Target= vrotate(<%.6g,%.6g,%.6g>,<%.4g,%.4g,%.4g>);\n" % \
|
||||
# (povdataname, -(ob.location.x+0.1), -(ob.location.y+0.1), -(ob.location.z+0.1),
|
||||
# ob.rotation_euler.x, ob.rotation_euler.y, ob.rotation_euler.z))
|
||||
|
||||
direction = ( # XXX currently not used (replaced by track to?)
|
||||
ob.location.x,
|
||||
ob.location.y,
|
||||
ob.location.z,
|
||||
) # not taking matrix into account
|
||||
rmatrix = global_matrix @ ob.matrix_world
|
||||
|
||||
# ob.rotation_euler.to_matrix().to_4x4() * mathutils.Vector((0,0,1))
|
||||
# XXX Is result of the below offset by 90 degrees?
|
||||
up = ob.matrix_world.to_3x3()[1].xyz # * global_matrix
|
||||
|
||||
# XXX TO CHANGE:
|
||||
# formerly:
|
||||
# tab_write("#declare %s = rainbow {\n"%povdataname)
|
||||
|
||||
# clumsy for now but remove the rainbow from instancing
|
||||
# system because not an object. use lamps later instead of meshes
|
||||
|
||||
# del data_ref[dataname]
|
||||
tab_write("rainbow {\n")
|
||||
|
||||
tab_write("angle %.4f\n" % angle)
|
||||
tab_write("width %.4f\n" % width)
|
||||
tab_write("distance %.4f\n" % distance)
|
||||
tab_write("arc_angle %.4f\n" % ob.pov.arc_angle)
|
||||
tab_write("falloff_angle %.4f\n" % ob.pov.falloff_angle)
|
||||
tab_write("direction <%.4f,%.4f,%.4f>\n" % rmatrix.translation[:])
|
||||
tab_write("up <%.4f,%.4f,%.4f>\n" % (up[0], up[1], up[2]))
|
||||
tab_write("color_map {\n")
|
||||
tab_write("[0.000 color srgbt<1.0, 0.5, 1.0, 1.0>]\n")
|
||||
tab_write("[0.130 color srgbt<0.5, 0.5, 1.0, 0.9>]\n")
|
||||
tab_write("[0.298 color srgbt<0.2, 0.2, 1.0, 0.7>]\n")
|
||||
tab_write("[0.412 color srgbt<0.2, 1.0, 1.0, 0.4>]\n")
|
||||
tab_write("[0.526 color srgbt<0.2, 1.0, 0.2, 0.4>]\n")
|
||||
tab_write("[0.640 color srgbt<1.0, 1.0, 0.2, 0.4>]\n")
|
||||
tab_write("[0.754 color srgbt<1.0, 0.5, 0.2, 0.6>]\n")
|
||||
tab_write("[0.900 color srgbt<1.0, 0.2, 0.2, 0.7>]\n")
|
||||
tab_write("[1.000 color srgbt<1.0, 0.2, 0.2, 1.0>]\n")
|
||||
tab_write("}\n")
|
||||
|
||||
pov_mat_name = "Default_texture"
|
||||
# tab_write("texture {%s}\n"%pov_mat_name)
|
||||
write_object_modifiers(scene, ob, file)
|
||||
# tab_write("rotate x*90\n")
|
||||
# matrix = global_matrix @ ob.matrix_world
|
||||
# write_matrix(matrix)
|
||||
tab_write("}\n")
|
||||
# continue #Don't render proxy mesh, skip to next object
|
||||
|
||||
|
||||
def export_smoke(file, smoke_obj_name, smoke_path, comments, global_matrix, write_matrix):
|
||||
"""export Blender smoke type fluids to pov media using df3 library"""
|
||||
|
||||
flowtype = -1 # XXX todo: not used yet? should trigger emissive for fire type
|
||||
depsgraph = bpy.context.evaluated_depsgraph_get()
|
||||
smoke_obj = bpy.data.objects[smoke_obj_name].evaluated_get(depsgraph)
|
||||
domain = None
|
||||
smoke_modifier = None
|
||||
# Search smoke domain target for smoke modifiers
|
||||
for mod in smoke_obj.modifiers:
|
||||
if mod.type == 'FLUID':
|
||||
if mod.fluid_type == 'FLOW':
|
||||
if mod.flow_settings.flow_type == 'BOTH':
|
||||
flowtype = 2
|
||||
else:
|
||||
if mod.flow_settings.smoke_flow_type == 'SMOKE':
|
||||
flowtype = 0
|
||||
else:
|
||||
if mod.flow_settings.smoke_flow_type == 'FIRE':
|
||||
flowtype = 1
|
||||
|
||||
if mod.fluid_type == 'DOMAIN':
|
||||
domain = smoke_obj
|
||||
smoke_modifier = mod
|
||||
|
||||
eps = 0.000001 # XXX not used currently. restore from corner case ... zero div?
|
||||
if domain is not None:
|
||||
mod_set = smoke_modifier.domain_settings
|
||||
channeldata = []
|
||||
for v in mod_set.density_grid:
|
||||
channeldata.append(v.real)
|
||||
print(v.real)
|
||||
## Usage en voxel texture:
|
||||
# channeldata = []
|
||||
# if channel == 'density':
|
||||
# for v in mod_set.density_grid:
|
||||
# channeldata.append(v.real)
|
||||
|
||||
# if channel == 'fire':
|
||||
# for v in mod_set.flame_grid:
|
||||
# channeldata.append(v.real)
|
||||
|
||||
resolution = mod_set.resolution_max
|
||||
big_res = []
|
||||
big_res.append(mod_set.domain_resolution[0])
|
||||
big_res.append(mod_set.domain_resolution[1])
|
||||
big_res.append(mod_set.domain_resolution[2])
|
||||
|
||||
if mod_set.use_noise:
|
||||
big_res[0] = big_res[0] * (mod_set.noise_scale + 1)
|
||||
big_res[1] = big_res[1] * (mod_set.noise_scale + 1)
|
||||
big_res[2] = big_res[2] * (mod_set.noise_scale + 1)
|
||||
# else:
|
||||
# p = []
|
||||
##gather smoke domain settings
|
||||
# BBox = domain.bound_box
|
||||
# p.append([BBox[0][0], BBox[0][1], BBox[0][2]])
|
||||
# p.append([BBox[6][0], BBox[6][1], BBox[6][2]])
|
||||
# mod_set = smoke_modifier.domain_settings
|
||||
# resolution = mod_set.resolution_max
|
||||
# smokecache = mod_set.point_cache
|
||||
# ret = read_cache(smokecache, mod_set.use_noise, mod_set.noise_scale + 1, flowtype)
|
||||
# res_x = ret[0]
|
||||
# res_y = ret[1]
|
||||
# res_z = ret[2]
|
||||
# density = ret[3]
|
||||
# fire = ret[4]
|
||||
|
||||
# if res_x * res_y * res_z > 0:
|
||||
##new cache format
|
||||
# big_res = []
|
||||
# big_res.append(res_x)
|
||||
# big_res.append(res_y)
|
||||
# big_res.append(res_z)
|
||||
# else:
|
||||
# max = domain.dimensions[0]
|
||||
# if (max - domain.dimensions[1]) < -eps:
|
||||
# max = domain.dimensions[1]
|
||||
|
||||
# if (max - domain.dimensions[2]) < -eps:
|
||||
# max = domain.dimensions[2]
|
||||
|
||||
# big_res = [int(round(resolution * domain.dimensions[0] / max, 0)),
|
||||
# int(round(resolution * domain.dimensions[1] / max, 0)),
|
||||
# int(round(resolution * domain.dimensions[2] / max, 0))]
|
||||
|
||||
# if mod_set.use_noise:
|
||||
# big_res = [big_res[0] * (mod_set.noise_scale + 1),
|
||||
# big_res[1] * (mod_set.noise_scale + 1),
|
||||
# big_res[2] * (mod_set.noise_scale + 1)]
|
||||
|
||||
# if channel == 'density':
|
||||
# channeldata = density
|
||||
|
||||
# if channel == 'fire':
|
||||
# channeldata = fire
|
||||
|
||||
# sc_fr = '%s/%s/%s/%05d' % (
|
||||
# efutil.export_path,
|
||||
# efutil.scene_filename(),
|
||||
# bpy.context.scene.name,
|
||||
# bpy.context.scene.frame_current
|
||||
# )
|
||||
# if not os.path.exists( sc_fr ):
|
||||
# os.makedirs(sc_fr)
|
||||
#
|
||||
# smoke_filename = '%s.smoke' % bpy.path.clean_name(domain.name)
|
||||
# smoke_path = '/'.join([sc_fr, smoke_filename])
|
||||
#
|
||||
# with open(smoke_path, 'wb') as smoke_file:
|
||||
# # Binary densitygrid file format
|
||||
# #
|
||||
# # File header
|
||||
# smoke_file.write(b'SMOKE') #magic number
|
||||
# smoke_file.write(struct.pack('<I', big_res[0]))
|
||||
# smoke_file.write(struct.pack('<I', big_res[1]))
|
||||
# smoke_file.write(struct.pack('<I', big_res[2]))
|
||||
# Density data
|
||||
# smoke_file.write(struct.pack('<%df'%len(channeldata), *channeldata))
|
||||
#
|
||||
# LuxLog('Binary SMOKE file written: %s' % (smoke_path))
|
||||
|
||||
# return big_res[0], big_res[1], big_res[2], channeldata
|
||||
|
||||
mydf3 = df3_library.df3(big_res[0], big_res[1], big_res[2])
|
||||
sim_sizeX, sim_sizeY, sim_sizeZ = mydf3.size()
|
||||
for x in range(sim_sizeX):
|
||||
for y in range(sim_sizeY):
|
||||
for z in range(sim_sizeZ):
|
||||
mydf3.set(x, y, z, channeldata[((z * sim_sizeY + y) * sim_sizeX + x)])
|
||||
|
||||
mydf3.exportDF3(smoke_path)
|
||||
print('Binary smoke.df3 file written in preview directory')
|
||||
if comments:
|
||||
file.write("\n//--Smoke--\n\n")
|
||||
|
||||
# Note: We start with a default unit cube.
|
||||
# This is mandatory to read correctly df3 data - otherwise we could just directly use bbox
|
||||
# coordinates from the start, and avoid scale/translate operations at the end...
|
||||
file.write("box{<0,0,0>, <1,1,1>\n")
|
||||
file.write(" pigment{ rgbt 1 }\n")
|
||||
file.write(" hollow\n")
|
||||
file.write(" interior{ //---------------------\n")
|
||||
file.write(" media{ method 3\n")
|
||||
file.write(" emission <1,1,1>*1\n") # 0>1 for dark smoke to white vapour
|
||||
file.write(" scattering{ 1, // Type\n")
|
||||
file.write(" <1,1,1>*0.1\n")
|
||||
file.write(" } // end scattering\n")
|
||||
file.write(" density{density_file df3 \"%s\"\n" % (smoke_path))
|
||||
file.write(" color_map {\n")
|
||||
file.write(" [0.00 rgb 0]\n")
|
||||
file.write(" [0.05 rgb 0]\n")
|
||||
file.write(" [0.20 rgb 0.2]\n")
|
||||
file.write(" [0.30 rgb 0.6]\n")
|
||||
file.write(" [0.40 rgb 1]\n")
|
||||
file.write(" [1.00 rgb 1]\n")
|
||||
file.write(" } // end color_map\n")
|
||||
file.write(" } // end of density\n")
|
||||
file.write(" samples %i // higher = more precise\n" % resolution)
|
||||
file.write(" } // end of media --------------------------\n")
|
||||
file.write(" } // end of interior\n")
|
||||
|
||||
# START OF TRANSFORMATIONS
|
||||
|
||||
# Size to consider here are bbox dimensions (i.e. still in object space, *before* applying
|
||||
# loc/rot/scale and other transformations (like parent stuff), aka matrix_world).
|
||||
bbox = smoke_obj.bound_box
|
||||
dim = [
|
||||
abs(bbox[6][0] - bbox[0][0]),
|
||||
abs(bbox[6][1] - bbox[0][1]),
|
||||
abs(bbox[6][2] - bbox[0][2]),
|
||||
]
|
||||
|
||||
# We scale our cube to get its final size and shapes but still in *object* space (same as Blender's bbox).
|
||||
file.write("scale<%.6g,%.6g,%.6g>\n" % (dim[0], dim[1], dim[2]))
|
||||
|
||||
# We offset our cube such that (0,0,0) coordinate matches Blender's object center.
|
||||
file.write("translate<%.6g,%.6g,%.6g>\n" % (bbox[0][0], bbox[0][1], bbox[0][2]))
|
||||
|
||||
# We apply object's transformations to get final loc/rot/size in world space!
|
||||
# Note: we could combine the two previous transformations with this matrix directly...
|
||||
write_matrix(global_matrix @ smoke_obj.matrix_world)
|
||||
|
||||
# END OF TRANSFORMATIONS
|
||||
|
||||
file.write("}\n")
|
||||
|
||||
# file.write(" interpolate 1\n")
|
||||
# file.write(" frequency 0\n")
|
||||
# file.write(" }\n")
|
||||
# file.write("}\n")
|
||||
|
||||
|
||||
classes = ()
|
||||
|
||||
|
||||
def register():
|
||||
for cls in classes:
|
||||
register_class(cls)
|
||||
|
||||
|
||||
def unregister():
|
||||
for cls in classes:
|
||||
unregister_class(cls)
|
|
@ -0,0 +1,800 @@
|
|||
# ##### BEGIN GPL LICENSE BLOCK #####
|
||||
#
|
||||
# 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 2
|
||||
# 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
|
||||
# MERCHANTABILITY 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, write to the Free Software Foundation,
|
||||
# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
#
|
||||
# ##### END GPL LICENSE BLOCK #####
|
||||
|
||||
# <pep8 compliant>
|
||||
|
||||
"""User interface to camera frame, optics distortions, and environment
|
||||
|
||||
with world, sky, atmospheric effects such as rainbows or smoke """
|
||||
|
||||
import bpy
|
||||
from bpy.utils import register_class, unregister_class
|
||||
from bpy.types import Operator, Menu, Panel
|
||||
from bl_operators.presets import AddPresetBase
|
||||
|
||||
from bl_ui import properties_data_camera
|
||||
|
||||
for member in dir(properties_data_camera):
|
||||
subclass = getattr(properties_data_camera, member)
|
||||
try:
|
||||
subclass.COMPAT_ENGINES.add('POVRAY_RENDER')
|
||||
except BaseException as e:
|
||||
print(e.__doc__)
|
||||
print('An exception occurred: {}'.format(e))
|
||||
pass
|
||||
del properties_data_camera
|
||||
|
||||
# ##################################
|
||||
# # Use only a subset of the world panels
|
||||
# from bl_ui import properties_world
|
||||
|
||||
# # TORECREATE##DEPRECATED#properties_world.WORLD_PT_preview.COMPAT_ENGINES.add('POVRAY_RENDER')
|
||||
# properties_world.WORLD_PT_context_world.COMPAT_ENGINES.add('POVRAY_RENDER')
|
||||
# # TORECREATE##DEPRECATED#properties_world.WORLD_PT_world.COMPAT_ENGINES.add('POVRAY_RENDER')
|
||||
# del properties_world
|
||||
|
||||
##################################
|
||||
# Physics Main wrapping every class 'as is'
|
||||
from bl_ui import properties_physics_common
|
||||
|
||||
for member in dir(properties_physics_common):
|
||||
subclass = getattr(properties_physics_common, member)
|
||||
try:
|
||||
subclass.COMPAT_ENGINES.add('POVRAY_RENDER')
|
||||
except BaseException as e:
|
||||
print(e.__doc__)
|
||||
print('An exception occurred: {}'.format(e))
|
||||
pass
|
||||
del properties_physics_common
|
||||
|
||||
# Physics Rigid Bodies wrapping every class 'as is'
|
||||
from bl_ui import properties_physics_rigidbody
|
||||
|
||||
for member in dir(properties_physics_rigidbody):
|
||||
subclass = getattr(properties_physics_rigidbody, member)
|
||||
try:
|
||||
subclass.COMPAT_ENGINES.add('POVRAY_RENDER')
|
||||
except BaseException as e:
|
||||
print(e.__doc__)
|
||||
print('An exception occurred: {}'.format(e))
|
||||
pass
|
||||
del properties_physics_rigidbody
|
||||
|
||||
# Physics Rigid Body Constraint wrapping every class 'as is'
|
||||
from bl_ui import properties_physics_rigidbody_constraint
|
||||
|
||||
for member in dir(properties_physics_rigidbody_constraint):
|
||||
subclass = getattr(properties_physics_rigidbody_constraint, member)
|
||||
try:
|
||||
subclass.COMPAT_ENGINES.add('POVRAY_RENDER')
|
||||
except BaseException as e:
|
||||
print(e.__doc__)
|
||||
print('An exception occurred: {}'.format(e))
|
||||
pass
|
||||
del properties_physics_rigidbody_constraint
|
||||
|
||||
# Physics Smoke and fluids wrapping every class 'as is'
|
||||
from bl_ui import properties_physics_fluid
|
||||
|
||||
for member in dir(properties_physics_fluid):
|
||||
subclass = getattr(properties_physics_fluid, member)
|
||||
try:
|
||||
subclass.COMPAT_ENGINES.add('POVRAY_RENDER')
|
||||
except BaseException as e:
|
||||
print(e.__doc__)
|
||||
print('An exception occurred: {}'.format(e))
|
||||
pass
|
||||
del properties_physics_fluid
|
||||
|
||||
# Physics softbody wrapping every class 'as is'
|
||||
from bl_ui import properties_physics_softbody
|
||||
|
||||
for member in dir(properties_physics_softbody):
|
||||
subclass = getattr(properties_physics_softbody, member)
|
||||
try:
|
||||
subclass.COMPAT_ENGINES.add('POVRAY_RENDER')
|
||||
except BaseException as e:
|
||||
print(e.__doc__)
|
||||
print('An exception occurred: {}'.format(e))
|
||||
pass
|
||||
del properties_physics_softbody
|
||||
|
||||
# Physics Field wrapping every class 'as is'
|
||||
from bl_ui import properties_physics_field
|
||||
|
||||
for member in dir(properties_physics_field):
|
||||
subclass = getattr(properties_physics_field, member)
|
||||
try:
|
||||
subclass.COMPAT_ENGINES.add('POVRAY_RENDER')
|
||||
except BaseException as e:
|
||||
print(e.__doc__)
|
||||
print('An exception occurred: {}'.format(e))
|
||||
pass
|
||||
del properties_physics_field
|
||||
|
||||
# Physics Cloth wrapping every class 'as is'
|
||||
from bl_ui import properties_physics_cloth
|
||||
|
||||
for member in dir(properties_physics_cloth):
|
||||
subclass = getattr(properties_physics_cloth, member)
|
||||
try:
|
||||
subclass.COMPAT_ENGINES.add('POVRAY_RENDER')
|
||||
except BaseException as e:
|
||||
print(e.__doc__)
|
||||
print('An exception occurred: {}'.format(e))
|
||||
pass
|
||||
del properties_physics_cloth
|
||||
|
||||
# Physics Dynamic Paint wrapping every class 'as is'
|
||||
from bl_ui import properties_physics_dynamicpaint
|
||||
|
||||
for member in dir(properties_physics_dynamicpaint):
|
||||
subclass = getattr(properties_physics_dynamicpaint, member)
|
||||
try:
|
||||
subclass.COMPAT_ENGINES.add('POVRAY_RENDER')
|
||||
except BaseException as e:
|
||||
print(e.__doc__)
|
||||
print('An exception occurred: {}'.format(e))
|
||||
pass
|
||||
del properties_physics_dynamicpaint
|
||||
|
||||
from bl_ui import properties_particle
|
||||
|
||||
for member in dir(properties_particle): # add all "particle" panels from blender
|
||||
subclass = getattr(properties_particle, member)
|
||||
try:
|
||||
subclass.COMPAT_ENGINES.add('POVRAY_RENDER')
|
||||
except BaseException as e:
|
||||
print(e.__doc__)
|
||||
print('An exception occurred: {}'.format(e))
|
||||
pass
|
||||
del properties_particle
|
||||
|
||||
|
||||
class CameraDataButtonsPanel:
|
||||
"""Use this class to define buttons from the camera data tab of
|
||||
properties window."""
|
||||
|
||||
bl_space_type = 'PROPERTIES'
|
||||
bl_region_type = 'WINDOW'
|
||||
bl_context = "data"
|
||||
COMPAT_ENGINES = {'POVRAY_RENDER'}
|
||||
|
||||
@classmethod
|
||||
def poll(cls, context):
|
||||
cam = context.camera
|
||||
rd = context.scene.render
|
||||
return cam and (rd.engine in cls.COMPAT_ENGINES)
|
||||
|
||||
|
||||
class WorldButtonsPanel:
|
||||
"""Use this class to define buttons from the world tab of
|
||||
properties window."""
|
||||
|
||||
bl_space_type = 'PROPERTIES'
|
||||
bl_region_type = 'WINDOW'
|
||||
bl_context = "world"
|
||||
COMPAT_ENGINES = {'POVRAY_RENDER'}
|
||||
|
||||
@classmethod
|
||||
def poll(cls, context):
|
||||
wld = context.world
|
||||
rd = context.scene.render
|
||||
return wld and (rd.engine in cls.COMPAT_ENGINES)
|
||||
|
||||
|
||||
###############################################################################
|
||||
# Camera Settings
|
||||
###############################################################################
|
||||
class CAMERA_PT_POV_cam_dof(CameraDataButtonsPanel, Panel):
|
||||
"""Use this class for camera depth of field focal blur buttons."""
|
||||
|
||||
bl_label = "POV Aperture"
|
||||
COMPAT_ENGINES = {'POVRAY_RENDER'}
|
||||
bl_parent_id = "DATA_PT_camera_dof_aperture"
|
||||
bl_options = {'HIDE_HEADER'}
|
||||
# def draw_header(self, context):
|
||||
# cam = context.camera
|
||||
|
||||
# self.layout.prop(cam.pov, "dof_enable", text="")
|
||||
|
||||
def draw(self, context):
|
||||
layout = self.layout
|
||||
|
||||
cam = context.camera
|
||||
|
||||
layout.active = cam.dof.use_dof
|
||||
layout.use_property_split = True # Active single-column layout
|
||||
|
||||
flow = layout.grid_flow(
|
||||
row_major=True, columns=0, even_columns=True, even_rows=False, align=False
|
||||
)
|
||||
|
||||
col = flow.column()
|
||||
col.label(text="F-Stop value will export as")
|
||||
col.label(text="POV aperture : " + "%.3f" % (1 / cam.dof.aperture_fstop * 1000))
|
||||
|
||||
col = flow.column()
|
||||
col.prop(cam.pov, "dof_samples_min")
|
||||
col.prop(cam.pov, "dof_samples_max")
|
||||
col.prop(cam.pov, "dof_variance")
|
||||
col.prop(cam.pov, "dof_confidence")
|
||||
|
||||
|
||||
class CAMERA_PT_POV_cam_nor(CameraDataButtonsPanel, Panel):
|
||||
"""Use this class for camera normal perturbation buttons."""
|
||||
|
||||
bl_label = "POV Perturbation"
|
||||
COMPAT_ENGINES = {'POVRAY_RENDER'}
|
||||
|
||||
def draw_header(self, context):
|
||||
cam = context.camera
|
||||
|
||||
self.layout.prop(cam.pov, "normal_enable", text="")
|
||||
|
||||
def draw(self, context):
|
||||
layout = self.layout
|
||||
|
||||
cam = context.camera
|
||||
|
||||
layout.active = cam.pov.normal_enable
|
||||
|
||||
layout.prop(cam.pov, "normal_patterns")
|
||||
layout.prop(cam.pov, "cam_normal")
|
||||
layout.prop(cam.pov, "turbulence")
|
||||
layout.prop(cam.pov, "scale")
|
||||
|
||||
|
||||
class CAMERA_PT_POV_replacement_text(CameraDataButtonsPanel, Panel):
|
||||
"""Use this class for camera text replacement field."""
|
||||
|
||||
bl_label = "Custom POV Code"
|
||||
COMPAT_ENGINES = {'POVRAY_RENDER'}
|
||||
|
||||
def draw(self, context):
|
||||
layout = self.layout
|
||||
|
||||
cam = context.camera
|
||||
|
||||
col = layout.column()
|
||||
col.label(text="Replace properties with:")
|
||||
col.prop(cam.pov, "replacement_text", text="")
|
||||
|
||||
|
||||
###############################################################################
|
||||
# World background and sky sphere Settings
|
||||
###############################################################################
|
||||
|
||||
|
||||
class WORLD_PT_POV_world(WorldButtonsPanel, Panel):
|
||||
"""Use this class to define pov world buttons"""
|
||||
|
||||
bl_label = "World"
|
||||
|
||||
COMPAT_ENGINES = {'POVRAY_RENDER'}
|
||||
|
||||
def draw(self, context):
|
||||
layout = self.layout
|
||||
|
||||
world = context.world.pov
|
||||
|
||||
row = layout.row(align=True)
|
||||
row.menu(WORLD_MT_POV_presets.__name__, text=WORLD_MT_POV_presets.bl_label)
|
||||
row.operator(WORLD_OT_POV_add_preset.bl_idname, text="", icon='ADD')
|
||||
row.operator(WORLD_OT_POV_add_preset.bl_idname, text="", icon='REMOVE').remove_active = True
|
||||
|
||||
row = layout.row()
|
||||
row.prop(world, "use_sky_paper")
|
||||
row.prop(world, "use_sky_blend")
|
||||
row.prop(world, "use_sky_real")
|
||||
|
||||
row = layout.row()
|
||||
row.column().prop(world, "horizon_color")
|
||||
col = row.column()
|
||||
col.prop(world, "zenith_color")
|
||||
col.active = world.use_sky_blend
|
||||
row.column().prop(world, "ambient_color")
|
||||
|
||||
# row = layout.row()
|
||||
# row.prop(world, "exposure") #Re-implement later as a light multiplier
|
||||
# row.prop(world, "color_range")
|
||||
|
||||
|
||||
class WORLD_PT_POV_mist(WorldButtonsPanel, Panel):
|
||||
"""Use this class to define pov mist buttons."""
|
||||
|
||||
bl_label = "Mist"
|
||||
bl_options = {'DEFAULT_CLOSED'}
|
||||
COMPAT_ENGINES = {'POVRAY_RENDER'}
|
||||
|
||||
def draw_header(self, context):
|
||||
world = context.world
|
||||
|
||||
self.layout.prop(world.mist_settings, "use_mist", text="")
|
||||
|
||||
def draw(self, context):
|
||||
layout = self.layout
|
||||
|
||||
world = context.world
|
||||
|
||||
layout.active = world.mist_settings.use_mist
|
||||
|
||||
split = layout.split()
|
||||
|
||||
col = split.column()
|
||||
col.prop(world.mist_settings, "intensity")
|
||||
col.prop(world.mist_settings, "start")
|
||||
|
||||
col = split.column()
|
||||
col.prop(world.mist_settings, "depth")
|
||||
col.prop(world.mist_settings, "height")
|
||||
|
||||
layout.prop(world.mist_settings, "falloff")
|
||||
|
||||
|
||||
class WORLD_MT_POV_presets(Menu):
|
||||
"""Apply world preset to all concerned properties"""
|
||||
|
||||
bl_label = "World Presets"
|
||||
preset_subdir = "pov/world"
|
||||
preset_operator = "script.execute_preset"
|
||||
draw = bpy.types.Menu.draw_preset
|
||||
|
||||
|
||||
class WORLD_OT_POV_add_preset(AddPresetBase, Operator):
|
||||
"""Add a World Preset recording current values"""
|
||||
|
||||
bl_idname = "object.world_preset_add"
|
||||
bl_label = "Add World Preset"
|
||||
preset_menu = "WORLD_MT_POV_presets"
|
||||
|
||||
# variable used for all preset values
|
||||
preset_defines = ["scene = bpy.context.scene"]
|
||||
|
||||
# properties to store in the preset
|
||||
preset_values = [
|
||||
"scene.world.use_sky_blend",
|
||||
"scene.world.horizon_color",
|
||||
"scene.world.zenith_color",
|
||||
"scene.world.ambient_color",
|
||||
"scene.world.mist_settings.use_mist",
|
||||
"scene.world.mist_settings.intensity",
|
||||
"scene.world.mist_settings.depth",
|
||||
"scene.world.mist_settings.start",
|
||||
"scene.pov.media_enable",
|
||||
"scene.pov.media_scattering_type",
|
||||
"scene.pov.media_samples",
|
||||
"scene.pov.media_diffusion_scale",
|
||||
"scene.pov.media_diffusion_color",
|
||||
"scene.pov.media_absorption_scale",
|
||||
"scene.pov.media_absorption_color",
|
||||
"scene.pov.media_eccentricity",
|
||||
]
|
||||
|
||||
# where to store the preset
|
||||
preset_subdir = "pov/world"
|
||||
|
||||
|
||||
class RENDER_PT_POV_media(WorldButtonsPanel, Panel):
|
||||
"""Use this class to define a pov global atmospheric media buttons."""
|
||||
|
||||
bl_label = "Atmosphere Media"
|
||||
COMPAT_ENGINES = {'POVRAY_RENDER'}
|
||||
|
||||
def draw_header(self, context):
|
||||
scene = context.scene
|
||||
|
||||
self.layout.prop(scene.pov, "media_enable", text="")
|
||||
|
||||
def draw(self, context):
|
||||
layout = self.layout
|
||||
|
||||
scene = context.scene
|
||||
|
||||
layout.active = scene.pov.media_enable
|
||||
|
||||
col = layout.column()
|
||||
col.prop(scene.pov, "media_scattering_type", text="")
|
||||
col = layout.column()
|
||||
col.prop(scene.pov, "media_samples", text="Samples")
|
||||
split = layout.split()
|
||||
col = split.column(align=True)
|
||||
col.label(text="Scattering:")
|
||||
col.prop(scene.pov, "media_diffusion_scale")
|
||||
col.prop(scene.pov, "media_diffusion_color", text="")
|
||||
col = split.column(align=True)
|
||||
col.label(text="Absorption:")
|
||||
col.prop(scene.pov, "media_absorption_scale")
|
||||
col.prop(scene.pov, "media_absorption_color", text="")
|
||||
if scene.pov.media_scattering_type == '5':
|
||||
col = layout.column()
|
||||
col.prop(scene.pov, "media_eccentricity", text="Eccentricity")
|
||||
|
||||
|
||||
###############################################################################
|
||||
# Lights settings
|
||||
###############################################################################
|
||||
|
||||
################################################################################
|
||||
# from bl_ui import properties_data_light
|
||||
# for member in dir(properties_data_light):
|
||||
# subclass = getattr(properties_data_light, member)
|
||||
# try:
|
||||
# subclass.COMPAT_ENGINES.add('POVRAY_RENDER')
|
||||
# except BaseException as e:
|
||||
# print e.__doc__
|
||||
# print('An exception occurred: {}'.format(e))
|
||||
# pass
|
||||
# del properties_data_light
|
||||
#########################LIGHTS################################
|
||||
|
||||
from bl_ui import properties_data_light
|
||||
|
||||
# # These panels are kept
|
||||
# properties_data_light.DATA_PT_custom_props_light.COMPAT_ENGINES.add('POVRAY_RENDER')
|
||||
# properties_data_light.DATA_PT_context_light.COMPAT_ENGINES.add('POVRAY_RENDER')
|
||||
|
||||
## make some native panels contextual to some object variable
|
||||
## by recreating custom panels inheriting their properties
|
||||
class PovLightButtonsPanel(properties_data_light.DataButtonsPanel):
|
||||
"""Use this class to define buttons from the light data tab of
|
||||
properties window."""
|
||||
|
||||
COMPAT_ENGINES = {'POVRAY_RENDER'}
|
||||
POV_OBJECT_TYPES = {'RAINBOW'}
|
||||
|
||||
@classmethod
|
||||
def poll(cls, context):
|
||||
obj = context.object
|
||||
# We use our parent class poll func too, avoids to re-define too much things...
|
||||
return (
|
||||
super(PovLightButtonsPanel, cls).poll(context)
|
||||
and obj
|
||||
and obj.pov.object_as not in cls.POV_OBJECT_TYPES
|
||||
)
|
||||
|
||||
|
||||
# We cannot inherit from RNA classes (like e.g. properties_data_mesh.DATA_PT_vertex_groups).
|
||||
# Complex py/bpy/rna interactions (with metaclass and all) simply do not allow it to work.
|
||||
# So we simply have to explicitly copy here the interesting bits. ;)
|
||||
from bl_ui import properties_data_light
|
||||
|
||||
# for member in dir(properties_data_light):
|
||||
# subclass = getattr(properties_data_light, member)
|
||||
# try:
|
||||
# subclass.COMPAT_ENGINES.add('POVRAY_RENDER')
|
||||
# except BaseException as e:
|
||||
# print(e.__doc__)
|
||||
# print('An exception occurred: {}'.format(e))
|
||||
# pass
|
||||
|
||||
# Now only These panels are kept
|
||||
properties_data_light.DATA_PT_custom_props_light.COMPAT_ENGINES.add('POVRAY_RENDER')
|
||||
properties_data_light.DATA_PT_context_light.COMPAT_ENGINES.add('POVRAY_RENDER')
|
||||
|
||||
|
||||
class LIGHT_PT_POV_preview(PovLightButtonsPanel, Panel):
|
||||
# XXX Needs update and docstring
|
||||
bl_label = properties_data_light.DATA_PT_preview.bl_label
|
||||
|
||||
draw = properties_data_light.DATA_PT_preview.draw
|
||||
|
||||
|
||||
class LIGHT_PT_POV_light(PovLightButtonsPanel, Panel):
|
||||
"""UI panel to main pov light parameters"""
|
||||
|
||||
# bl_label = properties_data_light.DATA_PT_light.bl_label
|
||||
|
||||
# draw = properties_data_light.DATA_PT_light.draw
|
||||
# class DATA_PT_POV_light(DataButtonsPanel, Panel):
|
||||
bl_label = "Light"
|
||||
# COMPAT_ENGINES = {'POVRAY_RENDER'}
|
||||
|
||||
def draw(self, context):
|
||||
layout = self.layout
|
||||
|
||||
light = context.light
|
||||
|
||||
layout.row().prop(light, "type", expand=True)
|
||||
|
||||
split = layout.split()
|
||||
|
||||
col = split.column()
|
||||
sub = col.column()
|
||||
sub.prop(light, "color", text="")
|
||||
sub.prop(light, "energy")
|
||||
|
||||
if light.type in {'POINT', 'SPOT'}:
|
||||
sub.label(text="Falloff:")
|
||||
sub.prop(light, "falloff_type", text="")
|
||||
sub.prop(light, "distance")
|
||||
|
||||
if light.falloff_type == 'LINEAR_QUADRATIC_WEIGHTED':
|
||||
col.label(text="Attenuation Factors:")
|
||||
sub = col.column(align=True)
|
||||
sub.prop(light, "linear_attenuation", slider=True, text="Linear")
|
||||
sub.prop(light, "quadratic_attenuation", slider=True, text="Quadratic")
|
||||
|
||||
elif light.falloff_type == 'INVERSE_COEFFICIENTS':
|
||||
col.label(text="Inverse Coefficients:")
|
||||
sub = col.column(align=True)
|
||||
sub.prop(light, "constant_coefficient", text="Constant")
|
||||
sub.prop(light, "linear_coefficient", text="Linear")
|
||||
sub.prop(light, "quadratic_coefficient", text="Quadratic")
|
||||
|
||||
if light.type == 'AREA':
|
||||
col.prop(light, "distance")
|
||||
|
||||
# restore later as interface to POV light groups ?
|
||||
# col = split.column()
|
||||
# col.prop(light, "use_own_layer", text="This Layer Only")
|
||||
|
||||
|
||||
class LIGHT_MT_POV_presets(Menu):
|
||||
"""Use this class to define preset menu for pov lights."""
|
||||
|
||||
bl_label = "Lamp Presets"
|
||||
preset_subdir = "pov/light"
|
||||
preset_operator = "script.execute_preset"
|
||||
draw = bpy.types.Menu.draw_preset
|
||||
|
||||
|
||||
class LIGHT_OT_POV_add_preset(AddPresetBase, Operator):
|
||||
"""Operator to add a Light Preset"""
|
||||
|
||||
bl_idname = "object.light_preset_add"
|
||||
bl_label = "Add Light Preset"
|
||||
preset_menu = "LIGHT_MT_POV_presets"
|
||||
|
||||
# variable used for all preset values
|
||||
preset_defines = ["lightdata = bpy.context.object.data"]
|
||||
|
||||
# properties to store in the preset
|
||||
preset_values = ["lightdata.type", "lightdata.color"]
|
||||
|
||||
# where to store the preset
|
||||
preset_subdir = "pov/light"
|
||||
|
||||
|
||||
# Draw into the existing light panel
|
||||
def light_panel_func(self, context):
|
||||
"""Menu to browse and add light preset"""
|
||||
layout = self.layout
|
||||
|
||||
row = layout.row(align=True)
|
||||
row.menu(LIGHT_MT_POV_presets.__name__, text=LIGHT_MT_POV_presets.bl_label)
|
||||
row.operator(LIGHT_OT_POV_add_preset.bl_idname, text="", icon='ADD')
|
||||
row.operator(LIGHT_OT_POV_add_preset.bl_idname, text="", icon='REMOVE').remove_active = True
|
||||
|
||||
|
||||
'''#TORECREATE##DEPRECATED#
|
||||
class LIGHT_PT_POV_sunsky(PovLightButtonsPanel, Panel):
|
||||
bl_label = properties_data_light.DATA_PT_sunsky.bl_label
|
||||
|
||||
@classmethod
|
||||
def poll(cls, context):
|
||||
lamp = context.light
|
||||
engine = context.scene.render.engine
|
||||
return (lamp and lamp.type == 'SUN') and (engine in cls.COMPAT_ENGINES)
|
||||
|
||||
draw = properties_data_light.DATA_PT_sunsky.draw
|
||||
|
||||
'''
|
||||
|
||||
|
||||
class LIGHT_PT_POV_shadow(PovLightButtonsPanel, Panel):
|
||||
# Todo : update and docstring
|
||||
bl_label = "Shadow"
|
||||
|
||||
@classmethod
|
||||
def poll(cls, context):
|
||||
light = context.light
|
||||
engine = context.scene.render.engine
|
||||
return light and (engine in cls.COMPAT_ENGINES)
|
||||
|
||||
def draw(self, context):
|
||||
layout = self.layout
|
||||
|
||||
light = context.light
|
||||
|
||||
layout.row().prop(light.pov, "shadow_method", expand=True)
|
||||
|
||||
split = layout.split()
|
||||
col = split.column()
|
||||
|
||||
col.prop(light.pov, "use_halo")
|
||||
sub = col.column(align=True)
|
||||
sub.active = light.pov.use_halo
|
||||
sub.prop(light.pov, "halo_intensity", text="Intensity")
|
||||
|
||||
if light.pov.shadow_method == 'NOSHADOW' and light.type == 'AREA':
|
||||
split = layout.split()
|
||||
|
||||
col = split.column()
|
||||
col.label(text="Form factor sampling:")
|
||||
|
||||
sub = col.row(align=True)
|
||||
|
||||
if light.shape == 'SQUARE':
|
||||
sub.prop(light, "shadow_ray_samples_x", text="Samples")
|
||||
elif light.shape == 'RECTANGLE':
|
||||
sub.prop(light.pov, "shadow_ray_samples_x", text="Samples X")
|
||||
sub.prop(light.pov, "shadow_ray_samples_y", text="Samples Y")
|
||||
|
||||
if light.pov.shadow_method != 'NOSHADOW':
|
||||
split = layout.split()
|
||||
|
||||
col = split.column()
|
||||
col.prop(light, "shadow_color", text="")
|
||||
|
||||
# col = split.column()
|
||||
# col.prop(light.pov, "use_shadow_layer", text="This Layer Only")
|
||||
# col.prop(light.pov, "use_only_shadow")
|
||||
|
||||
if light.pov.shadow_method == 'RAY_SHADOW':
|
||||
split = layout.split()
|
||||
|
||||
col = split.column()
|
||||
col.label(text="Sampling:")
|
||||
|
||||
if light.type in {'POINT', 'SUN', 'SPOT'}:
|
||||
sub = col.row()
|
||||
|
||||
sub.prop(light.pov, "shadow_ray_samples_x", text="Samples")
|
||||
# any equivalent in pov?
|
||||
# sub.prop(light, "shadow_soft_size", text="Soft Size")
|
||||
|
||||
elif light.type == 'AREA':
|
||||
sub = col.row(align=True)
|
||||
|
||||
if light.shape == 'SQUARE':
|
||||
sub.prop(light.pov, "shadow_ray_samples_x", text="Samples")
|
||||
elif light.shape == 'RECTANGLE':
|
||||
sub.prop(light.pov, "shadow_ray_samples_x", text="Samples X")
|
||||
sub.prop(light.pov, "shadow_ray_samples_y", text="Samples Y")
|
||||
|
||||
|
||||
class LIGHT_PT_POV_area(PovLightButtonsPanel, Panel):
|
||||
"""Area light UI panel"""
|
||||
|
||||
bl_label = properties_data_light.DATA_PT_area.bl_label
|
||||
bl_parent_id = "LIGHT_PT_POV_light"
|
||||
bl_context = "data"
|
||||
|
||||
@classmethod
|
||||
def poll(cls, context):
|
||||
lamp = context.light
|
||||
engine = context.scene.render.engine
|
||||
return (lamp and lamp.type == 'AREA') and (engine in cls.COMPAT_ENGINES)
|
||||
|
||||
draw = properties_data_light.DATA_PT_area.draw
|
||||
|
||||
|
||||
class LIGHT_PT_POV_spot(PovLightButtonsPanel, Panel):
|
||||
bl_label = properties_data_light.DATA_PT_spot.bl_label
|
||||
bl_parent_id = "LIGHT_PT_POV_light"
|
||||
bl_context = "data"
|
||||
|
||||
@classmethod
|
||||
def poll(cls, context):
|
||||
lamp = context.light
|
||||
engine = context.scene.render.engine
|
||||
return (lamp and lamp.type == 'SPOT') and (engine in cls.COMPAT_ENGINES)
|
||||
|
||||
draw = properties_data_light.DATA_PT_spot.draw
|
||||
|
||||
|
||||
class LIGHT_PT_POV_falloff_curve(PovLightButtonsPanel, Panel):
|
||||
bl_label = properties_data_light.DATA_PT_falloff_curve.bl_label
|
||||
bl_options = properties_data_light.DATA_PT_falloff_curve.bl_options
|
||||
|
||||
@classmethod
|
||||
def poll(cls, context):
|
||||
lamp = context.light
|
||||
engine = context.scene.render.engine
|
||||
|
||||
return (
|
||||
lamp and lamp.type in {'POINT', 'SPOT'} and lamp.falloff_type == 'CUSTOM_CURVE'
|
||||
) and (engine in cls.COMPAT_ENGINES)
|
||||
|
||||
draw = properties_data_light.DATA_PT_falloff_curve.draw
|
||||
|
||||
|
||||
class OBJECT_PT_POV_rainbow(PovLightButtonsPanel, Panel):
|
||||
"""Use this class to define buttons from the rainbow panel of
|
||||
properties window. inheriting lamp buttons panel class"""
|
||||
|
||||
bl_label = "POV-Ray Rainbow"
|
||||
COMPAT_ENGINES = {'POVRAY_RENDER'}
|
||||
# bl_options = {'HIDE_HEADER'}
|
||||
@classmethod
|
||||
def poll(cls, context):
|
||||
engine = context.scene.render.engine
|
||||
obj = context.object
|
||||
return obj and obj.pov.object_as == 'RAINBOW' and (engine in cls.COMPAT_ENGINES)
|
||||
|
||||
def draw(self, context):
|
||||
layout = self.layout
|
||||
|
||||
obj = context.object
|
||||
|
||||
col = layout.column()
|
||||
|
||||
if obj.pov.object_as == 'RAINBOW':
|
||||
if not obj.pov.unlock_parameters:
|
||||
col.prop(
|
||||
obj.pov, "unlock_parameters", text="Exported parameters below", icon='LOCKED'
|
||||
)
|
||||
col.label(text="Rainbow projection angle: " + str(obj.data.spot_size))
|
||||
col.label(text="Rainbow width: " + str(obj.data.spot_blend))
|
||||
col.label(text="Rainbow distance: " + str(obj.data.shadow_buffer_clip_start))
|
||||
col.label(text="Rainbow arc angle: " + str(obj.pov.arc_angle))
|
||||
col.label(text="Rainbow falloff angle: " + str(obj.pov.falloff_angle))
|
||||
|
||||
else:
|
||||
col.prop(
|
||||
obj.pov, "unlock_parameters", text="Edit exported parameters", icon='UNLOCKED'
|
||||
)
|
||||
col.label(text="3D view proxy may get out of synch")
|
||||
col.active = obj.pov.unlock_parameters
|
||||
|
||||
layout.operator("pov.cone_update", text="Update", icon="MESH_CONE")
|
||||
|
||||
# col.label(text="Parameters:")
|
||||
col.prop(obj.data, "spot_size", text="Rainbow Projection Angle")
|
||||
col.prop(obj.data, "spot_blend", text="Rainbow width")
|
||||
col.prop(obj.data, "shadow_buffer_clip_start", text="Visibility distance")
|
||||
col.prop(obj.pov, "arc_angle")
|
||||
col.prop(obj.pov, "falloff_angle")
|
||||
|
||||
|
||||
del properties_data_light
|
||||
|
||||
|
||||
classes = (
|
||||
WORLD_PT_POV_world,
|
||||
WORLD_MT_POV_presets,
|
||||
WORLD_OT_POV_add_preset,
|
||||
WORLD_PT_POV_mist,
|
||||
RENDER_PT_POV_media,
|
||||
LIGHT_PT_POV_preview,
|
||||
LIGHT_PT_POV_light,
|
||||
LIGHT_PT_POV_shadow,
|
||||
LIGHT_PT_POV_spot,
|
||||
LIGHT_PT_POV_area,
|
||||
LIGHT_MT_POV_presets,
|
||||
LIGHT_OT_POV_add_preset,
|
||||
OBJECT_PT_POV_rainbow,
|
||||
CAMERA_PT_POV_cam_dof,
|
||||
CAMERA_PT_POV_cam_nor,
|
||||
CAMERA_PT_POV_replacement_text,
|
||||
)
|
||||
|
||||
|
||||
def register():
|
||||
|
||||
for cls in classes:
|
||||
register_class(cls)
|
||||
bpy.types.LIGHT_PT_POV_light.prepend(light_panel_func)
|
||||
|
||||
|
||||
def unregister():
|
||||
|
||||
for cls in reversed(classes):
|
||||
unregister_class(cls)
|
||||
bpy.types.LIGHT_PT_POV_light.remove(light_panel_func)
|
|
@ -0,0 +1,514 @@
|
|||
# ##### BEGIN GPL LICENSE BLOCK #####
|
||||
#
|
||||
# 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 2
|
||||
# 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
|
||||
# MERCHANTABILITY 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, write to the Free Software Foundation,
|
||||
# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
#
|
||||
# ##### END GPL LICENSE BLOCK #####
|
||||
|
||||
# <pep8 compliant>
|
||||
"""Declare stage set and surrounding (camera, lights, environment) properties controllable in UI"""
|
||||
import bpy
|
||||
from bpy.utils import register_class, unregister_class
|
||||
from bpy.types import PropertyGroup
|
||||
from bpy.props import (
|
||||
FloatVectorProperty,
|
||||
StringProperty,
|
||||
BoolProperty,
|
||||
IntProperty,
|
||||
FloatProperty,
|
||||
EnumProperty,
|
||||
PointerProperty,
|
||||
CollectionProperty,
|
||||
)
|
||||
|
||||
from .shading_properties import (
|
||||
active_texture_name_from_uilist,
|
||||
active_texture_name_from_search,
|
||||
brush_texture_update,
|
||||
)
|
||||
|
||||
###############################################################################
|
||||
# Camera POV properties.
|
||||
###############################################################################
|
||||
class RenderPovSettingsCamera(PropertyGroup):
|
||||
|
||||
"""Declare camera properties controllable in UI and translated to POV."""
|
||||
|
||||
# DOF Toggle
|
||||
dof_enable: BoolProperty(
|
||||
name="Depth Of Field", description="Enable POV Depth Of Field ", default=False
|
||||
)
|
||||
|
||||
# Aperture (Intensity of the Blur)
|
||||
dof_aperture: FloatProperty(
|
||||
name="Aperture",
|
||||
description="Similar to a real camera's aperture effect over focal blur (though not "
|
||||
"in physical units and independent of focal length). "
|
||||
"Increase to get more blur",
|
||||
min=0.01,
|
||||
max=1.00,
|
||||
default=0.50,
|
||||
)
|
||||
|
||||
# Aperture adaptive sampling
|
||||
dof_samples_min: IntProperty(
|
||||
name="Samples Min",
|
||||
description="Minimum number of rays to use for each pixel",
|
||||
min=1,
|
||||
max=128,
|
||||
default=3,
|
||||
)
|
||||
|
||||
dof_samples_max: IntProperty(
|
||||
name="Samples Max",
|
||||
description="Maximum number of rays to use for each pixel",
|
||||
min=1,
|
||||
max=128,
|
||||
default=9,
|
||||
)
|
||||
|
||||
dof_variance: IntProperty(
|
||||
name="Variance",
|
||||
description="Minimum threshold (fractional value) for adaptive DOF sampling (up "
|
||||
"increases quality and render time). The value for the variance should "
|
||||
"be in the range of the smallest displayable color difference",
|
||||
min=1,
|
||||
max=100000,
|
||||
soft_max=10000,
|
||||
default=8192,
|
||||
)
|
||||
|
||||
dof_confidence: FloatProperty(
|
||||
name="Confidence",
|
||||
description="Probability to reach the real color value. Larger confidence values "
|
||||
"will lead to more samples, slower traces and better images",
|
||||
min=0.01,
|
||||
max=0.99,
|
||||
default=0.20,
|
||||
)
|
||||
|
||||
normal_enable: BoolProperty(name="Perturbated Camera", default=False)
|
||||
|
||||
cam_normal: FloatProperty(name="Normal Strength", min=0.0, max=1.0, default=0.001)
|
||||
|
||||
normal_patterns: EnumProperty(
|
||||
name="Pattern",
|
||||
description="",
|
||||
items=(
|
||||
("agate", "Agate", ""),
|
||||
("boxed", "Boxed", ""),
|
||||
("bumps", "Bumps", ""),
|
||||
("cells", "Cells", ""),
|
||||
("crackle", "Crackle", ""),
|
||||
("dents", "Dents", ""),
|
||||
("granite", "Granite", ""),
|
||||
("leopard", "Leopard", ""),
|
||||
("marble", "Marble", ""),
|
||||
("onion", "Onion", ""),
|
||||
("pavement", "Pavement", ""),
|
||||
("planar", "Planar", ""),
|
||||
("quilted", "Quilted", ""),
|
||||
("ripples", "Ripples", ""),
|
||||
("radial", "Radial", ""),
|
||||
("spherical", "Spherical", ""),
|
||||
("spiral1", "Spiral1", ""),
|
||||
("spiral2", "Spiral2", ""),
|
||||
("spotted", "Spotted", ""),
|
||||
("square", "Square", ""),
|
||||
("tiling", "Tiling", ""),
|
||||
("waves", "Waves", ""),
|
||||
("wood", "Wood", ""),
|
||||
("wrinkles", "Wrinkles", ""),
|
||||
),
|
||||
default="agate",
|
||||
)
|
||||
|
||||
turbulence: FloatProperty(name="Turbulence", min=0.0, max=100.0, default=0.1)
|
||||
|
||||
scale: FloatProperty(name="Scale", min=0.0, default=1.0)
|
||||
|
||||
##################################CustomPOV Code############################
|
||||
# Only DUMMIES below for now:
|
||||
replacement_text: StringProperty(
|
||||
name="Texts in blend file",
|
||||
description="Type the declared name in custom POV code or an external .inc "
|
||||
"it points at. camera {} expected",
|
||||
default="",
|
||||
)
|
||||
|
||||
|
||||
###############################################################################
|
||||
# Light POV properties.
|
||||
###############################################################################
|
||||
class RenderPovSettingsLight(PropertyGroup):
|
||||
|
||||
"""Declare light properties controllable in UI and translated to POV."""
|
||||
|
||||
# former Space properties from removed Blender Internal
|
||||
use_limited_texture_context: BoolProperty(
|
||||
name="",
|
||||
description="Use the limited version of texture user (for ‘old shading’ mode)",
|
||||
default=True,
|
||||
)
|
||||
|
||||
texture_context: EnumProperty(
|
||||
name="Texture context",
|
||||
description="Type of texture data to display and edit",
|
||||
items=(
|
||||
("MATERIAL", "", "Show material textures", "MATERIAL", 0), # "Show material textures"
|
||||
("WORLD", "", "Show world textures", "WORLD", 1), # "Show world textures"
|
||||
("LAMP", "", "Show lamp textures", "LIGHT", 2), # "Show lamp textures"
|
||||
(
|
||||
"PARTICLES",
|
||||
"",
|
||||
"Show particles textures",
|
||||
"PARTICLES",
|
||||
3,
|
||||
), # "Show particles textures"
|
||||
(
|
||||
"LINESTYLE",
|
||||
"",
|
||||
"Show linestyle textures",
|
||||
"LINE_DATA",
|
||||
4,
|
||||
), # "Show linestyle textures"
|
||||
(
|
||||
"OTHER",
|
||||
"",
|
||||
"Show other data textures",
|
||||
"TEXTURE_DATA",
|
||||
5,
|
||||
), # "Show other data textures"
|
||||
),
|
||||
default="MATERIAL",
|
||||
)
|
||||
|
||||
shadow_method: EnumProperty(
|
||||
name="Shadow",
|
||||
description="",
|
||||
items=(
|
||||
("NOSHADOW", "No Shadow", "No Shadow"),
|
||||
("RAY_SHADOW", "Ray Shadow", "Ray Shadow, Use ray tracing for shadow"),
|
||||
),
|
||||
default="RAY_SHADOW",
|
||||
)
|
||||
|
||||
active_texture_index: IntProperty(name="Index for texture_slots", default=0)
|
||||
|
||||
use_halo: BoolProperty(
|
||||
name="Halo", description="Render spotlight with a volumetric halo", default=False
|
||||
)
|
||||
|
||||
halo_intensity: FloatProperty(
|
||||
name="Halo intensity",
|
||||
description="Brightness of the spotlight halo cone",
|
||||
soft_min=0.0,
|
||||
soft_max=1.0,
|
||||
default=1.0,
|
||||
)
|
||||
|
||||
shadow_ray_samples_x: IntProperty(
|
||||
name="Number of samples taken extra (samples x samples)", min=1, soft_max=64, default=1
|
||||
)
|
||||
|
||||
shadow_ray_samples_y: IntProperty(
|
||||
name="Number of samples taken extra (samples x samples)", min=1, soft_max=64, default=1
|
||||
)
|
||||
|
||||
shadow_ray_sample_method: EnumProperty(
|
||||
name="",
|
||||
description="Method for generating shadow samples: Adaptive QMC is fastest,"
|
||||
"Constant QMC is less noisy but slower",
|
||||
items=(
|
||||
("ADAPTIVE_QMC", "", "Halton samples distribution", "", 0),
|
||||
("CONSTANT_QMC", "", "QMC samples distribution", "", 1),
|
||||
(
|
||||
"CONSTANT_JITTERED",
|
||||
"",
|
||||
"Uses POV jitter keyword",
|
||||
"",
|
||||
2,
|
||||
), # "Show other data textures"
|
||||
),
|
||||
default="CONSTANT_JITTERED",
|
||||
)
|
||||
|
||||
use_jitter: BoolProperty(
|
||||
name="Jitter",
|
||||
description="Use noise for sampling (Constant Jittered sampling)",
|
||||
default=False,
|
||||
)
|
||||
|
||||
|
||||
###############################################################################
|
||||
# World POV properties.
|
||||
###############################################################################
|
||||
class RenderPovSettingsWorld(PropertyGroup):
|
||||
|
||||
"""Declare world properties controllable in UI and translated to POV."""
|
||||
|
||||
# former Space properties from removed Blender Internal
|
||||
use_limited_texture_context: BoolProperty(
|
||||
name="",
|
||||
description="Use the limited version of texture user (for ‘old shading’ mode)",
|
||||
default=True,
|
||||
)
|
||||
|
||||
texture_context: EnumProperty(
|
||||
name="Texture context",
|
||||
description="Type of texture data to display and edit",
|
||||
items=(
|
||||
("MATERIAL", "", "Show material textures", "MATERIAL", 0), # "Show material textures"
|
||||
("WORLD", "", "Show world textures", "WORLD", 1), # "Show world textures"
|
||||
("LIGHT", "", "Show lamp textures", "LIGHT", 2), # "Show lamp textures"
|
||||
(
|
||||
"PARTICLES",
|
||||
"",
|
||||
"Show particles textures",
|
||||
"PARTICLES",
|
||||
3,
|
||||
), # "Show particles textures"
|
||||
(
|
||||
"LINESTYLE",
|
||||
"",
|
||||
"Show linestyle textures",
|
||||
"LINE_DATA",
|
||||
4,
|
||||
), # "Show linestyle textures"
|
||||
(
|
||||
"OTHER",
|
||||
"",
|
||||
"Show other data textures",
|
||||
"TEXTURE_DATA",
|
||||
5,
|
||||
), # "Show other data textures"
|
||||
),
|
||||
default="MATERIAL",
|
||||
)
|
||||
|
||||
use_sky_blend: BoolProperty(
|
||||
name="Blend Sky",
|
||||
description="Render background with natural progression from horizon to zenith",
|
||||
default=False,
|
||||
)
|
||||
|
||||
use_sky_paper: BoolProperty(
|
||||
name="Paper Sky", description="Flatten blend or texture coordinates", default=False
|
||||
)
|
||||
|
||||
use_sky_real: BoolProperty(
|
||||
name="Real Sky",
|
||||
description="Render background with a real horizon, relative to the camera angle",
|
||||
default=False,
|
||||
)
|
||||
|
||||
horizon_color: FloatVectorProperty(
|
||||
name="Horizon Color",
|
||||
description="Color at the horizon",
|
||||
precision=4,
|
||||
step=0.01,
|
||||
min=0,
|
||||
soft_max=1,
|
||||
default=(0.050876, 0.050876, 0.050876),
|
||||
options={"ANIMATABLE"},
|
||||
subtype="COLOR",
|
||||
)
|
||||
|
||||
zenith_color: FloatVectorProperty(
|
||||
name="Zenith Color",
|
||||
description="Color at the zenith",
|
||||
precision=4,
|
||||
step=0.01,
|
||||
min=0,
|
||||
soft_max=1,
|
||||
default=(0.0, 0.0, 0.0),
|
||||
options={"ANIMATABLE"},
|
||||
subtype="COLOR",
|
||||
)
|
||||
|
||||
ambient_color: FloatVectorProperty(
|
||||
name="Ambient Color",
|
||||
description="Ambient color of the world",
|
||||
precision=4,
|
||||
step=0.01,
|
||||
min=0,
|
||||
soft_max=1,
|
||||
default=(0.0, 0.0, 0.0),
|
||||
options={"ANIMATABLE"},
|
||||
subtype="COLOR",
|
||||
)
|
||||
active_texture_index: IntProperty(
|
||||
name="Index for texture_slots", default=0, update=brush_texture_update
|
||||
)
|
||||
|
||||
|
||||
class WorldTextureSlot(PropertyGroup):
|
||||
"""Declare world texture slot level properties for UI and translated to POV."""
|
||||
|
||||
bl_idname = ("pov_texture_slots",)
|
||||
bl_description = ("Texture_slots from Blender-2.79",)
|
||||
|
||||
# Adding a "real" texture datablock as property is not possible
|
||||
# (or at least not easy through a dynamically populated EnumProperty).
|
||||
# That's why we'll use a prop_search() UILayout function in texturing_gui.py.
|
||||
# So we'll assign the name of the needed texture datablock to the below StringProperty.
|
||||
texture: StringProperty(update=active_texture_name_from_uilist)
|
||||
# and use another temporary StringProperty to change the linked data
|
||||
texture_search: StringProperty(
|
||||
name="", update=active_texture_name_from_search, description="Browse Texture to be linked"
|
||||
)
|
||||
|
||||
blend_factor: FloatProperty(
|
||||
name="Blend",
|
||||
description="Amount texture affects color progression of the " "background",
|
||||
soft_min=0.0,
|
||||
soft_max=1.0,
|
||||
default=1.0,
|
||||
)
|
||||
|
||||
horizon_factor: FloatProperty(
|
||||
name="Horizon",
|
||||
description="Amount texture affects color of the horizon",
|
||||
soft_min=0.0,
|
||||
soft_max=1.0,
|
||||
default=1.0,
|
||||
)
|
||||
|
||||
object: StringProperty(
|
||||
name="Object",
|
||||
description="Object to use for mapping with Object texture coordinates",
|
||||
default="",
|
||||
)
|
||||
|
||||
offset: FloatVectorProperty(
|
||||
name="Offset",
|
||||
description=("Fine tune of the texture mapping X, Y and Z locations "),
|
||||
precision=4,
|
||||
step=0.1,
|
||||
soft_min=-100.0,
|
||||
soft_max=100.0,
|
||||
default=(0.0, 0.0, 0.0),
|
||||
options={"ANIMATABLE"},
|
||||
subtype="TRANSLATION",
|
||||
)
|
||||
|
||||
scale: FloatVectorProperty(
|
||||
name="Size",
|
||||
subtype="XYZ",
|
||||
size=3,
|
||||
description="Set scaling for the texture’s X, Y and Z sizes ",
|
||||
precision=4,
|
||||
step=0.1,
|
||||
soft_min=-100.0,
|
||||
soft_max=100.0,
|
||||
default=(1.0, 1.0, 1.0),
|
||||
options={"ANIMATABLE"},
|
||||
)
|
||||
|
||||
texture_coords: EnumProperty(
|
||||
name="Coordinates",
|
||||
description="Texture coordinates used to map the texture onto the background",
|
||||
items=(
|
||||
("VIEW", "View", "Use view vector for the texture coordinates"),
|
||||
(
|
||||
"GLOBAL",
|
||||
"Global",
|
||||
"Use global coordinates for the texture coordinates (interior mist)",
|
||||
),
|
||||
(
|
||||
"ANGMAP",
|
||||
"AngMap",
|
||||
"Use 360 degree angular coordinates, e.g. for spherical light probes",
|
||||
),
|
||||
("SPHERE", "Sphere", "For 360 degree panorama sky, spherical mapped, only top half"),
|
||||
("EQUIRECT", "Equirectangular", "For 360 degree panorama sky, equirectangular mapping"),
|
||||
("TUBE", "Tube", "For 360 degree panorama sky, cylindrical mapped, only top half"),
|
||||
("OBJECT", "Object", "Use linked object’s coordinates for texture coordinates"),
|
||||
),
|
||||
default="VIEW",
|
||||
)
|
||||
|
||||
use_map_blend: BoolProperty(
|
||||
name="Blend Map", description="Affect the color progression of the background", default=True
|
||||
)
|
||||
|
||||
use_map_horizon: BoolProperty(
|
||||
name="Horizon Map", description="Affect the color of the horizon", default=False
|
||||
)
|
||||
|
||||
use_map_zenith_down: BoolProperty(
|
||||
name="", description="Affect the color of the zenith below", default=False
|
||||
)
|
||||
|
||||
use_map_zenith_up: BoolProperty(
|
||||
name="Zenith Up Map", description="Affect the color of the zenith above", default=False
|
||||
)
|
||||
|
||||
zenith_down_factor: FloatProperty(
|
||||
name="Zenith Down",
|
||||
description="Amount texture affects color of the zenith below",
|
||||
soft_min=0.0,
|
||||
soft_max=1.0,
|
||||
default=1.0,
|
||||
)
|
||||
|
||||
zenith_up_factor: FloatProperty(
|
||||
name="Zenith Up",
|
||||
description="Amount texture affects color of the zenith above",
|
||||
soft_min=0.0,
|
||||
soft_max=1.0,
|
||||
default=1.0,
|
||||
)
|
||||
|
||||
|
||||
"""
|
||||
# class WORLD_TEXTURE_SLOTS_UL_layerlist(bpy.types.UIList):
|
||||
# texture_slots:
|
||||
|
||||
class WorldTextureSlots(bpy.props.PropertyGroup):
|
||||
index = bpy.prop.PropertyInt(name='index')
|
||||
# foo = random prop
|
||||
|
||||
bpy.types.World.texture_slots = bpy.props.CollectionProperty(type=PropertyGroup)
|
||||
|
||||
for i in range(18): # length of world texture slots
|
||||
world.texture_slots.add()
|
||||
"""
|
||||
|
||||
classes = (
|
||||
RenderPovSettingsCamera,
|
||||
RenderPovSettingsLight,
|
||||
RenderPovSettingsWorld,
|
||||
WorldTextureSlot,
|
||||
)
|
||||
|
||||
|
||||
def register():
|
||||
for cls in classes:
|
||||
register_class(cls)
|
||||
|
||||
bpy.types.Camera.pov = PointerProperty(type=RenderPovSettingsCamera)
|
||||
bpy.types.Light.pov = PointerProperty(type=RenderPovSettingsLight)
|
||||
bpy.types.World.pov = PointerProperty(type=RenderPovSettingsWorld)
|
||||
bpy.types.World.pov_texture_slots = CollectionProperty(type=WorldTextureSlot)
|
||||
|
||||
|
||||
def unregister():
|
||||
del bpy.types.Camera.pov
|
||||
del bpy.types.Light.pov
|
||||
del bpy.types.World.pov
|
||||
del bpy.types.World.pov_texture_slots
|
||||
|
||||
for cls in reversed(classes):
|
||||
unregister_class(cls)
|
|
@ -0,0 +1,529 @@
|
|||
# ***** BEGIN GPL LICENSE BLOCK *****
|
||||
#
|
||||
# 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 2
|
||||
# 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
|
||||
# MERCHANTABILITY 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, write to the Free Software Foundation,
|
||||
# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
#
|
||||
# #**** END GPL LICENSE BLOCK #****
|
||||
|
||||
# <pep8 compliant>
|
||||
|
||||
"""Support POV Scene Description Language snippets or full includes: import,
|
||||
|
||||
load, create or edit"""
|
||||
|
||||
import bpy
|
||||
from bpy.props import StringProperty, BoolProperty, CollectionProperty
|
||||
from bpy_extras.io_utils import ImportHelper
|
||||
|
||||
from mathutils import Vector
|
||||
from math import pi
|
||||
|
||||
|
||||
def export_custom_code(file):
|
||||
"""write all POV user defined custom code to exported file """
|
||||
# Write CurrentAnimation Frame for use in Custom POV Code
|
||||
file.write("#declare CURFRAMENUM = %d;\n" % bpy.context.scene.frame_current)
|
||||
# Change path and uncomment to add an animated include file by hand:
|
||||
file.write("//#include \"/home/user/directory/animation_include_file.inc\"\n")
|
||||
for txt in bpy.data.texts:
|
||||
if txt.pov.custom_code == 'both':
|
||||
# Why are the newlines needed?
|
||||
file.write("\n")
|
||||
file.write(txt.as_string())
|
||||
file.write("\n")
|
||||
|
||||
|
||||
#############################IMPORT
|
||||
|
||||
|
||||
class ImportPOV(bpy.types.Operator, ImportHelper):
|
||||
"""Load Povray files"""
|
||||
|
||||
bl_idname = "import_scene.pov"
|
||||
bl_label = "POV-Ray files (.pov/.inc)"
|
||||
bl_options = {'PRESET', 'UNDO'}
|
||||
COMPAT_ENGINES = {'POVRAY_RENDER'}
|
||||
|
||||
# -----------
|
||||
# File props.
|
||||
files: CollectionProperty(
|
||||
type=bpy.types.OperatorFileListElement, options={'HIDDEN', 'SKIP_SAVE'}
|
||||
)
|
||||
directory: StringProperty(maxlen=1024, subtype='FILE_PATH', options={'HIDDEN', 'SKIP_SAVE'})
|
||||
|
||||
filename_ext = {".pov", ".inc"}
|
||||
filter_glob: StringProperty(default="*.pov;*.inc", options={'HIDDEN'})
|
||||
|
||||
import_at_cur: BoolProperty(
|
||||
name="Import at Cursor Location", description="Ignore Object Matrix", default=False
|
||||
)
|
||||
|
||||
def execute(self, context):
|
||||
from mathutils import Matrix
|
||||
|
||||
verts = []
|
||||
faces = []
|
||||
materials = []
|
||||
blend_mats = [] ##############
|
||||
pov_mats = [] ##############
|
||||
colors = []
|
||||
mat_names = []
|
||||
lenverts = None
|
||||
lenfaces = None
|
||||
suffix = -1
|
||||
name = 'Mesh2_%s' % suffix
|
||||
name_search = False
|
||||
verts_search = False
|
||||
faces_search = False
|
||||
plane_search = False
|
||||
box_search = False
|
||||
cylinder_search = False
|
||||
sphere_search = False
|
||||
cone_search = False
|
||||
tex_search = False ##################
|
||||
cache = []
|
||||
matrixes = {}
|
||||
write_matrix = False
|
||||
index = None
|
||||
value = None
|
||||
# file_pov = bpy.path.abspath(self.filepath) #was used for single files
|
||||
|
||||
def mat_search(cache):
|
||||
r = g = b = 0.5
|
||||
f = t = 0
|
||||
color = None
|
||||
|
||||
for item, value in enumerate(cache):
|
||||
|
||||
if value == 'texture':
|
||||
pass
|
||||
|
||||
if value == 'pigment':
|
||||
|
||||
if cache[item + 2] in {'rgb', 'srgb'}:
|
||||
pass
|
||||
|
||||
elif cache[item + 2] in {'rgbf', 'srgbf'}:
|
||||
pass
|
||||
|
||||
elif cache[item + 2] in {'rgbt', 'srgbt'}:
|
||||
try:
|
||||
r, g, b, t = (
|
||||
float(cache[item + 3]),
|
||||
float(cache[item + 4]),
|
||||
float(cache[item + 5]),
|
||||
float(cache[item + 6]),
|
||||
)
|
||||
except BaseException as e:
|
||||
print(e.__doc__)
|
||||
print('An exception occurred: {}'.format(e))
|
||||
r = g = b = t = float(cache[item + 2])
|
||||
color = (r, g, b, t)
|
||||
|
||||
elif cache[item + 2] in {'rgbft', 'srgbft'}:
|
||||
pass
|
||||
|
||||
else:
|
||||
pass
|
||||
|
||||
if colors == [] or (colors != [] and color not in colors):
|
||||
colors.append(color)
|
||||
name = ob.name + "_mat"
|
||||
mat_names.append(name)
|
||||
mat = bpy.data.materials.new(name)
|
||||
mat.diffuse_color = (r, g, b)
|
||||
mat.alpha = 1 - t
|
||||
if mat.alpha != 1:
|
||||
mat.use_transparency = True
|
||||
ob.data.materials.append(mat)
|
||||
|
||||
else:
|
||||
for i, value in enumerate(colors):
|
||||
if color == value:
|
||||
ob.data.materials.append(bpy.data.materials[mat_names[i]])
|
||||
|
||||
for file in self.files:
|
||||
print("Importing file: " + file.name)
|
||||
file_pov = self.directory + file.name
|
||||
for line in open(file_pov):
|
||||
string = line.replace("{", " ")
|
||||
string = string.replace("}", " ")
|
||||
string = string.replace("<", " ")
|
||||
string = string.replace(">", " ")
|
||||
string = string.replace(",", " ")
|
||||
lw = string.split()
|
||||
# lenwords = len(lw) # Not used... why written?
|
||||
if lw:
|
||||
if lw[0] == "object":
|
||||
write_matrix = True
|
||||
if write_matrix:
|
||||
if lw[0] not in {"object", "matrix"}:
|
||||
index = lw[0]
|
||||
if lw[0] in {"matrix"}:
|
||||
value = [
|
||||
float(lw[1]),
|
||||
float(lw[2]),
|
||||
float(lw[3]),
|
||||
float(lw[4]),
|
||||
float(lw[5]),
|
||||
float(lw[6]),
|
||||
float(lw[7]),
|
||||
float(lw[8]),
|
||||
float(lw[9]),
|
||||
float(lw[10]),
|
||||
float(lw[11]),
|
||||
float(lw[12]),
|
||||
]
|
||||
matrixes[index] = value
|
||||
write_matrix = False
|
||||
for line in open(file_pov):
|
||||
S = line.replace("{", " { ")
|
||||
S = S.replace("}", " } ")
|
||||
S = S.replace(",", " ")
|
||||
S = S.replace("<", "")
|
||||
S = S.replace(">", " ")
|
||||
S = S.replace("=", " = ")
|
||||
S = S.replace(";", " ; ")
|
||||
S = S.split()
|
||||
# lenS = len(S) # Not used... why written?
|
||||
for i, word in enumerate(S):
|
||||
##################Primitives Import##################
|
||||
if word == 'cone':
|
||||
cone_search = True
|
||||
name_search = False
|
||||
if cone_search:
|
||||
cache.append(word)
|
||||
if cache[-1] == '}':
|
||||
try:
|
||||
x0 = float(cache[2])
|
||||
y0 = float(cache[3])
|
||||
z0 = float(cache[4])
|
||||
r0 = float(cache[5])
|
||||
x1 = float(cache[6])
|
||||
y1 = float(cache[7])
|
||||
z1 = float(cache[8])
|
||||
r1 = float(cache[9])
|
||||
# Y is height in most pov files, not z
|
||||
bpy.ops.pov.cone_add(base=r0, cap=r1, height=(y1 - y0))
|
||||
ob = context.object
|
||||
ob.location = (x0, y0, z0)
|
||||
# ob.scale = (r,r,r)
|
||||
mat_search(cache)
|
||||
except ValueError:
|
||||
pass
|
||||
cache = []
|
||||
cone_search = False
|
||||
if word == 'plane':
|
||||
plane_search = True
|
||||
name_search = False
|
||||
if plane_search:
|
||||
cache.append(word)
|
||||
if cache[-1] == '}':
|
||||
try:
|
||||
bpy.ops.pov.addplane()
|
||||
ob = context.object
|
||||
mat_search(cache)
|
||||
except ValueError:
|
||||
pass
|
||||
cache = []
|
||||
plane_search = False
|
||||
if word == 'box':
|
||||
box_search = True
|
||||
name_search = False
|
||||
if box_search:
|
||||
cache.append(word)
|
||||
if cache[-1] == '}':
|
||||
try:
|
||||
x0 = float(cache[2])
|
||||
y0 = float(cache[3])
|
||||
z0 = float(cache[4])
|
||||
x1 = float(cache[5])
|
||||
y1 = float(cache[6])
|
||||
z1 = float(cache[7])
|
||||
# imported_corner_1=(x0, y0, z0)
|
||||
# imported_corner_2 =(x1, y1, z1)
|
||||
center = ((x0 + x1) / 2, (y0 + y1) / 2, (z0 + z1) / 2)
|
||||
bpy.ops.pov.addbox()
|
||||
ob = context.object
|
||||
ob.location = center
|
||||
mat_search(cache)
|
||||
|
||||
except ValueError:
|
||||
pass
|
||||
cache = []
|
||||
box_search = False
|
||||
if word == 'cylinder':
|
||||
cylinder_search = True
|
||||
name_search = False
|
||||
if cylinder_search:
|
||||
cache.append(word)
|
||||
if cache[-1] == '}':
|
||||
try:
|
||||
x0 = float(cache[2])
|
||||
y0 = float(cache[3])
|
||||
z0 = float(cache[4])
|
||||
x1 = float(cache[5])
|
||||
y1 = float(cache[6])
|
||||
z1 = float(cache[7])
|
||||
imported_cyl_loc = (x0, y0, z0)
|
||||
imported_cyl_loc_cap = (x1, y1, z1)
|
||||
|
||||
r = float(cache[8])
|
||||
|
||||
vec = Vector(imported_cyl_loc_cap) - Vector(imported_cyl_loc)
|
||||
depth = vec.length
|
||||
rot = Vector((0, 0, 1)).rotation_difference(
|
||||
vec
|
||||
) # Rotation from Z axis.
|
||||
trans = rot @ Vector( # XXX Not used, why written?
|
||||
(0, 0, depth / 2)
|
||||
) # Such that origin is at center of the base of the cylinder.
|
||||
# center = ((x0 + x1)/2,(y0 + y1)/2,(z0 + z1)/2)
|
||||
scale_z = sqrt((x1 - x0) ** 2 + (y1 - y0) ** 2 + (z1 - z0) ** 2) / 2
|
||||
bpy.ops.pov.addcylinder(
|
||||
R=r,
|
||||
imported_cyl_loc=imported_cyl_loc,
|
||||
imported_cyl_loc_cap=imported_cyl_loc_cap,
|
||||
)
|
||||
ob = context.object
|
||||
ob.location = (x0, y0, z0)
|
||||
ob.rotation_euler = rot.to_euler()
|
||||
ob.scale = (1, 1, scale_z)
|
||||
|
||||
# scale data rather than obj?
|
||||
# bpy.ops.object.mode_set(mode='EDIT')
|
||||
# bpy.ops.mesh.reveal()
|
||||
# bpy.ops.mesh.select_all(action='SELECT')
|
||||
# bpy.ops.transform.resize(value=(1,1,scale_z), orient_type='LOCAL')
|
||||
# bpy.ops.mesh.hide(unselected=False)
|
||||
# bpy.ops.object.mode_set(mode='OBJECT')
|
||||
|
||||
mat_search(cache)
|
||||
|
||||
except ValueError:
|
||||
pass
|
||||
cache = []
|
||||
cylinder_search = False
|
||||
if word == 'sphere':
|
||||
sphere_search = True
|
||||
name_search = False
|
||||
if sphere_search:
|
||||
cache.append(word)
|
||||
if cache[-1] == '}':
|
||||
x = y = z = r = 0
|
||||
try:
|
||||
x = float(cache[2])
|
||||
y = float(cache[3])
|
||||
z = float(cache[4])
|
||||
r = float(cache[5])
|
||||
|
||||
except ValueError:
|
||||
pass
|
||||
except:
|
||||
x = y = z = float(cache[2])
|
||||
r = float(cache[3])
|
||||
bpy.ops.pov.addsphere(R=r, imported_loc=(x, y, z))
|
||||
ob = context.object
|
||||
ob.location = (x, y, z)
|
||||
ob.scale = (r, r, r)
|
||||
mat_search(cache)
|
||||
cache = []
|
||||
sphere_search = False
|
||||
##################End Primitives Import##################
|
||||
if word == '#declare':
|
||||
name_search = True
|
||||
if name_search:
|
||||
cache.append(word)
|
||||
if word == 'mesh2':
|
||||
name_search = False
|
||||
if cache[-2] == '=':
|
||||
name = cache[-3]
|
||||
else:
|
||||
suffix += 1
|
||||
cache = []
|
||||
if word in {'texture', ';'}:
|
||||
name_search = False
|
||||
cache = []
|
||||
if word == 'vertex_vectors':
|
||||
verts_search = True
|
||||
if verts_search:
|
||||
cache.append(word)
|
||||
if word == '}':
|
||||
verts_search = False
|
||||
lenverts = cache[2]
|
||||
cache.pop()
|
||||
cache.pop(0)
|
||||
cache.pop(0)
|
||||
cache.pop(0)
|
||||
for j in range(int(lenverts)):
|
||||
x = j * 3
|
||||
y = (j * 3) + 1
|
||||
z = (j * 3) + 2
|
||||
verts.append((float(cache[x]), float(cache[y]), float(cache[z])))
|
||||
cache = []
|
||||
# if word == 'face_indices':
|
||||
# faces_search = True
|
||||
if word == 'texture_list': ########
|
||||
tex_search = True #######
|
||||
if tex_search: #########
|
||||
if (
|
||||
word not in {'texture_list', 'texture', '{', '}', 'face_indices'}
|
||||
and not word.isdigit()
|
||||
): ##############
|
||||
pov_mats.append(word) #################
|
||||
if word == 'face_indices':
|
||||
tex_search = False ################
|
||||
faces_search = True
|
||||
if faces_search:
|
||||
cache.append(word)
|
||||
if word == '}':
|
||||
faces_search = False
|
||||
lenfaces = cache[2]
|
||||
cache.pop()
|
||||
cache.pop(0)
|
||||
cache.pop(0)
|
||||
cache.pop(0)
|
||||
lf = int(lenfaces)
|
||||
var = int(len(cache) / lf)
|
||||
for k in range(lf):
|
||||
if var == 3:
|
||||
v0 = k * 3
|
||||
v1 = k * 3 + 1
|
||||
v2 = k * 3 + 2
|
||||
faces.append((int(cache[v0]), int(cache[v1]), int(cache[v2])))
|
||||
if var == 4:
|
||||
v0 = k * 4
|
||||
v1 = k * 4 + 1
|
||||
v2 = k * 4 + 2
|
||||
m = k * 4 + 3
|
||||
materials.append((int(cache[m])))
|
||||
faces.append((int(cache[v0]), int(cache[v1]), int(cache[v2])))
|
||||
if var == 6:
|
||||
v0 = k * 6
|
||||
v1 = k * 6 + 1
|
||||
v2 = k * 6 + 2
|
||||
m0 = k * 6 + 3
|
||||
m1 = k * 6 + 4
|
||||
m2 = k * 6 + 5
|
||||
materials.append(
|
||||
(int(cache[m0]), int(cache[m1]), int(cache[m2]))
|
||||
)
|
||||
faces.append((int(cache[v0]), int(cache[v1]), int(cache[v2])))
|
||||
# mesh = pov_define_mesh(None, verts, [], faces, name, hide_geometry=False)
|
||||
# ob = object_utils.object_data_add(context, mesh, operator=None)
|
||||
|
||||
me = bpy.data.meshes.new(name) ########
|
||||
ob = bpy.data.objects.new(name, me) ##########
|
||||
bpy.context.collection.objects.link(ob) #########
|
||||
me.from_pydata(verts, [], faces) ############
|
||||
|
||||
for mat in bpy.data.materials: ##############
|
||||
blend_mats.append(mat.name) #############
|
||||
for m_name in pov_mats: #####################
|
||||
if m_name not in blend_mats: ###########
|
||||
povMat = bpy.data.materials.new(m_name) #################
|
||||
mat_search(cache)
|
||||
ob.data.materials.append(
|
||||
bpy.data.materials[m_name]
|
||||
) ###################
|
||||
if materials: ##################
|
||||
for l, val in enumerate(materials): ####################
|
||||
try: ###################
|
||||
ob.data.polygons[
|
||||
l
|
||||
].material_index = val ####################
|
||||
except TypeError: ###################
|
||||
ob.data.polygons[l].material_index = int(
|
||||
val[0]
|
||||
) ##################
|
||||
|
||||
blend_mats = [] #########################
|
||||
pov_mats = [] #########################
|
||||
materials = [] #########################
|
||||
cache = []
|
||||
name_search = True
|
||||
if name in matrixes and not self.import_at_cur:
|
||||
global_matrix = Matrix.Rotation(pi / 2.0, 4, 'X')
|
||||
ob = bpy.context.object
|
||||
matrix = ob.matrix_world
|
||||
v = matrixes[name]
|
||||
matrix[0][0] = v[0]
|
||||
matrix[1][0] = v[1]
|
||||
matrix[2][0] = v[2]
|
||||
matrix[0][1] = v[3]
|
||||
matrix[1][1] = v[4]
|
||||
matrix[2][1] = v[5]
|
||||
matrix[0][2] = v[6]
|
||||
matrix[1][2] = v[7]
|
||||
matrix[2][2] = v[8]
|
||||
matrix[0][3] = v[9]
|
||||
matrix[1][3] = v[10]
|
||||
matrix[2][3] = v[11]
|
||||
matrix = global_matrix * ob.matrix_world
|
||||
ob.matrix_world = matrix
|
||||
verts = []
|
||||
faces = []
|
||||
|
||||
# if word == 'pigment':
|
||||
# try:
|
||||
# #all indices have been incremented once to fit a bad test file
|
||||
# r,g,b,t = float(S[2]),float(S[3]),float(S[4]),float(S[5])
|
||||
# color = (r,g,b,t)
|
||||
|
||||
# except IndexError:
|
||||
# #all indices have been incremented once to fit alternate test file
|
||||
# r,g,b,t = float(S[3]),float(S[4]),float(S[5]),float(S[6])
|
||||
# color = (r,g,b,t)
|
||||
# except UnboundLocalError:
|
||||
# # In case no transmit is specified ? put it to 0
|
||||
# r,g,b,t = float(S[2]),float(S[3]),float(S[4],0)
|
||||
# color = (r,g,b,t)
|
||||
|
||||
# except ValueError:
|
||||
# color = (0.8,0.8,0.8,0)
|
||||
# pass
|
||||
|
||||
# if colors == [] or (colors != [] and color not in colors):
|
||||
# colors.append(color)
|
||||
# name = ob.name+"_mat"
|
||||
# mat_names.append(name)
|
||||
# mat = bpy.data.materials.new(name)
|
||||
# mat.diffuse_color = (r,g,b)
|
||||
# mat.alpha = 1-t
|
||||
# if mat.alpha != 1:
|
||||
# mat.use_transparency=True
|
||||
# ob.data.materials.append(mat)
|
||||
# print (colors)
|
||||
# else:
|
||||
# for m in range(len(colors)):
|
||||
# if color == colors[m]:
|
||||
# ob.data.materials.append(bpy.data.materials[mat_names[m]])
|
||||
|
||||
##To keep Avogadro Camera angle:
|
||||
# for obj in bpy.context.view_layer.objects:
|
||||
# if obj.type == "CAMERA":
|
||||
# track = obj.constraints.new(type = "TRACK_TO")
|
||||
# track.target = ob
|
||||
# track.track_axis ="TRACK_NEGATIVE_Z"
|
||||
# track.up_axis = "UP_Y"
|
||||
# obj.location = (0,0,0)
|
||||
return {'FINISHED'}
|
||||
|
||||
|
||||
def register():
|
||||
bpy.utils.register_class(ImportPOV)
|
||||
|
||||
|
||||
def unregister():
|
||||
bpy.utils.unregister_class(ImportPOV)
|
|
@ -0,0 +1,268 @@
|
|||
# ##### BEGIN GPL LICENSE BLOCK #####
|
||||
#
|
||||
# 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 2
|
||||
# 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
|
||||
# MERCHANTABILITY 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, write to the Free Software Foundation,
|
||||
# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
#
|
||||
# ##### END GPL LICENSE BLOCK #####
|
||||
|
||||
# <pep8 compliant>
|
||||
"""User interface to POV Scene Description Language snippets or full includes:
|
||||
|
||||
import, load, create or edit """
|
||||
|
||||
import bpy
|
||||
from bpy.utils import register_class, unregister_class
|
||||
from bpy.types import Operator, Menu, Panel
|
||||
from sys import platform # really import here, as in ui.py and in render.py?
|
||||
import os # really import here and in render.py?
|
||||
from os.path import isfile
|
||||
|
||||
|
||||
def locate_docpath():
|
||||
"""POV can be installed with some include files.
|
||||
|
||||
Get their path as defined in user preferences or registry keys for
|
||||
the user to be able to invoke them."""
|
||||
|
||||
addon_prefs = bpy.context.preferences.addons[__package__].preferences
|
||||
# Use the system preference if its set.
|
||||
pov_documents = addon_prefs.docpath_povray
|
||||
if pov_documents:
|
||||
if os.path.exists(pov_documents):
|
||||
return pov_documents
|
||||
# Implicit else, as here return was still not triggered:
|
||||
print(
|
||||
"User Preferences path to povray documents %r NOT FOUND, checking $PATH" % pov_documents
|
||||
)
|
||||
|
||||
# Windows Only
|
||||
if platform.startswith('win'):
|
||||
import winreg
|
||||
|
||||
try:
|
||||
win_reg_key = winreg.OpenKey(
|
||||
winreg.HKEY_CURRENT_USER, "Software\\POV-Ray\\v3.7\\Windows"
|
||||
)
|
||||
win_docpath = winreg.QueryValueEx(win_reg_key, "DocPath")[0]
|
||||
pov_documents = os.path.join(win_docpath, "Insert Menu")
|
||||
if os.path.exists(pov_documents):
|
||||
return pov_documents
|
||||
except FileNotFoundError:
|
||||
return ""
|
||||
# search the path all os's
|
||||
pov_documents_default = "include"
|
||||
|
||||
os_path_ls = os.getenv("PATH").split(':') + [""]
|
||||
|
||||
for dir_name in os_path_ls:
|
||||
pov_documents = os.path.join(dir_name, pov_documents_default)
|
||||
if os.path.exists(pov_documents):
|
||||
return pov_documents
|
||||
return ""
|
||||
|
||||
|
||||
################################################################################
|
||||
class TextButtonsPanel:
|
||||
"""Use this class to define buttons from the side tab of
|
||||
text window."""
|
||||
|
||||
bl_space_type = 'TEXT_EDITOR'
|
||||
bl_region_type = 'UI'
|
||||
bl_label = "POV-Ray"
|
||||
COMPAT_ENGINES = {'POVRAY_RENDER'}
|
||||
|
||||
@classmethod
|
||||
def poll(cls, context):
|
||||
text = context.space_data
|
||||
rd = context.scene.render
|
||||
return text and (rd.engine in cls.COMPAT_ENGINES)
|
||||
|
||||
|
||||
###############################################################################
|
||||
# Text Povray Settings
|
||||
###############################################################################
|
||||
|
||||
|
||||
class TEXT_OT_POV_insert(Operator):
|
||||
"""Use this class to create blender text editor operator to insert pov snippets like other pov IDEs"""
|
||||
|
||||
bl_idname = "text.povray_insert"
|
||||
bl_label = "Insert"
|
||||
|
||||
filepath: bpy.props.StringProperty(name="Filepath", subtype='FILE_PATH')
|
||||
|
||||
@classmethod
|
||||
def poll(cls, context):
|
||||
text = context.space_data.text
|
||||
return context.area.type == 'TEXT_EDITOR' and text is not None
|
||||
# return bpy.ops.text.insert.poll() this Bpy op has no poll()
|
||||
|
||||
def execute(self, context):
|
||||
if self.filepath and isfile(self.filepath):
|
||||
file = open(self.filepath, "r")
|
||||
bpy.ops.text.insert(text=file.read())
|
||||
|
||||
# places the cursor at the end without scrolling -.-
|
||||
# context.space_data.text.write(file.read())
|
||||
file.close()
|
||||
return {'FINISHED'}
|
||||
|
||||
|
||||
def validinsert(ext):
|
||||
"""Since preview images could be in same folder, filter only insertable text"""
|
||||
return ext in {".txt", ".inc", ".pov"}
|
||||
|
||||
|
||||
class TEXT_MT_POV_insert(Menu):
|
||||
"""Use this class to create a menu launcher in text editor for the TEXT_OT_POV_insert operator ."""
|
||||
|
||||
bl_label = "Insert"
|
||||
bl_idname = "TEXT_MT_POV_insert"
|
||||
|
||||
def draw(self, context):
|
||||
pov_documents = locate_docpath()
|
||||
prop = self.layout.operator("wm.path_open", text="Open folder", icon='FILE_FOLDER')
|
||||
prop.filepath = pov_documents
|
||||
self.layout.separator()
|
||||
|
||||
pov_insert_items_list = []
|
||||
for root, dirs, files in os.walk(pov_documents): # todo: structure submenus by dir
|
||||
pov_insert_items_list.append(root)
|
||||
print(pov_insert_items_list)
|
||||
self.path_menu(
|
||||
pov_insert_items_list,
|
||||
"text.povray_insert",
|
||||
# {"internal": True},
|
||||
filter_ext=validinsert,
|
||||
)
|
||||
|
||||
|
||||
class TEXT_PT_POV_custom_code(TextButtonsPanel, Panel):
|
||||
"""Use this class to create a panel in text editor for the user to decide if he renders text
|
||||
|
||||
only or adds to 3d scene."""
|
||||
|
||||
bl_label = "POV"
|
||||
COMPAT_ENGINES = {'POVRAY_RENDER'}
|
||||
|
||||
def draw(self, context):
|
||||
layout = self.layout
|
||||
|
||||
text = context.space_data.text
|
||||
|
||||
pov_documents = locate_docpath()
|
||||
if not pov_documents:
|
||||
layout.label(text="Please configure ", icon="INFO")
|
||||
layout.label(text="default pov include path ")
|
||||
layout.label(text="in addon preferences")
|
||||
# layout.separator()
|
||||
layout.operator(
|
||||
"preferences.addon_show",
|
||||
text="Go to Render: Persistence of Vision addon",
|
||||
icon="PREFERENCES",
|
||||
).module = "render_povray"
|
||||
|
||||
# layout.separator()
|
||||
else:
|
||||
# print(pov_documents)
|
||||
layout.menu(TEXT_MT_POV_insert.bl_idname)
|
||||
|
||||
if text:
|
||||
box = layout.box()
|
||||
box.label(text='Source to render:', icon='RENDER_STILL')
|
||||
row = box.row()
|
||||
row.prop(text.pov, "custom_code", expand=True)
|
||||
if text.pov.custom_code in {'3dview'}:
|
||||
box.operator("render.render", icon='OUTLINER_DATA_ARMATURE')
|
||||
if text.pov.custom_code in {'text'}:
|
||||
rtext = bpy.context.space_data.text # is r a typo ? or why written, not used
|
||||
box.operator("text.run", icon='ARMATURE_DATA')
|
||||
# layout.prop(text.pov, "custom_code")
|
||||
elif text.pov.custom_code in {'both'}:
|
||||
box.operator("render.render", icon='POSE_HLT')
|
||||
layout.label(text="Please specify declared", icon="INFO")
|
||||
layout.label(text="items in properties ")
|
||||
# layout.label(text="")
|
||||
layout.label(text="replacement fields")
|
||||
|
||||
|
||||
###############################################
|
||||
# Text editor templates from header menu
|
||||
|
||||
|
||||
class TEXT_MT_POV_templates(Menu):
|
||||
"""Use this class to create a menu for the same pov templates scenes as other pov IDEs."""
|
||||
|
||||
bl_label = "POV"
|
||||
|
||||
# We list templates on file evaluation, we can assume they are static data,
|
||||
# and better avoid running this on every draw call.
|
||||
template_paths = [os.path.join(os.path.dirname(__file__), "templates_pov")]
|
||||
|
||||
def draw(self, context):
|
||||
self.path_menu(self.template_paths, "text.open", props_default={"internal": True})
|
||||
|
||||
|
||||
def menu_func_templates(self, context):
|
||||
"""Add POV files to the text editor templates menu"""
|
||||
# Do not depend on POV being active renderer here...
|
||||
self.layout.menu("TEXT_MT_POV_templates")
|
||||
|
||||
|
||||
###############################################
|
||||
# POV Import menu
|
||||
class VIEW_MT_POV_import(Menu):
|
||||
"""Use this class for the import menu."""
|
||||
|
||||
bl_idname = "POVRAY_MT_import_tools"
|
||||
bl_label = "Import"
|
||||
|
||||
def draw(self, context):
|
||||
layout = self.layout
|
||||
layout.operator_context = 'INVOKE_REGION_WIN'
|
||||
layout.operator("import_scene.pov", icon="FORCE_LENNARDJONES")
|
||||
|
||||
|
||||
def menu_func_import(self, context):
|
||||
"""Add the import operator to menu"""
|
||||
engine = context.scene.render.engine
|
||||
if engine == 'POVRAY_RENDER':
|
||||
self.layout.operator("import_scene.pov", icon="FORCE_LENNARDJONES")
|
||||
|
||||
|
||||
classes = (
|
||||
VIEW_MT_POV_import,
|
||||
TEXT_OT_POV_insert,
|
||||
TEXT_MT_POV_insert,
|
||||
TEXT_PT_POV_custom_code,
|
||||
TEXT_MT_POV_templates,
|
||||
)
|
||||
|
||||
|
||||
def register():
|
||||
|
||||
for cls in classes:
|
||||
register_class(cls)
|
||||
|
||||
bpy.types.TOPBAR_MT_file_import.append(menu_func_import)
|
||||
bpy.types.TEXT_MT_templates.append(menu_func_templates)
|
||||
|
||||
|
||||
def unregister():
|
||||
|
||||
bpy.types.TEXT_MT_templates.remove(menu_func_templates)
|
||||
bpy.types.TOPBAR_MT_file_import.remove(menu_func_import)
|
||||
|
||||
for cls in reversed(classes):
|
||||
unregister_class(cls)
|
|
@ -0,0 +1,57 @@
|
|||
# ##### BEGIN GPL LICENSE BLOCK #####
|
||||
#
|
||||
# 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 2
|
||||
# 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
|
||||
# MERCHANTABILITY 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, write to the Free Software Foundation,
|
||||
# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
#
|
||||
# ##### END GPL LICENSE BLOCK #####
|
||||
|
||||
# <pep8 compliant>
|
||||
import bpy
|
||||
|
||||
"""Declare pov native file syntax properties controllable in UI hooks and text blocks"""
|
||||
|
||||
from bpy.utils import register_class, unregister_class
|
||||
from bpy.types import PropertyGroup
|
||||
from bpy.props import EnumProperty, PointerProperty
|
||||
|
||||
###############################################################################
|
||||
# Text POV properties.
|
||||
###############################################################################
|
||||
|
||||
|
||||
class RenderPovSettingsText(PropertyGroup):
|
||||
|
||||
"""Declare text properties to use UI as an IDE or render text snippets to POV."""
|
||||
|
||||
custom_code: EnumProperty(
|
||||
name="Custom Code",
|
||||
description="rendered source: Both adds text at the " "top of the exported POV file",
|
||||
items=(("3dview", "View", ""), ("text", "Text", ""), ("both", "Both", "")),
|
||||
default="text",
|
||||
)
|
||||
|
||||
|
||||
classes = (RenderPovSettingsText,)
|
||||
|
||||
|
||||
def register():
|
||||
for cls in classes:
|
||||
register_class(cls)
|
||||
bpy.types.Text.pov = PointerProperty(type=RenderPovSettingsText)
|
||||
|
||||
|
||||
def unregister():
|
||||
del bpy.types.Text.pov
|
||||
for cls in reversed(classes):
|
||||
unregister_class(cls)
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,688 @@
|
|||
# ##### BEGIN GPL LICENSE BLOCK #####
|
||||
#
|
||||
# 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 2
|
||||
# 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
|
||||
# MERCHANTABILITY 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, write to the Free Software Foundation,
|
||||
# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
#
|
||||
# ##### END GPL LICENSE BLOCK #####
|
||||
|
||||
# <pep8 compliant>
|
||||
""""User interface for shaders exported to POV textures."""
|
||||
|
||||
import bpy
|
||||
from bpy.utils import register_class, unregister_class
|
||||
from bpy.types import Operator, Menu, Panel
|
||||
from bl_operators.presets import AddPresetBase
|
||||
|
||||
# Example of wrapping every class 'as is' except some
|
||||
from bl_ui import properties_material
|
||||
|
||||
for member in dir(properties_material):
|
||||
subclass = getattr(properties_material, member)
|
||||
try:
|
||||
# mat=bpy.context.active_object.active_material
|
||||
# if (mat and mat.pov.type == "SURFACE"
|
||||
# and not (mat.pov.material_use_nodes or mat.use_nodes)):
|
||||
# and (engine in cls.COMPAT_ENGINES)) if subclasses were sorted
|
||||
subclass.COMPAT_ENGINES.add('POVRAY_RENDER')
|
||||
except BaseException as e:
|
||||
print(e.__doc__)
|
||||
print('An exception occurred: {}'.format(e))
|
||||
pass
|
||||
del properties_material
|
||||
|
||||
from .shading_properties import check_material
|
||||
|
||||
|
||||
def simple_material(mat):
|
||||
"""Test if a material uses nodes"""
|
||||
if (mat is not None) and (not mat.use_nodes):
|
||||
return True
|
||||
return False
|
||||
|
||||
|
||||
class MaterialButtonsPanel:
|
||||
"""Use this class to define buttons from the material tab of
|
||||
properties window."""
|
||||
|
||||
bl_space_type = 'PROPERTIES'
|
||||
bl_region_type = 'WINDOW'
|
||||
bl_context = "material"
|
||||
COMPAT_ENGINES = {'POVRAY_RENDER'}
|
||||
|
||||
@classmethod
|
||||
def poll(cls, context):
|
||||
mat = context.material
|
||||
rd = context.scene.render
|
||||
return mat and (rd.engine in cls.COMPAT_ENGINES)
|
||||
|
||||
|
||||
class MATERIAL_MT_POV_sss_presets(Menu):
|
||||
"""Use this class to define pov sss preset menu."""
|
||||
|
||||
bl_label = "SSS Presets"
|
||||
preset_subdir = "pov/material/sss"
|
||||
preset_operator = "script.execute_preset"
|
||||
draw = bpy.types.Menu.draw_preset
|
||||
|
||||
|
||||
class MATERIAL_OT_POV_sss_add_preset(AddPresetBase, Operator):
|
||||
"""Add an SSS Preset"""
|
||||
|
||||
bl_idname = "material.sss_preset_add"
|
||||
bl_label = "Add SSS Preset"
|
||||
preset_menu = "MATERIAL_MT_POV_sss_presets"
|
||||
|
||||
# variable used for all preset values
|
||||
preset_defines = ["material = bpy.context.material"]
|
||||
|
||||
# properties to store in the preset
|
||||
preset_values = [
|
||||
"material.pov_subsurface_scattering.radius",
|
||||
"material.pov_subsurface_scattering.color",
|
||||
]
|
||||
|
||||
# where to store the preset
|
||||
preset_subdir = "pov/material/sss"
|
||||
|
||||
|
||||
class MATERIAL_PT_POV_sss(MaterialButtonsPanel, Panel):
|
||||
"""Use this class to define pov sss buttons panel."""
|
||||
|
||||
bl_label = "Subsurface Scattering"
|
||||
bl_options = {'DEFAULT_CLOSED'}
|
||||
COMPAT_ENGINES = {'POVRAY_RENDER'}
|
||||
|
||||
@classmethod
|
||||
def poll(cls, context):
|
||||
mat = context.material
|
||||
engine = context.scene.render.engine
|
||||
return (
|
||||
check_material(mat)
|
||||
and (mat.pov.type in {'SURFACE', 'WIRE'})
|
||||
and (engine in cls.COMPAT_ENGINES)
|
||||
)
|
||||
|
||||
def draw_header(self, context):
|
||||
mat = context.material # FORMERLY : #active_node_mat(context.material)
|
||||
sss = mat.pov_subsurface_scattering
|
||||
|
||||
self.layout.active = not mat.pov.use_shadeless
|
||||
self.layout.prop(sss, "use", text="")
|
||||
|
||||
def draw(self, context):
|
||||
layout = self.layout
|
||||
|
||||
mat = context.material # FORMERLY : #active_node_mat(context.material)
|
||||
sss = mat.pov_subsurface_scattering
|
||||
|
||||
layout.active = (sss.use) and (not mat.pov.use_shadeless)
|
||||
|
||||
row = layout.row().split()
|
||||
sub = row.row(align=True).split(align=True, factor=0.75)
|
||||
sub.menu(MATERIAL_MT_POV_sss_presets.__name__, text=MATERIAL_MT_POV_sss_presets.bl_label)
|
||||
sub.operator(MATERIAL_OT_POV_sss_add_preset.bl_idname, text="", icon='ADD')
|
||||
sub.operator(
|
||||
MATERIAL_OT_POV_sss_add_preset.bl_idname, text="", icon='REMOVE'
|
||||
).remove_active = True
|
||||
|
||||
split = layout.split()
|
||||
|
||||
col = split.column()
|
||||
col.prop(sss, "ior")
|
||||
col.prop(sss, "scale")
|
||||
col.prop(sss, "color", text="")
|
||||
col.prop(sss, "radius", text="RGB Radius", expand=True)
|
||||
|
||||
col = split.column()
|
||||
sub = col.column(align=True)
|
||||
sub.label(text="Blend:")
|
||||
sub.prop(sss, "color_factor", text="Color")
|
||||
sub.prop(sss, "texture_factor", text="Texture")
|
||||
sub.label(text="Scattering Weight:")
|
||||
sub.prop(sss, "front")
|
||||
sub.prop(sss, "back")
|
||||
col.separator()
|
||||
col.prop(sss, "error_threshold", text="Error")
|
||||
|
||||
|
||||
class MATERIAL_PT_POV_activate_node(MaterialButtonsPanel, Panel):
|
||||
"""Use this class to define an activate pov nodes button."""
|
||||
|
||||
bl_label = "Activate Node Settings"
|
||||
bl_context = "material"
|
||||
bl_options = {'HIDE_HEADER'}
|
||||
COMPAT_ENGINES = {'POVRAY_RENDER'}
|
||||
|
||||
@classmethod
|
||||
def poll(cls, context):
|
||||
engine = context.scene.render.engine
|
||||
mat = context.material
|
||||
return (
|
||||
mat
|
||||
and mat.pov.type == "SURFACE"
|
||||
and (engine in cls.COMPAT_ENGINES)
|
||||
and not (mat.pov.material_use_nodes or mat.use_nodes)
|
||||
)
|
||||
|
||||
def draw(self, context):
|
||||
layout = self.layout
|
||||
# layout.operator("pov.material_use_nodes", icon='SOUND')#'NODETREE')
|
||||
# the above replaced with a context hook below:
|
||||
layout.operator(
|
||||
"WM_OT_context_toggle", text="Use POV-Ray Nodes", icon='NODETREE'
|
||||
).data_path = "material.pov.material_use_nodes"
|
||||
|
||||
|
||||
class MATERIAL_PT_POV_active_node(MaterialButtonsPanel, Panel):
|
||||
"""Use this class to show pov active node properties buttons."""
|
||||
|
||||
bl_label = "Active Node Settings"
|
||||
bl_context = "material"
|
||||
bl_options = {'HIDE_HEADER'}
|
||||
COMPAT_ENGINES = {'POVRAY_RENDER'}
|
||||
|
||||
@classmethod
|
||||
def poll(cls, context):
|
||||
engine = context.scene.render.engine
|
||||
mat = context.material
|
||||
return (
|
||||
mat
|
||||
and mat.pov.type == "SURFACE"
|
||||
and (engine in cls.COMPAT_ENGINES)
|
||||
and mat.pov.material_use_nodes
|
||||
)
|
||||
|
||||
def draw(self, context):
|
||||
layout = self.layout
|
||||
mat = context.material
|
||||
node_tree = mat.node_tree
|
||||
if node_tree:
|
||||
node = node_tree.nodes.active
|
||||
if mat.use_nodes:
|
||||
if node:
|
||||
layout.prop(mat.pov, "material_active_node")
|
||||
if node.bl_idname == "PovrayMaterialNode":
|
||||
layout.context_pointer_set("node", node)
|
||||
if hasattr(node, "draw_buttons_ext"):
|
||||
node.draw_buttons_ext(context, layout)
|
||||
elif hasattr(node, "draw_buttons"):
|
||||
node.draw_buttons(context, layout)
|
||||
value_inputs = [
|
||||
socket
|
||||
for socket in node.inputs
|
||||
if socket.enabled and not socket.is_linked
|
||||
]
|
||||
if value_inputs:
|
||||
layout.separator()
|
||||
layout.label(text="Inputs:")
|
||||
for socket in value_inputs:
|
||||
row = layout.row()
|
||||
socket.draw(context, row, node, socket.name)
|
||||
else:
|
||||
layout.context_pointer_set("node", node)
|
||||
if hasattr(node, "draw_buttons_ext"):
|
||||
node.draw_buttons_ext(context, layout)
|
||||
elif hasattr(node, "draw_buttons"):
|
||||
node.draw_buttons(context, layout)
|
||||
value_inputs = [
|
||||
socket
|
||||
for socket in node.inputs
|
||||
if socket.enabled and not socket.is_linked
|
||||
]
|
||||
if value_inputs:
|
||||
layout.separator()
|
||||
layout.label(text="Inputs:")
|
||||
for socket in value_inputs:
|
||||
row = layout.row()
|
||||
socket.draw(context, row, node, socket.name)
|
||||
else:
|
||||
layout.label(text="No active nodes!")
|
||||
|
||||
|
||||
class MATERIAL_PT_POV_specular(MaterialButtonsPanel, Panel):
|
||||
"""Use this class to define standard material specularity (highlights) buttons."""
|
||||
|
||||
bl_label = "Specular"
|
||||
COMPAT_ENGINES = {'POVRAY_RENDER'}
|
||||
|
||||
@classmethod
|
||||
def poll(cls, context):
|
||||
mat = context.material
|
||||
engine = context.scene.render.engine
|
||||
return (
|
||||
check_material(mat)
|
||||
and (mat.pov.type in {'SURFACE', 'WIRE'})
|
||||
and (engine in cls.COMPAT_ENGINES)
|
||||
)
|
||||
|
||||
def draw(self, context):
|
||||
layout = self.layout
|
||||
|
||||
mat = context.material.pov
|
||||
|
||||
layout.active = not mat.use_shadeless
|
||||
|
||||
split = layout.split()
|
||||
|
||||
col = split.column()
|
||||
col.prop(mat, "specular_color", text="")
|
||||
col.prop(mat, "specular_intensity", text="Intensity")
|
||||
|
||||
col = split.column()
|
||||
col.prop(mat, "specular_shader", text="")
|
||||
col.prop(mat, "use_specular_ramp", text="Ramp")
|
||||
|
||||
col = layout.column()
|
||||
if mat.specular_shader in {'COOKTORR', 'PHONG'}:
|
||||
col.prop(mat, "specular_hardness", text="Hardness")
|
||||
elif mat.specular_shader == 'BLINN':
|
||||
row = col.row()
|
||||
row.prop(mat, "specular_hardness", text="Hardness")
|
||||
row.prop(mat, "specular_ior", text="IOR")
|
||||
elif mat.specular_shader == 'WARDISO':
|
||||
col.prop(mat, "specular_slope", text="Slope")
|
||||
elif mat.specular_shader == 'TOON':
|
||||
row = col.row()
|
||||
row.prop(mat, "specular_toon_size", text="Size")
|
||||
row.prop(mat, "specular_toon_smooth", text="Smooth")
|
||||
|
||||
if mat.use_specular_ramp:
|
||||
layout.separator()
|
||||
layout.template_color_ramp(mat, "specular_ramp", expand=True)
|
||||
layout.separator()
|
||||
|
||||
row = layout.row()
|
||||
row.prop(mat, "specular_ramp_input", text="Input")
|
||||
row.prop(mat, "specular_ramp_blend", text="Blend")
|
||||
|
||||
layout.prop(mat, "specular_ramp_factor", text="Factor")
|
||||
|
||||
|
||||
class MATERIAL_PT_POV_mirror(MaterialButtonsPanel, Panel):
|
||||
"""Use this class to define standard material reflectivity (mirror) buttons."""
|
||||
|
||||
bl_label = "Mirror"
|
||||
bl_options = {'DEFAULT_CLOSED'}
|
||||
bl_idname = "MATERIAL_PT_POV_raytrace_mirror"
|
||||
COMPAT_ENGINES = {'POVRAY_RENDER'}
|
||||
|
||||
@classmethod
|
||||
def poll(cls, context):
|
||||
mat = context.material
|
||||
engine = context.scene.render.engine
|
||||
return (
|
||||
check_material(mat)
|
||||
and (mat.pov.type in {'SURFACE', 'WIRE'})
|
||||
and (engine in cls.COMPAT_ENGINES)
|
||||
)
|
||||
|
||||
def draw_header(self, context):
|
||||
mat = context.material
|
||||
raym = mat.pov_raytrace_mirror
|
||||
|
||||
self.layout.prop(raym, "use", text="")
|
||||
|
||||
def draw(self, context):
|
||||
layout = self.layout
|
||||
|
||||
mat = context.material # Formerly : #mat = active_node_mat(context.material)
|
||||
raym = mat.pov_raytrace_mirror
|
||||
|
||||
layout.active = raym.use
|
||||
|
||||
split = layout.split()
|
||||
|
||||
col = split.column()
|
||||
col.prop(raym, "reflect_factor")
|
||||
col.prop(raym, "mirror_color", text="")
|
||||
|
||||
col = split.column()
|
||||
col.prop(raym, "fresnel")
|
||||
sub = col.column()
|
||||
sub.active = raym.fresnel > 0.0
|
||||
sub.prop(raym, "fresnel_factor", text="Blend")
|
||||
|
||||
split = layout.split()
|
||||
|
||||
col = split.column()
|
||||
col.separator()
|
||||
col.prop(raym, "depth")
|
||||
col.prop(raym, "distance", text="Max Dist")
|
||||
col.separator()
|
||||
sub = col.split(factor=0.4)
|
||||
sub.active = raym.distance > 0.0
|
||||
sub.label(text="Fade To:")
|
||||
sub.prop(raym, "fade_to", text="")
|
||||
|
||||
col = split.column()
|
||||
col.label(text="Gloss:")
|
||||
col.prop(raym, "gloss_factor", text="Amount")
|
||||
sub = col.column()
|
||||
sub.active = raym.gloss_factor < 1.0
|
||||
sub.prop(raym, "gloss_threshold", text="Threshold")
|
||||
sub.prop(raym, "gloss_samples", text="Noise")
|
||||
sub.prop(raym, "gloss_anisotropic", text="Anisotropic")
|
||||
|
||||
|
||||
class MATERIAL_PT_POV_transp(MaterialButtonsPanel, Panel):
|
||||
"""Use this class to define pov material transparency (alpha) buttons."""
|
||||
|
||||
bl_label = "Transparency"
|
||||
COMPAT_ENGINES = {'POVRAY_RENDER'}
|
||||
|
||||
@classmethod
|
||||
def poll(cls, context):
|
||||
mat = context.material
|
||||
engine = context.scene.render.engine
|
||||
return (
|
||||
check_material(mat)
|
||||
and (mat.pov.type in {'SURFACE', 'WIRE'})
|
||||
and (engine in cls.COMPAT_ENGINES)
|
||||
)
|
||||
|
||||
def draw_header(self, context):
|
||||
mat = context.material
|
||||
|
||||
if simple_material(mat):
|
||||
self.layout.prop(mat.pov, "use_transparency", text="")
|
||||
|
||||
def draw(self, context):
|
||||
layout = self.layout
|
||||
|
||||
base_mat = context.material
|
||||
mat = context.material # FORMERLY active_node_mat(context.material)
|
||||
rayt = mat.pov_raytrace_transparency
|
||||
|
||||
if simple_material(base_mat):
|
||||
row = layout.row()
|
||||
row.active = mat.pov.use_transparency
|
||||
row.prop(mat.pov, "transparency_method", expand=True)
|
||||
|
||||
split = layout.split()
|
||||
split.active = base_mat.pov.use_transparency
|
||||
|
||||
col = split.column()
|
||||
col.prop(mat.pov, "alpha")
|
||||
row = col.row()
|
||||
row.active = (base_mat.pov.transparency_method != 'MASK') and (not mat.pov.use_shadeless)
|
||||
row.prop(mat.pov, "specular_alpha", text="Specular")
|
||||
|
||||
col = split.column()
|
||||
col.active = not mat.pov.use_shadeless
|
||||
col.prop(rayt, "fresnel")
|
||||
sub = col.column()
|
||||
sub.active = rayt.fresnel > 0.0
|
||||
sub.prop(rayt, "fresnel_factor", text="Blend")
|
||||
|
||||
if base_mat.pov.transparency_method == 'RAYTRACE':
|
||||
layout.separator()
|
||||
split = layout.split()
|
||||
split.active = base_mat.pov.use_transparency
|
||||
|
||||
col = split.column()
|
||||
col.prop(rayt, "ior")
|
||||
col.prop(rayt, "filter")
|
||||
col.prop(rayt, "falloff")
|
||||
col.prop(rayt, "depth_max")
|
||||
col.prop(rayt, "depth")
|
||||
|
||||
col = split.column()
|
||||
col.label(text="Gloss:")
|
||||
col.prop(rayt, "gloss_factor", text="Amount")
|
||||
sub = col.column()
|
||||
sub.active = rayt.gloss_factor < 1.0
|
||||
sub.prop(rayt, "gloss_threshold", text="Threshold")
|
||||
sub.prop(rayt, "gloss_samples", text="Samples")
|
||||
|
||||
|
||||
class MATERIAL_PT_POV_reflection(MaterialButtonsPanel, Panel):
|
||||
"""Use this class to define more pov specific reflectivity buttons."""
|
||||
|
||||
bl_label = "POV-Ray Reflection"
|
||||
bl_parent_id = "MATERIAL_PT_POV_raytrace_mirror"
|
||||
COMPAT_ENGINES = {'POVRAY_RENDER'}
|
||||
|
||||
@classmethod
|
||||
def poll(cls, context):
|
||||
engine = context.scene.render.engine
|
||||
mat = context.material
|
||||
return (
|
||||
mat
|
||||
and mat.pov.type == "SURFACE"
|
||||
and (engine in cls.COMPAT_ENGINES)
|
||||
and not (mat.pov.material_use_nodes or mat.use_nodes)
|
||||
)
|
||||
|
||||
def draw(self, context):
|
||||
layout = self.layout
|
||||
mat = context.material
|
||||
col = layout.column()
|
||||
col.prop(mat.pov, "irid_enable")
|
||||
if mat.pov.irid_enable:
|
||||
col = layout.column()
|
||||
col.prop(mat.pov, "irid_amount", slider=True)
|
||||
col.prop(mat.pov, "irid_thickness", slider=True)
|
||||
col.prop(mat.pov, "irid_turbulence", slider=True)
|
||||
col.prop(mat.pov, "conserve_energy")
|
||||
col2 = col.split().column()
|
||||
|
||||
if not mat.pov_raytrace_mirror.use:
|
||||
col2.label(text="Please Check Mirror settings :")
|
||||
col2.active = mat.pov_raytrace_mirror.use
|
||||
col2.prop(mat.pov, "mirror_use_IOR")
|
||||
if mat.pov.mirror_use_IOR:
|
||||
col2.alignment = 'CENTER'
|
||||
col2.label(text="The current Raytrace ")
|
||||
col2.label(text="Transparency IOR is: " + str(mat.pov_raytrace_transparency.ior))
|
||||
col2.prop(mat.pov, "mirror_metallic")
|
||||
|
||||
|
||||
'''
|
||||
#group some native Blender (SSS) and POV (Fade)settings under such a parent panel?
|
||||
class MATERIAL_PT_POV_interior(MaterialButtonsPanel, Panel):
|
||||
bl_label = "POV-Ray Interior"
|
||||
bl_idname = "material.pov_interior"
|
||||
#bl_parent_id = "material.absorption"
|
||||
COMPAT_ENGINES = {'POVRAY_RENDER'}
|
||||
@classmethod
|
||||
def poll(cls, context):
|
||||
engine = context.scene.render.engine
|
||||
mat=context.material
|
||||
return mat and mat.pov.type == "SURFACE" and (engine in cls.COMPAT_ENGINES) and not (mat.pov.material_use_nodes or mat.use_nodes)
|
||||
|
||||
|
||||
def draw_header(self, context):
|
||||
mat = context.material
|
||||
'''
|
||||
|
||||
|
||||
class MATERIAL_PT_POV_fade_color(MaterialButtonsPanel, Panel):
|
||||
"""Use this class to define pov fading (absorption) color buttons."""
|
||||
|
||||
bl_label = "POV-Ray Absorption"
|
||||
COMPAT_ENGINES = {'POVRAY_RENDER'}
|
||||
# bl_parent_id = "material.pov_interior"
|
||||
|
||||
@classmethod
|
||||
def poll(cls, context):
|
||||
engine = context.scene.render.engine
|
||||
mat = context.material
|
||||
return (
|
||||
mat
|
||||
and mat.pov.type == "SURFACE"
|
||||
and (engine in cls.COMPAT_ENGINES)
|
||||
and not (mat.pov.material_use_nodes or mat.use_nodes)
|
||||
)
|
||||
|
||||
def draw_header(self, context):
|
||||
mat = context.material
|
||||
|
||||
self.layout.prop(mat.pov, "interior_fade_color", text="")
|
||||
|
||||
def draw(self, context):
|
||||
layout = self.layout
|
||||
mat = context.material
|
||||
# layout.active = mat.pov.interior_fade_color
|
||||
if mat.pov.interior_fade_color != (0.0, 0.0, 0.0):
|
||||
layout.label(text="Raytrace transparency")
|
||||
layout.label(text="depth max Limit needs")
|
||||
layout.label(text="to be non zero to fade")
|
||||
|
||||
|
||||
class MATERIAL_PT_POV_caustics(MaterialButtonsPanel, Panel):
|
||||
"""Use this class to define pov caustics buttons."""
|
||||
|
||||
bl_label = "Caustics"
|
||||
COMPAT_ENGINES = {'POVRAY_RENDER'}
|
||||
|
||||
@classmethod
|
||||
def poll(cls, context):
|
||||
engine = context.scene.render.engine
|
||||
mat = context.material
|
||||
return (
|
||||
mat
|
||||
and mat.pov.type == "SURFACE"
|
||||
and (engine in cls.COMPAT_ENGINES)
|
||||
and not (mat.pov.material_use_nodes or mat.use_nodes)
|
||||
)
|
||||
|
||||
def draw_header(self, context):
|
||||
mat = context.material
|
||||
if mat.pov.caustics_enable:
|
||||
self.layout.prop(mat.pov, "caustics_enable", text="", icon="PMARKER_SEL")
|
||||
else:
|
||||
self.layout.prop(mat.pov, "caustics_enable", text="", icon="PMARKER")
|
||||
|
||||
def draw(self, context):
|
||||
|
||||
layout = self.layout
|
||||
|
||||
mat = context.material
|
||||
layout.active = mat.pov.caustics_enable
|
||||
col = layout.column()
|
||||
if mat.pov.caustics_enable:
|
||||
col.prop(mat.pov, "refraction_caustics")
|
||||
if mat.pov.refraction_caustics:
|
||||
|
||||
col.prop(mat.pov, "refraction_type", text="")
|
||||
|
||||
if mat.pov.refraction_type == "1":
|
||||
col.prop(mat.pov, "fake_caustics_power", slider=True)
|
||||
elif mat.pov.refraction_type == "2":
|
||||
col.prop(mat.pov, "photons_dispersion", slider=True)
|
||||
col.prop(mat.pov, "photons_dispersion_samples", slider=True)
|
||||
col.prop(mat.pov, "photons_reflection")
|
||||
|
||||
if not mat.pov.refraction_caustics and not mat.pov.photons_reflection:
|
||||
col = layout.column()
|
||||
col.alignment = 'CENTER'
|
||||
col.label(text="Caustics override is on, ")
|
||||
col.label(text="but you didn't chose any !")
|
||||
|
||||
|
||||
class MATERIAL_PT_strand(MaterialButtonsPanel, Panel):
|
||||
"""Use this class to define Blender strand antialiasing buttons."""
|
||||
|
||||
bl_label = "Strand"
|
||||
bl_options = {'DEFAULT_CLOSED'}
|
||||
COMPAT_ENGINES = {'POVRAY_RENDER'}
|
||||
|
||||
@classmethod
|
||||
def poll(cls, context):
|
||||
mat = context.material
|
||||
engine = context.scene.render.engine
|
||||
return (
|
||||
mat and (mat.pov.type in {'SURFACE', 'WIRE', 'HALO'}) and (engine in cls.COMPAT_ENGINES)
|
||||
)
|
||||
|
||||
def draw(self, context):
|
||||
layout = self.layout
|
||||
|
||||
mat = context.material # don't use node material
|
||||
tan = mat.strand
|
||||
|
||||
split = layout.split()
|
||||
|
||||
col = split.column()
|
||||
sub = col.column(align=True)
|
||||
sub.label(text="Size:")
|
||||
sub.prop(tan, "root_size", text="Root")
|
||||
sub.prop(tan, "tip_size", text="Tip")
|
||||
sub.prop(tan, "size_min", text="Minimum")
|
||||
sub.prop(tan, "use_blender_units")
|
||||
sub = col.column()
|
||||
sub.active = not mat.pov.use_shadeless
|
||||
sub.prop(tan, "use_tangent_shading")
|
||||
col.prop(tan, "shape")
|
||||
|
||||
col = split.column()
|
||||
col.label(text="Shading:")
|
||||
col.prop(tan, "width_fade")
|
||||
ob = context.object
|
||||
if ob and ob.type == 'MESH':
|
||||
col.prop_search(tan, "uv_layer", ob.data, "uv_layers", text="")
|
||||
else:
|
||||
col.prop(tan, "uv_layer", text="")
|
||||
col.separator()
|
||||
sub = col.column()
|
||||
sub.active = not mat.pov.use_shadeless
|
||||
sub.label(text="Surface diffuse:")
|
||||
sub = col.column()
|
||||
sub.prop(tan, "blend_distance", text="Distance")
|
||||
|
||||
|
||||
class MATERIAL_PT_POV_replacement_text(MaterialButtonsPanel, Panel):
|
||||
"""Use this class to define pov custom code declared name field."""
|
||||
|
||||
bl_label = "Custom POV Code"
|
||||
COMPAT_ENGINES = {'POVRAY_RENDER'}
|
||||
|
||||
def draw(self, context):
|
||||
layout = self.layout
|
||||
mat = context.material
|
||||
col = layout.column()
|
||||
col.alignment = 'RIGHT'
|
||||
col.label(text="Override properties with this")
|
||||
col.label(text="text editor {pov code} block")
|
||||
layout.prop(mat.pov, "replacement_text", text="#declare name", icon='SYNTAX_ON')
|
||||
|
||||
|
||||
classes = (
|
||||
MATERIAL_PT_POV_sss,
|
||||
MATERIAL_MT_POV_sss_presets,
|
||||
MATERIAL_OT_POV_sss_add_preset,
|
||||
MATERIAL_PT_strand,
|
||||
MATERIAL_PT_POV_activate_node,
|
||||
MATERIAL_PT_POV_active_node,
|
||||
MATERIAL_PT_POV_specular,
|
||||
MATERIAL_PT_POV_mirror,
|
||||
MATERIAL_PT_POV_transp,
|
||||
MATERIAL_PT_POV_reflection,
|
||||
## MATERIAL_PT_POV_interior,
|
||||
MATERIAL_PT_POV_fade_color,
|
||||
MATERIAL_PT_POV_caustics,
|
||||
MATERIAL_PT_POV_replacement_text,
|
||||
)
|
||||
|
||||
|
||||
def register():
|
||||
|
||||
for cls in classes:
|
||||
register_class(cls)
|
||||
|
||||
|
||||
def unregister():
|
||||
|
||||
for cls in reversed(classes):
|
||||
unregister_class(cls)
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,902 @@
|
|||
# ***** BEGIN GPL LICENSE BLOCK *****
|
||||
#
|
||||
# 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 2
|
||||
# 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
|
||||
# MERCHANTABILITY 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, write to the Free Software Foundation,
|
||||
# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
#
|
||||
# #**** END GPL LICENSE BLOCK #****
|
||||
|
||||
# <pep8 compliant>
|
||||
|
||||
"""Translate blender texture influences into POV."""
|
||||
import os
|
||||
import bpy
|
||||
|
||||
|
||||
def write_texture_influence(
|
||||
using_uberpov,
|
||||
mater,
|
||||
material_names_dictionary,
|
||||
local_material_names,
|
||||
path_image,
|
||||
exported_lights_count,
|
||||
image_format,
|
||||
img_map,
|
||||
img_map_transforms,
|
||||
tab_write,
|
||||
comments,
|
||||
string_strip_hyphen,
|
||||
safety,
|
||||
col,
|
||||
preview_dir,
|
||||
unpacked_images,
|
||||
):
|
||||
"""Translate Blender texture influences to various POV texture tricks and write to pov file."""
|
||||
material_finish = material_names_dictionary[mater.name]
|
||||
if mater.pov.use_transparency:
|
||||
trans = 1.0 - mater.pov.alpha
|
||||
else:
|
||||
trans = 0.0
|
||||
if (mater.pov.specular_color.s == 0.0) or (mater.pov.diffuse_shader == "MINNAERT"):
|
||||
# No layered texture because of aoi pattern used for minnaert and pov can't layer patterned
|
||||
colored_specular_found = False
|
||||
else:
|
||||
colored_specular_found = True
|
||||
|
||||
if mater.pov.use_transparency and mater.pov.transparency_method == "RAYTRACE":
|
||||
pov_filter = mater.pov_raytrace_transparency.filter * (1.0 - mater.pov.alpha)
|
||||
trans = (1.0 - mater.pov.alpha) - pov_filter
|
||||
else:
|
||||
pov_filter = 0.0
|
||||
|
||||
##############SF
|
||||
texture_dif = ""
|
||||
texture_spec = ""
|
||||
texture_norm = ""
|
||||
texture_alpha = ""
|
||||
# procedural_flag=False
|
||||
tmpidx = -1
|
||||
for t in mater.pov_texture_slots:
|
||||
|
||||
tmpidx += 1
|
||||
# index = mater.pov.active_texture_index
|
||||
slot = mater.pov_texture_slots[tmpidx] # [index]
|
||||
povtex = slot.texture # slot.name
|
||||
tex = bpy.data.textures[povtex]
|
||||
|
||||
if t and (t.use and (tex is not None)):
|
||||
# 'NONE' ('NONE' type texture is different from no texture covered above)
|
||||
if tex.type == "NONE" and tex.pov.tex_pattern_type == "emulator":
|
||||
continue # move to next slot
|
||||
|
||||
# Implicit else-if (as not skipped by previous "continue")
|
||||
# PROCEDURAL
|
||||
if tex.type != "IMAGE" and tex.type != "NONE":
|
||||
procedural_flag = True
|
||||
image_filename = "PAT_%s" % string_strip_hyphen(bpy.path.clean_name(tex.name))
|
||||
if image_filename:
|
||||
if t.use_map_color_diffuse:
|
||||
texture_dif = image_filename
|
||||
# colvalue = t.default_value # UNUSED
|
||||
t_dif = t
|
||||
if t_dif.texture.pov.tex_gamma_enable:
|
||||
img_gamma = " gamma %.3g " % t_dif.texture.pov.tex_gamma_value
|
||||
if t.use_map_specular or t.use_map_raymir:
|
||||
texture_spec = image_filename
|
||||
# colvalue = t.default_value # UNUSED
|
||||
t_spec = t
|
||||
if t.use_map_normal:
|
||||
texture_norm = image_filename
|
||||
# colvalue = t.normal_factor/10 # UNUSED
|
||||
# textNormName=tex.image.name + ".normal"
|
||||
# was the above used? --MR
|
||||
t_nor = t
|
||||
if t.use_map_alpha:
|
||||
texture_alpha = image_filename
|
||||
# colvalue = t.alpha_factor * 10.0 # UNUSED
|
||||
# textDispName=tex.image.name + ".displ"
|
||||
# was the above used? --MR
|
||||
t_alpha = t
|
||||
|
||||
# RASTER IMAGE
|
||||
elif tex.type == "IMAGE" and tex.image and tex.pov.tex_pattern_type == "emulator":
|
||||
procedural_flag = False
|
||||
# PACKED
|
||||
if tex.image.packed_file:
|
||||
orig_image_filename = tex.image.filepath_raw
|
||||
unpackedfilename = os.path.join(
|
||||
preview_dir,
|
||||
("unpacked_img_" + (string_strip_hyphen(bpy.path.clean_name(tex.name)))),
|
||||
)
|
||||
if not os.path.exists(unpackedfilename):
|
||||
# record which images that were newly copied and can be safely
|
||||
# cleaned up
|
||||
unpacked_images.append(unpackedfilename)
|
||||
tex.image.filepath_raw = unpackedfilename
|
||||
tex.image.save()
|
||||
image_filename = unpackedfilename.replace("\\", "/")
|
||||
# .replace("\\","/") to get only forward slashes as it's what POV prefers,
|
||||
# even on windows
|
||||
tex.image.filepath_raw = orig_image_filename
|
||||
# FILE
|
||||
else:
|
||||
image_filename = path_image(tex.image)
|
||||
# IMAGE SEQUENCE BEGINS
|
||||
if image_filename:
|
||||
if bpy.data.images[tex.image.name].source == "SEQUENCE":
|
||||
korvaa = "." + str(tex.image_user.frame_offset + 1).zfill(3) + "."
|
||||
image_filename = image_filename.replace(".001.", korvaa)
|
||||
print(" seq debug ")
|
||||
print(image_filename)
|
||||
# IMAGE SEQUENCE ENDS
|
||||
img_gamma = ""
|
||||
if image_filename:
|
||||
texdata = bpy.data.textures[t.texture]
|
||||
if t.use_map_color_diffuse:
|
||||
texture_dif = image_filename
|
||||
# colvalue = t.default_value # UNUSED
|
||||
t_dif = t
|
||||
print(texdata)
|
||||
if texdata.pov.tex_gamma_enable:
|
||||
img_gamma = " gamma %.3g " % t_dif.texture.pov.tex_gamma_value
|
||||
if t.use_map_specular or t.use_map_raymir:
|
||||
texture_spec = image_filename
|
||||
# colvalue = t.default_value # UNUSED
|
||||
t_spec = t
|
||||
if t.use_map_normal:
|
||||
texture_norm = image_filename
|
||||
# colvalue = t.normal_factor/10 # UNUSED
|
||||
# textNormName=tex.image.name + ".normal"
|
||||
# was the above used? --MR
|
||||
t_nor = t
|
||||
if t.use_map_alpha:
|
||||
texture_alpha = image_filename
|
||||
# colvalue = t.alpha_factor * 10.0 # UNUSED
|
||||
# textDispName=tex.image.name + ".displ"
|
||||
# was the above used? --MR
|
||||
t_alpha = t
|
||||
|
||||
####################################################################################
|
||||
|
||||
tab_write("\n")
|
||||
# THIS AREA NEEDS TO LEAVE THE TEXTURE OPEN UNTIL ALL MAPS ARE WRITTEN DOWN.
|
||||
# --MR
|
||||
current_material_name = string_strip_hyphen(material_names_dictionary[mater.name])
|
||||
local_material_names.append(current_material_name)
|
||||
tab_write("\n#declare MAT_%s = \ntexture{\n" % current_material_name)
|
||||
################################################################################
|
||||
|
||||
if mater.pov.replacement_text != "":
|
||||
tab_write("%s\n" % mater.pov.replacement_text)
|
||||
#################################################################################
|
||||
# XXX TODO: replace by new POV MINNAERT rather than aoi
|
||||
if mater.pov.diffuse_shader == "MINNAERT":
|
||||
tab_write("\n")
|
||||
tab_write("aoi\n")
|
||||
tab_write("texture_map {\n")
|
||||
tab_write("[%.3g finish {diffuse %.3g}]\n" % (mater.darkness / 2.0, 2.0 - mater.darkness))
|
||||
tab_write("[%.3g\n" % (1.0 - (mater.darkness / 2.0)))
|
||||
|
||||
if mater.pov.diffuse_shader == "FRESNEL":
|
||||
# For FRESNEL diffuse in POV, we'll layer slope patterned textures
|
||||
# with lamp vector as the slope vector and nest one slope per lamp
|
||||
# into each texture map's entry.
|
||||
|
||||
c = 1
|
||||
while c <= exported_lights_count:
|
||||
tab_write("slope { lampTarget%s }\n" % (c))
|
||||
tab_write("texture_map {\n")
|
||||
# Diffuse Fresnel value and factor go up to five,
|
||||
# other kind of values needed: used the number 5 below to remap
|
||||
tab_write(
|
||||
"[%.3g finish {diffuse %.3g}]\n"
|
||||
% (
|
||||
(5.0 - mater.diffuse_fresnel) / 5,
|
||||
(mater.diffuse_intensity * ((5.0 - mater.diffuse_fresnel_factor) / 5)),
|
||||
)
|
||||
)
|
||||
tab_write(
|
||||
"[%.3g\n" % ((mater.diffuse_fresnel_factor / 5) * (mater.diffuse_fresnel / 5.0))
|
||||
)
|
||||
c += 1
|
||||
|
||||
# if shader is a 'FRESNEL' or 'MINNAERT': slope pigment pattern or aoi
|
||||
# and texture map above, the rest below as one of its entry
|
||||
|
||||
if texture_spec != "" or texture_alpha != "":
|
||||
if texture_spec != "":
|
||||
# tab_write("\n")
|
||||
tab_write("pigment_pattern {\n")
|
||||
|
||||
mapping_spec = img_map_transforms(t_spec)
|
||||
if texture_spec and texture_spec.startswith("PAT_"):
|
||||
tab_write("function{f%s(x,y,z).grey}\n" % texture_spec)
|
||||
tab_write("%s\n" % mapping_spec)
|
||||
else:
|
||||
|
||||
tab_write(
|
||||
'uv_mapping image_map{%s "%s" %s}\n'
|
||||
% (image_format(texture_spec), texture_spec, img_map(t_spec))
|
||||
)
|
||||
tab_write("%s\n" % mapping_spec)
|
||||
tab_write("}\n")
|
||||
tab_write("texture_map {\n")
|
||||
tab_write("[0 \n")
|
||||
|
||||
if texture_dif == "":
|
||||
if texture_alpha != "":
|
||||
tab_write("\n")
|
||||
|
||||
mapping_alpha = img_map_transforms(t_alpha)
|
||||
|
||||
if texture_alpha and texture_alpha.startswith("PAT_"):
|
||||
tab_write("function{f%s(x,y,z).transmit}%s\n" % (texture_alpha, mapping_alpha))
|
||||
else:
|
||||
|
||||
tab_write(
|
||||
"pigment {pigment_pattern {uv_mapping image_map"
|
||||
'{%s "%s" %s}%s'
|
||||
% (
|
||||
image_format(texture_alpha),
|
||||
texture_alpha,
|
||||
img_map(t_alpha),
|
||||
mapping_alpha,
|
||||
)
|
||||
)
|
||||
tab_write("}\n")
|
||||
tab_write("pigment_map {\n")
|
||||
tab_write("[0 color rgbft<0,0,0,1,1>]\n")
|
||||
tab_write(
|
||||
"[1 color rgbft<%.3g, %.3g, %.3g, %.3g, %.3g>]\n"
|
||||
% (col[0], col[1], col[2], pov_filter, trans)
|
||||
)
|
||||
tab_write("}\n")
|
||||
tab_write("}\n")
|
||||
|
||||
else:
|
||||
|
||||
tab_write(
|
||||
"pigment {rgbft<%.3g, %.3g, %.3g, %.3g, %.3g>}\n"
|
||||
% (col[0], col[1], col[2], pov_filter, trans)
|
||||
)
|
||||
|
||||
if texture_spec != "":
|
||||
# ref_level_bound 1 is no specular
|
||||
tab_write("finish {%s}\n" % (safety(material_finish, ref_level_bound=1)))
|
||||
|
||||
else:
|
||||
# ref_level_bound 2 is translated spec
|
||||
tab_write("finish {%s}\n" % (safety(material_finish, ref_level_bound=2)))
|
||||
|
||||
else:
|
||||
mapping_dif = img_map_transforms(t_dif)
|
||||
|
||||
if texture_alpha != "":
|
||||
mapping_alpha = img_map_transforms(t_alpha)
|
||||
|
||||
tab_write("pigment {\n")
|
||||
tab_write("pigment_pattern {\n")
|
||||
if texture_alpha and texture_alpha.startswith("PAT_"):
|
||||
tab_write("function{f%s(x,y,z).transmit}%s\n" % (texture_alpha, mapping_alpha))
|
||||
else:
|
||||
tab_write(
|
||||
'uv_mapping image_map{%s "%s" %s}%s}\n'
|
||||
% (
|
||||
image_format(texture_alpha),
|
||||
texture_alpha,
|
||||
img_map(t_alpha),
|
||||
mapping_alpha,
|
||||
)
|
||||
)
|
||||
tab_write("pigment_map {\n")
|
||||
tab_write("[0 color rgbft<0,0,0,1,1>]\n")
|
||||
# if texture_alpha and texture_alpha.startswith("PAT_"):
|
||||
# tab_write("[1 pigment{%s}]\n" %texture_dif)
|
||||
if texture_dif and not texture_dif.startswith("PAT_"):
|
||||
tab_write(
|
||||
'[1 uv_mapping image_map {%s "%s" %s} %s]\n'
|
||||
% (
|
||||
image_format(texture_dif),
|
||||
texture_dif,
|
||||
(img_gamma + img_map(t_dif)),
|
||||
mapping_dif,
|
||||
)
|
||||
)
|
||||
elif texture_dif and texture_dif.startswith("PAT_"):
|
||||
tab_write("[1 %s]\n" % texture_dif)
|
||||
tab_write("}\n")
|
||||
tab_write("}\n")
|
||||
if texture_alpha and texture_alpha.startswith("PAT_"):
|
||||
tab_write("}\n")
|
||||
|
||||
else:
|
||||
if texture_dif and texture_dif.startswith("PAT_"):
|
||||
tab_write("pigment{%s}\n" % texture_dif)
|
||||
else:
|
||||
tab_write(
|
||||
'pigment {uv_mapping image_map {%s "%s" %s}%s}\n'
|
||||
% (
|
||||
image_format(texture_dif),
|
||||
texture_dif,
|
||||
(img_gamma + img_map(t_dif)),
|
||||
mapping_dif,
|
||||
)
|
||||
)
|
||||
|
||||
if texture_spec != "":
|
||||
# ref_level_bound 1 is no specular
|
||||
tab_write("finish {%s}\n" % (safety(material_finish, ref_level_bound=1)))
|
||||
|
||||
else:
|
||||
# ref_level_bound 2 is translated specular
|
||||
tab_write("finish {%s}\n" % (safety(material_finish, ref_level_bound=2)))
|
||||
|
||||
## scale 1 rotate y*0
|
||||
# imageMap = ("{image_map {%s \"%s\" %s }\n" % \
|
||||
# (image_format(textures),textures,img_map(t_dif)))
|
||||
# tab_write("uv_mapping pigment %s} %s finish {%s}\n" % \
|
||||
# (imageMap,mapping,safety(material_finish)))
|
||||
# tab_write("pigment {uv_mapping image_map {%s \"%s\" %s}%s} " \
|
||||
# "finish {%s}\n" % \
|
||||
# (image_format(texture_dif), texture_dif, img_map(t_dif),
|
||||
# mapping_dif, safety(material_finish)))
|
||||
if texture_norm != "":
|
||||
## scale 1 rotate y*0
|
||||
|
||||
mapping_normal = img_map_transforms(t_nor)
|
||||
|
||||
if texture_norm and texture_norm.startswith("PAT_"):
|
||||
tab_write(
|
||||
"normal{function{f%s(x,y,z).grey} bump_size %.4g %s}\n"
|
||||
% (texture_norm, (-t_nor.normal_factor * 9.5), mapping_normal)
|
||||
)
|
||||
else:
|
||||
tab_write("normal {\n")
|
||||
# XXX TODO: fix and propagate the micro normals reflection blur below to non textured materials
|
||||
if (
|
||||
mater.pov_raytrace_mirror.use
|
||||
and mater.pov_raytrace_mirror.gloss_factor < 1.0
|
||||
and not using_uberpov
|
||||
):
|
||||
tab_write("average\n")
|
||||
tab_write("normal_map{\n")
|
||||
# 0.5 for entries below means a 50 percent mix
|
||||
# between the micro normal and user bump map
|
||||
# order seems indifferent as commutative
|
||||
tab_write(
|
||||
"[0.025 bumps %.4g scale 0.1*%.4g]\n"
|
||||
% (
|
||||
(10 / (mater.pov_raytrace_mirror.gloss_factor + 0.01)),
|
||||
(10 / (mater.pov_raytrace_mirror.gloss_samples + 0.001)),
|
||||
)
|
||||
) # micronormals blurring
|
||||
tab_write(
|
||||
"[0.025 bumps %.4g scale 0.1*%.4g phase 0.1]\n"
|
||||
% (
|
||||
(10 / (mater.pov_raytrace_mirror.gloss_factor + 0.01)),
|
||||
(1 / (mater.pov_raytrace_mirror.gloss_samples + 0.001)),
|
||||
)
|
||||
) # micronormals blurring
|
||||
tab_write(
|
||||
"[0.025 bumps %.4g scale 0.1*%.4g phase 0.15]\n"
|
||||
% (
|
||||
(10 / (mater.pov_raytrace_mirror.gloss_factor + 0.01)),
|
||||
(1 / (mater.pov_raytrace_mirror.gloss_samples + 0.001)),
|
||||
)
|
||||
) # micronormals blurring
|
||||
tab_write(
|
||||
"[0.025 bumps %.4g scale 0.1*%.4g phase 0.2]\n"
|
||||
% (
|
||||
(10 / (mater.pov_raytrace_mirror.gloss_factor + 0.01)),
|
||||
(1 / (mater.pov_raytrace_mirror.gloss_samples + 0.001)),
|
||||
)
|
||||
) # micronormals blurring
|
||||
tab_write(
|
||||
"[0.025 bumps %.4g scale 0.1*%.4g phase 0.25]\n"
|
||||
% (
|
||||
(10 / (mater.pov_raytrace_mirror.gloss_factor + 0.01)),
|
||||
(1 / (mater.pov_raytrace_mirror.gloss_samples + 0.001)),
|
||||
)
|
||||
) # micronormals blurring
|
||||
tab_write(
|
||||
"[0.025 bumps %.4g scale 0.1*%.4g phase 0.3]\n"
|
||||
% (
|
||||
(10 / (mater.pov_raytrace_mirror.gloss_factor + 0.01)),
|
||||
(1 / (mater.pov_raytrace_mirror.gloss_samples + 0.001)),
|
||||
)
|
||||
) # micronormals blurring
|
||||
tab_write(
|
||||
"[0.025 bumps %.4g scale 0.1*%.4g phase 0.35]\n"
|
||||
% (
|
||||
(10 / (mater.pov_raytrace_mirror.gloss_factor + 0.01)),
|
||||
(1 / (mater.pov_raytrace_mirror.gloss_samples + 0.001)),
|
||||
)
|
||||
) # micronormals blurring
|
||||
tab_write(
|
||||
"[0.025 bumps %.4g scale 0.1*%.4g phase 0.4]\n"
|
||||
% (
|
||||
(10 / (mater.pov_raytrace_mirror.gloss_factor + 0.01)),
|
||||
(1 / (mater.pov_raytrace_mirror.gloss_samples + 0.001)),
|
||||
)
|
||||
) # micronormals blurring
|
||||
tab_write(
|
||||
"[0.025 bumps %.4g scale 0.1*%.4g phase 0.45]\n"
|
||||
% (
|
||||
(10 / (mater.pov_raytrace_mirror.gloss_factor + 0.01)),
|
||||
(1 / (mater.pov_raytrace_mirror.gloss_samples + 0.001)),
|
||||
)
|
||||
) # micronormals blurring
|
||||
tab_write(
|
||||
"[0.025 bumps %.4g scale 0.1*%.4g phase 0.5]\n"
|
||||
% (
|
||||
(10 / (mater.pov_raytrace_mirror.gloss_factor + 0.01)),
|
||||
(1 / (mater.pov_raytrace_mirror.gloss_samples + 0.001)),
|
||||
)
|
||||
) # micronormals blurring
|
||||
tab_write("[1.0 ") # Proceed with user bump...
|
||||
tab_write(
|
||||
"uv_mapping bump_map "
|
||||
'{%s "%s" %s bump_size %.4g }%s'
|
||||
% (
|
||||
image_format(texture_norm),
|
||||
texture_norm,
|
||||
img_map(t_nor),
|
||||
(-t_nor.normal_factor * 9.5),
|
||||
mapping_normal,
|
||||
)
|
||||
)
|
||||
# ...Then close its last entry and the the normal_map itself
|
||||
if (
|
||||
mater.pov_raytrace_mirror.use
|
||||
and mater.pov_raytrace_mirror.gloss_factor < 1.0
|
||||
and not using_uberpov
|
||||
):
|
||||
tab_write("]}}\n")
|
||||
else:
|
||||
tab_write("]}\n")
|
||||
if texture_spec != "":
|
||||
tab_write("]\n")
|
||||
##################Second index for mapping specular max value###############
|
||||
tab_write("[1 \n")
|
||||
|
||||
if texture_dif == "" and mater.pov.replacement_text == "":
|
||||
if texture_alpha != "":
|
||||
mapping_alpha = img_map_transforms(t_alpha)
|
||||
|
||||
if texture_alpha and texture_alpha.startswith("PAT_"):
|
||||
tab_write("function{f%s(x,y,z).transmit %s}\n" % (texture_alpha, mapping_alpha))
|
||||
else:
|
||||
tab_write(
|
||||
"pigment {pigment_pattern {uv_mapping image_map"
|
||||
'{%s "%s" %s}%s}\n'
|
||||
% (image_format(texture_alpha), texture_alpha, img_map(t_alpha), mapping_alpha)
|
||||
)
|
||||
tab_write("pigment_map {\n")
|
||||
tab_write("[0 color rgbft<0,0,0,1,1>]\n")
|
||||
tab_write(
|
||||
"[1 color rgbft<%.3g, %.3g, %.3g, %.3g, %.3g>]\n"
|
||||
% (col[0], col[1], col[2], pov_filter, trans)
|
||||
)
|
||||
tab_write("}\n")
|
||||
tab_write("}\n")
|
||||
|
||||
else:
|
||||
tab_write(
|
||||
"pigment {rgbft<%.3g, %.3g, %.3g, %.3g, %.3g>}\n"
|
||||
% (col[0], col[1], col[2], pov_filter, trans)
|
||||
)
|
||||
|
||||
if texture_spec != "":
|
||||
# ref_level_bound 3 is full specular
|
||||
tab_write("finish {%s}\n" % (safety(material_finish, ref_level_bound=3)))
|
||||
|
||||
if (
|
||||
mater.pov_raytrace_mirror.use
|
||||
and mater.pov_raytrace_mirror.gloss_factor < 1.0
|
||||
and not using_uberpov
|
||||
):
|
||||
tab_write("normal {\n")
|
||||
tab_write("average\n")
|
||||
tab_write("normal_map{\n")
|
||||
# 0.5 for entries below means a 50 percent mix
|
||||
# between the micro normal and user bump map
|
||||
# order seems indifferent as commutative
|
||||
tab_write(
|
||||
"[0.025 bumps %.4g scale 0.1*%.4g]\n"
|
||||
% (
|
||||
(10 / (mater.pov_raytrace_mirror.gloss_factor + 0.01)),
|
||||
(10 / (mater.pov_raytrace_mirror.gloss_samples + 0.001)),
|
||||
)
|
||||
) # micronormals blurring
|
||||
tab_write(
|
||||
"[0.025 bumps %.4g scale 0.1*%.4g phase 0.1]\n"
|
||||
% (
|
||||
(10 / (mater.pov_raytrace_mirror.gloss_factor + 0.01)),
|
||||
(1 / (mater.pov_raytrace_mirror.gloss_samples + 0.001)),
|
||||
)
|
||||
) # micronormals blurring
|
||||
tab_write(
|
||||
"[0.025 bumps %.4g scale 0.1*%.4g phase 0.15]\n"
|
||||
% (
|
||||
(10 / (mater.pov_raytrace_mirror.gloss_factor + 0.01)),
|
||||
(1 / (mater.pov_raytrace_mirror.gloss_samples + 0.001)),
|
||||
)
|
||||
) # micronormals blurring
|
||||
tab_write(
|
||||
"[0.025 bumps %.4g scale 0.1*%.4g phase 0.2]\n"
|
||||
% (
|
||||
(10 / (mater.pov_raytrace_mirror.gloss_factor + 0.01)),
|
||||
(1 / (mater.pov_raytrace_mirror.gloss_samples + 0.001)),
|
||||
)
|
||||
) # micronormals blurring
|
||||
tab_write(
|
||||
"[0.025 bumps %.4g scale 0.1*%.4g phase 0.25]\n"
|
||||
% (
|
||||
(10 / (mater.pov_raytrace_mirror.gloss_factor + 0.01)),
|
||||
(1 / (mater.pov_raytrace_mirror.gloss_samples + 0.001)),
|
||||
)
|
||||
) # micronormals blurring
|
||||
tab_write(
|
||||
"[0.025 bumps %.4g scale 0.1*%.4g phase 0.3]\n"
|
||||
% (
|
||||
(10 / (mater.pov_raytrace_mirror.gloss_factor + 0.01)),
|
||||
(1 / (mater.pov_raytrace_mirror.gloss_samples + 0.001)),
|
||||
)
|
||||
) # micronormals blurring
|
||||
tab_write(
|
||||
"[0.025 bumps %.4g scale 0.1*%.4g phase 0.35]\n"
|
||||
% (
|
||||
(10 / (mater.pov_raytrace_mirror.gloss_factor + 0.01)),
|
||||
(1 / (mater.pov_raytrace_mirror.gloss_samples + 0.001)),
|
||||
)
|
||||
) # micronormals blurring
|
||||
tab_write(
|
||||
"[0.025 bumps %.4g scale 0.1*%.4g phase 0.4]\n"
|
||||
% (
|
||||
(10 / (mater.pov_raytrace_mirror.gloss_factor + 0.01)),
|
||||
(1 / (mater.pov_raytrace_mirror.gloss_samples + 0.001)),
|
||||
)
|
||||
) # micronormals blurring
|
||||
tab_write(
|
||||
"[0.025 bumps %.4g scale 0.1*%.4g phase 0.45]\n"
|
||||
% (
|
||||
(10 / (mater.pov_raytrace_mirror.gloss_factor + 0.01)),
|
||||
(1 / (mater.pov_raytrace_mirror.gloss_samples + 0.001)),
|
||||
)
|
||||
) # micronormals blurring
|
||||
tab_write(
|
||||
"[0.025 bumps %.4g scale 0.1*%.4g phase 0.5]\n"
|
||||
% (
|
||||
(10 / (mater.pov_raytrace_mirror.gloss_factor + 0.01)),
|
||||
(1 / (mater.pov_raytrace_mirror.gloss_samples + 0.001)),
|
||||
)
|
||||
) # micronormals blurring
|
||||
# XXX IF USER BUMP_MAP
|
||||
if texture_norm != "":
|
||||
tab_write(
|
||||
"[1.0 "
|
||||
) # Blurry reflection or not Proceed with user bump in either case...
|
||||
tab_write(
|
||||
"uv_mapping bump_map "
|
||||
'{%s "%s" %s bump_size %.4g }%s]\n'
|
||||
% (
|
||||
image_format(texture_norm),
|
||||
texture_norm,
|
||||
img_map(t_nor),
|
||||
(-t_nor.normal_factor * 9.5),
|
||||
mapping_normal,
|
||||
)
|
||||
)
|
||||
# ...Then close the normal_map itself if blurry reflection
|
||||
if (
|
||||
mater.pov_raytrace_mirror.use
|
||||
and mater.pov_raytrace_mirror.gloss_factor < 1.0
|
||||
and not using_uberpov
|
||||
):
|
||||
tab_write("}}\n")
|
||||
else:
|
||||
tab_write("}\n")
|
||||
elif colored_specular_found:
|
||||
# ref_level_bound 1 is no specular
|
||||
tab_write("finish {%s}\n" % (safety(material_finish, ref_level_bound=1)))
|
||||
|
||||
else:
|
||||
# ref_level_bound 2 is translated specular
|
||||
tab_write("finish {%s}\n" % (safety(material_finish, ref_level_bound=2)))
|
||||
|
||||
elif mater.pov.replacement_text == "":
|
||||
mapping_dif = img_map_transforms(t_dif)
|
||||
|
||||
if texture_alpha != "":
|
||||
|
||||
mapping_alpha = img_map_transforms(t_alpha)
|
||||
|
||||
if texture_alpha and texture_alpha.startswith("PAT_"):
|
||||
tab_write(
|
||||
"pigment{pigment_pattern {function{f%s(x,y,z).transmit}%s}\n"
|
||||
% (texture_alpha, mapping_alpha)
|
||||
)
|
||||
else:
|
||||
tab_write(
|
||||
"pigment {pigment_pattern {uv_mapping image_map"
|
||||
'{%s "%s" %s}%s}\n'
|
||||
% (image_format(texture_alpha), texture_alpha, img_map(t_alpha), mapping_alpha)
|
||||
)
|
||||
tab_write("pigment_map {\n")
|
||||
tab_write("[0 color rgbft<0,0,0,1,1>]\n")
|
||||
if texture_alpha and texture_alpha.startswith("PAT_"):
|
||||
tab_write("[1 function{f%s(x,y,z).transmit}%s]\n" % (texture_alpha, mapping_alpha))
|
||||
elif texture_dif and not texture_dif.startswith("PAT_"):
|
||||
tab_write(
|
||||
'[1 uv_mapping image_map {%s "%s" %s} %s]\n'
|
||||
% (
|
||||
image_format(texture_dif),
|
||||
texture_dif,
|
||||
(img_map(t_dif) + img_gamma),
|
||||
mapping_dif,
|
||||
)
|
||||
)
|
||||
elif texture_dif and texture_dif.startswith("PAT_"):
|
||||
tab_write("[1 %s %s]\n" % (texture_dif, mapping_dif))
|
||||
tab_write("}\n")
|
||||
tab_write("}\n")
|
||||
|
||||
else:
|
||||
if texture_dif and texture_dif.startswith("PAT_"):
|
||||
tab_write("pigment{%s %s}\n" % (texture_dif, mapping_dif))
|
||||
else:
|
||||
tab_write("pigment {\n")
|
||||
tab_write("uv_mapping image_map {\n")
|
||||
# tab_write("%s \"%s\" %s}%s\n" % \
|
||||
# (image_format(texture_dif), texture_dif,
|
||||
# (img_gamma + img_map(t_dif)),mapping_dif))
|
||||
tab_write('%s "%s" \n' % (image_format(texture_dif), texture_dif))
|
||||
tab_write("%s\n" % (img_gamma + img_map(t_dif)))
|
||||
tab_write("}\n")
|
||||
tab_write("%s\n" % mapping_dif)
|
||||
tab_write("}\n")
|
||||
|
||||
if texture_spec != "":
|
||||
# ref_level_bound 3 is full specular
|
||||
tab_write("finish {%s}\n" % (safety(material_finish, ref_level_bound=3)))
|
||||
else:
|
||||
# ref_level_bound 2 is translated specular
|
||||
tab_write("finish {%s}\n" % (safety(material_finish, ref_level_bound=2)))
|
||||
|
||||
## scale 1 rotate y*0
|
||||
# imageMap = ("{image_map {%s \"%s\" %s }" % \
|
||||
# (image_format(textures), textures,img_map(t_dif)))
|
||||
# tab_write("\n\t\t\tuv_mapping pigment %s} %s finish {%s}" % \
|
||||
# (imageMap, mapping, safety(material_finish)))
|
||||
# tab_write("\n\t\t\tpigment {uv_mapping image_map " \
|
||||
# "{%s \"%s\" %s}%s} finish {%s}" % \
|
||||
# (image_format(texture_dif), texture_dif,img_map(t_dif),
|
||||
# mapping_dif, safety(material_finish)))
|
||||
if texture_norm != "" and mater.pov.replacement_text == "":
|
||||
|
||||
mapping_normal = img_map_transforms(t_nor)
|
||||
|
||||
if texture_norm and texture_norm.startswith("PAT_"):
|
||||
tab_write(
|
||||
"normal{function{f%s(x,y,z).grey} bump_size %.4g %s}\n"
|
||||
% (texture_norm, (-t_nor.normal_factor * 9.5), mapping_normal)
|
||||
)
|
||||
else:
|
||||
tab_write("normal {\n")
|
||||
# XXX TODO: fix and propagate the micro normals reflection blur below to non textured materials
|
||||
if (
|
||||
mater.pov_raytrace_mirror.use
|
||||
and mater.pov_raytrace_mirror.gloss_factor < 1.0
|
||||
and not using_uberpov
|
||||
):
|
||||
tab_write("average\n")
|
||||
tab_write("normal_map{\n")
|
||||
# 0.5 for entries below means a 50 percent mix
|
||||
# between the micro normal and user bump map
|
||||
# order seems indifferent as commutative
|
||||
tab_write(
|
||||
"[0.025 bumps %.4g scale 0.1*%.4g]\n"
|
||||
% (
|
||||
(10 / (mater.pov_raytrace_mirror.gloss_factor + 0.01)),
|
||||
(10 / (mater.pov_raytrace_mirror.gloss_samples + 0.001)),
|
||||
)
|
||||
) # micronormals blurring
|
||||
tab_write(
|
||||
"[0.025 bumps %.4g scale 0.1*%.4g phase 0.1]\n"
|
||||
% (
|
||||
(10 / (mater.pov_raytrace_mirror.gloss_factor + 0.01)),
|
||||
(1 / (mater.pov_raytrace_mirror.gloss_samples + 0.001)),
|
||||
)
|
||||
) # micronormals blurring
|
||||
tab_write(
|
||||
"[0.025 bumps %.4g scale 0.1*%.4g phase 0.15]\n"
|
||||
% (
|
||||
(10 / (mater.pov_raytrace_mirror.gloss_factor + 0.01)),
|
||||
(1 / (mater.pov_raytrace_mirror.gloss_samples + 0.001)),
|
||||
)
|
||||
) # micronormals blurring
|
||||
tab_write(
|
||||
"[0.025 bumps %.4g scale 0.1*%.4g phase 0.2]\n"
|
||||
% (
|
||||
(10 / (mater.pov_raytrace_mirror.gloss_factor + 0.01)),
|
||||
(1 / (mater.pov_raytrace_mirror.gloss_samples + 0.001)),
|
||||
)
|
||||
) # micronormals blurring
|
||||
tab_write(
|
||||
"[0.025 bumps %.4g scale 0.1*%.4g phase 0.25]\n"
|
||||
% (
|
||||
(10 / (mater.pov_raytrace_mirror.gloss_factor + 0.01)),
|
||||
(1 / (mater.pov_raytrace_mirror.gloss_samples + 0.001)),
|
||||
)
|
||||
) # micronormals blurring
|
||||
tab_write(
|
||||
"[0.025 bumps %.4g scale 0.1*%.4g phase 0.3]\n"
|
||||
% (
|
||||
(10 / (mater.pov_raytrace_mirror.gloss_factor + 0.01)),
|
||||
(1 / (mater.pov_raytrace_mirror.gloss_samples + 0.001)),
|
||||
)
|
||||
) # micronormals blurring
|
||||
tab_write(
|
||||
"[0.025 bumps %.4g scale 0.1*%.4g phase 0.35]\n"
|
||||
% (
|
||||
(10 / (mater.pov_raytrace_mirror.gloss_factor + 0.01)),
|
||||
(1 / (mater.pov_raytrace_mirror.gloss_samples + 0.001)),
|
||||
)
|
||||
) # micronormals blurring
|
||||
tab_write(
|
||||
"[0.025 bumps %.4g scale 0.1*%.4g phase 0.4]\n"
|
||||
% (
|
||||
(10 / (mater.pov_raytrace_mirror.gloss_factor + 0.01)),
|
||||
(1 / (mater.pov_raytrace_mirror.gloss_samples + 0.001)),
|
||||
)
|
||||
) # micronormals blurring
|
||||
tab_write(
|
||||
"[0.025 bumps %.4g scale 0.1*%.4g phase 0.45]\n"
|
||||
% (
|
||||
(10 / (mater.pov_raytrace_mirror.gloss_factor + 0.01)),
|
||||
(1 / (mater.pov_raytrace_mirror.gloss_samples + 0.001)),
|
||||
)
|
||||
) # micronormals blurring
|
||||
tab_write(
|
||||
"[0.025 bumps %.4g scale 0.1*%.4g phase 0.5]\n"
|
||||
% (
|
||||
(10 / (mater.pov_raytrace_mirror.gloss_factor + 0.01)),
|
||||
(1 / (mater.pov_raytrace_mirror.gloss_samples + 0.001)),
|
||||
)
|
||||
) # micronormals blurring
|
||||
tab_write(
|
||||
"[1.0 "
|
||||
) # Blurry reflection or not Proceed with user bump in either case...
|
||||
tab_write(
|
||||
"uv_mapping bump_map "
|
||||
'{%s "%s" %s bump_size %.4g }%s]\n'
|
||||
% (
|
||||
image_format(texture_norm),
|
||||
texture_norm,
|
||||
img_map(t_nor),
|
||||
(-t_nor.normal_factor * 9.5),
|
||||
mapping_normal,
|
||||
)
|
||||
)
|
||||
# ...Then close the normal_map itself if blurry reflection
|
||||
if (
|
||||
mater.pov_raytrace_mirror.use
|
||||
and mater.pov_raytrace_mirror.gloss_factor < 1.0
|
||||
and not using_uberpov
|
||||
):
|
||||
tab_write("}}\n")
|
||||
else:
|
||||
tab_write("}\n")
|
||||
if texture_spec != "" and mater.pov.replacement_text == "":
|
||||
tab_write("]\n")
|
||||
|
||||
tab_write("}\n")
|
||||
|
||||
# End of slope/ior texture_map
|
||||
if mater.pov.diffuse_shader == "MINNAERT" and mater.pov.replacement_text == "":
|
||||
tab_write("]\n")
|
||||
tab_write("}\n")
|
||||
if mater.pov.diffuse_shader == "FRESNEL" and mater.pov.replacement_text == "":
|
||||
c = 1
|
||||
while c <= exported_lights_count:
|
||||
tab_write("]\n")
|
||||
tab_write("}\n")
|
||||
c += 1
|
||||
|
||||
# Close first layer of POV "texture" (Blender material)
|
||||
tab_write("}\n")
|
||||
|
||||
colored_specular_found = bool(
|
||||
(mater.pov.specular_color.s > 0.0) and (mater.pov.diffuse_shader != "MINNAERT")
|
||||
)
|
||||
|
||||
# Write another layered texture using invisible diffuse and metallic trick
|
||||
# to emulate colored specular highlights
|
||||
special_texture_found = False
|
||||
tmpidx = -1
|
||||
for t in mater.pov_texture_slots:
|
||||
tmpidx += 1
|
||||
# index = mater.pov.active_texture_index
|
||||
slot = mater.pov_texture_slots[tmpidx] # [index]
|
||||
povtex = slot.texture # slot.name
|
||||
tex = bpy.data.textures[povtex]
|
||||
# Specular mapped textures would conflict with colored specular
|
||||
# because POV can't layer over or under pigment patterned textures
|
||||
special_texture_found = bool(
|
||||
t
|
||||
and t.use
|
||||
and ((tex.type == "IMAGE" and tex.image) or tex.type != "IMAGE")
|
||||
and (t.use_map_specular or t.use_map_raymir)
|
||||
)
|
||||
if colored_specular_found and not special_texture_found:
|
||||
if comments:
|
||||
tab_write(" // colored highlights with a stransparent metallic layer\n")
|
||||
else:
|
||||
tab_write("\n")
|
||||
|
||||
tab_write("texture {\n")
|
||||
tab_write(
|
||||
"pigment {rgbft<%.3g, %.3g, %.3g, 0, 1>}\n"
|
||||
% (
|
||||
mater.pov.specular_color[0],
|
||||
mater.pov.specular_color[1],
|
||||
mater.pov.specular_color[2],
|
||||
)
|
||||
)
|
||||
tab_write(
|
||||
"finish {%s}\n" % (safety(material_finish, ref_level_bound=2))
|
||||
) # ref_level_bound 2 is translated spec
|
||||
|
||||
texture_norm = ""
|
||||
for t in mater.pov_texture_slots:
|
||||
|
||||
if t and tex.pov.tex_pattern_type != "emulator":
|
||||
procedural_flag = True
|
||||
image_filename = string_strip_hyphen(bpy.path.clean_name(tex.name))
|
||||
if (
|
||||
t
|
||||
and tex.type == "IMAGE"
|
||||
and t.use
|
||||
and tex.image
|
||||
and tex.pov.tex_pattern_type == "emulator"
|
||||
):
|
||||
procedural_flag = False
|
||||
image_filename = path_image(tex.image)
|
||||
img_gamma = ""
|
||||
if image_filename:
|
||||
if t.use_map_normal:
|
||||
texture_norm = image_filename
|
||||
# colvalue = t.normal_factor/10 # UNUSED XXX *-9.5 !
|
||||
# textNormName=tex.image.name + ".normal"
|
||||
# was the above used? --MR
|
||||
t_nor = t
|
||||
if procedural_flag:
|
||||
tab_write(
|
||||
"normal{function"
|
||||
"{f%s(x,y,z).grey} bump_size %.4g}\n"
|
||||
% (texture_norm, (-t_nor.normal_factor * 9.5))
|
||||
)
|
||||
else:
|
||||
tab_write(
|
||||
"normal {uv_mapping bump_map "
|
||||
'{%s "%s" %s bump_size %.4g }%s}\n'
|
||||
% (
|
||||
image_format(texture_norm),
|
||||
texture_norm,
|
||||
img_map(t_nor),
|
||||
(-t_nor.normal_factor * 9.5),
|
||||
mapping_normal,
|
||||
)
|
||||
)
|
||||
|
||||
tab_write("}\n") # THEN IT CAN CLOSE LAST LAYER OF TEXTURE
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
4719
render_povray/ui.py
4719
render_povray/ui.py
File diff suppressed because it is too large
Load Diff
|
@ -33,8 +33,22 @@ from bpy.props import (
|
|||
EnumProperty,
|
||||
)
|
||||
|
||||
# Todo:
|
||||
# *update this file to just cover 2.79 to 3.xx and ui it from a Blender internal to pov menu
|
||||
# *as well as update from older pov > switch to QMC when pov 3.8 is out ?
|
||||
# *filter if possible files built in pre 2.79 versions. tell user their file is too old and may
|
||||
# be salvaged from older vesion of this operator from within latest stable blender 2.79 version.
|
||||
# else if bpy.app.version[0] == 2 and bpy.app.version[1] <= 92 and and bpy.app.version[1] >= 79:
|
||||
# warn users to update blender to 3.xx for creating their newer files then try to salvage
|
||||
# using this script
|
||||
#
|
||||
# if bpy.app.version[0] >= 3: # just test file created a)there or b)before, a) do nothing
|
||||
# "your version is relatively futureproof" > doing nothing
|
||||
# b)"use this operator to salvage your blends from latest stable 2.79"
|
||||
|
||||
|
||||
def update2_0_0_9():
|
||||
"""Update properties from older Blender versions. The render API changed a lot up to 2.79."""
|
||||
# Temporally register old props, so we can access their values.
|
||||
register()
|
||||
|
||||
|
@ -109,26 +123,16 @@ def update2_0_0_9():
|
|||
"pov_refraction_type",
|
||||
"pov_replacement_text",
|
||||
]:
|
||||
old_mat_props[k] = getattr(bpy.types.Material, k)[1].get(
|
||||
'default', None
|
||||
)
|
||||
old_mat_props[k] = getattr(bpy.types.Material, k)[1].get('default', None)
|
||||
|
||||
# Get default values of pov texture props.
|
||||
old_tex_props = {}
|
||||
for k in [
|
||||
"pov_tex_gamma_enable",
|
||||
"pov_tex_gamma_value",
|
||||
"pov_replacement_text",
|
||||
]:
|
||||
for k in ["pov_tex_gamma_enable", "pov_tex_gamma_value", "pov_replacement_text"]:
|
||||
old_tex_props[k] = getattr(bpy.types.Texture, k)[1].get('default', None)
|
||||
|
||||
# Get default values of pov object props.
|
||||
old_obj_props = {}
|
||||
for k in [
|
||||
"pov_importance_value",
|
||||
"pov_collect_photons",
|
||||
"pov_replacement_text",
|
||||
]:
|
||||
for k in ["pov_importance_value", "pov_collect_photons", "pov_replacement_text"]:
|
||||
old_obj_props[k] = getattr(bpy.types.Object, k)[1].get('default', None)
|
||||
|
||||
# Get default values of pov camera props.
|
||||
|
@ -189,7 +193,7 @@ def update2_0_0_9():
|
|||
|
||||
|
||||
class RenderCopySettings(bpy.types.Operator):
|
||||
"""Update old POV properties to new ones"""
|
||||
"""Update old POV properties to new ones."""
|
||||
|
||||
bl_idname = "scene.pov_update_properties"
|
||||
bl_label = "PovRay render: Update to script v0.0.9"
|
||||
|
@ -253,19 +257,13 @@ def register():
|
|||
|
||||
# Not a real pov option, just to know if we should write
|
||||
Scene.pov_radio_enable = BoolProperty(
|
||||
name="Enable Radiosity",
|
||||
description="Enable POV-Rays radiosity calculation",
|
||||
default=False,
|
||||
name="Enable Radiosity", description="Enable POV-Rays radiosity calculation", default=False
|
||||
)
|
||||
Scene.pov_radio_display_advanced = BoolProperty(
|
||||
name="Advanced Options",
|
||||
description="Show advanced options",
|
||||
default=False,
|
||||
name="Advanced Options", description="Show advanced options", default=False
|
||||
)
|
||||
Scene.pov_media_enable = BoolProperty(
|
||||
name="Enable Media",
|
||||
description="Enable POV-Rays atmospheric media",
|
||||
default=False,
|
||||
name="Enable Media", description="Enable POV-Rays atmospheric media", default=False
|
||||
)
|
||||
Scene.pov_media_samples = IntProperty(
|
||||
name="Samples",
|
||||
|
@ -288,9 +286,7 @@ def register():
|
|||
)
|
||||
|
||||
Scene.pov_baking_enable = BoolProperty(
|
||||
name="Enable Baking",
|
||||
description="Enable POV-Rays texture baking",
|
||||
default=False,
|
||||
name="Enable Baking", description="Enable POV-Rays texture baking", default=False
|
||||
)
|
||||
Scene.pov_indentation_character = EnumProperty(
|
||||
name="Indentation",
|
||||
|
@ -311,9 +307,7 @@ def register():
|
|||
)
|
||||
|
||||
Scene.pov_comments_enable = BoolProperty(
|
||||
name="Enable Comments",
|
||||
description="Add comments to pov file",
|
||||
default=True,
|
||||
name="Enable Comments", description="Add comments to pov file", default=True
|
||||
)
|
||||
|
||||
# Real pov options
|
||||
|
@ -339,11 +333,7 @@ def register():
|
|||
)
|
||||
|
||||
Scene.pov_antialias_depth = IntProperty(
|
||||
name="Antialias Depth",
|
||||
description="Depth of pixel for sampling",
|
||||
min=1,
|
||||
max=9,
|
||||
default=3,
|
||||
name="Antialias Depth", description="Depth of pixel for sampling", min=1, max=9, default=3
|
||||
)
|
||||
|
||||
Scene.pov_antialias_threshold = FloatProperty(
|
||||
|
@ -504,9 +494,7 @@ def register():
|
|||
|
||||
# max_sample - not available yet
|
||||
Scene.pov_radio_media = BoolProperty(
|
||||
name="Media",
|
||||
description="Radiosity estimation can be affected by media",
|
||||
default=False,
|
||||
name="Media", description="Radiosity estimation can be affected by media", default=False
|
||||
)
|
||||
|
||||
Scene.pov_radio_minimum_reuse = FloatProperty(
|
||||
|
@ -529,9 +517,7 @@ def register():
|
|||
)
|
||||
|
||||
Scene.pov_radio_normal = BoolProperty(
|
||||
name="Normals",
|
||||
description="Radiosity estimation can be affected by normals",
|
||||
default=False,
|
||||
name="Normals", description="Radiosity estimation can be affected by normals", default=False
|
||||
)
|
||||
|
||||
Scene.pov_radio_recursion_limit = IntProperty(
|
||||
|
@ -638,9 +624,7 @@ def register():
|
|||
)
|
||||
|
||||
Mat.pov_fake_caustics = BoolProperty(
|
||||
name="Fake Caustics",
|
||||
description="use only (Fast) fake refractive caustics",
|
||||
default=True,
|
||||
name="Fake Caustics", description="use only (Fast) fake refractive caustics", default=True
|
||||
)
|
||||
|
||||
Mat.pov_fake_caustics_power = FloatProperty(
|
||||
|
@ -654,9 +638,7 @@ def register():
|
|||
)
|
||||
|
||||
Mat.pov_photons_refraction = BoolProperty(
|
||||
name="Refractive Photon Caustics",
|
||||
description="more physically correct",
|
||||
default=False,
|
||||
name="Refractive Photon Caustics", description="more physically correct", default=False
|
||||
)
|
||||
|
||||
Mat.pov_photons_dispersion = FloatProperty(
|
||||
|
@ -752,9 +734,7 @@ def register():
|
|||
|
||||
# DOF Toggle
|
||||
Cam.pov_dof_enable = BoolProperty(
|
||||
name="Depth Of Field",
|
||||
description="Enable POV-Ray Depth Of Field ",
|
||||
default=True,
|
||||
name="Depth Of Field", description="Enable POV-Ray Depth Of Field ", default=True
|
||||
)
|
||||
|
||||
# Aperture (Intensity of the Blur)
|
||||
|
@ -816,12 +796,12 @@ def unregister():
|
|||
Obj = bpy.types.Object
|
||||
Cam = bpy.types.Camera
|
||||
Text = bpy.types.Text
|
||||
del Scene.pov_tempfiles_enable # CR
|
||||
del Scene.pov_scene_name # CR
|
||||
del Scene.pov_deletefiles_enable # CR
|
||||
del Scene.pov_scene_path # CR
|
||||
del Scene.pov_renderimage_path # CR
|
||||
del Scene.pov_list_lf_enable # CR
|
||||
del Scene.pov_tempfiles_enable
|
||||
del Scene.pov_scene_name
|
||||
del Scene.pov_deletefiles_enable
|
||||
del Scene.pov_scene_path
|
||||
del Scene.pov_renderimage_path
|
||||
del Scene.pov_list_lf_enable
|
||||
del Scene.pov_radio_enable
|
||||
del Scene.pov_radio_display_advanced
|
||||
del Scene.pov_radio_adc_bailout
|
||||
|
@ -836,56 +816,56 @@ def unregister():
|
|||
del Scene.pov_radio_nearest_count
|
||||
del Scene.pov_radio_normal
|
||||
del Scene.pov_radio_recursion_limit
|
||||
del Scene.pov_radio_pretrace_start # MR
|
||||
del Scene.pov_radio_pretrace_end # MR
|
||||
del Scene.pov_media_enable # MR
|
||||
del Scene.pov_media_samples # MR
|
||||
del Scene.pov_media_color # MR
|
||||
del Scene.pov_baking_enable # MR
|
||||
del Scene.pov_max_trace_level # MR
|
||||
del Scene.pov_photon_spacing # MR
|
||||
del Scene.pov_photon_max_trace_level # MR
|
||||
del Scene.pov_photon_adc_bailout # MR
|
||||
del Scene.pov_photon_gather_min # MR
|
||||
del Scene.pov_photon_gather_max # MR
|
||||
del Scene.pov_antialias_enable # CR
|
||||
del Scene.pov_antialias_method # CR
|
||||
del Scene.pov_antialias_depth # CR
|
||||
del Scene.pov_antialias_threshold # CR
|
||||
del Scene.pov_antialias_gamma # CR
|
||||
del Scene.pov_jitter_enable # CR
|
||||
del Scene.pov_jitter_amount # CR
|
||||
del Scene.pov_command_line_switches # CR
|
||||
del Scene.pov_indentation_character # CR
|
||||
del Scene.pov_indentation_spaces # CR
|
||||
del Scene.pov_comments_enable # CR
|
||||
del Mat.pov_irid_enable # MR
|
||||
del Mat.pov_mirror_use_IOR # MR
|
||||
del Mat.pov_mirror_metallic # MR
|
||||
del Mat.pov_conserve_energy # MR
|
||||
del Mat.pov_irid_amount # MR
|
||||
del Mat.pov_irid_thickness # MR
|
||||
del Mat.pov_irid_turbulence # MR
|
||||
del Mat.pov_interior_fade_color # MR
|
||||
del Mat.pov_caustics_enable # MR
|
||||
del Mat.pov_fake_caustics # MR
|
||||
del Mat.pov_fake_caustics_power # MR
|
||||
del Mat.pov_photons_refraction # MR
|
||||
del Mat.pov_photons_dispersion # MR
|
||||
del Mat.pov_photons_reflection # MR
|
||||
del Mat.pov_refraction_type # MR
|
||||
del Mat.pov_replacement_text # MR
|
||||
del Tex.pov_tex_gamma_enable # MR
|
||||
del Tex.pov_tex_gamma_value # MR
|
||||
del Tex.pov_replacement_text # MR
|
||||
del Obj.pov_importance_value # MR
|
||||
del Obj.pov_collect_photons # MR
|
||||
del Obj.pov_replacement_text # MR
|
||||
del Cam.pov_dof_enable # MR
|
||||
del Cam.pov_dof_aperture # MR
|
||||
del Cam.pov_dof_samples_min # MR
|
||||
del Cam.pov_dof_samples_max # MR
|
||||
del Cam.pov_dof_variance # MR
|
||||
del Cam.pov_dof_confidence # MR
|
||||
del Cam.pov_replacement_text # MR
|
||||
del Text.pov_custom_code # MR
|
||||
del Scene.pov_radio_pretrace_start
|
||||
del Scene.pov_radio_pretrace_end
|
||||
del Scene.pov_media_enable
|
||||
del Scene.pov_media_samples
|
||||
del Scene.pov_media_color
|
||||
del Scene.pov_baking_enable
|
||||
del Scene.pov_max_trace_level
|
||||
del Scene.pov_photon_spacing
|
||||
del Scene.pov_photon_max_trace_level
|
||||
del Scene.pov_photon_adc_bailout
|
||||
del Scene.pov_photon_gather_min
|
||||
del Scene.pov_photon_gather_max
|
||||
del Scene.pov_antialias_enable
|
||||
del Scene.pov_antialias_method
|
||||
del Scene.pov_antialias_depth
|
||||
del Scene.pov_antialias_threshold
|
||||
del Scene.pov_antialias_gamma
|
||||
del Scene.pov_jitter_enable
|
||||
del Scene.pov_jitter_amount
|
||||
del Scene.pov_command_line_switches
|
||||
del Scene.pov_indentation_character
|
||||
del Scene.pov_indentation_spaces
|
||||
del Scene.pov_comments_enable
|
||||
del Mat.pov_irid_enable
|
||||
del Mat.pov_mirror_use_IOR
|
||||
del Mat.pov_mirror_metallic
|
||||
del Mat.pov_conserve_energy
|
||||
del Mat.pov_irid_amount
|
||||
del Mat.pov_irid_thickness
|
||||
del Mat.pov_irid_turbulence
|
||||
del Mat.pov_interior_fade_color
|
||||
del Mat.pov_caustics_enable
|
||||
del Mat.pov_fake_caustics
|
||||
del Mat.pov_fake_caustics_power
|
||||
del Mat.pov_photons_refraction
|
||||
del Mat.pov_photons_dispersion
|
||||
del Mat.pov_photons_reflection
|
||||
del Mat.pov_refraction_type
|
||||
del Mat.pov_replacement_text
|
||||
del Tex.pov_tex_gamma_enable
|
||||
del Tex.pov_tex_gamma_value
|
||||
del Tex.pov_replacement_text
|
||||
del Obj.pov_importance_value
|
||||
del Obj.pov_collect_photons
|
||||
del Obj.pov_replacement_text
|
||||
del Cam.pov_dof_enable
|
||||
del Cam.pov_dof_aperture
|
||||
del Cam.pov_dof_samples_min
|
||||
del Cam.pov_dof_samples_max
|
||||
del Cam.pov_dof_variance
|
||||
del Cam.pov_dof_confidence
|
||||
del Cam.pov_replacement_text
|
||||
del Text.pov_custom_code
|
||||
|
|
Loading…
Reference in New Issue