import bpy import mathutils import math import random # load outfittemplate-nocube.blend, then run this # we need five materials # - the monitor (image texture) # - the metal for the case # - three colors for the buttons # - green (pressed down) # - grey/clear (most unpressed) # - red (unpressed but alert) monitor_mat = bpy.data.materials.new("ComputerMonitor") monitor_mat.diffuse_color = [0, 0.02, 0, 1] monitor_mat.specular_color = [0.9, 1, 0.9] monitor_mat.roughness = 0.05 monitor_mat.use_nodes = True mon_nodes = monitor_mat.node_tree.nodes mon_links = monitor_mat.node_tree.links mon_mat_output = mon_nodes.get('Material Output') mon_bsdf = mon_nodes.get('Principled BSDF') mon_bsdf.inputs['Roughness'].default_value = 0.1 mon_bsdf.inputs['Emission Strength'].default_value = 3 mon_img = bpy.data.images.load(filepath = '/home/jmelesky/code/endless-sky-artificial-crew-models/images/oscilloscreen.png') mon_imgtx = mon_nodes.new('ShaderNodeTexImage') mon_imgtx.image = mon_img mon_links.new(mon_imgtx.outputs['Color'], mon_bsdf.inputs['Base Color']) mon_ramp = mon_nodes.new('ShaderNodeValToRGB') mon_ramp.color_ramp.interpolation = 'B_SPLINE' mon_ramp.color_ramp.elements[0].position = 0.1 mon_ramp.color_ramp.elements[1].color = [0.05, 1.0, 0.0, 1.0] mon_links.new(mon_imgtx.outputs['Color'], mon_ramp.inputs['Fac']) mon_links.new(mon_ramp.outputs['Color'], mon_bsdf.inputs['Emission Color']) metal_mat = bpy.data.materials.new("ComputerMetal") metal_mat.use_nodes = True metal_nodes = metal_mat.node_tree.nodes metal_links = metal_mat.node_tree.links metal_mat_output = metal_nodes.get('Material Output') metal_bsdf = metal_nodes.get('Principled BSDF') metal_bsdf.inputs['Metallic'].default_value = 1.0 metal_bsdf.inputs['Base Color'].default_value = [0.16, 0.12, 0.08, 1.0] # metal_noise = metal_nodes.new('ShaderNodeTexNoise') # metal_noise.inputs['Scale'].default_value = 70.0 # metal_noise.inputs['Detail'].default_value = 15.0 # metal_noise.inputs['Roughness'].default_value = 0.6 # metal_ramp = metal_nodes.new('ShaderNodeValToRGB') # metal_ramp.color_ramp.elements[0].color = [0.08, 0.07, 0.03, 1.0] # metal_ramp.color_ramp.elements[1].color = [0.16, 0.155, 0.08, 1.0] # metal_links.new(metal_noise.outputs['Fac'], metal_ramp.inputs['Fac']) # metal_links.new(metal_ramp.outputs['Color'], metal_bsdf.inputs['Base Color']) metal_bump = metal_nodes.new('ShaderNodeBump') metal_bump.invert = True metal_bump.inputs['Strength'].default_value = 0.3 metal_noise2 = metal_nodes.new('ShaderNodeTexNoise') metal_noise2.inputs['Scale'].default_value = 70.0 metal_noise2.inputs['Detail'].default_value = 15.0 metal_noise2.inputs['Roughness'].default_value = 0.6 metal_links.new(metal_noise2.outputs['Fac'], metal_bump.inputs['Height']) metal_links.new(metal_bump.outputs['Normal'], metal_bsdf.inputs['Normal']) metal_links.new(metal_bump.outputs['Normal'], metal_bsdf.inputs['Roughness']) down_button_mat = bpy.data.materials.new("DownButton") down_button_mat.use_nodes = True down_button_mat.blend_method = 'BLEND' down_bsdf = down_button_mat.node_tree.nodes.get('Principled BSDF') down_bsdf.inputs['Base Color'].default_value = [0.5, 0.5, 0.5, 0.95] down_bsdf.inputs['Roughness'].default_value = 0.4 down_bsdf.inputs['Emission Color'].default_value = [0.2, 0.85, 0.2, 0.3] down_bsdf.inputs['Emission Strength'].default_value = 0.8 up_button_mat = bpy.data.materials.new("UpButton") up_button_mat.diffuse_color = [0.5, 0.5, 0.5, 0.4] up_button_mat.roughness = 0.8 up_button_mat.blend_method = 'BLEND' attn_button_mat = bpy.data.materials.new("AttnButton") attn_button_mat.use_nodes = True attn_button_mat.blend_method = 'BLEND' attn_bsdf = attn_button_mat.node_tree.nodes.get('Principled BSDF') attn_bsdf.inputs['Base Color'].default_value = [0.5, 0.5, 0.5, 0.95] attn_bsdf.inputs['Roughness'].default_value = 0.4 attn_bsdf.inputs['Emission Color'].default_value = [0.7, 0.1, 0.1, 0.3] attn_bsdf.inputs['Emission Strength'].default_value = 0.7 # now the big box back_bottom_left = (0,0,0) back_top_left = (0,0,8) front_top_left = (2,0,8) front_mid_left = (4,0,3) front_bottom_left = (4,0,0) back_bottom_right = (0,10,0) back_top_right = (0,10,8) front_top_right = (2,10,8) front_mid_right = (4,10,3) front_bottom_right = (4,10,0) box_vertices = [back_bottom_left, back_top_left, back_bottom_right, back_top_right, front_top_left, front_top_right, front_mid_left, front_mid_right, front_bottom_left, front_bottom_right] box_faces = [ (0,1,3,2), # the back of the box: back_bottom_left, back_top_left, back_top_right, back_bottom_right (0,2,9,8), # the bottom: back_bottom_left, back_bottom_right, front_bottom_right, front_bottom_left (8,9,7,6), # lower front plate: front_bottom_left, front_bottom_right, front_mid_right, front_mid_left (9,2,3,5,7), # right side panel (5 edges): front_bottom_right, back_bottom_right, back_top_right, front_top_right, front_mid_right (0,8,6,4,1), # left side panel: back_bottom_left, front_bottom_left, front_mid_left, front_top_left, back_top_left (6,7,5,4), # upper front plate: front_mid_left, front_mid_right, front_top_right, front_top_left (4,5,3,1), # top: front_top_left, front_top_right, back_top_right, back_top_left ] # box_mat = bpy.data.materials.new('MyBoxMaterial') # box_mat.use_nodes = True # if box_mat.node_tree: # box_mat.node_tree.links.clear() # box_mat.node_tree.nodes.clear() # box_output = box_mat.node_tree.nodes.new(type='ShaderNodeOutputMaterial') # box_shader = box_mat.node_tree.nodes.new(type='ShaderNodeBsdfDiffuse') # box_mat.node_tree.nodes['Diffuse BSDF'].inputs[0].default_value = (.125, .179, .263, 1) # box_mat.node_tree.links.new(box_shader.outputs[0], box_output.inputs[0]) box_mesh = bpy.data.meshes.new('MyComputerBoxMesh') box_mesh.from_pydata(box_vertices, [], box_faces) box_obj = bpy.data.objects.new('MyComputerBox', box_mesh) box_obj.data.materials.append(metal_mat) bpy.context.scene.collection.objects.link(box_obj) # the oscilloscope-style monitor monitor_location = mathutils.Vector((3, 2.5, 5.5)) monitor_scale = mathutils.Vector((.4, 1, 1)) monitor_rotation = mathutils.Euler((0, math.radians(203), math.radians(180))) bpy.ops.mesh.primitive_uv_sphere_add( segments=32, ring_count=16, radius=2, location=monitor_location, scale=monitor_scale, # this is relative to the size rotation=monitor_rotation) # smooth the monitor, add a texture monitor_obj = bpy.context.active_object for f in monitor_obj.data.polygons: f.use_smooth = True monitor_obj.data.update() monitor_obj.data.materials.append(monitor_mat) # three rows of buttons, randomly depressed # # a better way to do this would be to set the buttons in a group, # then rotate that entire group. i'm not there yet, so we're # using some magic numbers for positional offsets. buttons = [] for i in [7, 5.5, 4]: for j in [6.8, 7.2, 7.6, 8, 8.4, 8.8, 9.2]: if random.random() > .6: button_location = mathutils.Vector((5.0 - (i/2.5), j, i-.1)) button_material = down_button_mat else: button_location = mathutils.Vector((5.2 - (i/2.5), j, i)) if random.random() > .8: button_material = attn_button_mat else: button_material = up_button_mat bpy.ops.mesh.primitive_cube_add( size=1, location=button_location, rotation=monitor_rotation, scale=mathutils.Vector((.8, .2, .6))) button = bpy.context.active_object buttons.append(button) button.data.materials.append(button_material) box_obj.select_set(True) monitor_obj.select_set(True) for b in buttons: b.select_set(True) bpy.ops.transform.resize( value=(0.5, 0.5, 0.5) ) bpy.ops.transform.rotate( value=math.radians(90) ) bpy.ops.transform.translate( value=(-2.5,-5,-3.3) )