Rayas negras en vidrio
Soy bastante nuevo en Blender y estoy tratando de crear una visualización de mis resultados científicos. Comencé creando datos ficticios de la línea central y luego usé la curva de Bezier para la interpolación. Luego le asigné bisel (un cuadrado simple, definido por polilínea) y así creé un objeto 3D (también cerré las tapas). Al menos espero que sea un objeto 3D, no estoy seguro de si también debería usar alguna función de relleno.
Sin embargo, logré crear todo esto, ponerlo en un ambiente, donde rodeo mi objeto con paredes y pongo una luz. Le asigné un material similar al vidrio. Cuando renderizo (ciclos), mi imagen tiene extrañas rayas negras y no estoy seguro de cómo solucionarlo. Lo tengo todo en un guión que puedes encontrar a continuación.
Por supuesto, no me importa si la solución no está en un script de Python, me las arreglaré para convertirlo. Solo me gustaría entender por qué aparecen y cómo resolverlo.
import bpy
import numpy as np
# delete everything
print("\n\n\n\nNew run")
objs = [ob for ob in bpy.context.scene.objects]
bpy.ops.object.delete({"selected_objects": objs})
print("\n\n\n\n")
def dump(obj):
for attr in dir(obj):
if hasattr( obj, attr ):
print( "obj.%s = %s" % (attr, getattr(obj, attr)))
def polyline_from(coords, name, closed):
# create the Curve Datablock
curvedata = bpy.data.curves.new(name, type='CURVE')
curvedata.dimensions = '3D'
# map coords to spline
polyline = curvedata.splines.new('POLY')
polyline.points.add(len(coords)-1)
for i, coord in enumerate(coords):
x,y = coord
polyline.points[i].co = (x, y, 0, 1)
if(closed):
polyline.use_cyclic_u = True
# create Object
objectdata = bpy.data.objects.new(name+"Object", curvedata)
return objectdata
def curve_from(coords, name, closed, res=10):
# create the Curve Datablock
curvedata = bpy.data.curves.new(name, type='CURVE')
curvedata.dimensions = '3D'
curvedata.resolution_u = res
# map coords to spline
spline = curvedata.splines.new('BEZIER')
spline.bezier_points.add(len(coords)-1)
for i, p in enumerate(spline.bezier_points):
x,y,z = coords[i]
p.co = (x, y, z)
p.handle_left = (x, y, z)
p.handle_right = (x, y, z)
#Set automatic
p.handle_right_type = 'AUTO'
p.handle_left_type = 'AUTO'
if(closed):
spline.use_cyclic_u = True
# create Object
objectdata = bpy.data.objects.new(name+"Object", curvedata)
return objectdata
# create scene
scene = bpy.context.scene
scene.world.color = (0,0,0)
# select render engine
scene.render.engine = 'CYCLES'
# Set render resolution
scene.render.resolution_x = 1920
scene.render.resolution_y = 1080
# Generate fake data
def data(t):
x = np.linspace(0, 1, 10)
y = 0*x
z = x**2 * 0.2 * np.sin(t)
return np.array([x, y, z]).T
centerline_points = data(0)
# Cross section
cross_section_points = 0.5*np.array([
[-0.1,-0.1],
[ 0.1,-0.1],
[ 0.1, 0.1],
[-0.1, 0.1]
])
centerline = curve_from(
coords=centerline_points,
name="Centerline",
closed=False,
res=13
)
cross_section = polyline_from(
coords=cross_section_points,
name="CrossSection",
closed=True
)
# add bevel object
centerline.data.bevel_object = cross_section
centerline.data.use_fill_caps = True
# attach to scene and validate context
scene.collection.objects.link(centerline)
# clear all previous animation data
centerline.animation_data_clear()
# set first and last frame index
total_time = 2*np.pi # Animation should be 2*pi seconds long
fps = 10 # Frames per second (fps)
scene.frame_start = 0
scene.frame_end = int(total_time*fps)+1
# loop of frames and insert keyframes every 10th frame
keyframe_freq = 1
nlast = bpy.context.scene.frame_end
for n in range(nlast):
t = total_time*n/nlast
# Do computations
new_points = data(t)
# Check if n is a multiple of keyframe_freq
if n%keyframe_freq == 0:
# Set frame like this
scene.frame_set(n)
# Set current location like this
for (i, p) in enumerate(centerline.data.splines.active.bezier_points):
x,y,z = new_points[i]
p.co = (x,y,z)
p.keyframe_insert(data_path="co")
p.handle_left = (x, y, z)
p.keyframe_insert(data_path="handle_left")
p.handle_right = (x, y, z)
p.keyframe_insert(data_path="handle_right")
# create material
material = bpy.data.materials.new("Material")
centerline.active_material = material
material.use_nodes = True
material.node_tree.links.remove(material.node_tree.links[0])
material.node_tree.nodes.remove(material.node_tree.nodes['Principled BSDF'])
glass_node = material.node_tree.nodes.new("ShaderNodeBsdfGlass")
glass_node.inputs["Color"].default_value = (0.0, 0.8, 1.0, 1.0)
glass_node.inputs["Roughness"].default_value = 0.1
material.node_tree.links.new(material.node_tree.nodes["Material Output"].inputs["Surface"], glass_node.outputs["BSDF"])
# create plane
minx = -0.1
maxx = 1.1
miny = -0.25
maxy = 0.25
minz = -0.25
maxz = 0.25
bpy.ops.mesh.primitive_plane_add(size=30, location=(0.0,0.0,minz), rotation=(0.0,0.0,0.0))
basez1 = bpy.context.active_object
bpy.ops.mesh.primitive_plane_add(size=30, location=(0.0,0.0,15), rotation=(0.0,0.0,0.0))
basez2 = bpy.context.active_object
bpy.ops.mesh.primitive_plane_add(size=30, location=(0.0,-15,0.0), rotation=(-np.pi/2,0.0,0.0))
basey1 = bpy.context.active_object
bpy.ops.mesh.primitive_plane_add(size=30, location=(0.0,15,0.0), rotation=(np.pi/2,0.0,0.0))
basey2 = bpy.context.active_object
bpy.ops.mesh.primitive_plane_add(size=30, location=(-15,0.0,0.0), rotation=(0.0,-np.pi/2,0.0))
basex1 = bpy.context.active_object
bpy.ops.mesh.primitive_plane_add(size=30, location=(15,0.0,0.0), rotation=(0.0,np.pi/2,0.0))
basex2 = bpy.context.active_object
# create material
base_material = bpy.data.materials.new("BaseMaterial")
base_material.use_nodes = True
base_bsdf = base_material.node_tree.nodes["Principled BSDF"]
texture_image = base_material.node_tree.nodes.new('ShaderNodeTexImage')
texture_path = "/Users/jantomec/Downloads/fabric_pattern_05_8k_png/fabric_pattern_05_rough_8k.png"
texture_image.image = bpy.data.images.load(texture_path)
texture_image.texture_mapping.scale = (10,10,10)
base_material.node_tree.links.new(base_bsdf.inputs['Base Color'], texture_image.outputs['Color'])
basez1.active_material = base_material
basez2.active_material = base_material
basey1.active_material = base_material
basey2.active_material = base_material
basex1.active_material = base_material
basex2.active_material = base_material
# add light
# create light datablock, set attributes
light_data = bpy.data.lights.new(name="light_2.80", type='POINT')
light_data.energy = 10000
light_data.cycles.samples = 4
# create new object with our light datablock
light_object = bpy.data.objects.new(name="Light", object_data=light_data)
light_object.location = (7,-10,10)
# link light object
bpy.context.collection.objects.link(light_object)
# add camera
camera_data = bpy.data.cameras.new(name='Camera')
camera_object = bpy.data.objects.new('Camera', camera_data)
bpy.context.scene.collection.objects.link(camera_object)
# Set camera fov in degrees
camera_object.data.angle = 35*np.pi/180.0
# Set camera rotation in euler angles
xc = 1.3
yc = -3.0
zc = 0.75
midpoint = [(minx+maxx)/2, (miny+maxy)/2, (minz+maxz)/2]
camera_object.rotation_mode = 'XZY'
camera_object.rotation_euler[0] = np.pi/2
camera_object.rotation_euler[2] = np.arctan2(xc - midpoint[0], -(yc - midpoint[1]))
camera_object.rotation_euler[0] = np.pi/2 - np.arctan2(zc, np.sqrt((xc - midpoint[0])**2 * (yc-midpoint[1])**2)) + 0.07
# Set camera translation
camera_object.location = (xc, yc, zc)
Respuestas
Puede corregir eso suavizando un poco los bordes de la forma.
En ese caso, para hacerlo:
Invierta el objeto Bisel (como si no, la forma final tiene normales invertidas):
#Reversed indices to make the final shape correctly oriented
cross_section_points = 0.5*np.array([
[-0.1, 0.1],
[ 0.1, 0.1],
[ 0.1,-0.1],
[-0.1,-0.1]
])
Agregue un modificador de bisel al objeto "línea central":
# Bevel modifier
bevel_modifier = centerline.modifiers.new("Bevel", "BEVEL")
bevel_modifier.width = 0.005
bevel_modifier.segments = 3
bevel_modifier.limit_method = 'ANGLE'
Nota: primero, aunque esto era cáustico y debería ser (?). Sin embargo, esto no funciona aquí .