曇り空と今いるとこ
気ままに思いついた事を綴っていきます。 本サイトはプロモーションや広告を利用しています。 当サイトでは「広告」を掲載している場合があります。 消費者庁が問題としている「誇大な宣伝や表現」に配慮しコンテンツを制作しております。
Translate(ブログを翻訳)
2026-05-08 アクションゲーム、FPS、TPS のステージギミック
2025-11-02 引きこもり日本人の肌はMB-Labで表現できない
MB-Lab で作成する人型モデルは、白に近いベージュ、日に当たっていない引きこもり日本人の肌をMB-Labパラメータだけでは表現できませんでした。
少なくとも、私には見つけられませんでした。
ですが、日に当たっていない引きこもり日本人の肌を表現するため、blender で少し弄ってみます。
先ほども書きましたが、MB-Labパラメータだけでは表現できないので、MB-Labは「Finalize Character」ボタンを押し完了させます。
上部のタブを「Shading(シェーディング)」に切り替えます。
キャラクターを選択し、右上のマテリアル一覧から「MB_LAB_Character」-オレンジ色人型「MBlab_***」-オレンジ色逆三角形「MBlab_***」-緑色逆三角形「MBLab_human_***」-赤まだら模様球型「MBlab_skin***」を選択します。
blender画面中央下段のノードマップの左上に茶色の枠で「Human_mblab_skn_albedo」と書かれている小さい帯があるのでそれをクリック
2025-10-19 godot で TPS の視線によってキャラクターの頭部(顔)や腕の向きを変える
godot の TPS を作っていると、視線が上に向いてもキャラクターの顔や腕(銃を持っているなら銃口)が上に向かず不自然な時があります。
体とは別に頭部や腕(腕の付け根から)を別パーツとして作ると、視線と顔の向きを上向きや下向きにできる gdスクリプトを作りました。
頭部や腕と体(Skeleton3D)の接合は、Boneattached3D で繋げる前提です。
図にするとこんな感じ。

体(Skeleton3D)の配下に Boneattached3D が、頭部と左右の腕の分で計3つの Boneattached3D が並列に付きます。
その Boneattached3D の配下に、頭部や腕部のオブジェクトが付きます。
で、その頭部や腕にgdスクリプト(PlushAimer.gd)をアタッチします。
頭部にアタッチするスクリプトは次の通り
腕に付ける gdスクリプトは別にあり、左右で別々に付けます。
左右で内容・ファイル名(ArmPitchNode.gd)は一緒にしました。
次の通りです
2025-10-06 ubuntu touch アップデートきました
アップデートきました! 何でわざわざ書いているかと言うと、ブラウザで表示する youtube がカクカクしていたのが、滑らかに動くようになったから嬉しくてね!
このおかげで、ubuntu touch の waydroid にお世話になる時間が少なくなりました!
waydroid 少なめなのでバッテリー消費も少なくなった気がします。よかった よかった
2025-09-14 blender + MB-lab → mixamo に取り込むためボーン(bone)名変更と他修正
blender のアドオンで MB-lab があり、人物キャラクターを作るのに便利です。
そのキャラクターを mixamo にボーン情報を取り込むための手順を(主に備忘ですが)記載します
とりあえず、MB-lab の finalaiz する
MB-lab ではなにもポーズはかえないまま Aポーズとする
シェイプの適用は待って、ボーン名変更スクリプトと、Aポーズ(Apose)→Tポーズ(T-Pose)スクリプトを実行
(ボーン名変更スクリプトと、T-Aスクリプトは下部に記載します)
オブジェクトモードにする
体をクリック
右下の緑色の逆三角形を選択し、「シェイプキー」を全部適用
(下向きのへの字を押して「全シェイプキーを適用」が早いです)
右下のスパナのマークをクリックして、全てのモディファイアーを
「人のマーク」の付いたモディファイアー以外を適用して
(うっかり全部適用した場合は、
「Add Modifier」→「Armature」→「Object」にリグ(MBlab_sk***)を指定)
fbx 形式でエクスポートする
エクスポートするときは、右上の「シーンコレクション(箱のマーク)」「MB_LAB_Character(箱のマーク)」
の下の人のマークやオレンジの逆三角形のマーク全てを選択状態にしてエクスポートする
fbxエクスポート設定
・対象
選択したオブジェクト
可視オブジェクト
・オブジェクト
アーマチュア
メッシュ
・トランスフォーム
スケール 1.00 (デフォルトから変更しない)
スケールを適用 全ローカル (デフォルトから変更しない)
前方 -Zが前 (デフォルトから変更しない)
上 Yが上 (デフォルトから変更しない)
単位を適用 チェック入れ (デフォルトから変更しない)
空間の変換を私用 チェック入れ (デフォルトから変更しない)
トランスッフォームを適用 チェック入れ
・ジオメトリ
変更なし
・アーマチュア
変更なし
・アニメーション
チェックを外す
ボーン名変更スクリプト を記載します
2025-08-30 digispark のライブラリダウンロード URL 変更?
昔の記事とかに digistump から…みたいなことが書いてあるけど、
もう、URL変わったのかわかりませんがダウンロードできません。
× http://digistump.com/package_digistump_index.json
下記の URL に変更しましょう。
○ http://drazzy.com/package_drazzy.com_index.json
2025-07-19 godot 4.4.1 でアドベンチャーゲーム(ADV)のセリフを表示する枠・欄のようなものをざっくりと作る
extends Control
@onready var label = $Panel/Label
@onready var button_yes = $Panel/ButtonYes
@onready var button_no = $Panel/ButtonNo
var yes_callback: Callable = func(): pass
var no_callback: Callable = func(): pass
var _on_buttonYes_pressed: Callable = func(): pass
var _on_buttonNo_pressed: Callable = func(): pass
# サイズ・色などを直接設定する関数
func set_box_style_custom(box_size: Vector2, box_position: Vector2, bg_color: Color, text_color: Color):
$Panel.size = box_size
$Panel.position = box_position
var style_box := StyleBoxFlat.new()
style_box.bg_color = bg_color
style_box.corner_radius_all = 8
$Panel.add_theme_stylebox_override("panel", style_box)
$Panel/Label.add_theme_color_override("font_color", text_color)
# プリセットスタイルを適用する関数
func set_box_style(style: String = "default"):
match style:
"title":
MessageBoxStyler.apply_title_style(self)
_:
MessageBoxStyler.apply_default_style(self)
###func show_message(text: String, on_yes: Variant = null, on_no: Variant = null):
func show_message(
text: String,
on_yes: Variant = null,
on_no: Variant = null,
yes_text: String = "Yes",
no_text: String = "No"
):
if label == null:
push_error("x label が null です。ノード 'Panel/Label' を確認してください")
else:
label.text = text
visible = true
button_yes.visible = on_yes != null
button_no.visible = on_no != null
button_yes.text = yes_text
button_no.text = no_text
yes_callback = on_yes if on_yes != null else func(): pass
no_callback = on_no if on_no != null else func(): pass
yes_callback = on_yes if on_yes != null else func(): pass
no_callback = on_no if on_no != null else func(): pass
func _on_button_yes_pressed():
visible = false
yes_callback.call()
func _on_button_no_pressed():
visible = false
no_callback.call()
func _ready():
hide()
# o シグナルが接続されていない場合に備えて接続
$Panel/ButtonYes.pressed.connect(_on_button_yes_pressed)
$Panel/ButtonNo.pressed.connect(_on_button_no_pressed)
# デフォルトボタン動作
_on_buttonYes_pressed = func(): pass
_on_buttonNo_pressed = func(): pass
func _on_ButtonYes_pressed():
_on_buttonYes_pressed.call()
func _on_ButtonNo_pressed():
_on_buttonNo_pressed.call()
func set_button_texts(text1: String, text2: String):
if $ButtonYes and $ButtonNo:
$ButtonYes.text = text1
$ButtonNo.text = text2
else:
push_error("x ButtonYes または ButtonNo が見つかりません")
func set_callbacks(callback1: Callable, callback2: Callable):
_on_buttonYes_pressed = callback1
_on_buttonNo_pressed = callback2
# ---- message_box.gd ここまで ----#class_name MessageBoxStyler
static func apply_title_style(box: Control):
assert(box != null)
var panel := box.get_node("Panel")
panel.size = Vector2(800, 400)
panel.position = Vector2(500, 300)
panel.modulate = Color(2, 2, 2, 0.8)
var stylebox := StyleBoxFlat.new()
stylebox.bg_color = Color(0.1, 0.1, 0.1, 0.6)
stylebox.border_width_bottom = 2
stylebox.border_color = Color(1, 1, 0)
panel.add_theme_stylebox_override("bg", stylebox)
var label := box.get_node("Panel/Label")
if label.label_settings == null:
label.label_settings = LabelSettings.new()
label.label_settings.font_size = 48
label.horizontal_alignment = HORIZONTAL_ALIGNMENT_CENTER
label.vertical_alignment = VERTICAL_ALIGNMENT_CENTER
var button_yes := box.get_node("Panel/ButtonYes")
var button_no := box.get_node("Panel/ButtonNo")
button_yes.size = Vector2(400, 50)
button_yes.position = Vector2(100, 160)
button_yes.text = "Yes"
button_no.size = Vector2(400, 50)
button_no.position = Vector2(100, 260)
button_no.text = "No"
button_yes.size_flags_horizontal = 0
button_no.size_flags_horizontal = 0
###var font_settings := LabelSettings.new()
###font_settings.font_size = 36
# Yes ボタン
button_yes.text = "Yes"
button_yes.add_theme_font_size_override("font_size", 24)
button_yes.add_theme_color_override("font_color", Color(0, 0, 0, 1.0)) # 黒文字
var yes_style := StyleBoxFlat.new()
yes_style.bg_color = Color(0.4, 0.9, 0.4, 1.0) # 緑
button_yes.add_theme_stylebox_override("normal", yes_style)
# No ボタン
button_no.text = "No"
button_no.add_theme_font_size_override("font_size", 24)
button_no.add_theme_color_override("font_color", Color(0, 0, 0, 1.0))
var no_style := StyleBoxFlat.new()
no_style.bg_color = Color(0.9, 0.4, 0.4, 1.0) # 緑
button_no.add_theme_stylebox_override("normal", no_style)
print("ButtonNo pos: ", button_no.position)
print("ButtonNo size: ", button_no.size)
print("Panel size: ", panel.size)
# --- パネルが画面外にはみ出ないように調整 ---
var screen_size = box.get_viewport().get_visible_rect().size
# パネルのサイズが大きすぎたら調整
panel.size.x = min(panel.size.x, screen_size.x - 20)
panel.size.y = min(panel.size.y, screen_size.y - 20)
# パネルの位置がはみ出していたら調整
if panel.position.x + panel.size.x > screen_size.x:
panel.position.x = screen_size.x - panel.size.x - 10
if panel.position.y + panel.size.y > screen_size.y:
panel.position.y = screen_size.y - panel.size.y - 10
# 画面外に飛びすぎていたら 0 に制限(逆方向)
panel.position.x = max(panel.position.x, 10)
panel.position.y = max(panel.position.y, 10)
static func apply_default_style(box: Control):
assert(box != null)
var panel := box.get_node("Panel")
panel.size = Vector2(800, 240)
panel.position = Vector2(100, 500)
panel.modulate = Color(0, 0, 0, 0.8)
var stylebox := StyleBoxFlat.new()
stylebox.bg_color = Color(0.1, 0.1, 0.1, 0.6)
stylebox.border_width_bottom = 2
stylebox.border_color = Color(1, 0, 0)
panel.add_theme_stylebox_override("bg", stylebox)
var label := box.get_node("Panel/Label")
if label.label_settings == null:
label.label_settings = LabelSettings.new()
label.label_settings.font_size = 24
label.horizontal_alignment = HORIZONTAL_ALIGNMENT_LEFT
label.vertical_alignment = VERTICAL_ALIGNMENT_CENTER
panel.modulate = Color(1, 1, 1, 1) # ← 透明度の影響を排除
var button_yes := box.get_node("Panel/ButtonYes")
var button_no := box.get_node("Panel/ButtonNo")
# Yes ボタン
button_yes.text = "Yes"
button_yes.add_theme_font_size_override("font_size", 24)
button_yes.add_theme_color_override("font_color", Color(0, 0, 0, 1.0)) # 黒文字
var yes_style := StyleBoxFlat.new()
yes_style.bg_color = Color(0.4, 0.9, 0.4, 1.0) # 緑
button_yes.add_theme_stylebox_override("normal", yes_style)
button_yes.position = Vector2(100, 120)
# No ボタン
button_no.text = "No"
button_no.add_theme_font_size_override("font_size", 24)
button_no.add_theme_color_override("font_color", Color(0, 0, 0, 1.0)) # 黒文字
var no_style := StyleBoxFlat.new()
###no_style.bg_color = Color(1.0, 0.5, 0.6, 1.0) # ピンク寄り赤
no_style.bg_color = Color(0.4, 0.9, 0.4, 1.0) # 緑
button_no.add_theme_stylebox_override("normal", no_style)
button_no.position = Vector2(50, 60)
print("ButtonNo pos: ", button_no.position)
print("ButtonNo size: ", button_no.size)
print("Panel size: ", panel.size)
# --- パネルが画面外にはみ出ないように調整 ---
var screen_size = box.get_viewport().get_visible_rect().size
# パネルのサイズが大きすぎたら調整
panel.size.x = min(panel.size.x, screen_size.x - 20)
panel.size.y = min(panel.size.y, screen_size.y - 20)
# パネルの位置がはみ出していたら調整
if panel.position.x + panel.size.x > screen_size.x:
panel.position.x = screen_size.x - panel.size.x - 10
if panel.position.y + panel.size.y > screen_size.y:
panel.position.y = screen_size.y - panel.size.y - 10
# 画面外に飛びすぎていたら 0 に制限(逆方向)
panel.position.x = max(panel.position.x, 10)
panel.position.y = max(panel.position.y, 10)
#---- message_box_styler.gd ここまで ----#extends Node3D
@onready var msgbox = $world/CanvasLayer/MessageBox
###@onready var player = $world/Player # player の取得も必要ならここで
func _ready():
msgbox.set_box_style("title")
msgbox.show_message("This is GAME. start game?",
func():
###player.enabled = true
print("o YES select. move scene")
get_tree().change_scene_to_file("res://scene/_scene_0001/scene_0001.tscn"),
func():
###player.enabled = true
print("No select..."),
"Start Game",
"No Game"
)
#---- scene_0000.gd ----#2025-03-01 mixamo のモーションを blender に取り込む(rokoko使わないバージョン)
blender のアドオンの rokoko を導入してモーションとりこんでいたが、たまにキャラクターが空中にういたようなモーションになった。
そのため、rokoko を使わないで取り込む手順を模索してその結果を記載する。
vrm,fbx読み込みの後から記載
blender 上部メニューの「アニメーション」にする
下部のタイムラインの欄は「ドープシート」を選ぶ
「ドープシート」から「アクションエディター」に変える
上部のキャラクターが表示されている欄を「オブジェクトモード」にする
いったん、右上のツリー内の適用先の「(オレンジ色)Armature」をクリックし、
モーション持っている側の「(オレンジ色)Armature.001」をクリックする
###「アクションエディター」欄のタイムライン内の「概要」の直下の Armature.001 から jump 等に名前を変える
右上のツリー内の適用先の「(オレンジ色)Armature」をクリック
「アクションエディター」欄の「+ 新規」の左隣りの菱形が逆三角形でならんでいるアイコンプルダウンを展開し
「F Armature.001|mixamo.com|Layer0」を選択する
でてきた「Armature.001」を任意の名前(jump等)に変える
blender 上部メニューの「スクリプト作成」を選択し、「新規」を押し下記スクリプトを実行する。
### スクリプト実行だけではまだです。スクリプト実行後も適用の手順続きます。
### ここから ###
import bpy
# --- 設定 ---
target_armature_name = "Armature"
source_armature_name = "Armature.001"
bone_names = [
"mixamorig:Hips", "mixamorig:Spine", "mixamorig:Neck", "mixamorig:Head",
"mixamorig:RightShoulder", "mixamorig:RightHand",
"mixamorig:LeftShoulder", "mixamorig:LeftHand",
"mixamorig:RightFoot", "mixamorig:RightToeBase",
"mixamorig:LeftFoot", "mixamorig:LeftToeBase",
"mixamorig:Chest", "mixamorig:UpperChest",
"mixamorig:LeftUpperArm", "mixamorig:LeftLowerArm",
"mixamorig:LeftIndex1", "mixamorig:LeftIndex2", "mixamorig:LeftIndex3",
"mixamorig:LeftLittle1", "mixamorig:LeftLittle2", "mixamorig:LeftLittle3",
"mixamorig:LeftMiddle1", "mixamorig:LeftMiddle2", "mixamorig:LeftMiddle3",
"mixamorig:LeftRing1", "mixamorig:LeftRing2", "mixamorig:LeftRing3",
"mixamorig:LeftThumb1", "mixamorig:LeftThumb2", "mixamorig:LeftThumb3",
"mixamorig:RightUpperArm", "mixamorig:RightLowerArm",
"mixamorig:RightIndex1", "mixamorig:RightIndex2", "mixamorig:RightIndex3",
"mixamorig:RightLittle1", "mixamorig:RightLittle2", "mixamorig:RightLittle3",
"mixamorig:RightMiddle1", "mixamorig:RightMiddle2", "mixamorig:RightMiddle3",
"mixamorig:RightRing1", "mixamorig:RightRing2", "mixamorig:RightRing3",
"mixamorig:RightThumb1", "mixamorig:RightThumb2", "mixamorig:RightThumb3",
"mixamorig:LeftUpperLeg", "mixamorig:LeftLowerLeg", "mixamorig:LeftFoot", "mixamorig:LeftToe_End",
"mixamorig:RightUpperLeg", "mixamorig:RightLowerLeg", "mixamorig:RightFoot", "mixamorig:RightToe_End"
]
def retarget_mixamo_animation(target_armature_name, source_armature_name, bone_names):
"""Mixamo アニメーションをターゲットアーマチュアにリターゲットします。"""
try:
target_armature = bpy.data.objects[target_armature_name]
source_armature = bpy.data.objects[source_armature_name]
except KeyError as e:
print(f"エラー:オブジェクトが見つかりません: {e}")
return
if target_armature.type != 'ARMATURE' or source_armature.type != 'ARMATURE':
print("エラー:指定されたオブジェクトはアーマチュアではありません。")
return
bpy.context.view_layer.objects.active = target_armature # ターゲットアーマチュアをアクティブにする
for bone_name in bone_names:
target_bone = target_armature.pose.bones.get(bone_name)
source_bone = source_armature.pose.bones.get(bone_name)
if target_bone and source_bone:
# コンストレイントをクリア (既存のものを削除)
if bone_name in target_bone.constraints:
target_bone.constraints.remove(bone_name)
# コピー変換コンストレイントを Bone に追加
copy_transforms = target_bone.constraints.new('COPY_TRANSFORMS')
copy_transforms.target = source_armature
copy_transforms.subtarget = source_bone.name
print(f"ボーン '{bone_name}' にコンストレイントを追加")
else:
if not target_bone:
print(f"警告:ターゲットアーマチュア '{target_armature_name}' にボーン '{bone_name}' が見つかりません。スキップします。")
elif not source_bone:
print(f"警告:ソースアーマチュア '{source_armature_name}' にボーン '{bone_name}' が見つかりません。スキップします。")
print("Mixamo アニメーションのリターゲット処理が完了しました。")
# スクリプト実行
retarget_mixamo_animation(target_armature_name, source_armature_name, bone_names)
### ここまで ###
#########################
blender 上部メニューの「レイアウト」を選択し「ポーズモード」にする
右上のツリー内の適用先の「Armature」をクリック
左枠のキャラクターのそばの空いてるところで「A」キー
「ポーズモード」枠のメニューの「ポーズ」「アニメーション」「アニメーションをベイク」を選ぶ
最終フレームの欄に、モーションの最終フレームの数字をいれ、
「ビジュアルキーイング」「コンストレイントをクリア」「現在のアクションを上書き」に追加でチェック入れる
### あと始末
右シーンコレクション内に追加していたコレクションを
丸ごと削除する
Armature.001 のようなものが残ったら、それも削除する
2025-02-26 vroid studio → blender → mixamo → godot
#---------- スクリプトここから ----------import bpyfor x in bpy.context.object.data.bones:x.name = x.name.replace("J_Bip_C_", "mixamorig:")x.name = x.name.replace("J_Bip_L_", "mixamorig:Left")x.name = x.name.replace("J_Bip_R_", "mixamorig:Right")x.name = x.name.replace("LeftUpper", "LeftUp")x.name = x.name.replace("RightUpper", "RightUp")x.name = x.name.replace("mixamorig:Chest", "mixamorig:Spine1")x.name = x.name.replace("mixamorig:UpperChest", "mixamorig:Spine2")x.name = x.name.replace("LowerLeg", "Leg")x.name = x.name.replace("LowerArm", "ForeArm")x.name = x.name.replace("UpArm", "Arm")x.name = x.name.replace("LeftIndex", "LeftHandIndex")x.name = x.name.replace("LeftThumb", "LeftHandThumb")x.name = x.name.replace("LeftRing", "LeftHandRing")x.name = x.name.replace("LeftMiddle", "LeftHandMiddle")x.name = x.name.replace("LeftLittle", "LeftHandPinky")x.name = x.name.replace("RightIndex", "RightHandIndex")x.name = x.name.replace("RightThumb", "RightHandThumb")x.name = x.name.replace("RightRing", "RightHandRing")x.name = x.name.replace("RightMiddle", "RightHandMiddle")x.name = x.name.replace("RightLittle", "RightHandPinky")#---------- スクリプトここまで ----------

























