Created
May 10, 2021 06:52
-
-
Save CGArtPython/9805c9b5fb1d79a9ccc368adb4f214bf to your computer and use it in GitHub Desktop.
The code for this art: https://www.artstation.com/artwork/AqDyDq
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
""" | |
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