Skip to content

Instantly share code, notes, and snippets.

@CGArtPython
Created May 10, 2021 06:52
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save CGArtPython/9805c9b5fb1d79a9ccc368adb4f214bf to your computer and use it in GitHub Desktop.
Save CGArtPython/9805c9b5fb1d79a9ccc368adb4f214bf to your computer and use it in GitHub Desktop.
"""
Author: Viktor Stepanov
Licence: MIT
The code for this art:
https://www.artstation.com/artwork/AqDyDq
This is a simplified version without materials.
Tested with Blender 2.92
See full version with materials here:
https://gist.github.com/CGArtPython/4170d8ecec3c6212b3f8db531b194924
"""
import bpy
def setup_camera():
"""
Adds a camera to the scene
"""
loc = (-15.297300338745117, -20.347808837890625, -1.1497830152511597)
rot = (1.5498526096343994, -1.3148469690804632e-07, -0.6248275637626648)
bpy.ops.object.camera_add(
enter_editmode=False, align="VIEW", location=loc, rotation=rot
)
cam = bpy.context.active_object
bpy.context.scene.camera = cam
bpy.context.object.data.lens = 71
def set_cycles_scene(fps, loop_sec):
"""
Setup Cycles setting
"""
bpy.context.scene.render.fps = fps
frame_count = fps * loop_sec
bpy.context.scene.frame_end = frame_count
# set the background to black
world = bpy.data.worlds["World"]
world.node_tree.nodes["Background"].inputs[0].default_value = (0, 0, 0, 1)
# output to PNG images
bpy.context.scene.render.image_settings.file_format = "PNG"
# Set the render engine to Cycles
bpy.context.scene.render.engine = "CYCLES"
bpy.context.scene.cycles.device = "GPU"
bpy.context.scene.cycles.samples = 128
# Turn on denoising
bpy.context.scene.cycles.use_denoising = True
bpy.context.scene.cycles.use_adaptive_sampling = True
bpy.context.scene.cycles.denoiser = "NLM"
# Set Tile size
bpy.context.scene.render.tile_y = 512
bpy.context.scene.render.tile_x = 512
def create_control_empty(frame_count):
"""
Create an empty that will follow a path
making a perfect loop.
This will allow to drive the Displace modifier
"""
bpy.ops.curve.primitive_bezier_circle_add(
enter_editmode=False, align="WORLD", location=(0, 0, 0)
)
bezier_obj = bpy.context.active_object
bpy.context.object.data.path_duration = frame_count
bpy.ops.object.empty_add(type="PLAIN_AXES", align="WORLD", location=(0, 0, 0))
control_empty = bpy.context.active_object
bpy.ops.object.constraint_add(type="FOLLOW_PATH")
bpy.context.object.constraints["Follow Path"].target = bezier_obj
bpy.ops.constraint.followpath_path_animate(constraint="Follow Path", owner="OBJECT")
bpy.context.object.constraints["Follow Path"].use_curve_follow = True
return control_empty
def make_obj(frame_count):
"""
Generate the main object
"""
control_empty = create_control_empty(frame_count)
# create base object
bpy.ops.mesh.primitive_cube_add(
size=3, enter_editmode=False, align="WORLD", location=(0, 0, 0)
)
subdivide_lvl = 2
# apply the base Subdivision modifier
bpy.ops.object.modifier_add(type="SUBSURF")
mod_name = "base_Subdivision"
bpy.context.object.modifiers["Subdivision"].name = mod_name
bpy.context.object.modifiers[mod_name].levels = subdivide_lvl
bpy.context.object.modifiers[mod_name].render_levels = subdivide_lvl
# create texture that will drive the Displace modifier
bpy.ops.texture.new()
tex = bpy.data.textures["Texture"]
bpy.data.textures["Texture"].type = "CLOUDS"
bpy.data.textures["Texture"].noise_scale = 0.85
bpy.data.textures["Texture"].noise_depth = 10
# apply the Displace modifier
bpy.ops.object.modifier_add(type="DISPLACE")
bpy.context.object.modifiers["Displace"].texture = tex
bpy.context.object.modifiers["Displace"].texture_coords = "OBJECT"
bpy.context.object.modifiers["Displace"].strength = 1.6
bpy.context.object.modifiers["Displace"].texture_coords_object = control_empty
# apply the second Subdivision modifier
bpy.ops.object.modifier_add(type="SUBSURF")
mod_name = "scnd_Subdivision"
bpy.context.object.modifiers["Subdivision"].name = mod_name
bpy.context.object.modifiers[mod_name].render_levels = subdivide_lvl
bpy.context.object.modifiers[mod_name].levels = subdivide_lvl
# apply the Remesh modifier
bpy.ops.object.modifier_add(type="REMESH")
bpy.context.object.modifiers["Remesh"].mode = "BLOCKS"
bpy.context.object.modifiers["Remesh"].octree_depth = 5
# apply the Wireframe modifier
bpy.ops.object.modifier_add(type="WIREFRAME")
bpy.context.object.modifiers["Wireframe"].thickness = 0.03
bpy.context.object.modifiers["Wireframe"].use_replace = False
bpy.context.object.modifiers["Wireframe"].material_offset = 1
def delete_all_objects():
"""
Removing all of the objects from the scene
"""
# if Edit mode is enabled, then toggle it off
if bpy.context.active_object and bpy.context.active_object.mode == "EDIT":
bpy.ops.object.editmode_toggle()
bpy.ops.object.select_all(action="SELECT")
bpy.ops.object.delete()
# Remove orphan data
bpy.ops.outliner.orphans_purge()
def gen_scene(frame_count):
"""
Generate the scene
"""
make_obj(frame_count)
# add light
bpy.ops.object.light_add(type="POINT", radius=1, align="WORLD", location=(0, 0, 0))
bpy.context.object.data.energy = 100
bpy.context.object.data.color = (1, 0.342081, 0)
gen_floor()
def gen_floor():
"""
Generate the floor
"""
bpy.ops.mesh.primitive_plane_add(
size=50,
enter_editmode=False,
align="WORLD",
location=(0, 0, -2),
scale=(1, 1, 1),
)
def main():
"""
Start here
THIS IS THE VERSION WITHOUT ANY MATERIALS.
SEE THIS VERSION FOR CODE WITH MATERIALS:
https://gist.github.com/CGArtPython/4170d8ecec3c6212b3f8db531b194924
"""
fps = 30
loop_sec = 5
frame_count = fps * loop_sec
# Utility Building Blocks
delete_all_objects()
setup_camera()
set_cycles_scene(fps, loop_sec)
gen_scene(frame_count)
day = "day75"
scene_num = 1
bpy.context.scene.render.filepath = f"/tmp/day{day}_{scene_num}/"
main()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment