UE4 UIの端だけにフェード処理を掛ける

やあ

UIの端っこだけフェードアウトしたいなーって思って作ったよ。
f:id:pto8913:20201230131905p:plain

フェード処理をするためのマテリアル

f:id:pto8913:20201230132410p:plain
f:id:pto8913:20201230171640p:plain

線形グラデーションを掛け合わせて左右(上下)にかけてグラデーションさせてるだけ。
このマテリアルを右クリックしてインスタンスにしておくとパラメータを好きにいじれる。

注意

  1. UIで使う際にTextureSampleParameter2Dのパラメータの名前を一致させる必要がある。
  2. TextureSampleParameter2Dを最終カラーにつながないと下の画像のようになる。
    f:id:pto8913:20201230133151p:plain

UIで使う

f:id:pto8913:20201230132624p:plain
RetainerBoxの下にフェード処理を掛けたいウィジェットを入れるだけ。

RetainerBox -> 詳細 -> エフェクト -> EffectMaterialにさっき作ったマテリアルを割り当て、TextureParameterにマテリアルのTextureSampleParameter2Dのパラメータ名を入れる。

結果

f:id:pto8913:20201230131905p:plain

終わりです。

Blender python 骨をアーマチュアに追加する

やあ

同じボーン階層のキャラクターをいっぱい作った後に、骨を追加したいなって思って書いたよ。
※注意 : 今回はやってることはリーフボーンの追加なので、骨と骨の間に追加したい場合はちょっと書き換える必要があります。自分で使う機会があれば追記します。

スクリプト

import bpy
from typing import List, Any

def get_obj(name : str):
    return bpy.data.objects.get(name)
     
bpy.ops.object.mode_set(mode='OBJECT')

"""
骨を追加したいアーマチュアの名前
"""
target_obj_names = [
"Armature_A",
"Armature_B"
]

class NewBoneSpec:
    def __init__(self, 
        NewBoneName: str, ParentName: str, 
        Head: List[float] = [0.0, 0.0, 0.0], 
        Tail: List[float] = [0.0, 0.0, 1.0], 
        Roll: float = 0.0,
        bAutoTransform: bool = False
    ):
        self.parent = ParentName
        self.new_bone = NewBoneName
        self.head = Head
        self.tail = Tail
        self.roll = Roll
        self.bAutoTransform = bAutoTransform

class NewBoneMaker:
    def __init__(self, 
        Spec: NewBoneSpec,
        Armature: Any
    ):
        self.spec = Spec
        self.Armature = Armature
    def DoMake(self):
        if self.Armature:
            edit_bones = self.Armature.data.edit_bones
            if edit_bones:
                if not edit_bones.get(self.spec.new_bone):
                    new_bone = edit_bones.new(self.spec.new_bone)
                    if new_bone:
                        parent = target_edit_bone.get(self.spec.parent)
                        if parent:
                            new_bone.parent = target_edit_bone.get(self.spec.parent)
                            if self.spec.bAutoTransform:
                                head = [new_bone.parent.tail[0], new_bone.parent.tail[1], new_bone.parent.tail[2]]
                                new_bone.head = head
                                tail = [head[0], head[1], head[2] + 1.0]
                                new_bone.tail = tail
                                new_bone.roll = 0.0
                            else:
                                new_bone.head = new_bone_spec.head
                                new_bone.tail = new_bone_spec.tail
                                new_bone.roll = new_bone_spec.roll

new_bone_specs = [
    NewBoneSpec(NewBoneName="Weapon_R", ParentName="Hand_R", bAutoTransform=True),
    NewBoneSpec(NewBoneName="Weapon_L", ParentName="Hand_L", bAutoTransform=True),
]
for target_obj_name in target_obj_names:
    target_armature = get_obj(target_obj_name)
    if target_armature:
        target_armature.select = True
        bpy.ops.object.mode_set(mode='EDIT')
        target_edit_bone = target_armature.data.edit_bones
        if target_edit_bone:
            for new_bone_spec in new_bone_specs:
                new_bone_maker = NewBoneMaker(new_bone_spec, target_armature)
                new_bone_maker.DoMake()
        target_armature.select = False
    bpy.ops.object.mode_set(mode='OBJECT')

使い方

  1. target_obj_namesに骨を追加したいアーマチュアの名前を入れます。
  2. new_bone_specsに、新しく追加したい骨の名前と、その親の骨の名前を入れます。
    このとき、トランスフォームを手動で決めることもできます。
    また、bAutoTransform = Trueに指定すると、新しい骨が親の骨に対して垂直に追加されます。

  3. 実行

Blender python 骨を揃える

やあ

ブレンダーでキャラクターをいっぱい作った後にちょっと骨の位置を修正したいなーってなったときに書いた、骨を特定のアーマチュアに揃えるスクリプトだよ。

揃える元のアーマチュアがある場合

import bpy
from typing import Dict, List

def get_obj(name : str):
    return bpy.data.objects.get(name)

def get_children(result: Dict, target_bone) -> List:
    if len(target_bone.children) == 0:
        return []
    child_name = []
    next_tasks = []
    for child in target_bone.children:
        next_tasks.append(child)
        child_name.append(child.name)
    if target_bone.name in result:
        result[target_bone.name] += child_name
    else:
        result[target_bone.name] = child_name
    for child in next_tasks:
        get_children(result, child)
        
bpy.ops.object.mode_set(mode='OBJECT')
    
"""
---- ソースオブジェクト ----
"""
source_obj_name = "source_armature_name"
source_armature = get_obj(source_obj_name)
source_armature.select = True

root_bone_name = "Root"

"""
---- 処理をしたいオブジェクトの名前
"""
target_obj_names = [
"Armature_A",
"Armature_B"
]

"""
---- 処理をしたくない骨の親の名前 ----
例 : 
親 : Hand
子 : Thumb, Index, Middle, Ring, Pinky
となっているときに、
Handを追加すると、子が無視されます

"""
ignore_bones_parent_names = [
]

"""
---- 無視したい骨の名前 ----
"""
ignore_bone_names = [
]

"""
---- 無視したい骨の名前の一部 ----
"""
ignore_part_of_names = [
    "IK_", "C_"
]

"""
---- トランスフォーム : ヘッドを無視する骨の名前 ----
"""
ignore_head_bone_names = [
]

"""
---- トランスフォーム : テイルを無視する骨の名前 ----
"""
ignore_tail_bone_names = [
]

"""
---- トランスフォーム : ロールを無視する骨の名前 ----
"""
ignore_roll_bone_names = [
]

is_debug = True

for target_obj_name in target_obj_names:
    target_armature = get_obj(target_obj_name)
    if target_armature:
        if is_debug:
            print(target_armature)
        target_armature.select = True
        bpy.ops.object.mode_set(mode='EDIT')
        root_bone = target_armature.pose.bones.get(root_bone_name)
        if root_bone:
            children = dict()
            get_children(children, root_bone)
            for parent_name, childs in children.items():
                if parent_name in ignore_bones_parent_names:
                    continue
                for bone_name in childs:
                    if bone_name in ignore_bone_names:
                        continue
                    is_found_ignore_bone = False
                    for ignore_part_of_name in ignore_part_of_names:
                        if ignore_part_of_name in bone_name:
                            is_found_ignore_bone = True
                            break
                    if is_found_ignore_bone:
                        continue
                    target_bone = target_armature.data.edit_bones.get(bone_name)
                    if target_bone:
                        source_align_bone = source_armature.data.edit_bones.get(bone_name)
                        if source_align_bone:
                            if parent_name not in ignore_head_bone_names:
                                target_bone.head = [source_align_bone.head[0], source_align_bone.head[1], source_align_bone.head[2]]
                            if parent_name not in ignore_tail_bone_names:
                                target_bone.tail = [source_align_bone.tail[0], source_align_bone.tail[1], source_align_bone.tail[2]]
                            if parent_name not in ignore_roll_bone_names:
                                target_bone.roll = source_align_bone.roll
        else:
            if is_debug:
                print("root bone is None at : " + target_armature.name)
        bpy.ops.object.mode_set(mode='OBJECT')
        target_armature.select = False
    else:
        if is_debug:
            print("Target armature is None at : " + target_obj_name)
    bpy.ops.object.mode_set(mode='OBJECT')

# 指定するのが面倒だから全オブジェクトについて処理したい場合

import bpy
from typing import Dict, List

def get_obj(name : str):
    return bpy.data.objects[name]

def get_children(result: Dict, target_bone) -> List:
    if len(target_bone.children) == 0:
        return []
    child_name = []
    next_tasks = []
    for child in target_bone.children:
        next_tasks.append(child)
        child_name.append(child.name)
    if target_bone.name in result:
        result[target_bone.name] += child_name
    else:
        result[target_bone.name] = child_name
    for child in next_tasks:
        get_children(result, child)
        
bpy.ops.object.mode_set(mode='OBJECT')

"""
---- ソースオブジェクト ----
"""
source_obj_name = "Source_Armature"
 
source_armature = get_obj(source_obj_name)
source_armature.select = True

root_bone_name = "Root"

"""
---- 処理をしたくない骨の親の名前 ----
例 : 
親 : Hand
子 : Thumb, Index, Middle, Ring, Pinky
となっているときに、
Handを追加すると、子が無視されます

"""
ignore_bones_parent_names = [
]

"""
---- 無視したい骨の名前 ----
"""
ignore_bone_names = [
]

"""
---- 無視したい骨の名前の一部 ----
"""
ignore_part_of_names = [
    "IK_", "C_"
]

"""
---- トランスフォーム : ヘッドを無視する骨の名前 ----
"""
ignore_head_bone_names = [
]

"""
---- トランスフォーム : テイルを無視する骨の名前 ----
"""
ignore_tail_bone_names = [
]

"""
---- トランスフォーム : ロールを無視する骨の名前 ----
"""
ignore_roll_bone_names = [
]

is_debug = True

for obj in bpy.data.objects:
    if obj.type == "ARMATURE":
        target_armature = get_obj(obj.name)
        if target_armature:
            if is_debug:
                print(target_armature)
            target_armature.select = True
            bpy.ops.object.mode_set(mode='EDIT')
            root_bone = target_armature.pose.bones.get(root_bone_name)
            if root_bone:
                children = dict()
                get_children(children, root_bone)
                for parent_name, childs in children.items():
                    if parent_name in ignore_bones_parent_names:
                        continue
                    for bone_name in childs:
                        if bone_name in ignore_bone_names:
                            continue
                        is_found_ignore_bone = False
                        for ignore_part_of_name in ignore_part_of_names:
                            if ignore_part_of_name in bone_name:
                                is_found_ignore_bone = True
                                break
                        if is_found_ignore_bone:
                            continue
                        target_bone = target_armature.data.edit_bones.get(bone_name)
                        if target_bone:
                            source_align_bone = source_armature.data.edit_bones.get(bone_name)
                            if source_align_bone:
                                if parent_name not in ignore_head_bone_names:
                                    target_bone.head = [source_align_bone.head[0], source_align_bone.head[1], source_align_bone.head[2]]
                                if parent_name not in ignore_tail_bone_names:
                                    target_bone.tail = [source_align_bone.tail[0], source_align_bone.tail[1], source_align_bone.tail[2]]
                                if parent_name not in ignore_roll_bone_names:
                                    target_bone.roll = source_align_bone.roll
            else:
                if is_debug:
                    print("root bone is None " + target_armature.name)
            bpy.ops.object.mode_set(mode='OBJECT')
            target_armature.select = False
        else:
            if is_debug:
                print("Target armature is None " + obj.name)
        bpy.ops.object.mode_set(mode='OBJECT')

値を入力して揃える

import bpy
align_bone_name = "Hand_L"

target_obj_names = [
"Armature_A",
"Armature_B"
]
def get_obj(name : str):
    return bpy.data.objects.get(name)
    
source_align_bone_head = [-1.3189, 0.1459, 1.9255]
source_align_bone_tail = [-1.3189, -0.2293, 1.9255]
source_align_bone_roll = 0.0

if source_align_bone_head == source_align_bone_tail:
    print("""
        -------------- Warning. --------------
        
        The head vector matches the tail vector.
        This will cause align_bone to be removed.
        
        So, this script is cancelled.
        --------------------------------------
    """)
else:
    for target_obj_name in target_obj_names:
        target_armature = get_obj(target_obj_name)
        if target_armature:
            target_armature.select = True
            print(target_armature)
            bpy.ops.object.mode_set(mode='EDIT')
            target_bone = target_armature.data.edit_bones.get(align_bone_name)
            if target_bone:
                target_bone.head = source_align_bone_head
                target_bone.tail = source_align_bone_tail
                target_bone.roll = source_align_bone_roll
            bpy.ops.object.mode_set(mode='OBJECT')
            target_armature.select = False

Blender UE4のエフェクトで使うトルネード用のメッシュの作り方

半球

Shift+AメッシュUV Sphere
f:id:pto8913:20201208161650p:plain

Scale : x : 100, y : 100, z : 100
f:id:pto8913:20201208161747p:plain

Ctrl+1(Add Subdivision)→Apply
f:id:pto8913:20201208161855p:plain

Add ModifierSimpleDeform
f:id:pto8913:20201208162019p:plain
Axis : Z, Angle: 145
f:id:pto8913:20201208162027p:plain

f:id:pto8913:20201208162633p:plain

上を選択して、外側をCtrl+左クリック
f:id:pto8913:20201208162642p:plain
f:id:pto8913:20201208162659p:plain
Sで縮小。
f:id:pto8913:20201208162708p:plain
何回か縮小したら終わり。
f:id:pto8913:20201208162714p:plain

注意

UVは初期状態のまま拡大。
変に展開すると見た目がおかしくなります。
f:id:pto8913:20201208163950p:plain f:id:pto8913:20201208164033p:plain

UE4 Niagara scale

やあ

Niagaraで作ったエフェクトの大きさ変更する方法を書いておくよ。

ユーザーパラメータで拡大縮小する

ユーザーパラメータにfloat値のパラメータを作成。
f:id:pto8913:20201208154823p:plain

パラメータを掛ける。
f:id:pto8913:20201208155029p:plain

エディタから値を変える

f:id:pto8913:20201208155251p:plain

BPから値を変える

f:id:pto8913:20201208155748p:plain

トランスフォームの値で拡大縮小する

エミッタの設定→エミッタのプロパティ→エミッター→LocalSpaceにチェックを入れる。

f:id:pto8913:20201208154534p:plain

Mesh RendererSprite Rendererでしかテストしてないけど、レンダリングMesh Rendererを使用している場合でのみ変更されます。

UE4 Niagara LockAxis

  1. パラメータのパーティクル属性にSpriteFacingを追加。
    f:id:pto8913:20201205212303p:plain

  2. パラメータに追加したSpriteFacingをパーティクル更新にドラッグアンドドロップ
    f:id:pto8913:20201205212359p:plain

  3. レンダリングをクリックして、FacingModeCustomFacingVectorに設定。
    f:id:pto8913:20201205212513p:plain

  4. パーティクル更新に追加したSpriteFacingをいじると軸固定できます。
    f:id:pto8913:20201205212921p:plain

x = 1.0でx軸固定。
y = 1.0でy軸固定。
z = 1.0でz軸固定。