[maya][python]接合したメッシュの法線をいい感じに丸く滑らかにするツール furcraeaSmoothNormalTool.pyとfurcraeaSeamNormalTool.py

できます。まずは 選択したメッシュ、フェース、頂点の法線を滑らかにする Maya Python ツールとして作るのが扱いやすいです。

下のコードは、次の機能を持っています。

  • 選択範囲だけ法線をソフト化
  • メッシュ全体をソフト化
  • 角度を指定
  • 法線ロック解除
  • 法線の平均化
  • ハードエッジ化
  • 法線履歴の削除

furcraeaSmoothNormalTool.py

# -*- coding: utf-8 -*-
import maya.cmds as cmds


WINDOW_NAME = "furcraeaSmoothNormalTool"


def get_selected_mesh_components():
    """
    現在の選択を取得します。
    オブジェクト選択の場合は、そのメッシュ全体を返します。
    コンポーネント選択の場合は、そのまま返します。
    """
    selection = cmds.ls(selection=True, long=True, flatten=True) or []

    if not selection:
        cmds.warning("メッシュ、フェース、エッジ、頂点を選択してください。")
        return []

    result = []

    for item in selection:
        # コンポーネント選択
        if "." in item:
            result.append(item)
            continue

        # TransformからShapeを取得
        if cmds.nodeType(item) == "transform":
            shapes = cmds.listRelatives(
                item,
                shapes=True,
                noIntermediate=True,
                fullPath=True
            ) or []

            mesh_shapes = [
                shape for shape in shapes
                if cmds.nodeType(shape) == "mesh"
            ]

            if mesh_shapes:
                result.append(item)

        # Shapeが直接選択されている場合
        elif cmds.nodeType(item) == "mesh":
            parents = cmds.listRelatives(
                item,
                parent=True,
                fullPath=True
            ) or []

            if parents:
                result.append(parents[0])

    if not result:
        cmds.warning("選択内にポリゴンメッシュがありません。")

    return result


def unlock_normals():
    """選択したメッシュまたはコンポーネントの法線ロックを解除します。"""
    targets = get_selected_mesh_components()
    if not targets:
        return

    cmds.undoInfo(openChunk=True)

    try:
        for target in targets:
            try:
                cmds.polyNormalPerVertex(
                    target,
                    unFreezeNormal=True
                )
            except RuntimeError:
                pass

        cmds.inViewMessage(
            amg="<hl>法線ロックを解除しました</hl>",
            pos="midCenter",
            fade=True
        )

    finally:
        cmds.undoInfo(closeChunk=True)


def soften_normals(angle=None):
    """
    指定角度以下のエッジをソフト化します。

    angle:
        180の場合、基本的にすべてのエッジを滑らかにします。
        30~60程度なら、鋭い角を残しやすくなります。
    """
    targets = get_selected_mesh_components()
    if not targets:
        return

    if angle is None:
        angle = cmds.floatSliderGrp(
            "smoothNormalAngleSlider",
            query=True,
            value=True
        )

    cmds.undoInfo(openChunk=True)

    try:
        for target in targets:
            # ロックされた法線がある場合に備えて解除
            try:
                cmds.polyNormalPerVertex(
                    target,
                    unFreezeNormal=True
                )
            except RuntimeError:
                pass

            cmds.polySoftEdge(
                target,
                angle=angle,
                constructionHistory=True
            )

        cmds.inViewMessage(
            amg="<hl>法線を滑らかにしました:</hl> {}°".format(angle),
            pos="midCenter",
            fade=True
        )

    finally:
        cmds.undoInfo(closeChunk=True)


def soften_all():
    """選択したメッシュまたはコンポーネントを完全にソフト化します。"""
    soften_normals(180.0)


def harden_normals():
    """選択した範囲をハードエッジ化します。"""
    targets = get_selected_mesh_components()
    if not targets:
        return

    cmds.undoInfo(openChunk=True)

    try:
        for target in targets:
            try:
                cmds.polyNormalPerVertex(
                    target,
                    unFreezeNormal=True
                )
            except RuntimeError:
                pass

            cmds.polySoftEdge(
                target,
                angle=0,
                constructionHistory=True
            )

        cmds.inViewMessage(
            amg="<hl>ハードエッジ化しました</hl>",
            pos="midCenter",
            fade=True
        )

    finally:
        cmds.undoInfo(closeChunk=True)


def average_vertex_normals():
    """
    選択頂点の法線を平均化します。
    頂点以外を選択した場合は頂点へ変換します。
    """
    selection = cmds.ls(selection=True, long=True, flatten=True) or []

    if not selection:
        cmds.warning("平均化するメッシュまたはコンポーネントを選択してください。")
        return

    vertices = cmds.polyListComponentConversion(
        selection,
        toVertex=True
    )

    vertices = cmds.ls(
        vertices,
        flatten=True,
        long=True
    ) or []

    if not vertices:
        cmds.warning("頂点を取得できませんでした。")
        return

    cmds.undoInfo(openChunk=True)

    try:
        try:
            cmds.polyNormalPerVertex(
                vertices,
                unFreezeNormal=True
            )
        except RuntimeError:
            pass

        cmds.polyAverageNormal(
            vertices,
            distance=0.0,
            replaceNormalXYZ=(0, 0, 0)
        )

        cmds.inViewMessage(
            amg="<hl>頂点法線を平均化しました</hl>",
            pos="midCenter",
            fade=True
        )

    finally:
        cmds.undoInfo(closeChunk=True)


def conform_normals():
    """
    法線の向きを統一します。
    裏返ったフェースが混在している場合に使用します。
    """
    targets = get_selected_mesh_components()
    if not targets:
        return

    cmds.undoInfo(openChunk=True)

    try:
        for target in targets:
            cmds.polyNormal(
                target,
                normalMode=2,
                userNormalMode=0,
                constructionHistory=True
            )

        cmds.inViewMessage(
            amg="<hl>法線方向を統一しました</hl>",
            pos="midCenter",
            fade=True
        )

    finally:
        cmds.undoInfo(closeChunk=True)


def reverse_normals():
    """選択したフェースまたはメッシュの法線を反転します。"""
    targets = get_selected_mesh_components()
    if not targets:
        return

    cmds.undoInfo(openChunk=True)

    try:
        for target in targets:
            cmds.polyNormal(
                target,
                normalMode=0,
                userNormalMode=0,
                constructionHistory=True
            )

        cmds.inViewMessage(
            amg="<hl>法線を反転しました</hl>",
            pos="midCenter",
            fade=True
        )

    finally:
        cmds.undoInfo(closeChunk=True)


def delete_normal_history():
    """
    選択メッシュの履歴を削除します。
    法線処理以外の履歴も削除されるため注意してください。
    """
    targets = get_selected_mesh_components()
    if not targets:
        return

    transforms = set()

    for target in targets:
        object_name = target.split(".")[0]

        if cmds.nodeType(object_name) == "mesh":
            parents = cmds.listRelatives(
                object_name,
                parent=True,
                fullPath=True
            ) or []

            if parents:
                transforms.add(parents[0])
        else:
            transforms.add(object_name)

    if transforms:
        cmds.delete(list(transforms), constructionHistory=True)

        cmds.inViewMessage(
            amg="<hl>ヒストリを削除しました</hl>",
            pos="midCenter",
            fade=True
        )


def show_smooth_normal_tool():
    """UIを表示します。"""
    if cmds.window(WINDOW_NAME, exists=True):
        cmds.deleteUI(WINDOW_NAME)

    window = cmds.window(
        WINDOW_NAME,
        title="Smooth Normal Tool",
        sizeable=False,
        widthHeight=(340, 390)
    )

    cmds.columnLayout(
        adjustableColumn=True,
        rowSpacing=8
    )

    cmds.separator(height=8, style="none")

    cmds.text(
        label="メッシュ・フェース・エッジ・頂点に対応",
        align="center"
    )

    cmds.separator(height=8, style="in")

    cmds.floatSliderGrp(
        "smoothNormalAngleSlider",
        label="Soft Angle",
        field=True,
        minValue=0.0,
        maxValue=180.0,
        fieldMinValue=0.0,
        fieldMaxValue=180.0,
        value=60.0,
        columnWidth3=(80, 60, 180)
    )

    cmds.button(
        label="指定角度で滑らかにする",
        height=36,
        command=lambda *_: soften_normals()
    )

    cmds.button(
        label="すべて滑らかにする  180°",
        height=32,
        command=lambda *_: soften_all()
    )

    cmds.button(
        label="ハードエッジにする  0°",
        height=32,
        command=lambda *_: harden_normals()
    )

    cmds.separator(height=10, style="in")

    cmds.button(
        label="頂点法線を平均化",
        height=32,
        command=lambda *_: average_vertex_normals()
    )

    cmds.button(
        label="法線ロックを解除",
        height=32,
        command=lambda *_: unlock_normals()
    )

    cmds.separator(height=10, style="in")

    cmds.rowLayout(
        numberOfColumns=2,
        adjustableColumn=1,
        columnWidth2=(165, 165)
    )

    cmds.button(
        label="法線方向を統一",
        height=30,
        command=lambda *_: conform_normals()
    )

    cmds.button(
        label="法線を反転",
        height=30,
        command=lambda *_: reverse_normals()
    )

    cmds.setParent("..")

    cmds.separator(height=10, style="in")

    cmds.button(
        label="ヒストリを削除",
        height=30,
        command=lambda *_: delete_normal_history()
    )

    cmds.separator(height=8, style="none")

    cmds.showWindow(window)


show_smooth_normal_tool()

メッシュの接合部で法線がめちゃくちゃになってるパターンをどうにか滑らかにしたい

その場合は polySoftEdge だけでは直らない可能性が高いです。

接合部で法線が乱れる原因は主に次の2種類です。

  1. 頂点は接合されているが、法線がロック・分割されている
  2. 別メッシュ同士で、同じ位置にある頂点の法線が一致していない

特に髪・顔・首・胴体など、別メッシュの境界を滑らかにつなぎたい場合は、接合部の近接頂点を探して、両方の法線を平均化する必要があります。

以下は、選択した複数メッシュ間で、同じ位置にある頂点の法線を平均化するPythonツールです。

furcraeaSeamNormalTool.py

# -*- coding: utf-8 -*-

import maya.cmds as cmds
import maya.api.OpenMaya as om


WINDOW_NAME = "furcraeaSeamNormalTool"


def get_selected_mesh_dag_paths():
    """
    選択されたTransformまたはMesh Shapeから、
    MeshのMDagPathを取得する。
    """
    selection = om.MGlobal.getActiveSelectionList()
    mesh_paths = []

    for index in range(selection.length()):
        try:
            dag_path = selection.getDagPath(index)
        except RuntimeError:
            continue

        if dag_path.node().hasFn(om.MFn.kTransform):
            try:
                dag_path.extendToShape()
            except RuntimeError:
                continue

        if dag_path.node().hasFn(om.MFn.kMesh):
            mesh_paths.append(dag_path)

    return mesh_paths


def unlock_mesh_normals(dag_path):
    """
    メッシュ全体の頂点法線ロックを解除する。
    """
    mesh_name = dag_path.fullPathName()

    try:
        cmds.polyNormalPerVertex(
            mesh_name,
            unFreezeNormal=True
        )
    except RuntimeError:
        pass


def get_vertex_data(dag_path):
    """
    各頂点について以下を取得する。

    - 頂点番号
    - ワールド座標
    - 頂点法線
    """
    mesh_fn = om.MFnMesh(dag_path)

    points = mesh_fn.getPoints(om.MSpace.kWorld)
    normals = mesh_fn.getVertexNormals(
        True,
        om.MSpace.kWorld
    )

    result = []

    for vertex_id, point in enumerate(points):
        normal = normals[vertex_id]

        result.append({
            "dag_path": dag_path,
            "mesh_fn": mesh_fn,
            "vertex_id": vertex_id,
            "position": om.MVector(point.x, point.y, point.z),
            "normal": om.MVector(normal.x, normal.y, normal.z)
        })

    return result


def build_spatial_hash(vertex_data, tolerance):
    """
    頂点座標をグリッド化して、近接頂点を高速に検索する。
    """
    spatial_hash = {}

    for data in vertex_data:
        position = data["position"]

        key = (
            int(round(position.x / tolerance)),
            int(round(position.y / tolerance)),
            int(round(position.z / tolerance))
        )

        spatial_hash.setdefault(key, []).append(data)

    return spatial_hash


def get_neighbor_keys(position, tolerance):
    """
    誤差境界をまたいだ頂点も検索できるように、
    周囲27セルを返す。
    """
    center_x = int(round(position.x / tolerance))
    center_y = int(round(position.y / tolerance))
    center_z = int(round(position.z / tolerance))

    for offset_x in (-1, 0, 1):
        for offset_y in (-1, 0, 1):
            for offset_z in (-1, 0, 1):
                yield (
                    center_x + offset_x,
                    center_y + offset_y,
                    center_z + offset_z
                )


def average_seam_normals(tolerance=0.001, border_only=True):
    """
    選択した複数メッシュ間で、
    同じ位置にある頂点法線を平均化する。

    tolerance:
        同じ位置と判定する距離。

    border_only:
        Trueの場合は境界頂点のみを対象にする。
    """
    dag_paths = get_selected_mesh_dag_paths()

    if len(dag_paths) < 2:
        cmds.warning(
            "接合部を修正する2つ以上のメッシュを選択してください。"
        )
        return

    cmds.undoInfo(openChunk=True)

    try:
        all_vertex_data = []

        for dag_path in dag_paths:
            unlock_mesh_normals(dag_path)

            mesh_vertex_data = get_vertex_data(dag_path)

            if border_only:
                border_ids = get_border_vertex_ids(dag_path)

                mesh_vertex_data = [
                    data
                    for data in mesh_vertex_data
                    if data["vertex_id"] in border_ids
                ]

            all_vertex_data.extend(mesh_vertex_data)

        spatial_hash = build_spatial_hash(
            all_vertex_data,
            tolerance
        )

        processed = set()
        matched_groups = []

        for source_data in all_vertex_data:
            source_key = (
                source_data["dag_path"].fullPathName(),
                source_data["vertex_id"]
            )

            if source_key in processed:
                continue

            matching_vertices = []

            for neighbor_key in get_neighbor_keys(
                source_data["position"],
                tolerance
            ):
                candidates = spatial_hash.get(
                    neighbor_key,
                    []
                )

                for candidate in candidates:
                    candidate_key = (
                        candidate["dag_path"].fullPathName(),
                        candidate["vertex_id"]
                    )

                    if candidate_key in processed:
                        continue

                    # 同一メッシュ内の近接頂点は対象外
                    if (
                        candidate["dag_path"].fullPathName()
                        == source_data["dag_path"].fullPathName()
                    ):
                        continue

                    distance = (
                        candidate["position"]
                        - source_data["position"]
                    ).length()

                    if distance <= tolerance:
                        matching_vertices.append(candidate)

            if not matching_vertices:
                continue

            group = [source_data] + matching_vertices

            # 同一頂点の重複を除去
            unique_group = {}
            for data in group:
                key = (
                    data["dag_path"].fullPathName(),
                    data["vertex_id"]
                )
                unique_group[key] = data

            group = list(unique_group.values())

            if len(group) < 2:
                continue

            matched_groups.append(group)

            for data in group:
                processed.add((
                    data["dag_path"].fullPathName(),
                    data["vertex_id"]
                ))

        if not matched_groups:
            cmds.warning(
                "指定距離内に一致する接合頂点が見つかりませんでした。"
            )
            return

        apply_average_normals(matched_groups)

        cmds.inViewMessage(
            amg=(
                "<hl>接合部法線を平均化しました</hl>"
                "<br/>一致グループ数: {}"
            ).format(len(matched_groups)),
            pos="midCenter",
            fade=True
        )

    finally:
        cmds.undoInfo(closeChunk=True)


def get_border_vertex_ids(dag_path):
    """
    メッシュの境界エッジに含まれる頂点番号を取得する。
    """
    border_vertex_ids = set()

    edge_iterator = om.MItMeshEdge(dag_path)

    while not edge_iterator.isDone():
        if edge_iterator.onBoundary():
            border_vertex_ids.add(
                edge_iterator.vertexId(0)
            )
            border_vertex_ids.add(
                edge_iterator.vertexId(1)
            )

        edge_iterator.next()

    return border_vertex_ids


def apply_average_normals(matched_groups):
    """
    法線グループごとに平均法線を計算し、
    各頂点へ適用する。
    """
    mesh_updates = {}

    for group in matched_groups:
        average_normal = om.MVector()

        for data in group:
            average_normal += data["normal"]

        if average_normal.length() < 0.000001:
            continue

        average_normal.normalize()

        for data in group:
            mesh_name = data["dag_path"].fullPathName()

            if mesh_name not in mesh_updates:
                mesh_updates[mesh_name] = {
                    "mesh_fn": data["mesh_fn"],
                    "vertex_ids": [],
                    "normals": []
                }

            mesh_updates[mesh_name]["vertex_ids"].append(
                data["vertex_id"]
            )

            mesh_updates[mesh_name]["normals"].append(
                om.MVector(
                    average_normal.x,
                    average_normal.y,
                    average_normal.z
                )
            )

    for update_data in mesh_updates.values():
        mesh_fn = update_data["mesh_fn"]

        mesh_fn.setVertexNormals(
            update_data["normals"],
            update_data["vertex_ids"],
            om.MSpace.kWorld
        )


def run_from_ui(*args):
    tolerance = cmds.floatField(
        "seamNormalToleranceField",
        query=True,
        value=True
    )

    border_only = cmds.checkBox(
        "seamNormalBorderOnlyCheckBox",
        query=True,
        value=True
    )

    if tolerance <= 0:
        cmds.warning("許容距離は0より大きくしてください。")
        return

    average_seam_normals(
        tolerance=tolerance,
        border_only=border_only
    )


def show_seam_normal_tool():
    if cmds.window(WINDOW_NAME, exists=True):
        cmds.deleteUI(WINDOW_NAME)

    window = cmds.window(
        WINDOW_NAME,
        title="Seam Normal Smoother",
        sizeable=False,
        widthHeight=(360, 190)
    )

    cmds.columnLayout(
        adjustableColumn=True,
        rowSpacing=8
    )

    cmds.separator(height=8, style="none")

    cmds.text(
        label="接合する2つ以上のメッシュを選択",
        align="center"
    )

    cmds.text(
        label="同じ位置にある境界頂点の法線を平均化します",
        align="center"
    )

    cmds.separator(height=8, style="in")

    cmds.floatFieldGrp(
        "seamNormalToleranceField",
        numberOfFields=1,
        label="許容距離",
        value1=0.001,
        precision=6,
        columnWidth2=(100, 220)
    )

    cmds.checkBox(
        "seamNormalBorderOnlyCheckBox",
        label="境界頂点のみを処理",
        value=True
    )

    cmds.separator(height=8, style="in")

    cmds.button(
        label="接合部の法線を滑らかにする",
        height=38,
        command=run_from_ui
    )

    cmds.separator(height=8, style="none")

    cmds.showWindow(window)


show_seam_normal_tool()

[Houdini] Houdini Technical Artist HDA関連 021

[Houdini] Houdini Technical Artist HDA related 021

■ 最終形(これが実務ベース)

vector Nn = normalize(@N);

// 傾き制御
vector worldUp = {0,1,0};
Nn = normalize(lerp(worldUp, Nn, 0.3));

// 向き合わせ
matrix3 m = dihedral({0,1,0}, Nn);
p@orient = quaternion(m);

// ランダムひねり
float angle = rand(@ptnum + 10.0) * M_PI * 2;
p@orient = qmultiply(p@orient, quaternion(angle, Nn));

// サイズ
@pscale = fit01(rand(@ptnum), 0.5, 1.5);

// 浮かせる
@P += Nn * (@pscale * 0.5);

ビューポートの右下の目のアイコンでSmoothShade

  • 地面の傾き ✔
  • 棒が法線に沿って傾いてる ✔
  • 密度も出てる ✔
  • 表示もOK ✔

👉 完全に正しく動いてる

■ (TA的に重要)

👉 これ実は👇

UEのFoliage / HISM配置と同じことやってる

  • Scatter → 配置ポイント
  • N → Surface Normal
  • orient → Transform
  • pscale → Scale variation

生える場所を制限(超重要)

// 法線
vector Nn = normalize(@N);

// --- ① 急斜面は削除 ---
if (Nn.y < 0.7) {
    removepoint(0, @ptnum);
    return; // ←これ重要(下の処理止める)
}

// --- ② 傾き制御 ---
vector worldUp = {0,1,0};
Nn = normalize(lerp(worldUp, Nn, 0.3));

// --- ③ 向き合わせ ---
matrix3 m = dihedral({0,1,0}, Nn);
p@orient = quaternion(m);

// --- ④ ランダムひねり ---
float angle = rand(@ptnum + 10.0) * M_PI * 2;
p@orient = qmultiply(p@orient, quaternion(angle, Nn));

// --- ⑤ サイズ ---
@pscale = fit01(rand(@ptnum), 0.5, 1.5);

// --- ⑥ 浮かせる ---
@P += Nn * (@pscale * 0.5);

  • 傾きバラバラ ✔
  • サイズバラバラ ✔
  • ひねり入ってる ✔
  • 急斜面減ってる ✔

👉 完全に意図通り

[UE5][C++]正しい作業場所まとめ

正しい作業場所まとめ(重要)

作業内容やる場所
フォルダ作成 / リネームエクスプローラー
.uplugin / Build.cs 編集VS(テキスト)
.h / .cpp 追加エクスプローラーで追加後、フォルダ削除※
Generate Project Files
Generate Project Filesエクスプローラー(.uproject右クリック)
ビルドVS
アセット作成 / 動作確認UEエディタ

Runtime に追加とかはUEがわでやるの?VSでやるの?

結論:エクスプローラーでやる。VSではやらない。
これは断言できる。


[UE5.7][VisualStudio2022].uprojectが壊れた時に回復する方法

UEをLogを出しながら起動する
UnrealEditor.exe “プロジェクト名.uproject” -log

D:
cd D:\Program Files\Epic Games\UE_5.7\Engine\Binaries\Win64\
UnrealEditor.exe "D:\Sandbox\UE57CreatePlugin4\furcraeaUEOpenAI2\furcraeaUEOpenAI2\furcraeaUEOpenAI2.uproject" -log

pause

これを起動しているときに
Saved\Logs\プロジェクト名.log

D:\Sandbox\UE57CreatePlugin4\furcraeaUEOpenAI2\furcraeaUEOpenAI2\Saved\Logs
furcraeaUEOpenAI2.log
がどうなってるか見てみること。。。。

[UE5.6.1]1回目ビルドしたゲームが初回起動時に起動しない2回目Fatal errorエラー表示3回目真っ黒でフリーズ4回目起動する現象

UE5.6.1

1回目ビルドしたゲームが初回起動時に起動しない

2回目エラー表示

3回目エラー表示

4回目起動する

現象

#UE5ぷちコン #UE5

エラー内容

Fatal error: [File:D:\build\++UE5\Sync\Engine\Source\Runtime\RenderCore\Private\ShaderCodeArchive.cpp] [Line: 491] 
DecompressShaderWithOodleAndExtraLogging(): Could not decompress shader group with Oodle. Group Index: 273 Group IoStoreHash:3c8a0ef0516ede135e080909 Group NumShaders: 21 Shader Index: 6212 Shader In-group Index: 273 Shader Hash: 2561105F86D697C3EA5EA6F46D923073FF6A8EEA. The CPU (Intel(R) Core(TM) i9-14900) may be unstable; for details see http://www.radgametools.com/oodleintel.htm

Fatal error: [File:D:\build++UE5\Sync\Engine\Source\Runtime\RenderCore\Private\ShaderCodeArchive.cpp] [Line: 491]
DecompressShaderWithOodleAndExtraLogging(): Could not decompress shader group with Oodle. Group Index: 273 Group IoStoreHash:3c8a0ef0516ede135e080909 Group NumShaders: 21 Shader Index: 6212 Shader In-group Index: 273 Shader Hash: 2561105F86D697C3EA5EA6F46D923073FF6A8EEA. The CPU (Intel(R) Core(TM) i9-14900) may be unstable; for details see http://www.radgametools.com/oodleintel.htm

https://www.radgametools.com/oodleintel.htm

翻訳
致命的なエラー: [ファイル:D:\build++UE5\Sync\Engine\Source\Runtime\RenderCore\Private\ShaderCodeArchive.cpp] [行: 491]
DecompressShaderWithOodleAndExtraLogging(): Oodle を使用してシェーダーグループを解凍できませんでした。グループインデックス: 273、グループ IoStoreHash: 3c8a0ef0516ede135e080909、グループ NumShaders: 21、シェーダーインデックス: 6212、シェーダーグループ内インデックス: 273、シェーダーハッシュ: 2561105F86D697C3EA5EA6F46D923073FF6A8EEA。CPU (Intel(R) Core(TM) i9-14900) が不安定な可能性があります。詳細は http://www.radgametools.com/oodleintel.htm をご覧ください。

によると

Intelプロセッサの不安定性によりOodleの解凍に失敗

第 13 世代および第 14 世代 Intel Core プロセッサ (13xxx および 14xxx シリーズ) に影響するハードウェアの問題が確認されており、システム全体の不安定性として現れ、Oodle Data の解凍エラーや Unreal で構築されたゲームのクラッシュなどを引き起こします。

Unreal Engine ベースのゲームを開始するときに最もよくある失敗は次のタイプです。

DecompressShader(): シェーダーを解凍できませんでした (GetShaderCompressionFormat=Oodle)

しかし、この問題はOodleだけに影響するわけではなく、この不安定性に悩まされているマシンは、標準的なベンチマークやストレステストプログラムでも不具合を示すようになります。多くのスレッドでプロセッサを大量に使用するプログラムは、クラッシュや予期せぬ動作を引き起こす可能性があります。Adobe Premiere、RealBench、CineBench、Prime95、Handbrake、Visual Studioなど、多くのプログラムでクラッシュが発生しています。この問題は、CPUが原因であるにもかかわらず、GPUエラーメッセージ(「ビデオメモリ不足」エラーなど)として表示されることもあります。

Intel社は 、根本的な原因は チップ内のクロック信号回路の急速な劣化であり、これは他の複数の問題が重なった結果であると確認しました。これはチップ自体の物理的な摩耗であり、一度劣化が起こると残念ながら回復不可能です。影響を受けた部品は交換する必要があります。手順については、 こちらをご覧ください。

本稿執筆時点(2024年10月1日)では、回路の損傷につながる動作条件を回避するための新しいBIOSアップデートがリリースされつつあります。既製のノートパソコンまたはデスクトップPCをお使いの場合は、ベンダーが(少なくとも間もなく)この回避策を含むBIOSアップデートを配布しているはずです。症状が現れる前に、これらのアップデートをできるだけ早くインストールすることが重要です。クラッシュが発生してからでは、ソフトウェアによる解決策では手遅れです。ご自身でマシンを組み立てた場合は、マザーボードベンダーのウェブサイトで最新のBIOSイメージをご確認ください。

これは以前のページの更新版です。現在は廃止されている古いバージョンは、こちらにアーカイブされています。

[UE5.3.2][VisualStudio][Cpp]UnrealEngineのCPPプラグインからOpenAI(ChatGPT4o)を呼んで返り値jsonからパースしてメッセージをとる

今回は以下の続き

前は戻ったjsonをそのまま表示していたが今度は中身のみを表示する

.h

// Fill out your copyright notice in the Description page of Project Settings.

#pragma once

#include "CoreMinimal.h"
#include "Http.h"
#include "Json.h"
#include "GameFramework/Actor.h"
#include "CurlApiTest.generated.h"


UCLASS()
class FURCRAEAUEOPENAI_API ACurlApiTest : public AActor
{
	GENERATED_BODY()
	
public:	
	// Sets default values for this actor's properties
	ACurlApiTest();

protected:
	// Called when the game starts or when spawned
	virtual void BeginPlay() override;

public:	
	// Called every frame
	virtual void Tick(float DeltaTime) override;



	UFUNCTION(BlueprintCallable, Category = "Http")
	void SendChatCompletionRequest();
	void ProcessResponseSimple(FHttpRequestPtr Request, FHttpResponsePtr Response, bool bWasSuccessful);
	//void ProcessResponse(FHttpRequestPtr Request, FHttpResponsePtr Response, bool bWasSuccessful);
};

.cpp

// Fill out your copyright notice in the Description page of Project Settings.


#include "CurlApiTest.h"
#include "CurlRequest.h"
#include "Http.h"
#include "Json.h"
#include "Misc/Paths.h"
#include "Misc/ConfigCacheIni.h"

// Sets default values
ACurlApiTest::ACurlApiTest()
{
 	// Set this actor to call Tick() every frame.  You can turn this off to improve performance if you don't need it.
	PrimaryActorTick.bCanEverTick = true;

}

// Called when the game starts or when spawned
void ACurlApiTest::BeginPlay()
{
	Super::BeginPlay();
	SendChatCompletionRequest();
}

// Called every frame
void ACurlApiTest::Tick(float DeltaTime)
{
	Super::Tick(DeltaTime);

}



void ACurlApiTest::SendChatCompletionRequest()
{
	FString ApiKey = TEXT("sk-から始まる秘密鍵");

	TSharedRef<IHttpRequest> HttpRequest = FHttpModule::Get().CreateRequest();
	HttpRequest->SetURL("https://api.openai.com/v1/chat/completions");
	HttpRequest->SetVerb("POST");
	HttpRequest->SetHeader("Content-Type", "application/json");
	HttpRequest->SetHeader("Authorization", "Bearer " + ApiKey);

	// JSON Body
	FString Content = TEXT(R"(
    {
        "model": "gpt-4o-mini",
        "messages": [{"role": "user", "content": "Say this is a test!"}],
        "temperature": 0.7
    }
    )");

	HttpRequest->SetContentAsString(Content);

	HttpRequest->OnProcessRequestComplete().BindUObject(this, &ACurlApiTest::ProcessResponseSimple);
	/*
	HttpRequest->OnProcessRequestComplete().BindLambda([this](FHttpRequestPtr Request, FHttpResponsePtr Response, bool bWasSuccessful)
		{
			ProcessResponse(Request, Response, bWasSuccessful);
		});
	*/
	HttpRequest->ProcessRequest();
}



void ACurlApiTest::ProcessResponseSimple(FHttpRequestPtr Request, FHttpResponsePtr Response, bool bWasSuccessful)
{
	if (bWasSuccessful && Response.IsValid())
	{
		FString ResponseContent = Response->GetContentAsString();
		TSharedPtr<FJsonObject> JsonObject;
		TSharedRef<TJsonReader<>> Reader = TJsonReaderFactory<>::Create(ResponseContent);

		if (FJsonSerializer::Deserialize(Reader, JsonObject) && JsonObject.IsValid())
		{
			FString MessageContent = JsonObject->GetArrayField("choices")[0]->AsObject()->GetObjectField("message")->GetStringField("content");
			UE_LOG(LogTemp, Warning, TEXT("Response Message: %s"), *MessageContent);
		}
		else
		{
			UE_LOG(LogTemp, Error, TEXT("Failed to parse JSON response"));
		}
	}
	else
	{
		UE_LOG(LogTemp, Error, TEXT("Request failed"));
	}


}

WBP_ApiTestにボタン追加して

SendChatCompletionRequest を呼び出した

できた!

[UE5.3.2]Udemy Master Dynamic Combat, AI Challenges, and C++ Techniques to Create Your Own Epic Action Games in UE5 でのエラー PlayerAnimInstance.gen.cpp.obj : error LNK2001: unresolved external symbol  の解決方法

1>PlayerAnimInstance.gen.cpp.obj : error LNK2001: unresolved external symbol "public: static struct UE::Math::TIntPoint<int> const UE::Math::TIntPoint<int>::ZeroValue" (?ZeroValue@?$TIntPoint@H@Math@UE@@2U123@B)
1>Throwaway.gen.cpp.obj : error LNK2001: unresolved external symbol "public: static struct UE::Math::TIntPoint<int> const UE::Math::TIntPoint<int>::ZeroValue" (?ZeroValue@?$TIntPoint@H@Math@UE@@2U123@B)
1

リンクエラー(LNK2001)が発生しているようですね。このエラーは、コンパイラが ActionCombat.cpp.obj ファイル内で参照されているシンボルの定義を見つけられないことを示しています。以下のような原因が考えられます:

  1. 関数定義の欠如:ヘッダーファイルで宣言されたすべての関数に対応する定義がソースファイルにあることを確認してください。
  2. 関数シグネチャの不一致:宣言と定義の関数シグネチャが完全に一致していることを確認してください。
  3. ライブラリの不足:シンボルが外部ライブラリの一部である場合、そのライブラリがプロジェクト設定で正しくリンクされていることを確認してください。
  4. インクルードディレクティブ:必要なヘッダーファイルがすべてソースファイルにインクルードされていることを確認してください。

以下の手順でこのエラーをトラブルシューティングし、解決することができます:

  • 関数の宣言と定義を確認:ヘッダーファイルで宣言されたすべての関数に対応する定義がソースファイルにあることを確認します。
  • ヘッダーファイルのインクルードを確認:関数が宣言されているヘッダーファイルが、関数を使用するすべてのソースファイルにインクルードされていることを確認します。
  • 必要なライブラリをリンク:関数が静的または動的ライブラリの一部である場合、そのライブラリがビルドプロセス中にリンクされていることを確認します。
  • 関数の可視性を確認:関数が現在のスコープ内でアクセス可能であり、他のソースファイルで定義されている場合は extern として正しくマークされていることを確認します。

Games/ActionCombat 右クリックして Clean を実行してから Buildする。

やったーー!解決

[UE5.3]C++プロジェクトをリフレッシュプロジェクトファイルの作成時にエラーが発生しました

Running D:/Program Files/Epic Games/UE_5.3/Engine/Build/BatchFiles/Build.bat  -projectfiles -project="D:/Sandbox/UE53CratePlugin/UE5_VS/UE5_VS.uproject" -game -rocket -progress
Using bundled DotNet SDK version: 6.0.302
Running UnrealBuildTool: dotnet "..\..\Engine\Binaries\DotNET\UnrealBuildTool\UnrealBuildTool.dll" -projectfiles -project="D:/Sandbox/UE53CratePlugin/UE5_VS/UE5_VS.uproject" -game -rocket -progress
Log file: C:\Users\furcr\AppData\Local\UnrealBuildTool\Log_GPF.txt

Generating VisualStudio2019 project files:
Discovering modules, targets and source code for project...
Visual Studio 2019 does not support .NET 6.0 C# projects, these projects will not be added to the generated solution.
Please generate the Visual Studio 2022 solution if .NET 6.0 C# project support is required.
Microsoft platform targets must be compiled with Visual Studio 2022 17.4 (MSVC 14.34.x) or later for the installed engine. Please update Visual Studio 2022 and ensure no configuration is forcing WindowsTargetRules.Compiler to VisualStudio2019. The current compiler version was detected as: 14.29.30154

つまりは

D:/Program Files/Epic Games/UE_5.3/Engine/Build/BatchFiles/Build.bat -projectfiles -project="D:/Sandbox/UE53CratePlugin/UE5_VS/UE5_VS.uproject" -game -rocket -progress を実行しています
バンドルされた DotNet SDK バージョン 6.0.302 を使用しています
UnrealBuildTool を実行しています: dotnet "..\..\Engine\Binaries\DotNET\UnrealBuildTool\UnrealBuildTool.dll" -projectfiles -project="D:/Sandbox/UE53CratePlugin/UE5_VS/UE5_VS.uproject" -game -rocket -progress
ログ ファイル: C:\Users\furcr\AppData\Local\UnrealBuildTool\Log_GPF.txt

VisualStudio2019 プロジェクト ファイルを生成しています:
プロジェクトのモジュール、ターゲット、ソース コードを検出しています...
Visual Studio 2019 .NET 6.0 C# プロジェクトをサポートしていないため、これらのプロジェクトは生成されたソリューションに追加されません。
.NET 6.0 C# プロジェクトのサポートが必要な場合は、Visual Studio 2022 ソリューションを生成してください。
インストールされているエンジンでは、Microsoft プラットフォーム ターゲットを Visual Studio 2022 17.4 (MSVC 14.34.x) 以降でコンパイルする必要があります。Visual Studio 2022 を更新し、WindowsTargetRules.Compiler を VisualStudio2019 に強制する構成がないことを確認してください。現在のコンパイラ バージョンは 14.29.30154 として検出されました。

VS2022をつかえってこと

したらエラーでなくなった  

[VScode][C++] VScode でCodeRunnerのRun In Tarminalが出てこないの解決方法(MinGW)(64bit Windows11)

参考URL

この記事に基づいて書きます。

https://qiita.com/ochx/items/01449d09777187790ee4

CodeRunner の 拡張機能の設定 Run In Tarminalが出てこない のは 

配色テーマ でダークモダンを選ばないと出てきませんでした。ライトモダンじゃだめだった。

ちゃんちゃん。

furcr@furcraea_built MINGW64 /c/samples/ehararyu_cpp_sample/cpp/source010203
$ make
makefile:2: *** missing separator. Stop.

はmakefile の改行のあとが space だから Tab にする。

program : source.cpp
    cat source.cpp > program

source : source01 source02 source03
    cat source01 source02 source03 > source

program : source
	cat source > program

source : source01 source02 source03
	cat source01 source02 source03 > source