Skip to content

Instantly share code, notes, and snippets.

@coderofsalvation
Created October 9, 2025 11:38
Show Gist options
  • Save coderofsalvation/d9454f43b684784c167665a1cd57bf38 to your computer and use it in GitHub Desktop.
Save coderofsalvation/d9454f43b684784c167665a1cd57bf38 to your computer and use it in GitHub Desktop.
--- Environmake_0_1.py 2025-10-09 13:32:40.008777308 +0200
+++ Environmake_0_2b.py 2025-10-09 13:37:06.365106968 +0200
@@ -1,8 +1,8 @@
bl_info = {
"name": "Environmake",
"author": "Albert Bozesan and GPT-4",
- "version": (0, 1),
- "blender": (3, 4, 1),
+ "version": (0, 2),
+ "blender": (4, 0, 0),
"location": "View3D > N Panel > Environmake",
"description": "Generate a 360 sphere with displacement from equirectangular textures!",
"warning": "",
@@ -119,7 +119,10 @@
override["area"] = area
override["region"] = region
bpy.ops.object.mode_set(mode='EDIT')
- bpy.ops.transform.vertex_warp(override, warp_angle=warp_angle, offset_angle=0.0, min=-1.0, max=1.0, center=center)
+ if bpy.app.version < (4, 0, 0):
+ bpy.ops.transform.vertex_warp(override, warp_angle=warp_angle, offset_angle=0.0, min=-1.0, max=1.0, center=center)
+ else:
+ bpy.ops.transform.vertex_warp( warp_angle=warp_angle, offset_angle=0.0, min=-1.0, max=1.0, center=center)
break
# Create virtual set function
@@ -141,7 +144,8 @@
principled_bsdf.inputs["Base Color"].default_value = (0, 0, 0, 1)
# Set Specular to 0 and Roughness to 1
- principled_bsdf.inputs["Specular"].default_value = 0
+ specular_key = "Specular" if bpy.app.version < (4, 0, 0) else "Specular IOR Level"
+ principled_bsdf.inputs[specular_key].default_value = 0
principled_bsdf.inputs["Roughness"].default_value = 1
# Connect the tex_node.outputs["Color"] based on the shader mode
@@ -149,7 +153,8 @@
if environmake_props.shader_mode == "BASE_COLOR":
links.new(tex_node.outputs["Color"], principled_bsdf.inputs["Base Color"])
else: # "EMISSION" or otherwise
- links.new(tex_node.outputs["Color"], principled_bsdf.inputs["Emission"])
+ emission_key = "Emission" if bpy.app.version < (4, 0, 0) else "Emission Color"
+ links.new(tex_node.outputs["Color"], principled_bsdf.inputs[ emission_key ])
# Enable backface culling
mat.use_backface_culling = True
@@ -216,4 +221,4 @@
bpy.utils.unregister_class(ENVIRONMAKE_OT_open_help_page)
bl_info = {
"name": "Environmake",
"author": "Albert Bozesan and GPT-4",
"version": (0, 2),
"blender": (4, 0, 0),
"location": "View3D > N Panel > Environmake",
"description": "Generate a 360 sphere with displacement from equirectangular textures!",
"warning": "",
"doc_url": "",
"category": "3D View",
}
import bpy
import bmesh
import math
import mathutils
import webbrowser
class ENVIRONMAKE_OT_open_help_page(bpy.types.Operator):
bl_idname = "environmake.open_help_page"
bl_label = "How to use"
bl_options = {'REGISTER', 'UNDO'}
def execute(self, context):
url = "https://albertbozesan.com/environmake"
webbrowser.open(url)
return {'FINISHED'}
# Panel class with UI elements
class Environmake_PT_Panel(bpy.types.Panel):
bl_label = "Environmake"
bl_idname = "ENVIRONMAKE_PT_PANEL"
bl_space_type = "VIEW_3D"
bl_region_type = "UI"
bl_category = "Environmake"
def draw(self, context):
layout = self.layout
scene = context.scene
environmake_props = scene.environmake_props
layout.operator("environmake.open_help_page")
layout.label(text="Equirectangular Image")
layout.template_ID(environmake_props, "equirectangular_image", new="image.new", open="image.open")
layout.label(text="Depth Map")
layout.template_ID(environmake_props, "depth_map", new="image.new", open="image.open")
# Add the dropdown menu
layout.label(text="Shader Mode")
layout.prop(environmake_props, "shader_mode", text="")
# Create a row for buttons
row = layout.row()
# Add the "Generate" button to the row
row.operator("environmake.generate_virtual_set")
# layout.operator("environmake.generate_virtual_set")
# Operator class with main functionality
class Environmake_OT_GenerateVirtualSet(bpy.types.Operator):
bl_label = "Generate"
bl_idname = "environmake.generate_virtual_set"
def execute(self, context):
create_virtual_set(context)
return {'FINISHED'}
# Property group for image texture properties
class Environmake_Properties(bpy.types.PropertyGroup):
equirectangular_image: bpy.props.PointerProperty(type=bpy.types.Image)
depth_map: bpy.props.PointerProperty(type=bpy.types.Image)
shader_mode: bpy.props.EnumProperty(
name="Shader Mode",
items=[
("EMISSION", "Emission (no light influence)", "Emission mode"),
("BASE_COLOR", "Base Color (for relighting)", "Base Color mode")
],
default="EMISSION"
)
def set_viewport_preset(preset):
for area in bpy.context.screen.areas:
if area.type == 'VIEW_3D':
region = area.spaces[0].region_3d
if preset == 'front':
region.view_matrix = mathutils.Matrix((
( 1.0000, 0.0000, 0.0000, 0.0000),
( 0.0000, -0.0000, 1.0000, 0.0000),
(0.0000, -1.0000, 0.0000, 0.0000),
( 0.0000, 0.0000, 0.0000, 1.0000)
))
elif preset == 'back':
region.view_matrix = mathutils.Matrix((
( 1.0000, 0.0000, 0.0000, 0.0000),
( 0.0000, 0.0000, -1.0000, 0.0000),
(0.0000, -1.0000, 0.0000, 0.0000),
( 0.0000, 0.0000, 0.0000, 1.0000)
))
elif preset == 'right':
region.view_matrix = mathutils.Matrix((
(-0.0000, 1.0000, 0.0000, -0.0000),
( 0.0000, -0.0000, 1.0000, -1.0000),
( 1.0000, 0.0000, -0.0000, 1.0000),
( 0.0000, 0.0000, 0.0000, 1.0000)
))
region.view_perspective ='ORTHO'
def run_vertex_warp(warp_angle, center):
for area in bpy.context.screen.areas:
if area.type == "VIEW_3D":
for region in area.regions:
if region.type == "WINDOW":
override = bpy.context.copy()
override["area"] = area
override["region"] = region
bpy.ops.object.mode_set(mode='EDIT')
if bpy.app.version < (4, 0, 0):
bpy.ops.transform.vertex_warp(override, warp_angle=warp_angle, offset_angle=0.0, min=-1.0, max=1.0, center=center)
else:
bpy.ops.transform.vertex_warp( warp_angle=warp_angle, offset_angle=0.0, min=-1.0, max=1.0, center=center)
break
# Create virtual set function
def create_virtual_set(context):
# Create a new grid with 256 Subdivision X and 128 Subdivision Y
bpy.ops.mesh.primitive_grid_add(x_subdivisions=256, y_subdivisions=128, size=2)
grid = bpy.context.active_object
# Apply the first image texture as the base color of the grid's material
mat = bpy.data.materials.new(name="Environmake_Material")
mat.use_nodes = True
grid.data.materials.append(mat)
nodes = mat.node_tree.nodes
links = mat.node_tree.links
tex_node = nodes.new("ShaderNodeTexImage")
tex_node.image = context.scene.environmake_props.equirectangular_image
principled_bsdf = nodes.get("Principled BSDF")
principled_bsdf.inputs["Base Color"].default_value = (0, 0, 0, 1)
# Set Specular to 0 and Roughness to 1
specular_key = "Specular" if bpy.app.version < (4, 0, 0) else "Specular IOR Level"
principled_bsdf.inputs[specular_key].default_value = 0
principled_bsdf.inputs["Roughness"].default_value = 1
# Connect the tex_node.outputs["Color"] based on the shader mode
environmake_props = context.scene.environmake_props
if environmake_props.shader_mode == "BASE_COLOR":
links.new(tex_node.outputs["Color"], principled_bsdf.inputs["Base Color"])
else: # "EMISSION" or otherwise
emission_key = "Emission" if bpy.app.version < (4, 0, 0) else "Emission Color"
links.new(tex_node.outputs["Color"], principled_bsdf.inputs[ emission_key ])
# Enable backface culling
mat.use_backface_culling = True
# Enter edit mode
bpy.ops.object.mode_set(mode='EDIT')
# Enter edit mode, raise all vertices of the grid by 1 meter, and exit edit mode
bpy.ops.mesh.select_all(action="SELECT")
bpy.ops.transform.translate(value=(0, 0, 1))
def warp1():
run_vertex_warp(3.14159, (0, 0, 0))
set_viewport_preset('front')
bpy.app.timers.register(warp2, first_interval=0.1)
def close_edit_mode():
# Apply a displace modifier to the grid, with the second image texture, scale 0.5
bpy.ops.object.modifier_add(type="DISPLACE")
displace_mod = grid.modifiers["Displace"]
displace_mod.texture = bpy.data.textures.new("Displace_Texture", "IMAGE")
displace_mod.texture.image = context.scene.environmake_props.depth_map
displace_mod.strength = 0.5
# Change texture coordinates to UV
displace_mod.texture_coords = 'UV'
displace_mod.uv_layer = grid.data.uv_layers.active.name
bpy.ops.object.mode_set(mode="OBJECT")
# Apply shade smooth to the selected object
bpy.ops.object.shade_smooth()
# Create a new camera
bpy.ops.object.camera_add(location=(0, 0, 0), rotation=(math.radians(90), 0, 0))
camera = bpy.context.active_object
# Set focal length to 10
camera.data.lens = 10
# Set as the active camera
bpy.context.scene.camera = camera
def warp2():
run_vertex_warp(6.28318, (0, 0, 0))
# Merge by distance with default settings
bpy.ops.mesh.remove_doubles()
bpy.ops.mesh.flip_normals()
bpy.ops.transform.rotate(value=math.radians(-90), orient_axis='X')
bpy.app.timers.register(close_edit_mode, first_interval=0.1)
set_viewport_preset('right')
bpy.app.timers.register(warp1, first_interval=0.1)
def register():
bpy.utils.register_class(Environmake_Properties)
bpy.types.Scene.environmake_props = bpy.props.PointerProperty(type=Environmake_Properties)
bpy.utils.register_class(Environmake_PT_Panel)
bpy.utils.register_class(Environmake_OT_GenerateVirtualSet)
bpy.utils.register_class(ENVIRONMAKE_OT_open_help_page)
def unregister():
bpy.utils.unregister_class(Environmake_Properties)
del bpy.types.Scene.environmake_props
bpy.utils.unregister_class(Environmake_PT_Panel)
bpy.utils.unregister_class(Environmake_OT_GenerateVirtualSet)
bpy.utils.unregister_class(ENVIRONMAKE_OT_open_help_page)
if __name__ == "__main__":
register()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment