33from typing import TYPE_CHECKING
44
55import bpy
6- # from "C:/Program Files/Blender Foundation/blender-3.0.0-alpha+master.2b64b4d90d67-windows.amd64-release/3.0/scripts/addons/fast_pbr_viewport_render/fileRenamer.py" import moveImages
7- import os
8- from . fileRenamer import *
9- import glob
6+
7+ import bpy
8+ import subprocess
9+ import sys
1010
1111bl_info = {
1212 "name" : "Fast PBR Viewport Render" ,
1313 "blender" : (3 , 00 , 0 ),
1414 "category" : "Object" ,
1515}
1616
17- pathToStoreImagesIn = "C:/FromFastPBR/"
1817
18+ # installPackage('PILLOW')
19+ # installPackage('numpy')
1920__name__ # This is the name of the folder that the __init__.py is in. I think
2021addonName : str = bl_info ["name" ]
2122addonNameShort : str = "Fast PBR"
2223
24+ import importlib
25+ def putTextInBox (text ):
26+ lines = text .splitlines ()
27+ width = max (len (s ) for s in lines )
28+ res = ['┌' + '─' * width + '┐' ]
29+ for s in lines :
30+ res .append ('│' + (s + ' ' * width )[:width ] + '│' )
31+ res .append ('└' + '─' * width + '┘' )
32+ return '\n ' .join (res )
33+ def installPackage (package : str ):
34+ subprocess .check_call ([sys .executable , "-m" , "pip" , "install" , package ])
35+
36+ # Running installPackage is a slow operation, therefore we want to make sure that we only run it when necessary, hence this function to speed up registration/activation time of the addon SIGNIFICANTLY (like by 5-10 seconds).
37+ def attemptToImportModuleAndInstallItIfItIfTheCorespondingPackageDoesntExist (packageName , moduleName ):
38+ print ("Attempting" )
39+ try :
40+ importlib .import_module (moduleName )
41+ # from PIL import Image
42+ except Exception as error :
43+ print (putTextInBox (f"{ addonName } Error: ---\n { error } \n ---\n when attempting to import { moduleName } , we're assuming that you dont have { packageName } installed and will try to install it for you!" ))
44+ installPackage (packageName )
45+ importlib .import_module (moduleName ) # Doesnt actually work?
46+ ListOfModulesToAttemptToImportAndInstallItIfItIfTheCorespondingPackageDoesntExist = [['PILLOW' , 'PIL' ], ['numpy' ]]
47+ attemptToImportModuleAndInstallItIfItIfTheCorespondingPackageDoesntExist ('PILLOW' , 'PIL' )
48+ import PIL
49+ attemptToImportModuleAndInstallItIfItIfTheCorespondingPackageDoesntExist ('numpy' , 'numpy' )
50+ import numpy
51+ # import pi
52+ # attemptToImportModuleAndInstallItIfItIfTheCorespondingPackageDoesntExist('PILLOW', 'PIL')
53+ # attemptToImportModuleAndInstallItIfItIfTheCorespondingPackageDoesntExist('numpy', 'numpy')
54+ # from PIL import Images
55+ # if TYPE_CHECKING: # Importing packages just for intellisense as our import function wont run through VS Codes intellisense engine.
56+
57+ # import numpy
58+ # print(help(numpy))
59+
60+
61+ # materialToReplaceTo = ""
62+ # materialToReplaceFrom = ""
63+
64+ # bpy.ops.ed.undo_push()
65+
66+ # for object in bpy.context.scene.objects:
67+ # object: bpy.types.Object
68+ # for materialSlot in object.material_slots:
69+ # materialSlot: bpy.types.MaterialSlot
70+ # if materialSlot.material.name_full == materialToReplaceFrom:
71+ # materialSlot.material = bpy.data.materials.get(materialToReplaceTo)
72+
73+
74+
75+ # from "C:/Program Files/Blender Foundation/blender-3.0.0-alpha+master.2b64b4d90d67-windows.amd64-release/3.0/scripts/addons/fast_pbr_viewport_render/fileRenamer.py" import moveImages
76+ import os
77+ from .fileRenamer import *
78+ import glob
79+
80+
81+ pathToStoreImagesIn = "C:/FromFastPBR/"
82+
83+
84+
2385
2486
2587classesToRegister = list ()
3395disableRestore = True # Set to true for debugging
3496
3597# addonNameShort = "Fast PBR"
36-
98+ import pathlib
99+ pathToAddonDirectory = str (pathlib .Path (__file__ ).parent .resolve ())
100+ nameOfAssetsFileWithoutPath = 'FastPBRAssets.blend'
101+ pathToAssetsFile = pathToAddonDirectory + '/' + nameOfAssetsFileWithoutPath
102+ #
37103
38104#############################
39105##### Utility functions #####
40106#############################
41107# @bookmark Utility functions
108+ def appendAssetFromAssetsBlendFile (dataBlockToAppend : str , blendFileDataCategory : str ):
109+ """
110+ dataBlockToAppend is the name of the object/material/whatever you want to append.
111+ blendFileDataCategory is the type of data you want to append, if you go into the outliner > display mode > Data API you will see all these categories. Example values: "Material", "Object", "Node Groups" (etc). For some reason, the "s" at the end of some categories displayed in that list is not supposed to be included, which is rather confusing :)
112+ """
113+ bpy .ops .wm .append (filename = dataBlockToAppend , directory = pathToAssetsFile + '\\ ' + blendFileDataCategory + '\\ ' )
114+
115+ print ("filepath:" , nameOfAssetsFileWithoutPath )
116+ print ("directory:" , pathToAssetsFile + '\\ ' + blendFileDataCategory )
117+ print ("filename:" , dataBlockToAppend )
42118
43119def containsLowerCase (string ):
44120 # string: str = ""
@@ -92,14 +168,6 @@ def insertSpaceAfterCapital(string):
92168 return outputString
93169
94170
95- def putTextInBox (text ):
96- lines = text .splitlines ()
97- width = max (len (s ) for s in lines )
98- res = ['┌' + '─' * width + '┐' ]
99- for s in lines :
100- res .append ('│' + (s + ' ' * width )[:width ] + '│' )
101- res .append ('└' + '─' * width + '┘' )
102- return '\n ' .join (res )
103171
104172############################
105173# End of Utility functions #
@@ -1149,6 +1217,11 @@ def draw(cls, context):
11491217 # cls.layout.label(text=f"{cls.bl_label}First Sub Panel of Panel 1.")
11501218 # print("LOOK HERE ", f'{cls.settings.enable_pass=}'.split('=')[0].split('.')[-1])
11511219 cls .layout .prop (retrieveSettings (cls ), f'{ cls .settings .enable_pass = } ' .split ('=' )[0 ].split ('.' )[- 1 ])
1220+ cls .draw_pass_specific_ui_elements (context )
1221+
1222+
1223+ def draw_pass_specific_ui_elements (cls , context ):
1224+ pass
11521225
11531226 ##########
11541227 # UI END #
@@ -1193,7 +1266,8 @@ def save_to_disk(self):
11931266 # image.save_render(pathToStoreImagesIn, "test")
11941267 # image.filepath_raw = 'C:\FastPBRViewportRender'
11951268 # image.file_format = 'PNG'
1196- pathToStoreImageInIncludingFileNameAndFileExtension = 'C:/FastPBRViewportRender/'
1269+ # pathToStoreImageInIncludingFileNameAndFileExtension = 'C:/FastPBRViewportRender/'
1270+ pathToStoreImageInIncludingFileNameAndFileExtension = pathToStoreImagesIn
11971271 pathToStoreImageInIncludingFileNameAndFileExtension = pathToStoreImageInIncludingFileNameAndFileExtension + self .passName + ".png"
11981272 # bpy.context.scene.render.__format__
11991273 # image = bpy.data.images.new("Sprite", alpha=True, width=16, height=16)
@@ -1212,17 +1286,79 @@ def save_to_disk(self):
12121286 # bpy.ops.image.save_as(save_as_render=True, copy=True, filepath="//..\\..\\untitled321.png", relative_path=True, show_multiview=False, use_multiview=False)
12131287 # bpy.ops.image.
12141288
1289+ @classmethod
1290+ def perform_post_process (self ):
1291+ """Runs after save_to_disk"""
1292+ pass
12151293
12161294 @classmethod
12171295 def prepare_render_and_save (self ):
12181296 self .prepare_to_render ()
12191297 if retrieveSettingsUsing__name__insteadOfbl_idname (self ).enable_pass :
12201298 self .render ()
12211299 self .save_to_disk ()
1300+ self .perform_post_process ()
12221301
12231302# classesToRegister.append(classesToRegister.append(RenderPass))
12241303# @bookmark Normal pass
12251304
1305+
1306+ class RenderAppendedMaterialTypeRenderPass (RenderPass ): # A base class for render passes that are supposed to render a specific material only
1307+ f"""To use this class, assign the literal name of the material in our assets file that you want to render to the materialToRender variable.
1308+
1309+ Children of this class are typically found towards the bottom of the render pass section as its rendered in Eeevee."""
1310+
1311+ materialToRender = 'FastPBRNormal'
1312+ """This is the literal name of the material in our assets file that you want to render!"""
1313+
1314+ @classmethod
1315+ def prepare_to_render (self ):
1316+ bpy .context .space_data .shading .render_pass = 'DIFFUSE_COLOR'
1317+ bpy .context .scene .render .engine = 'BLENDER_EEVEE'
1318+ # bpy.context
1319+ # bpy.context.scene.render.engine = 'RENDER'
1320+ # Switch viewport view to rendered, rather than solid or wire or whatever.
1321+ bpy .context .space_data .shading .type = 'RENDERED'
1322+
1323+
1324+ print ("File path:" , pathlib .Path (__file__ ).parent .resolve ())
1325+
1326+ if bpy .data .materials .find (self .materialToRender ) < 0 :
1327+ appendAssetFromAssetsBlendFile (self .materialToRender , 'Material' )
1328+ for object in bpy .data .objects :
1329+ object : bpy .types .Object
1330+ for materialSlot in object .material_slots :
1331+ materialSlot : bpy .types .MaterialSlot
1332+ # materialSlot.link = 'FastPBRNormal'
1333+ materialSlot .material = bpy .data .materials .get (self .materialToRender )
1334+
1335+ @classmethod
1336+ def perform_post_process (self ):
1337+ pathToStoreImageInIncludingFileNameAndFileExtension = pathToStoreImagesIn
1338+ fileToPerformPostProcessOn = pathToStoreImageInIncludingFileNameAndFileExtension + self .passName + ".png"
1339+
1340+ print ("hello from post process" )
1341+ # from PIL import Image
1342+ # import numpy
1343+
1344+ im = Image .open (fileToPerformPostProcessOn )
1345+ im = im .convert ('RGBA' )
1346+
1347+ data = numpy .array (im ) # "data" is a height x width x 4 numpy array
1348+ red , green , blue , alpha = data .T # Temporarily unpack the bands for readability
1349+
1350+ # Replace white with red... (leaves alpha values alone...)
1351+ white_areas = (red < 3 ) & (blue < 3 ) & (green < 3 )
1352+ data [..., :- 1 ][white_areas .T ] = (128 , 128 , 255 ) # Transpose back needed
1353+ # white_areas = (red == 1) & (blue == 1) & (green == 1)
1354+ # data[..., :-1][white_areas.T] = (128, 128, 255) # Transpose back needed
1355+
1356+ im2 = Image .fromarray (data )
1357+ im2 = im2 .convert ('RGB' )
1358+ im2 .save (fileToPerformPostProcessOn )
1359+ im2 .show ()
1360+ print ("Second hello" )
1361+
12261362@renderPassDecorator
12271363class RenderNormalPassWithWorkbench (RenderPass ):
12281364 passName = "normal"
@@ -1420,6 +1556,13 @@ def prepare_to_render(self):
14201556 bpy .context .scene .display .shading .single_color = (999 , 999 , 999 )
14211557
14221558
1559+
1560+ @renderPassDecorator
1561+ class RenderNormalFromAppendedMaterial (RenderAppendedMaterialTypeRenderPass ):
1562+ passName = "normal"
1563+ materialToRender = 'FastPBRNormal'
1564+ def draw_pass_specific_ui_elements (cls , context ):
1565+ label_multiline (f"""Compared to rendering the normal pass with workbench, this pass has the advantage of that it totally ignores whether faces are pointing the wrong direction or not, they will always appear like as if they were pointing towards the camera, or a direction that has a maximum of a 90 degree angle from the camera. A downside of this pass is that it might not be able to replace the material of all objects if you have objects from other files linked in your blend.""" ,context ,cls .layout )
14231566
14241567
14251568###################################################################################
@@ -1481,6 +1624,8 @@ class FastPBRViewportRender(OperatorBaseClass):
14811624 # bl_label = "Fast PBR viewport render" # Display name in the interface.
14821625 # bl_options = {'REGISTER', 'UNDO'} # Enable undo for the operator.
14831626
1627+
1628+
14841629 def test (self ):
14851630 print ("wot" )
14861631 def execute (self , context ): # execute() is called when running the operator.
@@ -1494,6 +1639,53 @@ def execute(self, context): # execute() is called when running the operat
14941639 # renderNormalPassWithWorkbench.prepare_render_and_save()
14951640 BackupPrepareAndRestore .backupSettingsAndPrepareForRender ()
14961641
1642+ # bpy.ops.wm.append(
1643+ # filepath="cube.blend",
1644+ # directory="/home/lucas/Desktop/cube.blend\\Object\\",
1645+ # filename="Cube")
1646+
1647+ ##################################################
1648+ # import pathlib
1649+ # pathToAddonDirectory = str(pathlib.Path(__file__).parent.resolve())
1650+ # nameOfAssetsFileWithoutPath = 'FastPBRAssets.blend'
1651+ # pathToAssetsFile = pathToAddonDirectory + '/' + nameOfAssetsFileWithoutPath
1652+ # #
1653+ # def appendAssetFromAssetsBlendFile(dataBlockToAppend: str, blendFileDataCategory: str):
1654+ # """
1655+ # dataBlockToAppend is the name of the object/material/whatever you want to append.
1656+
1657+ # blendFileDataCategory is the type of data you want to append, if you go into the outliner > display mode > Data API you will see all these categories. Example values: "Material", "Object", "Node Groups" (etc). For some reason, the "s" at the end of some categories displayed in that list is not supposed to be included, which is rather confusing :)
1658+ # """
1659+ # bpy.ops.wm.append(filename=dataBlockToAppend, directory=pathToAssetsFile + '\\' + blendFileDataCategory + '\\')
1660+
1661+ # print("filepath:", nameOfAssetsFileWithoutPath)
1662+ # print("directory:", pathToAssetsFile + '\\' + blendFileDataCategory)
1663+ # print("filename:", dataBlockToAppend)
1664+
1665+ # pathToNormalAssetsFile = pathToAddonDirectory + '/' + 'FastPBRAssets.blend'
1666+ # print("File path:", pathlib.Path(__file__).parent.resolve())
1667+
1668+ # if bpy.data.materials.find('FastPBRNormal') < 0:
1669+ # appendAssetFromAssetsBlendFile('FastPBRNormal', 'Material')
1670+ # for object in bpy.data.objects:
1671+ # object: bpy.types.Object
1672+ # for materialSlot in object.material_slots:
1673+ # materialSlot: bpy.types.MaterialSlot
1674+ # # materialSlot.link = 'FastPBRNormal'
1675+ # materialSlot.material = bpy.data.materials.get('FastPBRNormal')
1676+ # materialSlot
1677+ ################################################
1678+
1679+ # print("File path:", pathlib.Path(__file__).parent.resolve())
1680+ # bpy.ops.wm.append(
1681+ # filepath="cube.blend",
1682+ # directory=pathToAssetsFile,
1683+ # filename="Cube")
1684+ # bpy.ops.wm.append(
1685+ # filepath="cube.blend",
1686+ # directory="C:/Program Files/Blender Foundation/blender-3.0.0-alpha+master.2b64b4d90d67-windows.amd64-release/3.0/scripts/addons/fast_pbr_viewport_render/FastPBRAssets.blend\\Object",
1687+ # filename="Cube")
1688+ # return {'FINISHED'}
14971689
14981690 # print("IMPORTANTEEE" + getGlobalAddonProperties().target_directory)
14991691
0 commit comments