# What would be a simple way to model a curved funnel?

I'd like to model a surface like this curved funnel (pic from Wolfram Math World): So far I've tried starting with a cone, subdividing it and scaling down successive rings of vertices, but it's a bit fiddly and the result wasn't great. Ideally I'd like a solution which doesn't involve too much vertex selection, so that I can implement it via the API.

Can anyone think of a better way?

Try using the Extra Objects addon, with its XYZ Math Surface mesh option!

Use the parametric equations with a = 5, say: Note that I use log(u + 1) instead of just log(u), because the domain of u includes zero.

Then invert the normals, shade smooth, and you'll get (To enable this addon, go to FileUser Preferences, select Add-ons, search for "Extra objects," and enable the "mesh" one. Then, to create the object, hit ShiftA and select Math SurfaceXYZ Math Surface.)

• Note that I suggest this because it gives you all of the precision of the Python solution, with the advantage of already having been implemented, tested, and tweakable! – wchargin Dec 19 '16 at 3:19
• Thanks, I like this solution. Using the same equations, I ended up with a curved funnel inside a cone. I had to delete the faces that made up the cone before flipping the remaining normals. – user2950747 Dec 19 '16 at 7:57
• @user2950747 Make sure to leave "U wrap" unchecked (see screenshot). – wchargin Dec 19 '16 at 17:06

You could make a bent line in the XY plane for example (1), a subdivision surface modifier and use a screw modifier (2) with

• screw : 0
• steps : as you like
• angle : 360

I would use the formula directly in python. It is the better approach to not use operator, but rather "absolute" calculations when creating objects in python.

Here is a rather messy mockup code for the funnel.

import bpy, math, bmesh
import numpy as np

def create_new_mesh(name = "myObj"):
me = bpy.data.meshes.new(name + "_GEO")
ob = bpy.data.objects.new(name, me)
scn = bpy.context.scene
scn.objects.active = ob
ob.select = True
ob.show_name = True
return ob, me

def funnel_vert_at(x, y, a = 1):
p = float(x**2+y**2)
return 0.5 * a * np.log(p)

def funnel_iteration(iteration_start, iteration_end, iteration_steps, i, exp = 8):
i_s = iteration_start**(1/exp)
i_e = iteration_end**(1/exp)
iteration_step = (i_e - i_s)/(iteration_steps-1)
return (iteration_step * i + i_s)**exp

def create_funnel_loops(iteration_start = 0.1, iteration_end = 1, iteration_steps = 9,rotation_steps = 24, iteration_exp = 8, a = 1):
verts = []
for i in range(0, iteration_steps):
for s in range(0, rotation_steps):
rad = math.pi*2 / rotation_steps * s
dist = funnel_iteration(iteration_start, iteration_end, iteration_steps, i, iteration_exp)
print(i, dist)
verts.append((x, y, funnel_vert_at(x, y, a)))

edges = []
for a in range(0, iteration_steps):
for b in range(0, rotation_steps):
next = 1
if b is rotation_steps - 1:
next = -b
b = b + a*rotation_steps
edges.append([b, b + next])
return verts, edges

me = create_new_mesh("Funnel")

verts, edges = create_funnel_loops(
iteration_start = 0.1,
iteration_end = 1,
iteration_steps = 7,
rotation_steps = 9,
iteration_exp = 8,
a = 1
)

me.from_pydata(verts, edges, [])
bpy.ops.object.mode_set(mode='EDIT')
bpy.ops.mesh.bridge_edge_loops()
bpy.ops.object.mode_set(mode='OBJECT')


The main formula is in the function funnel_vert_at(). X and Y are created in create_funnel_loops with the circle functions sin and cos.
Since I was too lazy to implement it, the script uses the internal Bridge Edge Loops function, in the final solution, the faces should be calculated as well.

I also calculated the funnel_iterations very roughly with the power function. You should reverse the funnel formula so that the spacing between the loops is more even. It is also possible to bevel a Curve (I used a path here, just because it's a straight line by default) and use a second Curve as an Taper Object which gives the desired shape: The advantage of this method is that the shape stays editable (non-destructive) When you're done, you can convert it with ALT+C from Curve to Mesh afterwards.