How to smooth the appearance of a specified subset of faces without topology changes with a script? This is a magnetic pole piece for an electric motor (there will be 12 in a circle). The bottom face is a hyperbola, the the top is a circle, and the sides are straight.

I would like the top and bottom curved surfaces to appear smooth when rendering in Cycles, but not create any visible rounding of the corners, or affect the large flat faces, so that even when illuminated sideways the top and bottom surfaces would appear smoothly curving.

I'll be doing a lot more to them algorithmically, so I need something that doesn't modify the topology of the mesh by adding/deleting edges, faces, vertices, etc.

edit: Since I'm generating the mesh algorithmically, I will know the indices of the faces that need to be smoothed. If I can target them for smoothing specifically, this would be the best way for me.

Below is a simplified script that shows how I generate them (I've skipped the math, happy to include it if it helps).

  



xpts_sharp = [ 7.196,  5.606,  4.009,  2.407, 0.803, -0.803, -2.407, 
              -4.009, -5.606, -7.196, -5.08, -4.298, -3.517, -2.735, 
              -1.954, -1.172, -0.391,  0.391, 1.172,  1.954,  2.735, 
               3.517,  4.298,  5.08 ]

ypts_sharp = [ 45.434, 45.657, 45.825, 45.937, 45.993, 45.993, 45.937, 
               45.825, 45.657, 45.434, 32.072, 31.832, 31.605, 31.398, 
               31.219, 31.084, 31.01,  31.01,  31.084, 31.219, 31.398, 
               31.605, 31.832, 32.072 ]

import bpy
import numpy as np

xpts = np.array(xpts_sharp)
ypts = np.array(ypts_sharp)
zpts = np.array([-50.0, 50.0])
scale = 0.1

xptss, yptss, zptss = scale*xpts, scale*ypts, scale*zpts
nxy, nz = len(xptss), len(zptss)

verts = []
for zpt in zptss:
    zapt  = zpt + np.zeros_like(xptss)
    vertz = list(zip(xptss, zapt, yptss))
    verts += vertz
nverts = len(verts)


faces = []
for iz in range(nz-1):
    for ixy in range(nxy):
        v1 = (iz+0)*nxy + (ixy+0)%nxy
        v2 = (iz+0)*nxy + (ixy+1)%nxy
        v3 = (iz+1)*nxy + (ixy+1)%nxy
        v4 = (iz+1)*nxy + (ixy+0)%nxy
        faces.append((v1, v2, v3, v4)[::-1])
face = list(range(nxy))
faces.append(face)
face = list(range(nverts-nxy, nverts))[::-1]
faces.append(face)

if 1 == 1:
    name = "pole_piece"

    me = bpy.data.meshes.new(name)
    ob = bpy.data.objects.new(name, me)

    bpy.context.scene.objects.link(ob)

    me.from_pydata(verts, [], faces)

    bpy.data.objects[name].select = False
    bpy.data.objects[name].select = True
Set your object to smooth shading.

Add an edge split modifier. Apply it if you wish.

Depending on the angle setting in the edge split modifier, surfaces will appear smooth shaded preserving sharp edges.

Internally, the modifier splits edges based on the angle of the adjacent faces.

This will add the edge split modifier and "apply" it. The topology will change.

if 1 == 1:
    name = "pole_piece"

    me = bpy.data.meshes.new(name)
    ob = bpy.data.objects.new(name, me)

    scene = bpy.context.scene
    scene.objects.link(ob)

    me.from_pydata(verts, [], faces)

    bpy.data.objects[name].select = False
    bpy.data.objects[name].select = True

    for p in ob.data.polygons:
        p.use_smooth = True
    mod = ob.modifiers.new("edge", type='EDGE_SPLIT')
    ob.data = ob.to_mesh(scene, True, 'PREVIEW')
    ob.modifiers.remove(mod)