Listras pretas em vidro
Eu sou muito novo no Blender e estou tentando criar uma visualização dos meus resultados científicos. Comecei criando dados fictícios da linha central e depois usei a curva de Bezier para interpolação. Em seguida, atribuí bisel a ele (um quadrado simples, definido por polilinha) e, assim, criei um objeto 3D (também fechei as tampas). Pelo menos espero que seja um objeto 3D, não tenho certeza se devo usar alguma função de preenchimento.
Mesmo assim, consegui criar tudo isso, colocar em um ambiente, onde envolvo meu objeto com paredes e coloco uma luz. Eu atribuí a ele um material parecido com vidro. Quando faço a renderização (ciclos), minha imagem tem estranhas listras pretas e não tenho certeza de como corrigi-la. Tenho tudo isso em um script que você encontra abaixo.
Claro, não me importo se a solução não estiver em um script Python, vou conseguir convertê-lo. Eu gostaria apenas de entender por que eles estão aparecendo e como resolver isso.
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)
Respostas
Você pode corrigir isso suavizando um pouco as bordas da forma.
Nesse caso, para fazer:
Inverta o objeto Bevel (se não, a forma final tem normais invertidos):
#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]
])
Adicione um modificador Bevel ao objeto "centerline":
# Bevel modifier
bevel_modifier = centerline.modifiers.new("Bevel", "BEVEL")
bevel_modifier.width = 0.005
bevel_modifier.segments = 3
bevel_modifier.limit_method = 'ANGLE'
Nota: primeiro embora isso fosse cáustico e deveria ser (?). Porém, isso não está funcionando aqui .