deep_computer.py 7.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222
  1. import bpy
  2. import mathutils
  3. import math
  4. import random
  5. # load outfittemplate-nocube.blend, then run this
  6. # we need five materials
  7. # - the monitor (image texture)
  8. # - the metal for the case
  9. # - three colors for the buttons
  10. # - green (pressed down)
  11. # - grey/clear (most unpressed)
  12. # - red (unpressed but alert)
  13. monitor_mat = bpy.data.materials.new("ComputerMonitor")
  14. monitor_mat.diffuse_color = [0, 0.02, 0, 1]
  15. monitor_mat.specular_color = [0.9, 1, 0.9]
  16. monitor_mat.roughness = 0.05
  17. monitor_mat.use_nodes = True
  18. mon_nodes = monitor_mat.node_tree.nodes
  19. mon_links = monitor_mat.node_tree.links
  20. mon_mat_output = mon_nodes.get('Material Output')
  21. mon_bsdf = mon_nodes.get('Principled BSDF')
  22. mon_bsdf.inputs['Roughness'].default_value = 0.1
  23. mon_bsdf.inputs['Emission Strength'].default_value = 3
  24. mon_img = bpy.data.images.load(filepath = '/home/jmelesky/code/endless-sky-artificial-crew-models/images/oscilloscreen.png')
  25. mon_imgtx = mon_nodes.new('ShaderNodeTexImage')
  26. mon_imgtx.image = mon_img
  27. mon_links.new(mon_imgtx.outputs['Color'], mon_bsdf.inputs['Base Color'])
  28. mon_ramp = mon_nodes.new('ShaderNodeValToRGB')
  29. mon_ramp.color_ramp.interpolation = 'B_SPLINE'
  30. mon_ramp.color_ramp.elements[0].position = 0.1
  31. mon_ramp.color_ramp.elements[1].color = [0.05, 1.0, 0.0, 1.0]
  32. mon_links.new(mon_imgtx.outputs['Color'], mon_ramp.inputs['Fac'])
  33. mon_links.new(mon_ramp.outputs['Color'], mon_bsdf.inputs['Emission Color'])
  34. metal_mat = bpy.data.materials.new("ComputerMetal")
  35. metal_mat.use_nodes = True
  36. metal_nodes = metal_mat.node_tree.nodes
  37. metal_links = metal_mat.node_tree.links
  38. metal_mat_output = metal_nodes.get('Material Output')
  39. metal_bsdf = metal_nodes.get('Principled BSDF')
  40. metal_bsdf.inputs['Metallic'].default_value = 1.0
  41. metal_bsdf.inputs['Base Color'].default_value = [0.16, 0.12, 0.08, 1.0]
  42. # metal_noise = metal_nodes.new('ShaderNodeTexNoise')
  43. # metal_noise.inputs['Scale'].default_value = 70.0
  44. # metal_noise.inputs['Detail'].default_value = 15.0
  45. # metal_noise.inputs['Roughness'].default_value = 0.6
  46. # metal_ramp = metal_nodes.new('ShaderNodeValToRGB')
  47. # metal_ramp.color_ramp.elements[0].color = [0.08, 0.07, 0.03, 1.0]
  48. # metal_ramp.color_ramp.elements[1].color = [0.16, 0.155, 0.08, 1.0]
  49. # metal_links.new(metal_noise.outputs['Fac'], metal_ramp.inputs['Fac'])
  50. # metal_links.new(metal_ramp.outputs['Color'], metal_bsdf.inputs['Base Color'])
  51. metal_bump = metal_nodes.new('ShaderNodeBump')
  52. metal_bump.invert = True
  53. metal_bump.inputs['Strength'].default_value = 0.3
  54. metal_noise2 = metal_nodes.new('ShaderNodeTexNoise')
  55. metal_noise2.inputs['Scale'].default_value = 70.0
  56. metal_noise2.inputs['Detail'].default_value = 15.0
  57. metal_noise2.inputs['Roughness'].default_value = 0.6
  58. metal_links.new(metal_noise2.outputs['Fac'], metal_bump.inputs['Height'])
  59. metal_links.new(metal_bump.outputs['Normal'], metal_bsdf.inputs['Normal'])
  60. metal_links.new(metal_bump.outputs['Normal'], metal_bsdf.inputs['Roughness'])
  61. down_button_mat = bpy.data.materials.new("DownButton")
  62. down_button_mat.use_nodes = True
  63. down_button_mat.blend_method = 'BLEND'
  64. down_bsdf = down_button_mat.node_tree.nodes.get('Principled BSDF')
  65. down_bsdf.inputs['Base Color'].default_value = [0.5, 0.5, 0.5, 0.95]
  66. down_bsdf.inputs['Roughness'].default_value = 0.4
  67. down_bsdf.inputs['Emission Color'].default_value = [0.2, 0.85, 0.2, 0.3]
  68. down_bsdf.inputs['Emission Strength'].default_value = 0.8
  69. up_button_mat = bpy.data.materials.new("UpButton")
  70. up_button_mat.diffuse_color = [0.5, 0.5, 0.5, 0.4]
  71. up_button_mat.roughness = 0.8
  72. up_button_mat.blend_method = 'BLEND'
  73. attn_button_mat = bpy.data.materials.new("AttnButton")
  74. attn_button_mat.use_nodes = True
  75. attn_button_mat.blend_method = 'BLEND'
  76. attn_bsdf = attn_button_mat.node_tree.nodes.get('Principled BSDF')
  77. attn_bsdf.inputs['Base Color'].default_value = [0.5, 0.5, 0.5, 0.95]
  78. attn_bsdf.inputs['Roughness'].default_value = 0.4
  79. attn_bsdf.inputs['Emission Color'].default_value = [0.7, 0.1, 0.1, 0.3]
  80. attn_bsdf.inputs['Emission Strength'].default_value = 0.7
  81. # now the big box
  82. back_bottom_left = (0,0,0)
  83. back_top_left = (0,0,8)
  84. front_top_left = (2,0,8)
  85. front_mid_left = (4,0,3)
  86. front_bottom_left = (4,0,0)
  87. back_bottom_right = (0,10,0)
  88. back_top_right = (0,10,8)
  89. front_top_right = (2,10,8)
  90. front_mid_right = (4,10,3)
  91. front_bottom_right = (4,10,0)
  92. box_vertices = [back_bottom_left, back_top_left, back_bottom_right, back_top_right,
  93. front_top_left, front_top_right, front_mid_left, front_mid_right,
  94. front_bottom_left, front_bottom_right]
  95. box_faces = [
  96. (0,1,3,2), # the back of the box: back_bottom_left, back_top_left, back_top_right, back_bottom_right
  97. (0,2,9,8), # the bottom: back_bottom_left, back_bottom_right, front_bottom_right, front_bottom_left
  98. (8,9,7,6), # lower front plate: front_bottom_left, front_bottom_right, front_mid_right, front_mid_left
  99. (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
  100. (0,8,6,4,1), # left side panel: back_bottom_left, front_bottom_left, front_mid_left, front_top_left, back_top_left
  101. (6,7,5,4), # upper front plate: front_mid_left, front_mid_right, front_top_right, front_top_left
  102. (4,5,3,1), # top: front_top_left, front_top_right, back_top_right, back_top_left
  103. ]
  104. # box_mat = bpy.data.materials.new('MyBoxMaterial')
  105. # box_mat.use_nodes = True
  106. # if box_mat.node_tree:
  107. # box_mat.node_tree.links.clear()
  108. # box_mat.node_tree.nodes.clear()
  109. # box_output = box_mat.node_tree.nodes.new(type='ShaderNodeOutputMaterial')
  110. # box_shader = box_mat.node_tree.nodes.new(type='ShaderNodeBsdfDiffuse')
  111. # box_mat.node_tree.nodes['Diffuse BSDF'].inputs[0].default_value = (.125, .179, .263, 1)
  112. # box_mat.node_tree.links.new(box_shader.outputs[0], box_output.inputs[0])
  113. box_mesh = bpy.data.meshes.new('MyComputerBoxMesh')
  114. box_mesh.from_pydata(box_vertices, [], box_faces)
  115. box_obj = bpy.data.objects.new('MyComputerBox', box_mesh)
  116. box_obj.data.materials.append(metal_mat)
  117. bpy.context.scene.collection.objects.link(box_obj)
  118. # the oscilloscope-style monitor
  119. monitor_location = mathutils.Vector((3, 2.5, 5.5))
  120. monitor_scale = mathutils.Vector((.4, 1, 1))
  121. monitor_rotation = mathutils.Euler((0, math.radians(203), math.radians(180)))
  122. bpy.ops.mesh.primitive_uv_sphere_add(
  123. segments=32,
  124. ring_count=16,
  125. radius=2,
  126. location=monitor_location,
  127. scale=monitor_scale, # this is relative to the size
  128. rotation=monitor_rotation)
  129. # smooth the monitor, add a texture
  130. monitor_obj = bpy.context.active_object
  131. for f in monitor_obj.data.polygons:
  132. f.use_smooth = True
  133. monitor_obj.data.update()
  134. monitor_obj.data.materials.append(monitor_mat)
  135. # three rows of buttons, randomly depressed
  136. #
  137. # a better way to do this would be to set the buttons in a group,
  138. # then rotate that entire group. i'm not there yet, so we're
  139. # using some magic numbers for positional offsets.
  140. buttons = []
  141. for i in [7, 5.5, 4]:
  142. for j in [6.8, 7.2, 7.6, 8, 8.4, 8.8, 9.2]:
  143. if random.random() > .6:
  144. button_location = mathutils.Vector((5.0 - (i/2.5), j, i-.1))
  145. button_material = down_button_mat
  146. else:
  147. button_location = mathutils.Vector((5.2 - (i/2.5), j, i))
  148. if random.random() > .8:
  149. button_material = attn_button_mat
  150. else:
  151. button_material = up_button_mat
  152. bpy.ops.mesh.primitive_cube_add(
  153. size=1,
  154. location=button_location,
  155. rotation=monitor_rotation,
  156. scale=mathutils.Vector((.8, .2, .6)))
  157. button = bpy.context.active_object
  158. buttons.append(button)
  159. button.data.materials.append(button_material)
  160. box_obj.select_set(True)
  161. monitor_obj.select_set(True)
  162. for b in buttons:
  163. b.select_set(True)
  164. bpy.ops.transform.resize(
  165. value=(0.5, 0.5, 0.5)
  166. )
  167. bpy.ops.transform.rotate(
  168. value=math.radians(90)
  169. )
  170. bpy.ops.transform.translate(
  171. value=(-2.5,-5,-3.3)
  172. )