"""参数化软乳几何生成（探索用）。
在局部坐标建模：乳根在 z=0 平面（贴胸壁），乳轴沿 +Z，乳尖朝 +Z。
参数可调：baseR(乳根半径) depth(乳长) sag(下垂弧量) squash(上扁下圆) point(乳尖锐度)。
环形规整拓扑，保证网页 shader(以uGrabPos做高斯fall)友好。
输出: 直接把网格对象建好 + 渲染三视图探形。"""
import bpy, math, sys, os

# ---------- 参数 ----------
baseR = float(sys.argv[sys.argv.index("-baseR")+1]) if "-baseR" in sys.argv else 0.20
depth = float(sys.argv[sys.argv.index("-depth")+1]) if "-depth" in sys.argv else 0.26
sag   = float(sys.argv[sys.argv.index("-sag")+1])   if "-sag" in sys.argv else 0.55
squash= float(sys.argv[sys.argv.index("-squash")+1]) if "-squash" in sys.argv else 0.30
point = float(sys.argv[sys.argv.index("-point")+1]) if "-point" in sys.argv else 1.15
rING  = float(sys.argv[sys.argv.index("-rings")+1]) if "-rings" in sys.argv else 20
sEG   = float(sys.argv[sys.argv.index("-segs")+1])  if "-segs" in sys.argv else 32
outdir= "/tmp/opencode/breast_shape"

def build_breast_mesh(name):
    verts=[]; faces=[]; uvs=[]
    rings=int(rING); segs=int(sEG)
    # 中心线: z 从0(根)到 depth(尖), y 下沉 sag(向下), 用正弦缓动
    # ring t 0..1 (0=根,1=尖)
    for i in range(rings+1):
        t=i/rings
        z=t*depth
        y=-sag*depth*math.sin(t*math.pi*0.5)  # 下垂:越近尖越明显
        # 半径:桃形——根收紧接胸壁,近根稍鼓出,向尖收0
        # upper: roots at baseR, bulge ~0.85 depth, taper to 0 at tip
        r=baseR*math.sin(min(1.0,t*1.15)*math.pi*0.5)*(1.0-0.10*t*t)
        # 乳尖锐度收缩
        if point>1.0:
            # 在 t>0.75 快速收缩成尖
            k=max(0.0,(t-0.72)/0.28)
            r*= (1.0-(1.0-1.0/point)*k*k)
        if i==rings:
            # 乳尖主顶点(单点)
            verts.append((0.0,y,z)); uvs.append((0.5,1.0)); continue
        for j in range(segs+1):
            a=j/segs*math.pi*2
            cx=math.cos(a)*r
            cy=math.sin(a)*r
            # squash: 上半(sin(a)>0, 即 cy 朝上)压扁 → 上扁下圆(桃形)
            if math.sin(a)>0:
                cy*= (1.0-squash)
            verts.append((cx, cy+y, z))
            uvs.append((j/segs, t))
    # faces
    for i in range(rings):
        for j in range(segs):
            a=i*(segs+1)+j; b=a+1; c=a+segs+1; d=c+1
            if i==rings-1:  # 最后一环接到乳尖单点
                tip=len(verts)-1
                faces.append((a, b, tip)); continue
            faces.append((a,c,b, b,c,d))
    # base cap (根部封闭接胸壁) —— 平面圆盖
    center=len(verts); verts.append((0.0,0.0,0.0)); uvs.append((0.5,0.0))
    for j in range(segs):
        a=j; b=j+1
        faces.append((a,b,center))
    me=bpy.data.meshes.new(name)
    me.from_pydata(verts, [], faces)
    me.update()
    # uv
    me.uv_layers.new(name="UVMap")
    ob=bpy.data.objects.new(name, me)
    bpy.context.collection.objects.link(ob)
    # 纯数据平滑: 每面 use_smooth + me.update() 重算平均顶点法线(无需操作符/多对象选择)
    for p in me.polygons: p.use_smooth=True
    me.update()
    return ob

# ---------- 场景 ----------
bpy.ops.wm.read_factory_settings(use_empty=True)
scene=bpy.context.scene
scene.render.engine="CYCLES"; scene.cycles.device="CPU"; scene.cycles.samples=16
scene.cycles.use_denoising=False
scene.render.resolution_x=520; scene.render.resolution_y=520
scene.world=bpy.data.worlds.new("W"); scene.world.use_nodes=True
bg=scene.world.node_tree.nodes["Background"]
bg.inputs[0].default_value=(0.92,0.93,0.97,1); bg.inputs[1].default_value=1.0

ob=build_breast_mesh("breast")

cam_d=bpy.data.cameras.new("cam"); cam=bpy.data.objects.new("cam",cam_d)
scene.collection.objects.link(cam); scene.camera=cam; cam_d.lens=70
sun_d=bpy.data.lights.new("sun","SUN"); sun=bpy.data.objects.new("sun",sun_d)
scene.collection.objects.link(sun); sun.rotation_euler=(math.radians(55),0,math.radians(35)); sun_d.energy=4
p_eye=bpy.data.lights.new("e","POINT"); p=bpy.data.objects.new("p",p_eye)
scene.collection.objects.link(p); p.location=(0.4,-0.5,0.6); p_eye.energy=40

import mathutils
os.makedirs(outdir,exist_ok=True)
# 相机对准对象包围盒中心
bco=[ob.matrix_world @ mathutils.Vector(c) for c in ob.bound_box]
center=mathutils.Vector((sum(v[0] for v in bco)/8,sum(v[1] for v in bco)/8,sum(v[2] for v in bco)/8))
target=(center[0],center[1],center[2])
maxd=max(mathutils.Vector((c[0]-target[0],c[1]-target[1],c[2]-target[2])).length for c in bco)
views={"front":(target[0],target[1]+maxd*3.4,target[2]),"side":(target[0]+maxd*3.4,target[1],target[2]),"threeq":(target[0]+maxd*2.6,target[1]+maxd*2.6,target[2]+maxd*0.5)}
for name,loc in views.items():
    cam.location=loc
    dirv=(target[0]-cam.location[0],target[1]-cam.location[1],target[2]-cam.location[2])
    cam.rotation_euler=mathutils.Vector(dirv).to_track_quat('-Z','Y').to_euler()
    scene.render.filepath=f"{outdir}/{name}.png"
    bpy.ops.render.render(write_still=True)
    print("WROTE",scene.render.filepath)
print("DONE")
