Blender Stack Exchange is a question and answer site for people who use Blender to create 3D graphics, animations, or games. Join them; it only takes a minute:

Sign up
Here's how it works:
  1. Anybody can ask a question
  2. Anybody can answer
  3. The best answers are voted up and rise to the top

I'd like to model a surface like this curved funnel (pic from Wolfram Math World):

enter image description here

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?

share|improve this question
up vote 7 down vote accepted

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

Use the parametric equations with a = 5, say:

The "Add X,Y,Z Function Surface" options with x = u cos(v), y = u sin(v), and z = 5 log(u + 1)

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

Rendered funnel

(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.)

share|improve this answer
    
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 10 hours ago
    
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 6 hours ago

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

(1) enter image description here

(2) enter image description here

share|improve this answer

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.link(ob)
    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)
            x = math.sin(rad) * dist
            y = math.cos(rad) * 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")[1]


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.

enter image description here

share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.