Rayures noires en verre

Nov 03 2020

Je suis assez nouveau dans Blender et j'essaye de créer une visualisation de mes résultats scientifiques. J'ai commencé par créer des données factices de la ligne centrale, puis j'ai utilisé la courbe de Bézier pour l'interpolation. Ensuite, je lui ai attribué un biseau (un carré simple, défini par une polyligne) et j'ai ainsi créé un objet 3D (j'ai également fermé les bouchons). Au moins j'espère que c'est un objet 3D, je ne sais pas si je devrais aussi utiliser une fonction de remplissage.

Néanmoins, j'ai réussi à créer tout cela, à le mettre dans un environnement, où j'entoure mon objet de murs et y met une lumière. Je lui ai attribué un matériau semblable au verre. Lors du rendu (cycles), mon image présente d'étranges bandes noires et je ne sais pas comment y remédier. J'ai tout dans un script que vous pouvez trouver ci-dessous.

Bien sûr, cela ne me dérange pas si la solution n'est pas dans un script Python, je parviendrai à la convertir. Je voudrais juste comprendre pourquoi ils apparaissent et comment le résoudre.

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)

Réponses

3 lemon Nov 03 2020 at 18:42

Vous pouvez corriger cela en lissant un peu les bords de la forme.

Dans ce cas, pour le faire:

Inversez l'objet Bevel (comme sinon, la forme finale a inversé les normales):

#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]
])

Ajoutez un modificateur Bevel à l'objet "centerline":

# Bevel modifier
bevel_modifier = centerline.modifiers.new("Bevel", "BEVEL")
bevel_modifier.width = 0.005
bevel_modifier.segments = 3
bevel_modifier.limit_method = 'ANGLE'

Remarque: d'abord, c'était des caustiques et cela devrait être (?). Cependant, cela ne fonctionne pas ici .