Skip to content

Commit

Permalink
Release v0.1.0 (#551)
Browse files Browse the repository at this point in the history
* Bump version to 0.1.0

* export prompt fix (#552)

* Force face selection mode (#553)

* Force face selection mode

* Add validation

* Move history to scene

* Update advanced presets

* Fix depth model check

* Review changes

---------

Co-authored-by: NullSenseStudio <[email protected]>
  • Loading branch information
carson-katri and NullSenseStudio authored Feb 15, 2023
1 parent c3f3a37 commit 057d780
Show file tree
Hide file tree
Showing 18 changed files with 160 additions and 96 deletions.
8 changes: 4 additions & 4 deletions __init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
"author": "Dream Textures contributors",
"description": "Use Stable Diffusion to generate unique textures straight from the shader editor.",
"blender": (3, 1, 0),
"version": (0, 0, 9),
"version": (0, 1, 0),
"location": "Image Editor -> Sidebar -> Dream",
"category": "Paint"
}
Expand Down Expand Up @@ -65,10 +65,10 @@ def register():

bpy.types.Scene.dream_textures_requirements_path = EnumProperty(name="Platform", items=requirements_path_items, description="Specifies which set of dependencies to install", default='requirements/mac-mps-cpu.txt' if sys.platform == 'darwin' else 'requirements/win-linux-cuda.txt')

StableDiffusionPreferences.__annotations__['history'] = CollectionProperty(type=DreamPrompt)

for cls in PREFERENCE_CLASSES:
bpy.utils.register_class(cls)

bpy.types.Scene.dream_textures_history = CollectionProperty(type=DreamPrompt)

check_for_updates()

Expand All @@ -79,7 +79,7 @@ def register():
bpy.types.Scene.init_depth = PointerProperty(name="Init Depth", type=bpy.types.Image, description="Use an existing depth map. Leave blank to generate one from the init image")
bpy.types.Scene.seamless_result = PointerProperty(type=SeamlessResult)
def get_selection_preview(self):
history = bpy.context.preferences.addons[StableDiffusionPreferences.bl_idname].preferences.history
history = bpy.context.scene.dream_textures_history
if self.dream_textures_history_selection > 0 and self.dream_textures_history_selection < len(history):
return history[self.dream_textures_history_selection].generate_prompt()
return ""
Expand Down
21 changes: 15 additions & 6 deletions builtin_presets/Debug.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,19 @@
import bpy
prompt = bpy.context.scene.dream_textures_prompt

prompt.precision = 'auto'
prompt.random_seed = True
prompt.seed = '0'
prompt.steps = 25
prompt.steps = 20
prompt.cfg_scale = 7.5
prompt.sampler_name = 'k_lms'
prompt.show_steps = True
prompt.scheduler = 'DPM Solver Multistep'
prompt.step_preview_mode = 'Accurate'
prompt.optimizations_attention_slicing = True
prompt.optimizations_attention_slice_size_src = 'auto'
prompt.optimizations_attention_slice_size = 1
prompt.optimizations_cudnn_benchmark = False
prompt.optimizations_tf32 = False
prompt.optimizations_amp = False
prompt.optimizations_half_precision = True
prompt.optimizations_sequential_cpu_offload = False
prompt.optimizations_channels_last_memory_format = False
prompt.optimizations_batch_size = 1
prompt.optimizations_vae_slicing = True
prompt.optimizations_cpu_only = False
19 changes: 14 additions & 5 deletions builtin_presets/Final.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,19 @@
import bpy
prompt = bpy.context.scene.dream_textures_prompt

prompt.precision = 'auto'
prompt.random_seed = True
prompt.seed = '0'
prompt.steps = 50
prompt.cfg_scale = 7.5
prompt.sampler_name = 'k_lms'
prompt.show_steps = False
prompt.scheduler = 'DPM Solver Multistep'
prompt.step_preview_mode = 'Fast'
prompt.optimizations_attention_slicing = True
prompt.optimizations_attention_slice_size_src = 'auto'
prompt.optimizations_attention_slice_size = 1
prompt.optimizations_cudnn_benchmark = False
prompt.optimizations_tf32 = False
prompt.optimizations_amp = False
prompt.optimizations_half_precision = True
prompt.optimizations_sequential_cpu_offload = False
prompt.optimizations_channels_last_memory_format = False
prompt.optimizations_batch_size = 1
prompt.optimizations_vae_slicing = True
prompt.optimizations_cpu_only = False
21 changes: 15 additions & 6 deletions builtin_presets/Preview.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,19 @@
import bpy
prompt = bpy.context.scene.dream_textures_prompt

prompt.precision = 'auto'
prompt.random_seed = True
prompt.seed = '0'
prompt.steps = 25
prompt.steps = 20
prompt.cfg_scale = 7.5
prompt.sampler_name = 'k_lms'
prompt.show_steps = False
prompt.scheduler = 'DPM Solver Multistep'
prompt.step_preview_mode = 'Fast'
prompt.optimizations_attention_slicing = True
prompt.optimizations_attention_slice_size_src = 'auto'
prompt.optimizations_attention_slice_size = 1
prompt.optimizations_cudnn_benchmark = False
prompt.optimizations_tf32 = False
prompt.optimizations_amp = False
prompt.optimizations_half_precision = True
prompt.optimizations_sequential_cpu_offload = False
prompt.optimizations_channels_last_memory_format = False
prompt.optimizations_batch_size = 1
prompt.optimizations_vae_slicing = True
prompt.optimizations_cpu_only = False
10 changes: 10 additions & 0 deletions generator_process/actions/prompt_to_image.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
import enum
import math
import os
import sys
from dataclasses import dataclass
from contextlib import nullcontext

Expand Down Expand Up @@ -155,6 +156,15 @@ class Optimizations:

cpu_only: bool = False

@staticmethod
def infer_device() -> str:
if sys.platform == "darwin":
return "mps"
elif Pipeline.directml_available():
return "privateuseone"
else:
return "cuda"

def can_use(self, property, device) -> bool:
if not getattr(self, property):
return False
Expand Down
4 changes: 2 additions & 2 deletions operators/dream_texture.py
Original file line number Diff line number Diff line change
Expand Up @@ -133,7 +133,7 @@ def done_callback(future):
image_hash = hashlib.sha256((np.array(image.pixels) * 255).tobytes()).hexdigest()
image['dream_textures_hash'] = image_hash
scene.dream_textures_prompt.hash = image_hash
history_entry = context.preferences.addons[StableDiffusionPreferences.bl_idname].preferences.history.add()
history_entry = context.scene.dream_textures_history.add()
for key, value in history_template.items():
setattr(history_entry, key, value)
history_entry.seed = str(seed)
Expand Down Expand Up @@ -174,7 +174,7 @@ def generate_next():
match generated_args['init_img_action']:
case 'modify':
models = list(filter(
lambda m: m.model == generated_args['model'],
lambda m: m.model_base == generated_args['model'],
context.preferences.addons[StableDiffusionPreferences.bl_idname].preferences.installed_models
))
supports_depth = generated_args['pipeline'].depth() and len(models) > 0 and ModelType[models[0].model_type] == ModelType.DEPTH
Expand Down
3 changes: 1 addition & 2 deletions operators/open_latest_version.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import requests
import json
import bpy
import webbrowser
from ..version import VERSION, version_tag, version_tuple
Expand Down Expand Up @@ -34,7 +33,7 @@ class OpenLatestVersion(bpy.types.Operator):
bl_options = {"REGISTER", "INTERNAL"}

@classmethod
def poll(self, context):
def poll(cls, context):
return True

def execute(self, context):
Expand Down
53 changes: 45 additions & 8 deletions operators/project.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,43 @@
('color', 'Depth and Color', 'Provide the scene depth and color as input'),
]

def _validate_projection(context):
if len(context.selected_objects) == 0:
def fix_selection(context, layout):
if context.object.mode != 'OBJECT':
layout.operator("object.mode_set", text="Switch to Object Mode", icon="OBJECT_DATAMODE").mode = 'OBJECT'
layout.operator("object.select_by_type", text="Select All Meshes", icon="RESTRICT_SELECT_OFF").type = 'MESH'
raise FixItError(
"""No objects selected
Select at least one object to project onto.""",
fix_selection
)
if context.object is not None and context.object.mode != 'EDIT':
def fix_mode(_, layout):
layout.operator("object.mode_set", text="Switch to Edit Mode", icon="EDITMODE_HLT").mode = 'EDIT'
raise FixItError(
"""Enter edit mode
In edit mode, select the faces to project onto.""",
fix_mode
)
has_selection = False
for obj in context.selected_objects:
if not hasattr(obj, "data"):
continue
mesh = bmesh.from_edit_mesh(obj.data)
bm = mesh.copy()
bm.select_mode = {'FACE'}
for f in bm.faces:
if f.select:
has_selection = True
break
if not has_selection:
raise FixItError(
"""No faces selected.
Select at least one face to project onto.""",
lambda ctx, layout: None
)

def dream_texture_projection_panels():
class DREAM_PT_dream_panel_projection(bpy.types.Panel):
"""Creates a Dream Textures panel for projection"""
Expand All @@ -51,15 +88,16 @@ def draw(self, context):
layout = self.layout
layout.use_property_split = True
layout.use_property_decorate = False

if is_force_show_download():
layout.operator(OpenLatestVersion.bl_idname, icon="IMPORT", text="Download Latest Release")
elif new_version_available():
layout.operator(OpenLatestVersion.bl_idname, icon="IMPORT")

layout.prop(context.scene.dream_textures_project_prompt, "pipeline")
if Pipeline[context.scene.dream_textures_project_prompt.pipeline].model():
layout.prop(context.scene.dream_textures_project_prompt, 'model')

if is_force_show_download():
layout.operator(OpenLatestVersion.bl_idname, icon="IMPORT", text="Download Latest Release")
elif new_version_available():
layout.operator(OpenLatestVersion.bl_idname, icon="IMPORT")

yield DREAM_PT_dream_panel_projection

Expand Down Expand Up @@ -101,10 +139,6 @@ def draw(self, context):
r = row.row()
r.operator(ProjectDreamTexture.bl_idname, icon="MOD_UVPROJECT")
r.enabled = Pipeline[context.scene.dream_textures_project_prompt.pipeline].depth() and context.object is not None and context.object.mode == 'EDIT'
if context.object is not None and context.object.mode != 'EDIT':
box = layout.box()
box.label(text="Enter Edit Mode", icon="ERROR")
box.label(text="In edit mode, select the faces to project onto.")
else:
disabled_row = row.row()
disabled_row.use_property_split = True
Expand All @@ -117,6 +151,7 @@ def draw(self, context):
# Validation
try:
prompt.validate(context, task=ModelType.DEPTH)
_validate_projection(context)
except FixItError as e:
error_box = layout.box()
error_box.use_property_split = False
Expand Down Expand Up @@ -224,6 +259,7 @@ class ProjectDreamTexture(bpy.types.Operator):
def poll(cls, context):
try:
context.scene.dream_textures_project_prompt.validate(context, task=ModelType.DEPTH)
_validate_projection(context)
except:
return False
return Generator.shared().can_use()
Expand Down Expand Up @@ -313,6 +349,7 @@ def vert_to_uv(v):
uv_layer, uv_layer_index = ProjectDreamTexture.get_uv_layer(mesh)

bm = mesh.copy()
bm.select_mode = {'FACE'}
bmesh.ops.split_edges(bm, edges=bm.edges)
bmesh.ops.delete(bm, geom=[f for f in bm.faces if not f.select], context='FACES')
target_objects.append((bm, bm.loops.layers.uv[uv_layer_index]))
Expand Down
39 changes: 16 additions & 23 deletions operators/view_history.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,24 +2,17 @@
from bpy_extras.io_utils import ImportHelper, ExportHelper
import json
import os
from ..property_groups.dream_prompt import scheduler_options
from ..property_groups.dream_prompt import DreamPrompt, scheduler_options
from ..preferences import StableDiffusionPreferences

class SCENE_UL_HistoryList(bpy.types.UIList):
def draw_item(self, context, layout, data, item, icon, active_data, active_propname):
if self.layout_type in {'DEFAULT', 'COMPACT'}:
if item.prompt_structure_token_subject == "SCENE_UL_HistoryList_header":
layout.label(text="Subject")
layout.label(text="Seed")
layout.label(text="Size")
layout.label(text="Steps")
layout.label(text="Sampler")
else:
layout.label(text=item.get_prompt_subject(), translate=False, icon_value=icon)
layout.label(text=f"{item.seed}", translate=False)
layout.label(text=f"{item.width}x{item.height}", translate=False)
layout.label(text=f"{item.steps} steps", translate=False)
layout.label(text=next(x for x in scheduler_options if x[0] == item.scheduler)[1], translate=False)
layout.label(text=item.get_prompt_subject(), translate=False, icon_value=icon)
layout.label(text=f"{item.seed}", translate=False)
layout.label(text=f"{item.width}x{item.height}", translate=False)
layout.label(text=f"{item.steps} steps", translate=False)
layout.label(text=next(x for x in scheduler_options if x[0] == item.scheduler)[1], translate=False)
elif self.layout_type == 'GRID':
layout.alignment = 'CENTER'
layout.label(text="", icon_value=icon)
Expand All @@ -32,10 +25,10 @@ class RecallHistoryEntry(bpy.types.Operator):

@classmethod
def poll(self, context):
return context.scene.dream_textures_history_selection is not None and context.scene.dream_textures_history_selection > 0
return context.scene.dream_textures_history_selection is not None

def execute(self, context):
selection = context.preferences.addons[StableDiffusionPreferences.bl_idname].preferences.history[context.scene.dream_textures_history_selection]
selection = context.scene.dream_textures_history[context.scene.dream_textures_history_selection]
for prop in selection.__annotations__.keys():
if hasattr(context.scene.dream_textures_prompt, prop):
setattr(context.scene.dream_textures_prompt, prop, getattr(selection, prop))
Expand Down Expand Up @@ -64,7 +57,7 @@ class ClearHistory(bpy.types.Operator):
bl_options = {'REGISTER'}

def execute(self, context):
context.preferences.addons[StableDiffusionPreferences.bl_idname].preferences.history.clear()
context.scene.dream_textures_history.clear()

return {"FINISHED"}

Expand All @@ -76,10 +69,10 @@ class RemoveHistorySelection(bpy.types.Operator):

@classmethod
def poll(self, context):
return context.scene.dream_textures_history_selection is not None and context.scene.dream_textures_history_selection > 0
return context.scene.dream_textures_history_selection is not None

def execute(self, context):
context.preferences.addons[StableDiffusionPreferences.bl_idname].preferences.history.remove(context.scene.dream_textures_history_selection)
context.scene.dream_textures_history.remove(context.scene.dream_textures_history_selection)

return {"FINISHED"}

Expand All @@ -98,22 +91,22 @@ class ExportHistorySelection(bpy.types.Operator, ExportHelper):

@classmethod
def poll(self, context):
return context.scene.dream_textures_history_selection is not None and context.scene.dream_textures_history_selection > 0
return context.scene.dream_textures_history_selection is not None

def invoke(self, context, event):
selection = context.preferences.addons[StableDiffusionPreferences.bl_idname].preferences.history[context.scene.dream_textures_history_selection]
selection = context.scene.dream_textures_history[context.scene.dream_textures_history_selection]
self.filepath = "untitled" if selection is None else selection.get_prompt_subject()
context.window_manager.fileselect_add(self)
return {'RUNNING_MODAL'}

def execute(self, context):
selection = context.preferences.addons[StableDiffusionPreferences.bl_idname].preferences.history[context.scene.dream_textures_history_selection]
selection = context.scene.dream_textures_history[context.scene.dream_textures_history_selection]
if selection is None:
self.report({"ERROR"}, "No valid selection to export.")
return {"FINISHED"}
with open(self.filepath, 'w', encoding='utf-8') as target:
args = selection.generate_args()
args['seed'] = selection.seed
args = {key: getattr(selection, key) for key in DreamPrompt.__annotations__}
args["outpaint_origin"] = list(args["outpaint_origin"])
json.dump(args, target, indent=4)

return {"FINISHED"}
Expand Down
2 changes: 2 additions & 0 deletions preferences.py
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@ class Model(bpy.types.PropertyGroup):
bl_idname = "dream_textures.Model"

model: bpy.props.StringProperty(name="Model")
model_base: bpy.props.StringProperty()
downloads: bpy.props.IntProperty(name="Downloads")
likes: bpy.props.IntProperty(name="Likes")
model_type: bpy.props.EnumProperty(name="Model Type", items=[(t.name, t.name, '') for t in ModelType])
Expand Down Expand Up @@ -94,6 +95,7 @@ def set_model_list(model_list: str, models: list):
for model in models:
m = getattr(bpy.context.preferences.addons[__package__].preferences, model_list).add()
m.model = model.id
m.model_base = os.path.basename(model.id)
m.downloads = model.downloads
m.likes = model.likes
try:
Expand Down
Loading

0 comments on commit 057d780

Please sign in to comment.