断面形状等を精密に再現したものではなく、あくまでも画像の輝度値から似たような雰囲気に仕立てたものとなりますのでご了承願います。
近頃は生成Ai関連の業務が多く、Grasshopperによるモデリングの時間がかなり減ってしまいましたが、忘れないように細々と触っております。
ここ数年にわたりAiの進化が激しく、デザインの提案レベルであれば短時間の画像生成で代用できてしまい、わざわざデータを作る必要が無いため、今後もこのような傾向が続きそうですね。
少し話が脱線しましたが、今回はシボ形状の作り方を解説していきます。
・ベタ塗りみたいに見えますが、実際には0.1mmピッチで点を作成しています。
・シボをそれっぽく再現するには点の密度を細かくする必要があるためデータサイズがかなり大きくなってしまいます。
・作成した点群をギリギリカバーする範囲のサーフェスを作成します。
・次に、シボのサンプル画像を用意します。上の画像はChat GPTを使って生成しました。
・サーフェスにおける点群の位置のUV座標を取り出し、Image Samplerのノードにつないで輝度値を取り出します。
・XY平面上のポリゴンメッシュを冒頭で作成した表面サーフェスにメッシュのモーフィングを行います。
----------------------------------------------------------------------------------------------------------------------
・Mesh Splitノードにそれぞれつないで分割し、その後ろにメッシュの結合、ウェルド処理をつなげたら完成です。
・次に、シボのサンプル画像を用意します。上の画像はChat GPTを使って生成しました。
・サイズが1254 x 1254で96dpiのpng画像です。
・取り出した輝度値をRemapノードにつないで0~最大深さの範囲に変換し、Z座標軸にかけ合わせてベクトルデータに変換します。
・Image Samplerの設定は、XとYの範囲が0 To 1、Channelはbrightnessを選択。
・計算したベクトルに沿って点を移動させたあと、Delaunay Mesh(ドロネーメッシュ)コンポーネントにつないでポリゴンメッシュを生成します。
・モーフィングの個所はノードで組む方法がなかなか思いつかなかったので、Chat GPTでPythonスクリプトを生成させる方法を取りました。スクリプトの中身は以下となります。
-----------------------------------------------------------------------------------------------------------------
"""GhPython (Rhino7)
Inputs
------
input : Mesh
target : Surface または BrepFace
Output
------
object : Mesh
"""
import Rhino
import Rhino.Geometry as rg
import Grasshopper as gh
# ==========================================================
# Utility
# ==========================================================
def clamp(value, minimum, maximum):
if value < minimum:
return minimum
if value > maximum:
return maximum
return value
def get_surface(obj):
"""Surface/BrepFaceどちらでも受け付ける"""
if obj is None:
return None
if isinstance(obj, rg.Surface):
return obj
if isinstance(obj, rg.BrepFace):
return obj.UnderlyingSurface()
if hasattr(obj, "UnderlyingSurface"):
return obj.UnderlyingSurface()
return None
# ==========================================================
# Morph
# ==========================================================
def morph_mesh(mesh, surface):
bbox = mesh.GetBoundingBox(True)
xmin = bbox.Min.X
ymin = bbox.Min.Y
zmin = bbox.Min.Z
xmax = bbox.Max.X
ymax = bbox.Max.Y
width = xmax - xmin
height = ymax - ymin
if width < Rhino.RhinoMath.ZeroTolerance:
raise Exception("BoundingBoxの幅が0です。")
if height < Rhino.RhinoMath.ZeroTolerance:
raise Exception("BoundingBoxの高さが0です。")
# Surface Domain
u_domain = surface.Domain(0)
v_domain = surface.Domain(1)
result = mesh.DuplicateMesh()
verts = result.Vertices
for i in range(verts.Count):
v = verts[i]
# -------------------------
# XY -> 0~1
# -------------------------
uu = (v.X - xmin) / width
vv = (v.Y - ymin) / height
uu = clamp(uu, 0.0, 1.0)
vv = clamp(vv, 0.0, 1.0)
# -------------------------
# Surface UV
# -------------------------
u = u_domain.ParameterAt(uu)
w = v_domain.ParameterAt(vv)
pt = surface.PointAt(u, w)
normal = surface.NormalAt(u, w)
normal.Unitize()
# 元メッシュの高さを保持
offset = v.Z - zmin
pt = pt + normal * offset
verts.SetVertex(i, pt)
result.Normals.ComputeNormals()
result.Compact()
return result
# ==========================================================
# Main
# ==========================================================
object = None
try:
if input is None:
raise Exception("Meshが入力されていません。")
if target is None:
raise Exception("Surfaceが入力されていません。")
if not isinstance(input, rg.Mesh):
raise Exception("inputはMeshを入力してください。")
srf = get_surface(target)
if srf is None:
raise Exception("targetはSurfaceまたはBrepFaceである必要があります。")
object = morph_mesh(input, srf)
except Exception as e:
ghenv.Component.AddRuntimeMessage(
gh.Kernel.GH_RuntimeMessageLevel.Error,
str(e)
)
if isinstance(input, rg.Mesh):
object = input.DuplicateMesh()
else:
object = None
----------------------------------------------------------------------------------------------------------------------
・シボ形状と相関を取る形状を作成します。
・冒頭で作成した形状のうち、シボを配置する表面のエッジ部分をZ方向に押し出しサーフェスを作成し、Mesh Brepノードにつないでメッシュに変換します。
・Mesh Brepノードの設定によってメッシュの細かさが変わります。今回は、Max Edgeの項目のみ変更しています。
・データのサイズが大きいため、小さなサンプル形状を作るぐらいが限界かもしれません。











0 件のコメント:
コメントを投稿