Skip to content

Commit

Permalink
Tag test
Browse files Browse the repository at this point in the history
  • Loading branch information
FConstans committed May 6, 2022
1 parent 29ece0d commit 61c05b8
Show file tree
Hide file tree
Showing 6 changed files with 149 additions and 57 deletions.
4 changes: 2 additions & 2 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,9 @@ jobs:
- name: Checkout
uses: actions/checkout@v2
- name: Build
run: zip -r repositioning.zip repositioning
run: zip -r repositioning-${{github.ref_name}}.zip repositioning
- name: Release
uses: softprops/action-gh-release@v1
if: startsWith(github.ref, 'refs/tags/')
with:
files: repositioning.zip
files: repositioning-${{github.ref_name}}.zip
60 changes: 39 additions & 21 deletions repositioning/__init__.py
Original file line number Diff line number Diff line change
@@ -1,29 +1,10 @@
from . import add_plane, main_panel, manage_textures, evaluate_shadow
import bpy

# ------------------------------------------------------------------------------------------------------------------------------------------
# ------------------------------------------------------------------------------------------------------------------------------------------
# We will be using RMSE coming from the Sewar package, to evaluate the obtained renders
# Because the version of python that bpy use is "isolated" in Blender, we have to make sure the package is installed inside of Blender:

import subprocess
import sys
import os
from pathlib import Path

py_exec = str(sys.executable)
# Get lib directory
lib = os.path.join(Path(py_exec).parent.parent, "lib")
# Ensure pip is installed
subprocess.call([py_exec, "-m", "ensurepip", "--user"])
# Update pip (not mandatory)
subprocess.call([py_exec, "-m", "pip", "install", "--upgrade", "pip"])
# Install packages
subprocess.call([py_exec, "-m", "pip", "install",
f"--target={str(lib)}", "sewar"])
import bpy

# ------------------------------------------------------------------------------------------------------------------------------------------
# ------------------------------------------------------------------------------------------------------------------------------------------

bl_info = {
"name": "Set a shadow baking environment",
"author": "Florence Constans",
Expand All @@ -35,20 +16,57 @@
"doc_url": "",
"category": "All",
}
# ------------------------------------------------------------------------------------------------------------------------------------------
# ------------------------------------------------------------------------------------------------------------------------------------------

import subprocess
import sys
import os
import importlib
from pathlib import Path


# We will be using RMSE coming from the Sewar package, to evaluate the obtained renders
# Because the version of python that bpy use is "isolated" in Blender, we have to make sure the package is installed inside of Blender:


if not importlib.util.find_spec("sewar"):

py_exec = str(sys.executable)

# # Get lib directory
lib = os.path.join(Path(py_exec).parent.parent, "lib")
# # Ensure pip is installed
# #subprocess.check_call([py_exec, "-m", "ensurepip", "--user"])
# # Update pip (not mandatory)
# #subprocess.check_call([py_exec, "-m", "pip", "install", "--upgrade", "pip"])
# # Install packages
subprocess.check_call([py_exec, '-m', 'pip', 'install',f"--target={str(lib)}", 'sewar'])
else :
print("Sewar already installed")

# ------------------------------------------------------------------------------------------------------------------------------------------
# ------------------------------------------------------------------------------------------------------------------------------------------

from . import add_plane, main_panel, manage_textures, evaluate_shadow, rotate_target



def register():

main_panel.register()
add_plane.register()
manage_textures.register()
evaluate_shadow.register()
rotate_target.register()


def unregister():
main_panel.unregister()
add_plane.unregister()
manage_textures.unregister()
evaluate_shadow.unregister()
rotate_target.unregister()


if __name__ == "__main__":
Expand Down
20 changes: 10 additions & 10 deletions repositioning/evaluate_shadow.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,31 +2,31 @@
import bpy


import sewar
import numpy
import PIL
from sewar.full_ref import rmse
from numpy import asarray
from PIL import Image

from . manage_textures import bake_shadow, save_image


def compare_textures():
object = bpy.context.active_object
object_material = bpy.data.materials[object.name]
object_material = bpy.data.materials[object.name_full]

ref_name = object.name+"_"+"ref_image"
shad_name = object.name+"_"+"shadow_image"
ref_name = object.name_full+"_"+"ref_image"
shad_name = object.name_full+"_"+"shadow_image"

if ref_name in bpy.data.materials[object.name].node_tree.nodes:
if ref_name in bpy.data.materials[object.name_full].node_tree.nodes:

save_image(object_material.node_tree.nodes[ref_name])
save_image(bake_shadow())

ref_image = numpy.asarray(PIL.Image.open(
ref_image = asarray(Image.open(
bpy.app.tempdir + ref_name+".png"))
shad_image = numpy.asarray(PIL.Image.open(
shad_image = asarray(Image.open(
bpy.app.tempdir + shad_name+".png"))

result = sewar.full_ref.rmse(ref_image, shad_image)
result = rmse(ref_image, shad_image)
return(result)
else:
return("Please, set a reference")
Expand Down
24 changes: 16 additions & 8 deletions repositioning/main_panel.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,17 @@ def draw(self, context):
box = layout.box()
box.label(text="Manage textures")

ref_node = obj.name+"_"+"ref_image"
shad_node = obj.name+"_"+"shadow_image"
ref_node = obj.name_full+"_"+"ref_image"
shad_node = obj.name_full+"_"+"shadow_image"

if obj.name not in bpy.data.materials:
result_box = layout.box()
result_box.label(text="Comparison actions")
result_box.operator(
'object.rotate_target', text='Select object as target').action = 'Select_target'
result_box.operator(
'object.rotate_target', text='Rotate targeted object').action = 'Rotate_object'

if obj.name_full not in bpy.data.materials:
box.operator('object.manage_textures',
text='Add baking dedicated material').action = 'Add_material'
else:
Expand All @@ -35,22 +42,23 @@ def draw(self, context):
save_box = box.box()
save_box.label(text="Save textures in temp")

if ref_node in bpy.data.materials[obj.name].node_tree.nodes:
if ref_node in bpy.data.materials[obj.name_full].node_tree.nodes:
tex_box.operator('object.manage_textures',
text='Draw on reference').action = 'Draw_reference'
save_box.operator('object.manage_textures',
text='Save drawn shadow').action = 'Save_reference'

if shad_node in bpy.data.materials[obj.name].node_tree.nodes:
if shad_node in bpy.data.materials[obj.name_full].node_tree.nodes:
save_box.operator('object.manage_textures',
text='Save baked shadow').action = 'Save_baked'
result_box = layout.box()
result_box.label(text="Compare")

result_box.operator('object.evaluate_shadow',
text='Compare shadows').action = 'Compare'
result_box.label(text="Comparison result")
score = result_box.box()
score.label(text=bpy.app.driver_namespace["shad_comparison"])
if "shad_comparison" in bpy.app.driver_namespace:
score.label(
text=bpy.app.driver_namespace["shad_comparison"])


def register():
Expand Down
35 changes: 19 additions & 16 deletions repositioning/manage_textures.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@

def add_object_material():
object = bpy.context.active_object
if object.name not in bpy.data.materials:
object_material = bpy.data.materials.new(object.name)
if object.name_full not in bpy.data.materials:
object_material = bpy.data.materials.new(object.name_full)
object_material.use_nodes = True # Mandatory for texture manipulation
object.data.materials.append(object_material)

Expand All @@ -18,23 +18,23 @@ def add_object_material():
bsdf.inputs['Base Color'], mix_node.outputs['Color'])

# A mix node to see both the baked texture and the drawn shadow at the same time
bpy.data.materials[object.name].node_tree.nodes["Mix"].inputs[0].default_value = 0.8
bpy.data.materials[object.name_full].node_tree.nodes["Mix"].inputs[0].default_value = 0.8

# Enable texture visibility in the ViewPort
if bpy.context.space_data.shading.type != 'MATERIAL':
bpy.context.space_data.shading.type = 'MATERIAL'

else:
object_material = bpy.data.materials[object.name]
object_material = bpy.data.materials[object.name_full]
object.data.materials.append(object_material)


def new_blank_image(img_name="tex_image"):

object = bpy.context.active_object
name = object.name+"_"+img_name
name = object.name_full+"_"+img_name

object_material = bpy.data.materials[object.name]
object_material = bpy.data.materials[object.name_full]

if name not in object_material.node_tree.nodes:
image = object_material.node_tree.nodes.new('ShaderNodeTexImage')
Expand All @@ -53,7 +53,7 @@ def new_blank_image(img_name="tex_image"):
# Image on which targeted shadow can be drawn
def new_reference_image(name="ref_image"):
object = bpy.context.active_object
object_material = bpy.data.materials[object.name]
object_material = bpy.data.materials[object.name_full]

reference_image = new_blank_image(name)

Expand All @@ -68,16 +68,18 @@ def new_reference_image(name="ref_image"):

# Save image from a node in temp directory of Blender
def save_image(node):
bpy.data.images[node.image.name].filepath_raw = bpy.app.tempdir + \
node.image.name+".png"
bpy.data.images[node.image.name].file_format = 'PNG'
bpy.data.images[node.image.name].save()
bpy.data.images[node.image.name_full].filepath_raw = bpy.app.tempdir + \
node.image.name_full+".png"
bpy.data.images[node.image.name_full].file_format = 'PNG'
bpy.data.images[node.image.name_full].save()


def bake_shadow():

global baked_image

object = bpy.context.active_object
object_material = bpy.data.materials[object.name]
object_material = bpy.data.materials[object.name_full]

blank_base = new_blank_image("blank")

Expand All @@ -86,7 +88,8 @@ def bake_shadow():
bsdf.inputs['Base Color'], blank_base.outputs['Color'])

baked_image = new_blank_image("shadow_image")
object_material.node_tree.nodes.active = object_material.node_tree.nodes[baked_image.name]
object_material.node_tree.nodes.active = object_material.node_tree.nodes[
baked_image.name]
bpy.context.scene.render.engine = 'CYCLES'
bpy.context.scene.cycles.preview_samples = 1
bpy.context.scene.cycles.samples = 1
Expand All @@ -107,13 +110,13 @@ def bake_shadow():

def draw_on_ref():
object = bpy.context.active_object
object_material = bpy.data.materials[object.name]
object_material = bpy.data.materials[object.name_full]

bpy.context.window.workspace = bpy.data.workspaces['Texture Paint']

# Image dedicated to reference drawing automatically selected back so that the baking texture won't be drawn on
object_material.node_tree.nodes.active = object_material.node_tree.nodes[
object.name+"_ref_image"]
object.name_full+"_ref_image"]


class OBJECT_OT_manage_textures(bpy.types.Operator):
Expand Down Expand Up @@ -155,7 +158,7 @@ def execute(self, context):
elif self.action == 'Reference_texture':
reference_image = new_reference_image()
elif self.action == 'Baking_texture':
baked_image = bake_shadow()
bake_shadow()
elif self.action == 'Save_reference':
save_image(reference_image)
elif self.action == 'Save_baked':
Expand Down
63 changes: 63 additions & 0 deletions repositioning/rotate_target.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@

import bpy

from math import radians
from sewar.full_ref import rmse
from numpy import asarray
from PIL import Image

from . manage_textures import bake_shadow, save_image
from . evaluate_shadow import compare_textures

global target
target = None

# This operator enable the user to chose an object as a target, then go back to select the object on which the target's shadow should be baked.
# It then gives an option to rotate the target object on the Z axis, accordingly to the shadow we expect to cast


def select_target_object():
return (bpy.context.active_object)


def rotate_object(target):
target.rotation_euler[2] += radians(10)
return("Rotation of target")


class OBJECT_OT_rotate_target(bpy.types.Operator):
bl_idname = "object.rotate_target"
bl_label = "Add materials and textures to a mesh"
bl_description = "This operator rotates a selected object in accordance with its expected casted shadow"
bl_options = {'REGISTER', 'UNDO'}

action: bpy.props.EnumProperty(items=[
('Select_target', 'Select object as target',
'Set active object as target of positionning'),
('Rotate_object', 'Launch rotation', 'Launch target object rotation ')
], name="Target rotation")

def execute(self, context):

global target

if self.action == 'Select_target':
target = select_target_object()
elif self.action == 'Rotate_object':
if target != None:
bpy.app.driver_namespace["shad_comparison"] = rotate_object(
target)

return {'FINISHED'}


def register():
bpy.utils.register_class(OBJECT_OT_rotate_target)


def unregister():
bpy.utils.unregister_class(OBJECT_OT_rotate_target)


if __name__ == "__main__":
register()

0 comments on commit 61c05b8

Please sign in to comment.