Blenderで遊ぶ(Production diary)
The main content is the process of creating the game engine assets currently being created.
2024年7月23日火曜日
2024年7月22日月曜日
Spatial Mini Games Privacy Policy
Our app does not collect, store, or share any personal information from users.
Data Not Collected
- Contact Information (name, email address, etc.)
- Health/Fitness Information
- Financial Information
- Location Data
- Sensitive Information
- User Content (photos, videos, audio data, etc.)
- Browsing/Search History
- Identifiers (user ID, device ID)
- Usage Data
- Diagnostic Data
- Environmental Scanning Data
- Physical Data
Our app does not collect data on hand movements, gaze positions, or any other gameplay-related data.
Spatial Mini Games
https://apps.apple.com/us/app/spatial-mini-games/id6553981220
Support mail:junichistamesi@gmail.com
Overview:
Spatial Mini Games is a collection of engaging and interactive spatial experiences designed for Apple Vision Pro. Utilize the power of visionOS to immerse yourself in various fun and challenging mini-games that will test your reflexes and spatial awareness. Perfect for casual play, each game is quick and accessible, ideal for solo play or friendly fun at home gatherings.
- Tap on a bubble to display the game start button, game description, and up to the top 10 previous scores.
- Tap the config button to access the music toggle button and the reset game data button.
- After selecting a game, a "Mini Games" panel is displayed, which changes to the Game Start button after 3 seconds.
- The selected game begins with a scanned representation of the actual wall.
- It is recommended to look around and ensure the wall is correctly scanned.
- Upon first use, the app will ask for permission to access hand movement and environmental data. You must select "Yes" to proceed with the game.
- If you accidentally select "No," go to settings, select the app, and allow access to "Hand Pose and Motion" and "Surroundings" for Spatial Mini Games.
- During any mini-game, tap the config button on your left wrist to display the music toggle button, home button, and remaining time.
2024年5月28日火曜日
How to transfer root bone pose animation to the animation of the entire armature
#RootPoseToArmature
import bpy
from mathutils import Matrix, Vector
# Note: This script will automatically set the armature's rotation mode to QUATERNION.
# The root bone will be deleted after the script runs.
# Make sure to back up your project before running this script.
# Set the name of the root bone
root_bone_name = "Root" # Set the name of the root bone
# Get the currently selected object
armature = bpy.context.active_object
if not armature or armature.type != 'ARMATURE':
raise ValueError("Please select an armature object.")
bpy.context.view_layer.objects.active = armature
# Switch to Object Mode to get the default pose
bpy.ops.object.mode_set(mode='OBJECT')
# Get the default global location and rotation of the root bone
root_bone = armature.pose.bones.get(root_bone_name)
if not root_bone:
raise ValueError(f"Root bone '{root_bone_name}' not found.")
# Get the armature's rest pose
armature_matrix_world = armature.matrix_world.copy()
root_bone_matrix_rest = armature.data.bones[root_bone_name].matrix_local.copy()
root_bone_matrix_world_rest = armature_matrix_world @ root_bone_matrix_rest
root_bone_default_loc, root_bone_default_rot, _ = root_bone_matrix_world_rest.decompose()
inverse_root_bone_default_rot = root_bone_default_rot.inverted()
# Get the IK targets
ik_targets = []
for bone in armature.pose.bones:
for constraint in bone.constraints:
if constraint.type == 'IK' and constraint.target:
target = constraint.target
if target.parent == armature:
ik_targets.append(target)
# Record the global positions of the IK targets for each keyframe
ik_target_keyframes = {}
for target in ik_targets:
ik_target_keyframes[target.name] = {}
if target.animation_data and target.animation_data.action:
for fcurve in target.animation_data.action.fcurves:
for keyframe in fcurve.keyframe_points:
frame = int(keyframe.co.x)
bpy.context.scene.frame_set(frame)
ik_target_keyframes[target.name][frame] = target.matrix_world.translation.copy()
# Get the animation data
animation_data = armature.animation_data
if not animation_data:
raise ValueError("Animation data not found.")
action = animation_data.action
if not action:
raise ValueError("Action not found in animation data.")
# Process the animation data and apply the root bone transform to the armature
transform_data = {'location': [], 'rotation_quaternion': [], 'scale': []}
for fcurve in action.fcurves:
if fcurve.data_path.startswith(f"pose.bones[\"{root_bone_name}\"]"):
for keyframe in fcurve.keyframe_points:
frame = int(keyframe.co.x)
# Move to the frame to set the keyframe
bpy.context.scene.frame_set(frame)
# Get the pose position of the root bone
root_bone_matrix = root_bone.matrix
# Calculate the global transform of the root bone
global_matrix = armature.matrix_world @ root_bone_matrix
# Decompose the matrix into location, rotation, and scale
global_loc, global_rot, global_scale = global_matrix.decompose()
# Save the transform data in the dictionary
transform_data['location'].append((frame, global_loc))
transform_data['rotation_quaternion'].append((frame, global_rot))
transform_data['scale'].append((frame, global_scale))
# Switch to Object Mode to apply transformations
bpy.ops.object.mode_set(mode='OBJECT')
# Automatically set the armature's rotation mode to QUATERNION
armature.rotation_mode = 'QUATERNION'
# Apply the transforms to the armature object and insert keyframes
for (frame, loc), (_, rot) in zip(transform_data['location'], transform_data['rotation_quaternion']):
# Correct the rotation for the root bone's default rotation
corrected_rot = (rot @ inverse_root_bone_default_rot)
# Create the translation matrices for the default and current locations
translation_matrix_to_default = Matrix.Translation(-root_bone_default_loc)
translation_matrix_back = Matrix.Translation(root_bone_default_loc)
translation_matrix_current = Matrix.Translation(loc)
# Create the rotation matrix for the corrected rotation
rotation_matrix = corrected_rot.to_matrix().to_4x4()
# Combine the matrices:
# 1. Translate to default position
# 2. Apply rotation
# 3. Translate to the current location
final_matrix = translation_matrix_current @ rotation_matrix @ translation_matrix_to_default
# Decompose the final matrix into location and rotation
final_loc, final_rot, _ = final_matrix.decompose()
# Apply the final location and rotation to the armature
armature.location = final_loc
armature.rotation_quaternion = final_rot
armature.keyframe_insert(data_path="location", frame=frame)
armature.keyframe_insert(data_path="rotation_quaternion", frame=frame)
for frame, scale in transform_data['scale']:
armature.scale = scale
armature.keyframe_insert(data_path="scale", frame=frame)
# Update the IK target positions for each frame
for target in ik_targets:
for frame, initial_position in ik_target_keyframes[target.name].items():
bpy.context.scene.frame_set(frame)
# Convert the initial position to the armature's local space at the current frame
local_pos = armature.matrix_world.inverted() @ initial_position
target.location = local_pos
target.keyframe_insert(data_path="location", frame=frame)
# Delete the root bone
bpy.ops.object.mode_set(mode='EDIT')
bones = armature.data.edit_bones
root_bone = bones.get(root_bone_name)
if root_bone:
bones.remove(root_bone)
# Restore the current frame
bpy.context.scene.frame_set(bpy.context.scene.frame_current)
2024年4月30日火曜日
UnityでつけたポーズをBlenderに取り込む方法(もっと簡単な方法あるかも)
Unityのエディタでシーンビュー内でつけたポーズをBlenderにもっていく方法
1. Unity側のスクリプトをポーズを付けたFBXにアタッチしてレストポーズにしたFBXを
referenceModelとして設定する。
ポーズを付けたFBXのrootBoneと出力先のパスを設定する。
2. インスペクター上で右クリックでExportBoneData
3. Blender側のスクリプトでアーマチュアの名前と読み込むポーズのファイルのパスを設定して RunScript
↓Unity側
using System.Collections.Generic;
using UnityEngine;
using System.IO;
[System.Serializable]
public class BoneData
{
public string name;
public Vector3 position;
public Vector3 scale;
public Quaternion rotation; // This will be Q_relative
}
[System.Serializable]
public class BoneDataList
{
public List<BoneData> bones = new List<BoneData>();
}
public class BoneDataExporter : MonoBehaviour
{
public Transform rootBone;
public GameObject referenceModel; // Add a field for the reference model
public string boneDataPath = "Assets/boneData.json";
[ContextMenu("Export Bone Data")]
void ExportBoneData()
{
BoneDataList boneDataList = new BoneDataList();
CollectBoneData(rootBone, boneDataList.bones, referenceModel.transform);
string json = JsonUtility.ToJson(boneDataList, true);
File.WriteAllText(boneDataPath, json);
Debug.Log("Bone data exported!");
}
void CollectBoneData(Transform bone, List<BoneData> boneData, Transform reference)
{
// Find the same bone in the reference model by name
Transform referenceBone = reference.FindChildRecursive(bone.name);
Quaternion Q0 = referenceBone != null ? referenceBone.localRotation : Quaternion.identity;
Quaternion Q = bone.localRotation;
Quaternion Q0_inv= Quaternion.Inverse(Q0);
Quaternion Q_relative =Q0_inv*Q;
Quaternion Q_final = new Quaternion(Q_relative.x, -Q_relative.y, -Q_relative.z, Q_relative.w);
boneData.Add(new BoneData
{
name = bone.name,
position = bone.localPosition,
scale = bone.localScale,
rotation = Q_final // Store the relative rotation
});
foreach (Transform child in bone)
{
CollectBoneData(child, boneData, reference);
}
}
}
↓Blender側
import bpy
import json
def apply_pose(armature_name, json_path):
with open(json_path, 'r') as f:
data = json.load(f)
armature = bpy.data.objects[armature_name]
bpy.context.view_layer.objects.active = armature
bpy.ops.object.mode_set(mode='POSE')
for bone_data in data['bones']:
bone = armature.pose.bones.get(bone_data['name'])
if bone:
bone.location = (bone_data['position']['x'], bone_data['position']['y'], bone_data['position']['z'])
bone.scale = (bone_data['scale']['x'], bone_data['scale']['y'], bone_data['scale']['z'])
# 注意:四元数は (w, x, y, z) の順で設定
bone.rotation_quaternion = (bone_data['rotation']['w'], bone_data['rotation']['x'], bone_data['rotation']['y'], bone_data['rotation']['z'])
# Save the pose
bpy.ops.object.posemode_toggle()
bpy.ops.wm.save_mainfile()
# ファイルパスは適宜設定してください
apply_pose('RobinArmature', 'C:boneData.json')
2024年4月22日月曜日
Efficient Use of Blender Assets
-How to bake actions in Blender
http://eizouasobi.blogspot.com/2024/04/how-to-bake-actions-in-blender.html
-How to split actions in Blender
http://eizouasobi.blogspot.com/2024/04/how-to-split-actions-in-blender.html
-How to use in game engine
https://eizouasobi.blogspot.com/2019/01/how-to-use-in-game-engine.html
Formatting Animation Name Files for Use with ActionMaking.py
If the animation number files attached to your assets are not in the correct format for use with the ActionMaking.py script, please use the FormatAnimationNamesAnimColonNum.py script to adjust them.
This script performs the following tasks:
-Removes empty lines and trailing colons: This step cleans up unnecessary formatting that may interfere with processing.
-Replaces spaces with colons: This adjustment is made for lines where the frame range and animation name are separated by spaces instead of colons, ensuring consistency in data format.
-Checks and adjusts the position of name and frame data: This part verifies whether the line format is 'frames:name' or 'name:frames' and adjusts accordingly.
-Processes frame data: Depending on the number of listed frame ranges, the script selects the appropriate frames (the middle ones if there are four frames, the first two if there are three).
For example, a file with lines like:
50-80-110-140:WalkForward:
IdleToTrot:3850-3880-3910
will be changed to:
WalkForward:80-110
IdleToTrot:3850-3880
If there are any extraneous comments or notes that cannot be adjusted by this script, please remove them before running the script.