TECH PLAY

電通総研

電通総研 の技術ブログ

822

こんにちは。X(クロス) イノベーション 本部 ソフトウェアデザインセンター セキュリティグループの耿です。 ElastiCache for Redis クラスタ ーの認証・認可方式のうち、 ロールベースのアクセスコントロール(RBAC) を AWS CDK で実装する方法に関する日本語の記事が見当たらなかったため、書き残しておきます。 ElastiCache for Redis の認証・認可方式 リソース構成 CDK による実装のサンプル ユーザーパスワード ユーザーとユーザーグループ VPC Redis クラスター Secrets Manager シークレットへのアクセス許可 ElastiCache for Redis の認証・認可方式 ElastiCache for Redis クラスタ ーに対する認証・認可には以下の方法があります。この記事では RBAC を対象とします。 認証なし Redis クラスタ ーと通信さえできれば全てのコマンドを実行可能 Redis AUTH 単一の トーク ン(パスワード)による認証 転送中の暗号化 ( TLS ) の有効化が必須 認証が成功すれば、Redis クラスタ ーの全コマンドを実行可能 RBAC(ロールベースのアクセスコントロール) Redis v6.0から導入された ACL を利用した認証・認可方式 ユーザー名とパスワードによる認証 複数のユーザーを作成可能 それぞれのユーザーが実施可能なコマンドとアクセス可能なキャッシュキーを制限可能 IAM Redis v7.0 から利用可能な認証・認可方式 有効期間が短い IAM 認証 トーク ンを利用 複数のユーザーを作成可能 それぞれのユーザーが実施可能なコマンドとアクセス可能なキャッシュキーを制限可能 IAM ポリシーにより、どの Redis ユーザーを利用できるか制御可能 リソース構成 CDK による実装を見る前に、リソース構成の概観を整理しておきます。 1つの Redis クラスタ ーには複数の Redis ユーザーグループを追加可能 1つの Redis ユーザーグループには複数の Redis ユーザーを所属可能 ユーザーはユーザー名とユーザーIDを持ち、複数のパスワードを設定可能 ユーザーに設定するアクセス文字列で、Redis クラスタ ーにおける実施可能なコマンドとアクセス可能なキャッシュキーが制限される Redis ユーザーのパスワードを IaC へ記載するのを回避するため、Secrets Manager を利用 アプリケーションの権限に応じて Secrets Manager シークレットへのアクセスを許可し、アプリケーション側の Redis クライアントで Redis ユーザー名とパスワードを利用する CDK による実装のサンプル こちら を参考にしました。 以下の例はシンプルに、1ユーザーグループ/1ユーザーの構成にしています。 ユーザーパスワード Secrets Managerでユーザーパスワードを生成します。 default という名前のユーザーは必須で作成する必要があり、今回はこの default ユーザーをそのまま利用することにします。以下はデフォルトの暗号鍵を利用しています。鍵の管理が必要な場合は別途 KMS キーを作成してください。 const userName = "default" ; const rbacUserSecret = new secretsmanager.Secret ( this , "RedisRbacUserSecret" , { secretName: "RedisRbacUserSecret" , generateSecretString: { secretStringTemplate: JSON .stringify ( { username: userName } ), generateStringKey: "password" , excludeCharacters: "@%*()_+=`~{}|[]\\:\";'?,./" , } , } ); ユーザーとユーザーグループ 執筆時点では CDK には ElastiCache の L2 コンスト ラク トが用意されていないため、L1 コンスト ラク トで作成します。 アクセス文字列 ( accessString ) でユーザーの権限を制限できますが、今回は全コマンドと全キャッシュキーへのアクセスを許可しています。 const userId = "user-1" ; const rbacUser = new elasticache.CfnUser ( this , "RedisRbacUser" , { userId: userId , userName: userName , engine: "redis" , accessString: "on ~* +@all" , passwords: [ rbacUserSecret.secretValueFromJson ( "password" ) .unsafeUnwrap () ] , } ); const rbacUserGroup = new elasticache.CfnUserGroup ( this , "RedisRbacUserGroup" , { userGroupId: "user-group" , engine: "redis" , userIds: [ rbacUser.userId ] , } ); rbacUserGroup.node.addDependency ( rbacUser ); CfnUser に渡すために、Secrets Manager シークレットで生成したパスワードに対して unsafeUnwrap() を呼んでいます。平文のパスワードは Redis ユーザーの作成に使われ、閲覧可能な場所には出現しないため安全な使い方になります。 VPC Redis クラスタ ーを配置する VPC とセキュリティグループを作成します。 const subnetName = "Isolated" ; const vpc = new ec2.Vpc ( this , "Vpc" , { subnetConfiguration: [ { cidrMask: 24 , name: subnetName , subnetType: ec2.SubnetType.PRIVATE_ISOLATED , } ] } ); const redisSG = new ec2.SecurityGroup ( this , 'RedisSG' , { vpc , allowAllOutbound: false , } ); Redis クラスタ ー Redis クラスタ ーを作成し、先に作成したユーザーグループを関連付けます。 const cluster = new elasticache.CfnReplicationGroup ( this , "RedisReplicationGroup" , { replicationGroupDescription: "my-replication-group" , engine: "redis" , engineVersion: "7.0" , cacheNodeType: "cache.t3.micro" , cacheSubnetGroupName: new elasticache.CfnSubnetGroup ( this , "SubnetGroup" , { description: "my-subnet-group" , subnetIds: vpc.selectSubnets ( { subnetGroupName: subnetName } ) .subnetIds , } ) .ref , cacheParameterGroupName: new elasticache.CfnParameterGroup ( this , "ParameterGroup" , { description: "my-parameter-group" , cacheParameterGroupFamily: "redis7" , } ) .ref , numNodeGroups: 1 , replicasPerNodeGroup: 1 , securityGroupIds: [ redisSG.securityGroupId ] , atRestEncryptionEnabled: true , transitEncryptionEnabled: true , userGroupIds: [ rbacUserGroup.userGroupId ] , } ); cluster.node.addDependency ( rbacUserGroup ); Secrets Manager シークレットへのアクセス許可 あとは Redis クラスタ ーへアクセスするアプリケーションが Secrets Manager シークレットにアクセスできるように、読み取り権限を付与すれば良いです。(CDKコードは省略します) CDK による Redis の RBAC の実装例はあまり見かけませんが、簡単に実装できました。 お読みいただいてありがとうございました。 私たちは同じチームで働いてくれる仲間を大募集しています!たくさんのご応募をお待ちしています。 セキュリティエンジニア(セキュリティ設計) 執筆: @kou.kinyo 、レビュー: @nakamura.toshihiro ( Shodo で執筆されました )
アバター
こんにちは。X(クロス) イノベーション 本部 ソフトウェアデザインセンター セキュリティグループの耿です。 ElastiCache for Redis クラスタ ーの認証・認可方式のうち、 ロールベースのアクセスコントロール(RBAC) を AWS CDK で実装する方法に関する日本語の記事が見当たらなかったため、書き残しておきます。 ElastiCache for Redis の認証・認可方式 リソース構成 CDK による実装のサンプル ユーザーパスワード ユーザーとユーザーグループ VPC Redis クラスター Secrets Manager シークレットへのアクセス許可 ElastiCache for Redis の認証・認可方式 ElastiCache for Redis クラスタ ーに対する認証・認可には以下の方法があります。この記事では RBAC を対象とします。 認証なし Redis クラスタ ーと通信さえできれば全てのコマンドを実行可能 Redis AUTH 単一の トーク ン(パスワード)による認証 転送中の暗号化 ( TLS ) の有効化が必須 認証が成功すれば、Redis クラスタ ーの全コマンドを実行可能 RBAC(ロールベースのアクセスコントロール) Redis v6.0から導入された ACL を利用した認証・認可方式 ユーザー名とパスワードによる認証 複数のユーザーを作成可能 それぞれのユーザーが実施可能なコマンドとアクセス可能なキャッシュキーを制限可能 IAM Redis v7.0 から利用可能な認証・認可方式 有効期間が短い IAM 認証 トーク ンを利用 複数のユーザーを作成可能 それぞれのユーザーが実施可能なコマンドとアクセス可能なキャッシュキーを制限可能 IAM ポリシーにより、どの Redis ユーザーを利用できるか制御可能 リソース構成 CDK による実装を見る前に、リソース構成の概観を整理しておきます。 1つの Redis クラスタ ーには複数の Redis ユーザーグループを追加可能 1つの Redis ユーザーグループには複数の Redis ユーザーを所属可能 ユーザーはユーザー名とユーザーIDを持ち、複数のパスワードを設定可能 ユーザーに設定するアクセス文字列で、Redis クラスタ ーにおける実施可能なコマンドとアクセス可能なキャッシュキーが制限される Redis ユーザーのパスワードを IaC へ記載するのを回避するため、Secrets Manager を利用 アプリケーションの権限に応じて Secrets Manager シークレットへのアクセスを許可し、アプリケーション側の Redis クライアントで Redis ユーザー名とパスワードを利用する CDK による実装のサンプル こちら を参考にしました。 以下の例はシンプルに、1ユーザーグループ/1ユーザーの構成にしています。 ユーザーパスワード Secrets Managerでユーザーパスワードを生成します。 default という名前のユーザーは必須で作成する必要があり、今回はこの default ユーザーをそのまま利用することにします。以下はデフォルトの暗号鍵を利用しています。鍵の管理が必要な場合は別途 KMS キーを作成してください。 const userName = "default" ; const rbacUserSecret = new secretsmanager.Secret ( this , "RedisRbacUserSecret" , { secretName: "RedisRbacUserSecret" , generateSecretString: { secretStringTemplate: JSON .stringify ( { username: userName } ), generateStringKey: "password" , excludeCharacters: "@%*()_+=`~{}|[]\\:\";'?,./" , } , } ); ユーザーとユーザーグループ 執筆時点では CDK には ElastiCache の L2 コンスト ラク トが用意されていないため、L1 コンスト ラク トで作成します。 アクセス文字列 ( accessString ) でユーザーの権限を制限できますが、今回は全コマンドと全キャッシュキーへのアクセスを許可しています。 const userId = "user-1" ; const rbacUser = new elasticache.CfnUser ( this , "RedisRbacUser" , { userId: userId , userName: userName , engine: "redis" , accessString: "on ~* +@all" , passwords: [ rbacUserSecret.secretValueFromJson ( "password" ) .unsafeUnwrap () ] , } ); const rbacUserGroup = new elasticache.CfnUserGroup ( this , "RedisRbacUserGroup" , { userGroupId: "user-group" , engine: "redis" , userIds: [ rbacUser.userId ] , } ); rbacUserGroup.node.addDependency ( rbacUser ); CfnUser に渡すために、Secrets Manager シークレットで生成したパスワードに対して unsafeUnwrap() を呼んでいます。平文のパスワードは Redis ユーザーの作成に使われ、閲覧可能な場所には出現しないため安全な使い方になります。 VPC Redis クラスタ ーを配置する VPC とセキュリティグループを作成します。 const subnetName = "Isolated" ; const vpc = new ec2.Vpc ( this , "Vpc" , { subnetConfiguration: [ { cidrMask: 24 , name: subnetName , subnetType: ec2.SubnetType.PRIVATE_ISOLATED , } ] } ); const redisSG = new ec2.SecurityGroup ( this , 'RedisSG' , { vpc , allowAllOutbound: false , } ); Redis クラスタ ー Redis クラスタ ーを作成し、先に作成したユーザーグループを関連付けます。 const cluster = new elasticache.CfnReplicationGroup ( this , "RedisReplicationGroup" , { replicationGroupDescription: "my-replication-group" , engine: "redis" , engineVersion: "7.0" , cacheNodeType: "cache.t3.micro" , cacheSubnetGroupName: new elasticache.CfnSubnetGroup ( this , "SubnetGroup" , { description: "my-subnet-group" , subnetIds: vpc.selectSubnets ( { subnetGroupName: subnetName } ) .subnetIds , } ) .ref , cacheParameterGroupName: new elasticache.CfnParameterGroup ( this , "ParameterGroup" , { description: "my-parameter-group" , cacheParameterGroupFamily: "redis7" , } ) .ref , numNodeGroups: 1 , replicasPerNodeGroup: 1 , securityGroupIds: [ redisSG.securityGroupId ] , atRestEncryptionEnabled: true , transitEncryptionEnabled: true , userGroupIds: [ rbacUserGroup.userGroupId ] , } ); cluster.node.addDependency ( rbacUserGroup ); Secrets Manager シークレットへのアクセス許可 あとは Redis クラスタ ーへアクセスするアプリケーションが Secrets Manager シークレットにアクセスできるように、読み取り権限を付与すれば良いです。(CDKコードは省略します) CDK による Redis の RBAC の実装例はあまり見かけませんが、簡単に実装できました。 お読みいただいてありがとうございました。 私たちは同じチームで働いてくれる仲間を大募集しています!たくさんのご応募をお待ちしています。 セキュリティエンジニア(セキュリティ設計) 執筆: @kou.kinyo 、レビュー: @nakamura.toshihiro ( Shodo で執筆されました )
アバター
こんにちは、金融ソリューション事業部の若本です。 前回の記事に続き、AIを用いてラップの生成を行います。 前回の記事は こちら です。 前回までのあらすじ ChatGPTでフリースタイル調のラップの生成をするためには、韻を別途取得するAIが必要でした。 そこで、語感踏みもある程度可能、かつ高速な韻の検索を実装しました。 韻を生成するパイプライン 今回の主目的は 「韻が踏めるラップをAIで生成すること」 です。 そのための最小限の構成として、韻のセットを複数取得して、その後にラップを生成することを考えます。 処理のパイプラインは下記の通りです。 「韻の検索」に加えて、主に追加で必要なものは下記の通りです。 ChatGPTに与えるプロンプト 韻を自動で取得する機能 1) ChatGPTに与えるプロンプト 下記のpromptをChatGPTに与えます。 単語/フレーズのセットを使用して、出力にラップを表示してください。 セットの中の単語/フレーズは連続して使用すること。 また、各セットのラップは短くし、同じ長さに収めること。 絶対に英語のみで出力してはいけません。 あなたはラッパーです。相手に向けてどちらかの方針でラップしてください。 1. 自分をアピールする 2. 相手を批判する 使用可能な表現:a yo、you know?、~してやる、そんな感じで、yeah 絶対に使用してはいけない表現:~だ、文末が「だ」で終わる表現 例: 単語/フレーズのセット: 1:単語A、単語B... 2:単語C、単語D... 出力: 1: ~省略~ 2: ~省略~ 単語/フレーズのセット: {data} 出力: {data}内には「1:単語A、単語B...」のような形で踏ませたい韻の情報を自動的に入れます。 ※「例:」の箇所は実際に使用したものから変えています。実際には、踏む単語と対応するラップをfew-shotとして与えました。 【試行錯誤した点】 条件付け(1~4行目) 口語調があまりにも多かった ため、短く区切るように指示しました。 ばらばらに韻を使うのではなく、なるべく隣接した場所で使うよう指示しています。 英語のフレーズを登録しているのですが、 英語のフレーズばかりだと英語でラップを始めます。 そのため、英語だけにしないように指示しています。 スタンス(6~8行目) 韻を踏む単語に引っ張られ過ぎて、ラッパーでなくなる ことが多かったのでスタンスを明確にしました。 表現の指示(10~11行目) ラッパーのよくある口癖を入れています。逆に、 ラッパーがあまり使わない印象のある「~だ」が目立ったので禁止しました。 few-shot(13行目~) 実際のラッパーの踏み方を例として与えました。出力の形式を覚えさせる意味合いが強いです。 OpenAIから プロンプトのTips も公開されていますので、適宜ご参照ください。 「~してはいけません」は守られない場合も多々あるため、禁止したい表現は英語で指示したほうが良い結果になりそうです。改良の余地は多々ありますが、目的達成には上記で十分でした。 2) 韻を自動で取得する機能 前回の記事の「韻の検索」を用いて、ランダムに単語のセットをN個選出します。 セットの中に含まれる単語/フレーズ数はM個です。 N, Mともにランダムな数字としました。どちらも最小値/最大値をお好みで指定します。 今回は多様性重視&ランダム性重視ということでこのような仕様としています。 選んだセット同士の相性が良くない可能性はありますが、何度も試していいものが出てくることを期待します。いわば 数打ちゃ当たる方式 です。 結果 上記の追加処理を統合します。筆者は flet を用いたアプリにしました。 ボタンをクリックすると5秒ほどで生成されたラップが返ってきます。 制作者の思い入れ補正もあると思いますが、手軽に出せて良い感じです。 ポンポン出せるだけでなく、たまにくらうものもあるので、ボタンを押す手が止まりません。 なお、韻の検索、ChatGPTの生成ともにランダムですので同じバースは出てきません。 ChatGPT バース集 以下、自動で生成されたラップのうち、くらったものをいくつか紹介します。 俺のラップで済ませる 言葉で訴える 伝わるはず 他のラッパーは食われる 俺の経験を踏まえる でもやっぱり好かれる ゆとりのあるstoryを語る 俺の強みはそこにある 解説:「済ませる/訴える/食われる/踏まえる/好かれる」「story/強み」の怒涛の踏み。言ってることは分かるようで分からないですが、余裕と自信を感じます。 Yo, check the format 俺のスタイルはforward Tobaccoの匂いが漂うstreet corner でも俺のラップはnever later このエリアで俺がrule the paper 言葉はweapon like a samurai saber 解説:英語も柔軟に取り込めています。オシャレ感があってすきです(語彙力)。 I write my rhymes with precision, like 清書 My stage presence is like a grand 劇場 My style's a fusion of East and 西洋 My skills keep growing, never stop 成長 解説:英語が出力の大半を占めることも。「My style's a fusion of East and 西洋」は韻を踏みつつも、このバースを象徴している良い パンチライン です。 多言語を操るChatGPTだからこその個性的なバース ですね。 おわりに 今回は手軽な方法でChatGPTのラップ生成を行いました。 上記のクオリティのものがザラに出てくるので、作っていて非常に楽しかったです。 今回は行っていませんが、対戦相手にアンサーしたり、曲のサンプリングをしたりなどもパイプラインを工夫すれば対応できるポテンシャルはあります(ここまでできればThis is HIPHOP ですね)。 ここまでお読みいただき、ありがとうございました。 皆さんもぜひGPTで色々遊んでみてください。Peace! 執筆: @wakamoto.ryosuke 、レビュー: @yamada.y ( Shodo で執筆されました )
アバター
こんにちは、金融ソリューション事業部の若本です。 前回の記事に続き、AIを用いてラップの生成を行います。 前回の記事は こちら です。 前回までのあらすじ ChatGPTでフリースタイル調のラップの生成をするためには、韻を別途取得するAIが必要でした。 そこで、語感踏みもある程度可能、かつ高速な韻の検索を実装しました。 韻を生成するパイプライン 今回の主目的は 「韻が踏めるラップをAIで生成すること」 です。 そのための最小限の構成として、韻のセットを複数取得して、その後にラップを生成することを考えます。 処理のパイプラインは下記の通りです。 「韻の検索」に加えて、主に追加で必要なものは下記の通りです。 ChatGPTに与えるプロンプト 韻を自動で取得する機能 1) ChatGPTに与えるプロンプト 下記のpromptをChatGPTに与えます。 単語/フレーズのセットを使用して、出力にラップを表示してください。 セットの中の単語/フレーズは連続して使用すること。 また、各セットのラップは短くし、同じ長さに収めること。 絶対に英語のみで出力してはいけません。 あなたはラッパーです。相手に向けてどちらかの方針でラップしてください。 1. 自分をアピールする 2. 相手を批判する 使用可能な表現:a yo、you know?、~してやる、そんな感じで、yeah 絶対に使用してはいけない表現:~だ、文末が「だ」で終わる表現 例: 単語/フレーズのセット: 1:単語A、単語B... 2:単語C、単語D... 出力: 1: ~省略~ 2: ~省略~ 単語/フレーズのセット: {data} 出力: {data}内には「1:単語A、単語B...」のような形で踏ませたい韻の情報を自動的に入れます。 ※「例:」の箇所は実際に使用したものから変えています。実際には、踏む単語と対応するラップをfew-shotとして与えました。 【試行錯誤した点】 条件付け(1~4行目) 口語調があまりにも多かった ため、短く区切るように指示しました。 ばらばらに韻を使うのではなく、なるべく隣接した場所で使うよう指示しています。 英語のフレーズを登録しているのですが、 英語のフレーズばかりだと英語でラップを始めます。 そのため、英語だけにしないように指示しています。 スタンス(6~8行目) 韻を踏む単語に引っ張られ過ぎて、ラッパーでなくなる ことが多かったのでスタンスを明確にしました。 表現の指示(10~11行目) ラッパーのよくある口癖を入れています。逆に、 ラッパーがあまり使わない印象のある「~だ」が目立ったので禁止しました。 few-shot(13行目~) 実際のラッパーの踏み方を例として与えました。出力の形式を覚えさせる意味合いが強いです。 OpenAIから プロンプトのTips も公開されていますので、適宜ご参照ください。 「~してはいけません」は守られない場合も多々あるため、禁止したい表現は英語で指示したほうが良い結果になりそうです。改良の余地は多々ありますが、目的達成には上記で十分でした。 2) 韻を自動で取得する機能 前回の記事の「韻の検索」を用いて、ランダムに単語のセットをN個選出します。 セットの中に含まれる単語/フレーズ数はM個です。 N, Mともにランダムな数字としました。どちらも最小値/最大値をお好みで指定します。 今回は多様性重視&ランダム性重視ということでこのような仕様としています。 選んだセット同士の相性が良くない可能性はありますが、何度も試していいものが出てくることを期待します。いわば 数打ちゃ当たる方式 です。 結果 上記の追加処理を統合します。筆者は flet を用いたアプリにしました。 ボタンをクリックすると5秒ほどで生成されたラップが返ってきます。 制作者の思い入れ補正もあると思いますが、手軽に出せて良い感じです。 ポンポン出せるだけでなく、たまにくらうものもあるので、ボタンを押す手が止まりません。 なお、韻の検索、ChatGPTの生成ともにランダムですので同じバースは出てきません。 ChatGPT バース集 以下、自動で生成されたラップのうち、くらったものをいくつか紹介します。 俺のラップで済ませる 言葉で訴える 伝わるはず 他のラッパーは食われる 俺の経験を踏まえる でもやっぱり好かれる ゆとりのあるstoryを語る 俺の強みはそこにある 解説:「済ませる/訴える/食われる/踏まえる/好かれる」「story/強み」の怒涛の踏み。言ってることは分かるようで分からないですが、余裕と自信を感じます。 Yo, check the format 俺のスタイルはforward Tobaccoの匂いが漂うstreet corner でも俺のラップはnever later このエリアで俺がrule the paper 言葉はweapon like a samurai saber 解説:英語も柔軟に取り込めています。オシャレ感があってすきです(語彙力)。 I write my rhymes with precision, like 清書 My stage presence is like a grand 劇場 My style's a fusion of East and 西洋 My skills keep growing, never stop 成長 解説:英語が出力の大半を占めることも。「My style's a fusion of East and 西洋」は韻を踏みつつも、このバースを象徴している良い パンチライン です。 多言語を操るChatGPTだからこその個性的なバース ですね。 おわりに 今回は手軽な方法でChatGPTのラップ生成を行いました。 上記のクオリティのものがザラに出てくるので、作っていて非常に楽しかったです。 今回は行っていませんが、対戦相手にアンサーしたり、曲のサンプリングをしたりなどもパイプラインを工夫すれば対応できるポテンシャルはあります(ここまでできればThis is HIPHOP ですね)。 ここまでお読みいただき、ありがとうございました。 皆さんもぜひGPTで色々遊んでみてください。Peace! 執筆: @wakamoto.ryosuke 、レビュー: @yamada.y ( Shodo で執筆されました )
アバター
こんにちは。最近MC battleにハマっております、ISID 金融ソリューション事業部の若本です。 イベント現場にも何度か足を運んでおり、行くたびにその月で一番大きい声を出しています。 さて、そんなラップにがっつり影響を受け、今回はラップができるAIを作成してみます。 なぜ韻を検索するのか ~GPTでできるよね?~ その前に、2023初頭の現在、工夫なしにAIで高度なラップはできません。 なので、 まずは韻を検索することから始めます。 「ChatGPTとかで普通にできるんじゃないの?」 と思われた方もいると思います。手始めにChatGPTに日本語でラップをさせてみましょう。 確かにラップしていますし、凄いことに違いはありません。が、真面目なラップすぎてヘッズには物足りません(個人の主観)。 これは、ChatGPTが韻を理解していないことが原因です。バースの意図はしっかり伝わりますが、肝心な韻がほぼ含まれていません。韻を理解していない理由は多々考えられますが、LLMにとって難しい問題設定になっているのと、データが足りていないの2つが主に考えられます。 要は、ChatGPTに韻を踏ませることはできません。 ChatGPTが韻を理解していないことは確認できました。 とはいえ、ラップ自体はそれらしくできるので、韻だけ与えてラップさせてみましょう。 先ほどのラップよりいい感じです。ラップできるやつ感が増しました。 韻をあらかじめ与えてあげることで、実際のラッパーに近いラップが実現できそうです。 とはいえ、毎回韻を指定するのは面倒なことこの上ないですよね。なので、 まずは似た韻を検索する仕組みを構築します。 韻について そもそも韻には下記のような種類があります。 完踏み 母音が完全一致するフレーズの組み合わせ e.g.) 「AI」(e-e-a-i)と「明細」(e-i(e)-a-i) 語感踏み 母音を濁したフレーズの組み合わせ e.g.) 機械学習 (i-a-i-a-u-u-u)とハイ拍手(a-i-a-u-u) その他 頭韻  前方の母音を合わせた組み合わせ e.g.)「 機械学習 」(i-a-i-…)と「嫌いなやつ」(i-a-i-…) 脚韻 後方の母音を合わせた組み合わせ e.g.)「AI」(e-e-a-i)と「限界」(e-n-a-i) 上記のうち、完踏みはフレーズの母音同士の一致率を計算するだけで済みます。これは、後述の古典的手法でも十分可能です。 しかし、語感踏みのような単語、例えば「文字数が明らかに違うけれど、早口にすると似て聞こえるような単語」は拾ってくることができません。 そこで、今回は「語感踏み」まで踏み込んだプログラムを目指します。 実用的な韻に必要なもの 上記を満たしていれば実用的な韻になるのかと問われると、答えは「否」です。 実際に使える"韻"を踏むためには、下記をはじめとして考慮すべき点があります。 英語も比較できる ラップでは英語のフレーズもたびたび登場します。そのため、日本語と英語を比較できることも重要になります。 意味的結びつきが強い単語を重視できる 前述の「AI」と「明細」で韻は踏めていますが、これらの単語で話を繋げることに苦労します。韻を踏みつつ、話を繋げやすい単語を選択する必要があります。 結果がすぐ出る 次々と言葉を紡ぐ必要があるので、すぐ結果が出ることも重要です。 上記以外にも実用上の観点が諸々あるかとは思いますが、今回は最低限上記に対応したいと思います。 韻を検索するAI 今回ベースとするのは、Universal Sentence Encoderによって得られたベクトル表現です。 つまり、 "韻"の情報をベクトル表現にします (以降、これを韻beddingと呼称します)。 やることは非常に簡単で、 1) 単語の読み方のうち母音だけ残し、2) 母音を連結した文字列(韻)からベクトルを取得します。 韻をベクトルすることにより、下記のようなメリットが享受できます。 韻をベクトル化することにより、「全体的な語感が近い単語」を引っ張ってくることができる(仮説) 検索速度が早い(ベクトルの最近傍探索ができる) 単語の意味と同じ尺度で評価できるようになる つまるところ「うまい、安い、早い」です。 事前に作成したフレーズ集の各単語について、2つのベクトル表現を取得します。 ここで、単語embeddingは単語の意味的な情報が、韻beddingは韻の情報が格納されています。 上記のようにして作成した韻bedding、単語embeddingをもとに、検索した単語と近いものを返します。 ベクトル近傍探索ライブラリである faiss を用いて、韻beddingから近い韻を持つものをN件取得し、その後下記の計算式で昇順ソートします。 ※今回は ユークリッド 距離を用いたため昇順ソートしています。 cosine 類似度×降順でも問題ありません。 類似度 = α×韻の類似度+(1.0-α) ×単語の類似度 αはお好みで0.0~1.0の間で変えてください。今回は単純に韻の精度が知りたいため、α=1.0の結果を見てみます。 使用したデータ mecab-ipadic-NEologd の辞書の一部を使用しました。 データとしては約10万語ほどの量になります。 結果 韻beddingでは下記のような結果が得られました。検索ワードは「エンジニア」です。 別単語扱いの「engineer」が最上位に来ているのがポイント高いです。英語でも検索できていることが分かります。 次点の「 メスシリンダー 」も踏まれるとクスっとなりそうなので良いです。 語感踏みのようなことができています ね。 とはいえ、そもそもベクトルでやる必要があるの?と思われるかもしれません。 そのため、文字同士の類似度を計算する手法で試した結果も確認してみます。 レーベンシュタイン距離 ジャロ・ウィンクラー距離 ゲシュタルト パターンマッチング 既存の手法はどれも似た結果になりました。 検索速度に目を向けると、ベクトル検索が5倍以上の差 を付けています。 今回の単語/フレーズ数は約10万です。1万を超えるとベクトル検索のほうが早くなってくる印象でした。 1検索速度 (s) 韻bedding 0.036 レーベンシュタイン距離 0.194 ジャロ・ウィンクラー距離 0.183 ゲシュタルト パターンマッチング 3.708 検索の質としても、文字数の制約が緩いベクトル表現のほうが面白い韻は多く(完全に好みですが)、 韻beddingの採用価値はある と感じました。 おわりに 今回作成したAIによって、登録したフレーズからそれらしき結果は得ることができました。 一方、検索だけでも下記のような課題が残っています。 アクセントの考慮が不十分 今回の手法では、発音のアクセントまで考慮した検索はできていません。 アクセント記号を含める処理( pyopenjtalk など)を噛ませることでアクセントもある程度考慮に含めることはできそうです。 フレーズ数の不足 事前に登録するフレーズを増やすことが重要ですが、これを集めるのが大変です。 本記事では mecab-ipadic-NEologd を使いましたが、「韻は踏めるものの使いづらいワード」も多くなってしまうので、データソースは気を付ける必要があります。 単語の組み合わせでマッチングできない 今回試した方法では、「登録してあるフレーズ」の中から韻を踏めるものを探しています。より実用的なものにしていくためには、単語の組み合わせからマッチングすることも考えていく必要もありそうです。 次回は、満を持して検索した韻から自動でラップ生成を行います。 (Part. 2に続く) ここまでお読みいただきありがとうございました。 執筆: @wakamoto.ryosuke 、レビュー: @yamada.y ( Shodo で執筆されました )
アバター
こんにちは。最近MC battleにハマっております、ISID 金融ソリューション事業部の若本です。 イベント現場にも何度か足を運んでおり、行くたびにその月で一番大きい声を出しています。 さて、そんなラップにがっつり影響を受け、今回はラップができるAIを作成してみます。 なぜ韻を検索するのか ~GPTでできるよね?~ その前に、2023初頭の現在、工夫なしにAIで高度なラップはできません。 なので、 まずは韻を検索することから始めます。 「ChatGPTとかで普通にできるんじゃないの?」 と思われた方もいると思います。手始めにChatGPTに日本語でラップをさせてみましょう。 確かにラップしていますし、凄いことに違いはありません。が、真面目なラップすぎてヘッズには物足りません(個人の主観)。 これは、ChatGPTが韻を理解していないことが原因です。バースの意図はしっかり伝わりますが、肝心な韻がほぼ含まれていません。韻を理解していない理由は多々考えられますが、LLMにとって難しい問題設定になっているのと、データが足りていないの2つが主に考えられます。 要は、ChatGPTに韻を踏ませることはできません。 ChatGPTが韻を理解していないことは確認できました。 とはいえ、ラップ自体はそれらしくできるので、韻だけ与えてラップさせてみましょう。 先ほどのラップよりいい感じです。ラップできるやつ感が増しました。 韻をあらかじめ与えてあげることで、実際のラッパーに近いラップが実現できそうです。 とはいえ、毎回韻を指定するのは面倒なことこの上ないですよね。なので、 まずは似た韻を検索する仕組みを構築します。 韻について そもそも韻には下記のような種類があります。 完踏み 母音が完全一致するフレーズの組み合わせ e.g.) 「AI」(e-e-a-i)と「明細」(e-i(e)-a-i) 語感踏み 母音を濁したフレーズの組み合わせ e.g.) 機械学習 (i-a-i-a-u-u-u)とハイ拍手(a-i-a-u-u) その他 頭韻  前方の母音を合わせた組み合わせ e.g.)「 機械学習 」(i-a-i-…)と「嫌いなやつ」(i-a-i-…) 脚韻 後方の母音を合わせた組み合わせ e.g.)「AI」(e-e-a-i)と「限界」(e-n-a-i) 上記のうち、完踏みはフレーズの母音同士の一致率を計算するだけで済みます。これは、後述の古典的手法でも十分可能です。 しかし、語感踏みのような単語、例えば「文字数が明らかに違うけれど、早口にすると似て聞こえるような単語」は拾ってくることができません。 そこで、今回は「語感踏み」まで踏み込んだプログラムを目指します。 実用的な韻に必要なもの 上記を満たしていれば実用的な韻になるのかと問われると、答えは「否」です。 実際に使える"韻"を踏むためには、下記をはじめとして考慮すべき点があります。 英語も比較できる ラップでは英語のフレーズもたびたび登場します。そのため、日本語と英語を比較できることも重要になります。 意味的結びつきが強い単語を重視できる 前述の「AI」と「明細」で韻は踏めていますが、これらの単語で話を繋げることに苦労します。韻を踏みつつ、話を繋げやすい単語を選択する必要があります。 結果がすぐ出る 次々と言葉を紡ぐ必要があるので、すぐ結果が出ることも重要です。 上記以外にも実用上の観点が諸々あるかとは思いますが、今回は最低限上記に対応したいと思います。 韻を検索するAI 今回ベースとするのは、Universal Sentence Encoderによって得られたベクトル表現です。 つまり、 "韻"の情報をベクトル表現にします (以降、これを韻beddingと呼称します)。 やることは非常に簡単で、 1) 単語の読み方のうち母音だけ残し、2) 母音を連結した文字列(韻)からベクトルを取得します。 韻をベクトルすることにより、下記のようなメリットが享受できます。 韻をベクトル化することにより、「全体的な語感が近い単語」を引っ張ってくることができる(仮説) 検索速度が早い(ベクトルの最近傍探索ができる) 単語の意味と同じ尺度で評価できるようになる つまるところ「うまい、安い、早い」です。 事前に作成したフレーズ集の各単語について、2つのベクトル表現を取得します。 ここで、単語embeddingは単語の意味的な情報が、韻beddingは韻の情報が格納されています。 上記のようにして作成した韻bedding、単語embeddingをもとに、検索した単語と近いものを返します。 ベクトル近傍探索ライブラリである faiss を用いて、韻beddingから近い韻を持つものをN件取得し、その後下記の計算式で昇順ソートします。 ※今回は ユークリッド 距離を用いたため昇順ソートしています。 cosine 類似度×降順でも問題ありません。 類似度 = α×韻の類似度+(1.0-α) ×単語の類似度 αはお好みで0.0~1.0の間で変えてください。今回は単純に韻の精度が知りたいため、α=1.0の結果を見てみます。 使用したデータ mecab-ipadic-NEologd の辞書の一部を使用しました。 データとしては約10万語ほどの量になります。 結果 韻beddingでは下記のような結果が得られました。検索ワードは「エンジニア」です。 別単語扱いの「engineer」が最上位に来ているのがポイント高いです。英語でも検索できていることが分かります。 次点の「 メスシリンダー 」も踏まれるとクスっとなりそうなので良いです。 語感踏みのようなことができています ね。 とはいえ、そもそもベクトルでやる必要があるの?と思われるかもしれません。 そのため、文字同士の類似度を計算する手法で試した結果も確認してみます。 レーベンシュタイン距離 ジャロ・ウィンクラー距離 ゲシュタルト パターンマッチング 既存の手法はどれも似た結果になりました。 検索速度に目を向けると、ベクトル検索が5倍以上の差 を付けています。 今回の単語/フレーズ数は約10万です。1万を超えるとベクトル検索のほうが早くなってくる印象でした。 1検索速度 (s) 韻bedding 0.036 レーベンシュタイン距離 0.194 ジャロ・ウィンクラー距離 0.183 ゲシュタルト パターンマッチング 3.708 検索の質としても、文字数の制約が緩いベクトル表現のほうが面白い韻は多く(完全に好みですが)、 韻beddingの採用価値はある と感じました。 おわりに 今回作成したAIによって、登録したフレーズからそれらしき結果は得ることができました。 一方、検索だけでも下記のような課題が残っています。 アクセントの考慮が不十分 今回の手法では、発音のアクセントまで考慮した検索はできていません。 アクセント記号を含める処理( pyopenjtalk など)を噛ませることでアクセントもある程度考慮に含めることはできそうです。 フレーズ数の不足 事前に登録するフレーズを増やすことが重要ですが、これを集めるのが大変です。 本記事では mecab-ipadic-NEologd を使いましたが、「韻は踏めるものの使いづらいワード」も多くなってしまうので、データソースは気を付ける必要があります。 単語の組み合わせでマッチングできない 今回試した方法では、「登録してあるフレーズ」の中から韻を踏めるものを探しています。より実用的なものにしていくためには、単語の組み合わせからマッチングすることも考えていく必要もありそうです。 次回は、満を持して検索した韻から自動でラップ生成を行います。 (Part. 2に続く) ここまでお読みいただきありがとうございました。 執筆: @wakamoto.ryosuke 、レビュー: @yamada.y ( Shodo で執筆されました )
アバター
こんにちは、ISID 金融ソリューション事業部の岡崎です。 今回は ZBrush で作成した3Dモデルを、UE5のタイムラインという機能を活用して、簡単なアニメーションを作成する手順をご紹介します。 はじめに UE5でオブジェクトにアニメーションをつける方法としてBlueprintのタイムラインを使用する方法があります。 タイムラインで設定した時間(タイミング)に、あらかじめ定義した値を出力する仕組みで、簡単なアニメーションが実装できます。 タイムラインを使用せずに、複雑なアニメーションを作成する手順も今後配信予定です。 今回はDCCツールの ZBrush を使用して、大砲の3Dオブジェクトを作成し、UE5内でその大砲を動かしたり弾を発射させるなどのアニメーションをつけていきます。 検証環境/ツール Unreal Engine5.1.1 ZBrush 2022.0.6 実装手順 ZBrush で大砲を作成 ZBrush で作成したオブジェクトをエクスポート UE5でFBXファイルをインポート UE5でタイムラインを使用したアニメーションの作成 1. ZBrush で大砲を作成 まず初めに ZBrush を使用して大砲の3Dオブジェクトを作成します。 今回詳しい作成方法は割愛しますが、 ZBrush の操作方法やオブジェクト作成手順につきましては、今後記事を配信予定です。 まずはバレル(銃身)部分を作成します。 今回は下記画像のようなバレルの形状で作成しています。 次にバレルを装着するベースの部分の作成を行います。 今回は本題ではないため割愛しますが、 ZBrush のローポリ編集を使用することで、下記画像のような無機質な形状も作成できます。 今回の実装のポイントとしては、バレルとベースの部分を2つの部品として、別々のオブジェクトで作成することです。 これにより、後述するタイムラインを利用したアニメーションに使用できます。 2. ZBrush で作成したオブジェクトをエクスポート ZBrush で作成したオブジェクトをUEで使用できるようにFBXに変換してエクスポートする必要があります。 ZBrush のZ プラグイン という機能を使用して、FBXエクスポートの手順を紹介します。 主にエクスポートで変更するのは下記部分になります。 出力する情報を選択 FBXのバージョンを選択 ファイルの形式を選択 メッシュを三角メッシュにするかどうか ポリペイントの出力をするかどうか エクスポート ① 出力する情報を選択 出力する情報を下記から選びます。 選択のみ : 選択したサブツール 表示のみ : 表示してあるサブツール すべて : 全てのサブツール 今回は、バレル部分とベースの部分で2種類のFBXを出力したかったので、 それぞれ個別に選択を行い「Select」を選びました。 ② FBXのバージョンを選択 「FBX2020」の部分をクリックすることで、バージョンが選択できます。 今回は「FBX2020」を選択しました。 ③ ファイルの形式を選択 ファイルの形式を下記から選びます。 bin ascii binの方がファイルサイズが小さく一般的なので、今回はこちらを選択しました。 ④ メッシュを三角メッシュにするかどうか メッシュを三角ポリゴンとしてエクスポートしたい場合はオンにします。 三角ポリゴンにすると、ポリゴン数が減りファイルが軽くなる代わりに、メッシュの再編集がしにくくなります。 今回は小さなファイルだったので、設定はオフのまま進めました。 ⑤ ポリペイントの出力をするかどうか ZBrush 上でもポリペイントという機能を使用することでオブジェクトに色をつけることができます。 サブツール内の筆のマークをオンにすることで、ポリペイントもFBXに含めることができます。 今回は、マテリアルや色の設定はUEで行うので、オフのまま進めます。 ⑥ エクスポート エクスポートボタンを押下し、モデルのエクスポートを行います。 3. UE5でFBXファイルをインポート 前工程で、バレルとベースの部分で2種類のFBXファイルを作成したので、 今回はそれらをUE5にインポートを行います。 今回は2種類のFBXファイル名を以下のように作成しています。 cannon.fbx cannon_base.fbx Content Drawerを開き、右クリックから「Import to Game」を押下し、前工程で作成した2つのFBXファイルをインポートします。 マテリアルに関してはUEで作成していくので、「Create New Materials」を選択します。   インポートすると下記キャプチャのに表示されます。 インポートしてきたcannon.fbxをダブルクリックしてアセットの編集画面を開きます。 想定していたものより小さくインポートされていたので、右側の詳細画面から「Transform」の値を変更します。 今回は「Import Uniform Scale」の値を16に変更します。またデフォルトでの向きを変更するために「Import Rotation」のY軸を90に変更します。 この設定値はインポートする際の設定値になるので、画面上部にある「Reimport Base Mesh」を押下し、再度インポートします。 インポートが完了するとオブジェクトの大きさや向きが変わります。 次にマテリアルを変更します。 UEでプロジェクトを作成時、Starter Contentsを含める設定をしていると様々なマテリアルがデフォルトでインストールされているので、今回はそこからマテリアルを選んでいきます。 右側の詳細画面からMaterial Slotsを開きます。 セレクトボックスから「M_Metal_ Chrome 」を選択します。最後にこのアセット編集画面を保存することで、FBXファイルのデフォルト値を変更できます。 cannon_base.fbxも同様に編集します。大きさや向きはcannon.fbxと同じように変更しました。 マテリアルに関しては、「M_Metal_Burnished_Steel」を選択しました。 同様に保存を行うことで、Content Drawerの表示もマテリアルが適応された形に変化します。 Content Drawerで2種類のFBXファイルを選択し、View Portに ドラッグ&ドロップ することで、オブジェクトの大きさやマテリアルの見え方を確認できます。 以上で、FBXのインポートの説明を終わります。次は実際にインポートしたファイルにBlueprintを利用してアニメーションをつけていきます。 4. UE5でタイムラインを使用したアニメーションの作成 大砲の球を作成 まずは大砲のアニメーションを作成する前に、大砲から発射される球を作っていきます。 Content Drawerを開き、大砲の球用のActorのBlueprintを作成します。 今回は「BP_projectile」という名前で生成しました。 Blueprintを作成したら、まずは コンポーネント を追加します。「 Sphere Collision」という衝突判定を行う コンポーネント を作成します。 「DefaultSceneRoot」に「 Sphere Collision」を ドラッグ&ドロップ を行います。 これでこの コンポーネント が親 コンポーネント として設定されます。 次に「DefaultSceneRoot」に設定した「 Sphere Collision」の子 コンポーネント として「 Sphere 」を追加します。 大きさやマテリアルを右側の詳細画面で変更します。 Transformから大きさを変更します。 今回はMaterialで「M_Metal_Gold」を選択しました。 指定が終わると、下記キャプチャのように大きさとマテリアルが変更されます。 次に「Projectile Movement」という コンポーネント を追加します。これはこのBlueprint内のオブジェクトを発射物として一定方向に移動させ続けることができます。 最後にContent Drawerに戻り、作成したBlueprintをView Portに ドラッグ&ドロップ して配置してみます。 下記動画のように移動している鉄球ができれば大砲の球は完成です。 次にインポートしてきた大砲にアニメーションをつけていきます。 大砲から球を発射させる 大砲の球を作った時と同じように新規のBlueprintを作成します。 今回は「BP_cannon」という名前で生成しました。 大砲の球の時と同様に「 Sphere 」の コンポーネント を追加し、「DefaultSceneRoot」に ドラッグ&ドロップ を行い親 コンポーネント とします。 ここでは名前を「cannon_base」と変更しました。 次に右側の「Static Mesh」から、FBXでインポートした「cannon_base」を選択します。 次に、「cannon_base」の子 コンポーネント として「cannon_barrel」という名前で「 Sphere 」の コンポーネント を追加します。 同様に「Static Mesh」から、FBXでインポートした「cannon」を選択します。 ここで詳細画面の「Collision Presets」を「No Collision」に変更しておきます。 次に、このActorをSpawnさせる際の位置や向きを取得するために「Arrow」 コンポーネント を追加します。 名前を「Projectile Spawn Point」に変更し、「cannon_barrel」の子 コンポーネント として設定します。 View Port上に矢印が追加されるので、大砲の球を生成したい位置に矢印を移動します。 次に、大砲から球を出すBlueprintを作成します。 「BP_cannon」のEvent Graphを開きます。 「Event BeginPlay」ノードから「Delay」ノードを作成し、「Duration」を1秒に設定します。次に「SpawnActor Actor from Class」ノードを繋ぎ、Classの属性を「BP_Projectile」を選択します。 左側のComponentsから「Projectile Spawn Point」を ドラッグ&ドロップ してView Portに配置します。 さらにそこから「Get World Location / Rotation」の2つのノードを作成し、「SpawnActor Actor from Class」のノードに繋ぎます。 繰り返し球が出るように、「SpawnActor Actor from Class」から「Delay」につなげることで、球の発射されるBlueprintは完了です。 ここで一旦、作成したBlueprintをView Portに配置してみます。 この段階ではまだバレルに動きはありませんが、バレルの先端から球が発射されるようになりました。 大砲の発射時にアニメーションをつける(バレルのアニメーション) 次にBlueprintのタイムラインという機能を使って大砲の発射時にアニメーションをつけていきます。 「BP_cannon」のEvent Graph上で右クリックを行い「Timeline」を検索しノードを作成します。 名前を「Cannon fire Timeline」と変更しました。ダブルクリックをすることでタイムラインの編集に入れます。 次に左上の「+Track」を押下し「Add Float Track」を選択し、「Cannon Barrel location」というトラックを作成します。 出てきたトラック上で右クリックで「Add key」を選択し、表の中にkeyを3つ作りました。 keyの値は下記の通りにしています。 Time:0.0 / Value :0 Time:0.2 / Value :70 Time:0.6 / Value :0 Event Graphに戻ると「Cannon fire Timeline」のノードに「Cannon Barrel Location」というアウトプットピンが追加されているのがわかります。 ここの返り値として、秒数ごとに上で設定した Value の値が排出されます。 今回の例で言うと、このタイムラインが発火したタイミングでValue0が返却され、0.2秒後にValue70が返却される。 さらに発火から0.6秒後にはValue0が返却されるという式になります。 次に設定した Value の分だけ大砲のバレル部分を動かして、球が発射される時の挙動を作っていきます。 左下からCannon Barrel コンポーネント を配置し、「Set Relative Location」と繋ぎます。 タイムラインで排出される Value の値を、バレルのX軸に対して適応することで、秒数ごとにバレルが伸び縮みする仕組みが作成できます。 次に、タイムラインが発火したことを知らせる値を作成します。 再びタイムライン編集画面に戻り、「+Track」を押下し、「Add Event Track」を選択し「Cannon fired」と名前を変更します。 発火したことを伝えるだけでいいので、値は気にせず「Time:0.0 / Value :0」のkeyを作成します。 「Cannon Fired」というピンが作成されたのを確認します。 「Event BeginPlay」から続く流れに、今回作成したタイムラインのノードを含めるために「SpawnActor Actor from Class」の実行ピンを「Cannon fire timeline」のPlay from Startピンに接続します。次に「Cannon Fired」ピンをDelayノードに接続し直します。 これにより球を発射するたびにバレルが動くようになります。 View Portに配置するとこのように見えます。ついにバレルが動くようになりました。 大砲の発射時にアニメーションをつける(爆発のエフェクト) 最後に、大砲が球を発射するときに、爆発のエフェクトを追加します。 「Spawn Emitter at Location」というノードを使うことで、任意のEmitter(今回は爆発エフェクト)を任意の場所に出すことができます。 Starter Contentsに含まれている「P_Explosion」をセレクトボックスから選びます。 次に「Get Actor Location」を作成し、現在の大砲の位置をBlueprint上に引用し、「Spawn Emitter at Location」のLocationピンに繋ぎます。 爆発が出る位置を、バレルの先端に変更したいので、「LocationX」だけの値を90に変更しました。 最後に、作成した爆発エフェクトのノードを大砲の球が生成される直前のノードに追加することで、爆発エフェクトを付加できます。 View Portで確認すると以下の動画のように見えます。 以上が、 ZBrush で作成した3Dモデルから、UE5のタイムラインという機能を活用して、簡単なアニメーションを作成する手順のご紹介でした。 所感 今回は ZBrush で作成したシンプルなモデルを、UEのタイムラインを用いてアニメーションさせました。 タイムラインで出力する値を利用する方法は、簡単なアニメーションを作るにはとても便利な手段だと感じました。 例えばユーザーに気づいてもらいたいアイテムを定期的に光らせたりするアニメーションは ノンゲーム の領域でも利用価値がとてもありそうです。 次回以降は、より複雑なアニメーションを作成する手順にも挑戦してみようと思います。 現在ISIDは web3領域のグループ横断組織 を立ち上げ、Web3および メタバース 領域のR&Dを行っております(カテゴリー「3DCG」の記事は こちら )。 もし本領域にご興味のある方や、一緒にチャレンジしていきたい方は、ぜひお気軽にご連絡ください! 私たちと同じチームで働いてくれる仲間を、是非お待ちしております! ISID採用ページ(Web3/メタバース/AI) 参考 https://www.udemy.com/course/unrealblueprint/learn/lecture/13833864#overview https://mononoco.com/creative/zbrush/fbx-exportimport 執筆: @okazaki.wataru 、レビュー: @wakamoto.ryosuke ( Shodo で執筆されました )
アバター
こんにちは、ISID 金融ソリューション事業部の岡崎です。 今回は ZBrush で作成した3Dモデルを、UE5のタイムラインという機能を活用して、簡単なアニメーションを作成する手順をご紹介します。 はじめに UE5でオブジェクトにアニメーションをつける方法としてBlueprintのタイムラインを使用する方法があります。 タイムラインで設定した時間(タイミング)に、あらかじめ定義した値を出力する仕組みで、簡単なアニメーションが実装できます。 タイムラインを使用せずに、複雑なアニメーションを作成する手順も今後配信予定です。 今回はDCCツールの ZBrush を使用して、大砲の3Dオブジェクトを作成し、UE5内でその大砲を動かしたり弾を発射させるなどのアニメーションをつけていきます。 検証環境/ツール Unreal Engine5.1.1 ZBrush 2022.0.6 実装手順 ZBrush で大砲を作成 ZBrush で作成したオブジェクトをエクスポート UE5でFBXファイルをインポート UE5でタイムラインを使用したアニメーションの作成 1. ZBrush で大砲を作成 まず初めに ZBrush を使用して大砲の3Dオブジェクトを作成します。 今回詳しい作成方法は割愛しますが、 ZBrush の操作方法やオブジェクト作成手順につきましては、今後記事を配信予定です。 まずはバレル(銃身)部分を作成します。 今回は下記画像のようなバレルの形状で作成しています。 次にバレルを装着するベースの部分の作成を行います。 今回は本題ではないため割愛しますが、 ZBrush のローポリ編集を使用することで、下記画像のような無機質な形状も作成できます。 今回の実装のポイントとしては、バレルとベースの部分を2つの部品として、別々のオブジェクトで作成することです。 これにより、後述するタイムラインを利用したアニメーションに使用できます。 2. ZBrush で作成したオブジェクトをエクスポート ZBrush で作成したオブジェクトをUEで使用できるようにFBXに変換してエクスポートする必要があります。 ZBrush のZ プラグイン という機能を使用して、FBXエクスポートの手順を紹介します。 主にエクスポートで変更するのは下記部分になります。 出力する情報を選択 FBXのバージョンを選択 ファイルの形式を選択 メッシュを三角メッシュにするかどうか ポリペイントの出力をするかどうか エクスポート ① 出力する情報を選択 出力する情報を下記から選びます。 選択のみ : 選択したサブツール 表示のみ : 表示してあるサブツール すべて : 全てのサブツール 今回は、バレル部分とベースの部分で2種類のFBXを出力したかったので、 それぞれ個別に選択を行い「Select」を選びました。 ② FBXのバージョンを選択 「FBX2020」の部分をクリックすることで、バージョンが選択できます。 今回は「FBX2020」を選択しました。 ③ ファイルの形式を選択 ファイルの形式を下記から選びます。 bin ascii binの方がファイルサイズが小さく一般的なので、今回はこちらを選択しました。 ④ メッシュを三角メッシュにするかどうか メッシュを三角ポリゴンとしてエクスポートしたい場合はオンにします。 三角ポリゴンにすると、ポリゴン数が減りファイルが軽くなる代わりに、メッシュの再編集がしにくくなります。 今回は小さなファイルだったので、設定はオフのまま進めました。 ⑤ ポリペイントの出力をするかどうか ZBrush 上でもポリペイントという機能を使用することでオブジェクトに色をつけることができます。 サブツール内の筆のマークをオンにすることで、ポリペイントもFBXに含めることができます。 今回は、マテリアルや色の設定はUEで行うので、オフのまま進めます。 ⑥ エクスポート エクスポートボタンを押下し、モデルのエクスポートを行います。 3. UE5でFBXファイルをインポート 前工程で、バレルとベースの部分で2種類のFBXファイルを作成したので、 今回はそれらをUE5にインポートを行います。 今回は2種類のFBXファイル名を以下のように作成しています。 cannon.fbx cannon_base.fbx Content Drawerを開き、右クリックから「Import to Game」を押下し、前工程で作成した2つのFBXファイルをインポートします。 マテリアルに関してはUEで作成していくので、「Create New Materials」を選択します。   インポートすると下記キャプチャのに表示されます。 インポートしてきたcannon.fbxをダブルクリックしてアセットの編集画面を開きます。 想定していたものより小さくインポートされていたので、右側の詳細画面から「Transform」の値を変更します。 今回は「Import Uniform Scale」の値を16に変更します。またデフォルトでの向きを変更するために「Import Rotation」のY軸を90に変更します。 この設定値はインポートする際の設定値になるので、画面上部にある「Reimport Base Mesh」を押下し、再度インポートします。 インポートが完了するとオブジェクトの大きさや向きが変わります。 次にマテリアルを変更します。 UEでプロジェクトを作成時、Starter Contentsを含める設定をしていると様々なマテリアルがデフォルトでインストールされているので、今回はそこからマテリアルを選んでいきます。 右側の詳細画面からMaterial Slotsを開きます。 セレクトボックスから「M_Metal_ Chrome 」を選択します。最後にこのアセット編集画面を保存することで、FBXファイルのデフォルト値を変更できます。 cannon_base.fbxも同様に編集します。大きさや向きはcannon.fbxと同じように変更しました。 マテリアルに関しては、「M_Metal_Burnished_Steel」を選択しました。 同様に保存を行うことで、Content Drawerの表示もマテリアルが適応された形に変化します。 Content Drawerで2種類のFBXファイルを選択し、View Portに ドラッグ&ドロップ することで、オブジェクトの大きさやマテリアルの見え方を確認できます。 以上で、FBXのインポートの説明を終わります。次は実際にインポートしたファイルにBlueprintを利用してアニメーションをつけていきます。 4. UE5でタイムラインを使用したアニメーションの作成 大砲の球を作成 まずは大砲のアニメーションを作成する前に、大砲から発射される球を作っていきます。 Content Drawerを開き、大砲の球用のActorのBlueprintを作成します。 今回は「BP_projectile」という名前で生成しました。 Blueprintを作成したら、まずは コンポーネント を追加します。「 Sphere Collision」という衝突判定を行う コンポーネント を作成します。 「DefaultSceneRoot」に「 Sphere Collision」を ドラッグ&ドロップ を行います。 これでこの コンポーネント が親 コンポーネント として設定されます。 次に「DefaultSceneRoot」に設定した「 Sphere Collision」の子 コンポーネント として「 Sphere 」を追加します。 大きさやマテリアルを右側の詳細画面で変更します。 Transformから大きさを変更します。 今回はMaterialで「M_Metal_Gold」を選択しました。 指定が終わると、下記キャプチャのように大きさとマテリアルが変更されます。 次に「Projectile Movement」という コンポーネント を追加します。これはこのBlueprint内のオブジェクトを発射物として一定方向に移動させ続けることができます。 最後にContent Drawerに戻り、作成したBlueprintをView Portに ドラッグ&ドロップ して配置してみます。 下記動画のように移動している鉄球ができれば大砲の球は完成です。 次にインポートしてきた大砲にアニメーションをつけていきます。 大砲から球を発射させる 大砲の球を作った時と同じように新規のBlueprintを作成します。 今回は「BP_cannon」という名前で生成しました。 大砲の球の時と同様に「 Sphere 」の コンポーネント を追加し、「DefaultSceneRoot」に ドラッグ&ドロップ を行い親 コンポーネント とします。 ここでは名前を「cannon_base」と変更しました。 次に右側の「Static Mesh」から、FBXでインポートした「cannon_base」を選択します。 次に、「cannon_base」の子 コンポーネント として「cannon_barrel」という名前で「 Sphere 」の コンポーネント を追加します。 同様に「Static Mesh」から、FBXでインポートした「cannon」を選択します。 ここで詳細画面の「Collision Presets」を「No Collision」に変更しておきます。 次に、このActorをSpawnさせる際の位置や向きを取得するために「Arrow」 コンポーネント を追加します。 名前を「Projectile Spawn Point」に変更し、「cannon_barrel」の子 コンポーネント として設定します。 View Port上に矢印が追加されるので、大砲の球を生成したい位置に矢印を移動します。 次に、大砲から球を出すBlueprintを作成します。 「BP_cannon」のEvent Graphを開きます。 「Event BeginPlay」ノードから「Delay」ノードを作成し、「Duration」を1秒に設定します。次に「SpawnActor Actor from Class」ノードを繋ぎ、Classの属性を「BP_Projectile」を選択します。 左側のComponentsから「Projectile Spawn Point」を ドラッグ&ドロップ してView Portに配置します。 さらにそこから「Get World Location / Rotation」の2つのノードを作成し、「SpawnActor Actor from Class」のノードに繋ぎます。 繰り返し球が出るように、「SpawnActor Actor from Class」から「Delay」につなげることで、球の発射されるBlueprintは完了です。 ここで一旦、作成したBlueprintをView Portに配置してみます。 この段階ではまだバレルに動きはありませんが、バレルの先端から球が発射されるようになりました。 大砲の発射時にアニメーションをつける(バレルのアニメーション) 次にBlueprintのタイムラインという機能を使って大砲の発射時にアニメーションをつけていきます。 「BP_cannon」のEvent Graph上で右クリックを行い「Timeline」を検索しノードを作成します。 名前を「Cannon fire Timeline」と変更しました。ダブルクリックをすることでタイムラインの編集に入れます。 次に左上の「+Track」を押下し「Add Float Track」を選択し、「Cannon Barrel location」というトラックを作成します。 出てきたトラック上で右クリックで「Add key」を選択し、表の中にkeyを3つ作りました。 keyの値は下記の通りにしています。 Time:0.0 / Value :0 Time:0.2 / Value :70 Time:0.6 / Value :0 Event Graphに戻ると「Cannon fire Timeline」のノードに「Cannon Barrel Location」というアウトプットピンが追加されているのがわかります。 ここの返り値として、秒数ごとに上で設定した Value の値が排出されます。 今回の例で言うと、このタイムラインが発火したタイミングでValue0が返却され、0.2秒後にValue70が返却される。 さらに発火から0.6秒後にはValue0が返却されるという式になります。 次に設定した Value の分だけ大砲のバレル部分を動かして、球が発射される時の挙動を作っていきます。 左下からCannon Barrel コンポーネント を配置し、「Set Relative Location」と繋ぎます。 タイムラインで排出される Value の値を、バレルのX軸に対して適応することで、秒数ごとにバレルが伸び縮みする仕組みが作成できます。 次に、タイムラインが発火したことを知らせる値を作成します。 再びタイムライン編集画面に戻り、「+Track」を押下し、「Add Event Track」を選択し「Cannon fired」と名前を変更します。 発火したことを伝えるだけでいいので、値は気にせず「Time:0.0 / Value :0」のkeyを作成します。 「Cannon Fired」というピンが作成されたのを確認します。 「Event BeginPlay」から続く流れに、今回作成したタイムラインのノードを含めるために「SpawnActor Actor from Class」の実行ピンを「Cannon fire timeline」のPlay from Startピンに接続します。次に「Cannon Fired」ピンをDelayノードに接続し直します。 これにより球を発射するたびにバレルが動くようになります。 View Portに配置するとこのように見えます。ついにバレルが動くようになりました。 大砲の発射時にアニメーションをつける(爆発のエフェクト) 最後に、大砲が球を発射するときに、爆発のエフェクトを追加します。 「Spawn Emitter at Location」というノードを使うことで、任意のEmitter(今回は爆発エフェクト)を任意の場所に出すことができます。 Starter Contentsに含まれている「P_Explosion」をセレクトボックスから選びます。 次に「Get Actor Location」を作成し、現在の大砲の位置をBlueprint上に引用し、「Spawn Emitter at Location」のLocationピンに繋ぎます。 爆発が出る位置を、バレルの先端に変更したいので、「LocationX」だけの値を90に変更しました。 最後に、作成した爆発エフェクトのノードを大砲の球が生成される直前のノードに追加することで、爆発エフェクトを付加できます。 View Portで確認すると以下の動画のように見えます。 以上が、 ZBrush で作成した3Dモデルから、UE5のタイムラインという機能を活用して、簡単なアニメーションを作成する手順のご紹介でした。 所感 今回は ZBrush で作成したシンプルなモデルを、UEのタイムラインを用いてアニメーションさせました。 タイムラインで出力する値を利用する方法は、簡単なアニメーションを作るにはとても便利な手段だと感じました。 例えばユーザーに気づいてもらいたいアイテムを定期的に光らせたりするアニメーションは ノンゲーム の領域でも利用価値がとてもありそうです。 次回以降は、より複雑なアニメーションを作成する手順にも挑戦してみようと思います。 現在ISIDは web3領域のグループ横断組織 を立ち上げ、Web3および メタバース 領域のR&Dを行っております(カテゴリー「3DCG」の記事は こちら )。 もし本領域にご興味のある方や、一緒にチャレンジしていきたい方は、ぜひお気軽にご連絡ください! 私たちと同じチームで働いてくれる仲間を、是非お待ちしております! ISID採用ページ(Web3/メタバース/AI) 参考 https://www.udemy.com/course/unrealblueprint/learn/lecture/13833864#overview https://mononoco.com/creative/zbrush/fbx-exportimport 執筆: @okazaki.wataru 、レビュー: @wakamoto.ryosuke ( Shodo で執筆されました )
アバター
こんにちは、X イノベーション 本部 ソフトウェアデザインセンター セキュリティグループの福山です。 好きな AWS サービスはSecurity HubとGuardDutyです。 はじめに 2023年4月10日にGuardDutyの新しい検出タイプが公表されましたので紹介します。 https://aws.amazon.com/jp/about-aws/whats-new/2023/04/amazon-guardduty-threat-detections-dns-traffic/ 追加された3つの検出タイプは、すべてDefense Evasionに関連しています。 Defense Evasionとは「防衛回避」のことで、セキュリティソフトに検知されないために攻撃者が攻撃を隠蔽することです。 今回、外部 DNS プロバイダーを使用するか、 HTTPS (DoH) または TLS (DoT) 経由で DNS トラフィック を送信するなどの手法を使用した防衛回避について検出できるようになりました。 各検出タイプについて、以下で説明します。 新しく追加された検出タイプ DefenseEvasion:EC2/UnusualDNSResolver 重要度:Medium(中) 使用可能なリージョン:GuardDutyがサポートされている全リージョン 検出ロジック:通常、EC2 インスタンス は、正当な DNS サーバーからの応答を受信することが期待されます。 この検出は、EC2 インスタンス が通常の DNS トラフィック パターンを学習し、長期間利用していないパブリック DNS リ ゾル バに対する DNS 通信を警告します。 補足:本機能が追加される前のGuardDutyには、デフォルトの AWS DNS リ ゾル バを使用して問題を見つけるといった制限がありました。 なので、例えばデフォルトの DNS 設定を Google DNS (8.8.8.8または8.8.4.4)とすると、攻撃は検出されずに任意の ドメイン にクエリを実行できてしまいます。 前提として、安易にデフォルトの AWS DNS 設定を外部 DNS に変えることは避けるべきですが、今回の機能追加によって検出できるようになりました。 参考: https://docs.aws.amazon.com/guardduty/latest/ug/guardduty_finding-types-ec2.html#defenseevasion-ec2-unusualdnsresolver DefenseEvasion:EC2/UnusualDoHActivity 重要度:Medium(中) 使用可能なリージョン:一部リージョン ※ を除くGuardDutyがサポートされている全リージョン 検出ロジック:この検出は、EC2 インスタンス の通常の DNS トラフィック パターンを学習し、長期間利用していないパブリックDoHサーバへのDoH通信を警告します。 補足:DoH( DNS over HTTPS )とは、 HTTPS を用いて DNS 通信を行う技術のことです。 従来の DNS は UDP による平文でしたが、これを HTTPS の技術を使用して暗号化します。 攻撃者は、DoHを使用して通常の DNS トラフィック を脅威検知から回避することがあります。 参考: https://docs.aws.amazon.com/guardduty/latest/ug/guardduty_finding-types-ec2.html#defenseevasion-ec2-unsualdohactivity DefenseEvasion:EC2/UnusualDoTActivity 重要度:Medium(中) 使用可能なリージョン:一部リージョン ※ を除くGuardDutyがサポートされている全リージョン 検出ロジック:この検出は、EC2 インスタンス の通常の DNS トラフィック パターンを学習し、長期間利用していないパブリックDoTサーバへのDoT通信を警告します。 補足:DoT( DNS over TLS )とは、 DNS 通信を TLS レベルで暗号化する技術のことです。 攻撃者は、DoTを使用して、通常の DNS トラフィック を脅威検知から回避することがあります。 参考: https://docs.aws.amazon.com/guardduty/latest/ug/guardduty_finding-types-ec2.html#defenseevasion-ec2-unusualdotactivity ※ 一部リージョン: AWS アジアパシフィック(大阪), AWS アジアパシフィック( ジャカルタ ), AWS アジアパシフィック(ソウル), 中国(北京、Sinnetが運営), 中国( 寧夏 、NWCDが運営) 所感 上記3タイプはデータソースとして VPC フローログを利用しているということで、今まで検出できなかったパターンを補完するアップデートとなりました。 DoHとDoTの利用はまだ普及していないため、「DefenseEvasion:EC2/UnusualDoHActivity」が検出される機会が増えそうです。 なお、直近で通信履歴がないものに対して検知されるため、誤検知も少なからず発生する可能性はあります。 検出されたらターゲットのIPを確認し、想定された正常な動きかどうか慎重に見極めた方が良さそうです。 私たちは同じチームで働いてくれる仲間を大募集しています!たくさんのご応募をお待ちしています。 セキュリティエンジニア(セキュリティ設計) 執筆: @fuku.dancho 、レビュー: @yamashita.tsuyoshi ( Shodo で執筆されました )
アバター
こんにちは、X イノベーション 本部 ソフトウェアデザインセンター セキュリティグループの福山です。 好きな AWS サービスはSecurity HubとGuardDutyです。 はじめに 2023年4月10日にGuardDutyの新しい検出タイプが公表されましたので紹介します。 https://aws.amazon.com/jp/about-aws/whats-new/2023/04/amazon-guardduty-threat-detections-dns-traffic/ 追加された3つの検出タイプは、すべてDefense Evasionに関連しています。 Defense Evasionとは「防衛回避」のことで、セキュリティソフトに検知されないために攻撃者が攻撃を隠蔽することです。 今回、外部 DNS プロバイダーを使用するか、 HTTPS (DoH) または TLS (DoT) 経由で DNS トラフィック を送信するなどの手法を使用した防衛回避について検出できるようになりました。 各検出タイプについて、以下で説明します。 新しく追加された検出タイプ DefenseEvasion:EC2/UnusualDNSResolver 重要度:Medium(中) 使用可能なリージョン:GuardDutyがサポートされている全リージョン 検出ロジック:通常、EC2 インスタンス は、正当な DNS サーバーからの応答を受信することが期待されます。 この検出は、EC2 インスタンス が通常の DNS トラフィック パターンを学習し、長期間利用していないパブリック DNS リ ゾル バに対する DNS 通信を警告します。 補足:本機能が追加される前のGuardDutyには、デフォルトの AWS DNS リ ゾル バを使用して問題を見つけるといった制限がありました。 なので、例えばデフォルトの DNS 設定を Google DNS (8.8.8.8または8.8.4.4)とすると、攻撃は検出されずに任意の ドメイン にクエリを実行できてしまいます。 前提として、安易にデフォルトの AWS DNS 設定を外部 DNS に変えることは避けるべきですが、今回の機能追加によって検出できるようになりました。 参考: https://docs.aws.amazon.com/guardduty/latest/ug/guardduty_finding-types-ec2.html#defenseevasion-ec2-unusualdnsresolver DefenseEvasion:EC2/UnusualDoHActivity 重要度:Medium(中) 使用可能なリージョン:一部リージョン ※ を除くGuardDutyがサポートされている全リージョン 検出ロジック:この検出は、EC2 インスタンス の通常の DNS トラフィック パターンを学習し、長期間利用していないパブリックDoHサーバへのDoH通信を警告します。 補足:DoH( DNS over HTTPS )とは、 HTTPS を用いて DNS 通信を行う技術のことです。 従来の DNS は UDP による平文でしたが、これを HTTPS の技術を使用して暗号化します。 攻撃者は、DoHを使用して通常の DNS トラフィック を脅威検知から回避することがあります。 参考: https://docs.aws.amazon.com/guardduty/latest/ug/guardduty_finding-types-ec2.html#defenseevasion-ec2-unsualdohactivity DefenseEvasion:EC2/UnusualDoTActivity 重要度:Medium(中) 使用可能なリージョン:一部リージョン ※ を除くGuardDutyがサポートされている全リージョン 検出ロジック:この検出は、EC2 インスタンス の通常の DNS トラフィック パターンを学習し、長期間利用していないパブリックDoTサーバへのDoT通信を警告します。 補足:DoT( DNS over TLS )とは、 DNS 通信を TLS レベルで暗号化する技術のことです。 攻撃者は、DoTを使用して、通常の DNS トラフィック を脅威検知から回避することがあります。 参考: https://docs.aws.amazon.com/guardduty/latest/ug/guardduty_finding-types-ec2.html#defenseevasion-ec2-unusualdotactivity ※ 一部リージョン: AWS アジアパシフィック(大阪), AWS アジアパシフィック( ジャカルタ ), AWS アジアパシフィック(ソウル), 中国(北京、Sinnetが運営), 中国( 寧夏 、NWCDが運営) 所感 上記3タイプはデータソースとして VPC フローログを利用しているということで、今まで検出できなかったパターンを補完するアップデートとなりました。 DoHとDoTの利用はまだ普及していないため、「DefenseEvasion:EC2/UnusualDoHActivity」が検出される機会が増えそうです。 なお、直近で通信履歴がないものに対して検知されるため、誤検知も少なからず発生する可能性はあります。 検出されたらターゲットのIPを確認し、想定された正常な動きかどうか慎重に見極めた方が良さそうです。 私たちは同じチームで働いてくれる仲間を大募集しています!たくさんのご応募をお待ちしています。 セキュリティエンジニア(セキュリティ設計) 執筆: @fuku.dancho 、レビュー: @yamashita.tsuyoshi ( Shodo で執筆されました )
アバター
ISID X(クロス) イノベーション 本部 の飯田です。 ブラックボックス 最適化を使って、なかなか 言語化 しにくい自分の思考パターン(好みの色)を表現する取り組みをしてみました。 ブラックボックス 最適化とOptuna ブラックボックス 最適化とは「ある関数の出力を最大化 (または最小化) するような入力を勾配情報などを使わずに探索する問題」と言われます。 参考 ある入力に対して、その出力結果だけしか取得することが出来ず、それ以外の情報が与えられないような状況で、結果を最適化(最小化・最大化)することを目的としています。 Optuna は株式会社Preferred Networksが開発しているハイパーパラメータの最適化を自動化するためのソフトウェア フレームワーク です。 optuna.org TPE (Tree-structured Parzen Estimator) 等の最適化 アルゴリズム が実装されています。 ライブラリの使い方も非常に簡単で、使いやすいと思っています。 つくったもの FastAPIで簡単な画面を作って、Optunaと組み合わせて、自分の好みの色を探してくれるWebアプリを作ってみました。 「色の好み」を ブラックボックス 関数と見立て、好みの値が最大になるような最適化をしていくイメージです。 内的な感覚(例:色の好み)の関数と見立てるという意味では、心理物理学という学問領域があります。 心理物理学は、外的な刺激と内的な感覚の対応関係を測定し、また 定量 的な計測をしようとする学問です。 「色の好み」を ブラックボックス 最適化で探る取り組みは、心理物理学に近しいものがあるかも知れません Web画面は下記のようなイメージです(今回、デザイン性は一切考慮しておりません笑) 結果 134試行を行った結果のベストパラメータは{'r': 59, 'g': 112, 'b': 160}でした。 実際に描画すると、こちらの色です。 自分の気持ちとしては、まぁまぁ合っている感じがしています。 最適化が進む様子はこんな様子でした。 コード 流れとしては、ざっくり下記のような流れです study.ask() で、過去の結果に基づいて、効率的に探索できる色を決定 FastAPI経由でHTML上で、その色を画面表示 提示された色の好みに対して点数を入力し、 API を呼びだす regist_trial(r,g,b,v)で、RGBと評価点を登録 メイン部分のコードは下記のような形です。 sampler = optuna.samplers.TPESampler(multivariate=True, n_startup_trials=10) study = optuna.create_study(direction='maximize', sampler=sampler) def regist_trial(r,g,b,v): trial = optuna.trial.create_trial( params={"r": int(r),"g": int(g),"b": int(b)}, distributions=study_search_space, value=int(v) ) study.add_trial(trial) def sugest_next_color(r,g,b,v): regist_trial(r,g,b,v) trial = study.ask() next_r = trial.suggest_int("r", 0, 255) next_g = trial.suggest_int("g",0, 255) next_b = trial.suggest_int("b",0, 255) return (next_r,next_g,next_b) 最後に Optunaは 機械学習 のハイパーパラメータ調整がまず浮かんで来ると思いますが、 ブラックボックス 最適化はいろいろな場面で有効活用できそうです。 料理や化学実験のレシピ・材料配合の最適化 システムのパラメータ調整 官能評価 などにも使えるんじゃないかと思います。 最適化が進む様子のアニメーションは見ていて気持ちいいですね。 最後に、私たちは一緒に働いてくれる仲間を募集しています! デジタル技術を社会課題解決につなげるようなプロジェクトを推進していきたいプロジェクトマネージャーやエンジニアを募集しています。 ぜひご応募ください! ソリューションアーキテクト スマートシティ導入コンサルタント/スマートシティ戦略コンサルタント 執筆: @iida.michitaka ( Shodo で執筆されました )
アバター
ISID X(クロス) イノベーション 本部 の三浦です。 筆者の関わっている案件では、コンテナ利用、 AWS Fargate利用を進めております。 AWS Fargateのお手軽さは非常に重宝しております。 しかし、そこで問題になってくるのが、管理作業(例: SQL 実行、EFSへのファイル配置)をどうするかです。 アプリケーション本体をせっかく AWS Fargateでやっているので、管理作業もできるだけサーバーレスでやりたいですよね? で、以前の記事では、『業務用の端末⇒ AWS _Fargate(ポート フォワ ード)⇒RDS』といった内容を書きました。 AWS FargateからSSMでRDSに接続 しかし、これには問題点がありまして、業務端末からのDBへの直接接続はセキュリ ティー ポリシー、データ持ち出しの観点で推奨されない場合があります。 そこで他のパターンとしては、『業務用の端末⇒ECS Exec(コンテナにログイン)⇒RDS』といった手段があるのですが、これには下記のような課題があります。 コンテナ内に本来不要なDB接続用のライブラリのインストールが必要 巨大な結果セットを返すような不適切な SQL 実行時にECSタスクのリソース(例:メモリ)を使用してしまいサービスによくない影響が出る コンテナ内に入ってオペレーションするのは、セキュリ ティー 的に望ましくない場合がある コンテナに本来不要なオペレーション用の権限をつけなければならない場合がある(例:データ授受用のs3へのアクセス権) ということで、業務用端末からDBへ直接接続せず、下記のようにセキュアな AWS CloudShellから下記のような経路で接続できないか試します。 『業務用の端末⇒ AWS CloudShell⇒ AWS Fargate(ポート フォワ ード)⇒RDS』 目次 目次 接続失敗編 接続成功編 接続失敗編 下記のように普通にフロントでstart-sessionするとstart-sessionのプロセスがフロントに残ることでそのままでは使えません。 ローカルならば他のターミナルを開いてそちらでDB接続のコマンドを実行すればいいのですが、 AWS CloudShellではそれができません。 aws ssm start-session \ --target ecs:${clusterID}_${taskid}_${CONTAINER_ID} \ --document-name AWS-StartPortForwardingSessionToRemoteHost \ --parameters "{\"host\":[\"XXXXXXXXXXXXXXX.ap-northeast-1.rds.amazonaws.com\"],\"portNumber\":[\"5432\"], \"localPortNumber\":[\"5432\"]}" 接続成功編 しかし、下記のようにstart-sessionをバックグランド実行することにより AWS CloudShellからポート フォワ ードして、RDSに接続可能です。 (aws ssm start-session \ --target ecs:${clusterID}_${taskid}_${CONTAINER_ID} \ --document-name AWS-StartPortForwardingSessionToRemoteHost \ --parameters "{\"host\":[\"xxxxxxxxxx.ap-northeast-1.rds.amazonaws.com\"],\"portNumber\":[\"5432\"], \"localPortNumber\":[\"5432\"]}" \ \ )& \ export PGPASSWORD=xxxxxxxxx psql -U userName -p 5432 -h localhost 終了処理は下記の「ps + kill」で可能です。 ということで、ちょっとした工夫で AWS CloudShellからRDSにポート フォワ ードで接続できるという内容でした。 執筆: @miura.toshihiko 、レビュー: 寺山 輝 (@terayama.akira) ( Shodo で執筆されました )
アバター
ISID X(クロス) イノベーション 本部 の三浦です。 筆者の関わっている案件では、コンテナ利用、 AWS Fargate利用を進めております。 AWS Fargateのお手軽さは非常に重宝しております。 しかし、そこで問題になってくるのが、管理作業(例: SQL 実行、EFSへのファイル配置)をどうするかです。 アプリケーション本体をせっかく AWS Fargateでやっているので、管理作業もできるだけサーバーレスでやりたいですよね? で、以前の記事では、『業務用の端末⇒ AWS _Fargate(ポート フォワ ード)⇒RDS』といった内容を書きました。 AWS FargateからSSMでRDSに接続 しかし、これには問題点がありまして、業務端末からのDBへの直接接続はセキュリ ティー ポリシー、データ持ち出しの観点で推奨されない場合があります。 そこで他のパターンとしては、『業務用の端末⇒ECS Exec(コンテナにログイン)⇒RDS』といった手段があるのですが、これには下記のような課題があります。 コンテナ内に本来不要なDB接続用のライブラリのインストールが必要 巨大な結果セットを返すような不適切な SQL 実行時にECSタスクのリソース(例:メモリ)を使用してしまいサービスによくない影響が出る コンテナ内に入ってオペレーションするのは、セキュリ ティー 的に望ましくない場合がある コンテナに本来不要なオペレーション用の権限をつけなければならない場合がある(例:データ授受用のs3へのアクセス権) ということで、業務用端末からDBへ直接接続せず、下記のようにセキュアな AWS CloudShellから下記のような経路で接続できないか試します。 『業務用の端末⇒ AWS CloudShell⇒ AWS Fargate(ポート フォワ ード)⇒RDS』 目次 目次 接続失敗編 接続成功編 接続失敗編 下記のように普通にフロントでstart-sessionするとstart-sessionのプロセスがフロントに残ることでそのままでは使えません。 ローカルならば他のターミナルを開いてそちらでDB接続のコマンドを実行すればいいのですが、 AWS CloudShellではそれができません。 aws ssm start-session \ --target ecs:${clusterID}_${taskid}_${CONTAINER_ID} \ --document-name AWS-StartPortForwardingSessionToRemoteHost \ --parameters "{\"host\":[\"XXXXXXXXXXXXXXX.ap-northeast-1.rds.amazonaws.com\"],\"portNumber\":[\"5432\"], \"localPortNumber\":[\"5432\"]}" 接続成功編 しかし、下記のようにstart-sessionをバックグランド実行することにより AWS CloudShellからポート フォワ ードして、RDSに接続可能です。 (aws ssm start-session \ --target ecs:${clusterID}_${taskid}_${CONTAINER_ID} \ --document-name AWS-StartPortForwardingSessionToRemoteHost \ --parameters "{\"host\":[\"xxxxxxxxxx.ap-northeast-1.rds.amazonaws.com\"],\"portNumber\":[\"5432\"], \"localPortNumber\":[\"5432\"]}" \ \ )& \ export PGPASSWORD=xxxxxxxxx psql -U userName -p 5432 -h localhost 終了処理は下記の「ps + kill」で可能です。 ということで、ちょっとした工夫で AWS CloudShellからRDSにポート フォワ ードで接続できるという内容でした。 執筆: @miura.toshihiko 、レビュー: 寺山 輝 (@terayama.akira) ( Shodo で執筆されました )
アバター
ISID X(クロス) イノベーション 本部 の飯田です。 ブラックボックス 最適化を使って、なかなか 言語化 しにくい自分の思考パターン(好みの色)を表現する取り組みをしてみました。 ブラックボックス 最適化とOptuna ブラックボックス 最適化とは「ある関数の出力を最大化 (または最小化) するような入力を勾配情報などを使わずに探索する問題」と言われます。 参考 ある入力に対して、その出力結果だけしか取得することが出来ず、それ以外の情報が与えられないような状況で、結果を最適化(最小化・最大化)することを目的としています。 Optuna は株式会社Preferred Networksが開発しているハイパーパラメータの最適化を自動化するためのソフトウェア フレームワーク です。 optuna.org TPE (Tree-structured Parzen Estimator) 等の最適化 アルゴリズム が実装されています。 ライブラリの使い方も非常に簡単で、使いやすいと思っています。 つくったもの FastAPIで簡単な画面を作って、Optunaと組み合わせて、自分の好みの色を探してくれるWebアプリを作ってみました。 「色の好み」を ブラックボックス 関数と見立て、好みの値が最大になるような最適化をしていくイメージです。 内的な感覚(例:色の好み)の関数と見立てるという意味では、心理物理学という学問領域があります。 心理物理学は、外的な刺激と内的な感覚の対応関係を測定し、また 定量 的な計測をしようとする学問です。 「色の好み」を ブラックボックス 最適化で探る取り組みは、心理物理学に近しいものがあるかも知れません Web画面は下記のようなイメージです(今回、デザイン性は一切考慮しておりません笑) 結果 134試行を行った結果のベストパラメータは{'r': 59, 'g': 112, 'b': 160}でした。 実際に描画すると、こちらの色です。 自分の気持ちとしては、まぁまぁ合っている感じがしています。 最適化が進む様子はこんな様子でした。 コード 流れとしては、ざっくり下記のような流れです study.ask() で、過去の結果に基づいて、効率的に探索できる色を決定 FastAPI経由でHTML上で、その色を画面表示 提示された色の好みに対して点数を入力し、 API を呼びだす regist_trial(r,g,b,v)で、RGBと評価点を登録 メイン部分のコードは下記のような形です。 sampler = optuna.samplers.TPESampler(multivariate=True, n_startup_trials=10) study = optuna.create_study(direction='maximize', sampler=sampler) def regist_trial(r,g,b,v): trial = optuna.trial.create_trial( params={"r": int(r),"g": int(g),"b": int(b)}, distributions=study_search_space, value=int(v) ) study.add_trial(trial) def sugest_next_color(r,g,b,v): regist_trial(r,g,b,v) trial = study.ask() next_r = trial.suggest_int("r", 0, 255) next_g = trial.suggest_int("g",0, 255) next_b = trial.suggest_int("b",0, 255) return (next_r,next_g,next_b) 最後に Optunaは 機械学習 のハイパーパラメータ調整がまず浮かんで来ると思いますが、 ブラックボックス 最適化はいろいろな場面で有効活用できそうです。 料理や化学実験のレシピ・材料配合の最適化 システムのパラメータ調整 官能評価 などにも使えるんじゃないかと思います。 最適化が進む様子のアニメーションは見ていて気持ちいいですね。 最後に、私たちは一緒に働いてくれる仲間を募集しています! デジタル技術を社会課題解決につなげるようなプロジェクトを推進していきたいプロジェクトマネージャーやエンジニアを募集しています。 ぜひご応募ください! ソリューションアーキテクト スマートシティ導入コンサルタント/スマートシティ戦略コンサルタント 執筆: @iida.michitaka ( Shodo で執筆されました )
アバター
こんにちは。ISID 金融ソリューション事業部の若本です。 生成系の画像/ 自然言語処理 AIが盛り上がりを見せる中、既存ソフトウェアへの組み込みや連携も活発に行われるようになってきました。 3DCG制作アプリケーションである Blender でも、アドオンを通じて Blender 内でAIが使いやすくなりつつあります。先日、diffusionが使用できるアドオンである「Stability for Blender 」がリリースされたのもその一例です。 今回はStability for Blender を用いてできることと、その手順をまとめます。 Stability for Blender について Stable Diffusionの開発を行っているStability AI社が提供する、 Blender 用のアドオン※です。 筆者は実施時点で最新であったv0.0.15をインストールして実施しました。v0.0.15時点の機能としては下記の3つがあります。 文章から画像生成 文章からテクスチャを生成する 画像から画像生成 Renderingから画像を生成する テクスチャからテクスチャを生成する 画像からアニメーション生成 Renderingからアニメーションを生成 DreamStudio (β版)に登録し、 API keyを発行する必要があります。 DreamStudioでは登録時に100creditほど使用可能になりますが、画像を生成するたびにcreditを消費していきますのでご注意ください。なお、 API keyとcreditともにDreamStudioのMy Accountから確認可能です。 ※Blender3.0以降がサポートされています。 Stability for blender を使ってみる stability for blender で出力するまでの一連の流れを説明します( Blender そのもののインストールは割愛します)。 公式サイト を参考に実施しました。 事前準備 リリースページ からアドオンのzipファイルをダウンロードします。前述の通り、筆者はv0.0.15をインストールしています。 blender を開き、メニューの「Edit>preferences>add-ons」を開きます。 右上部の「Install...」ボタンを押すとフォルダ エクスプローラ ーが開くので、先ほどダウンロードしたzipファイルを選択します。選択後、以下のような画面になっていればOKです。 画面に「Stability」のタブが表示されていればインストール完了となります。 DreamStudio (β版)に登録し、 API keyを取得します。 「Stability」のタブに API keyを入力すると以下のような画面になります。これで実施する準備が整いました。 文章からテクスチャを生成する Blender 上で与えた文章から画像を生成してみます。 まず、「init Type」の「Text Prompt Only」を選択します。 次に、promptの入力ボックスに欲しい画像を英語で指示します。今回は最初からデフォルトで設定されている下記promptをそのまま使用しました。 A dream of a distant galaxy 後は「Dream」を押下するだけで実行されます。 消費creditも併せて表示されるのは親切ですね。 10秒足らずで画像が生成されました。非常にお手軽です。 もちろん、生成した画像はテクスチャとしてそのまま使用できます。 Renderingから画像を生成する 画像から画像を生成する例として、Renderingの結果から画像を生成してみます。 まずは「init Type」の「Texture」を選択します。 メニューから「Render>Render image」を押下すると、新規ウィンドウでRenderingが実行されます。 カメラを設定している以前の記事のプロジェクトを使用しました。 Rendering画面からStabilityを実行します。 promptは以下としました。 An empty park with snow, concept art, matte painting, HQ, 4k 前述の通り、「Dream」を押下することで画像が生成されます。 Blender 上で見える景色をベースに画像を生成することができました。 ここで、「Stability」タブの「input Options」から各種パラメータを設定できます。 パラメータ名 概要 default Init Strength 入力画像にどれだけ準拠するかを設定します。 0.5 Prompt Strength プロンプトにどれだけ準拠するかを設定します。 7.5 Set seed Stable Diffusionのseedを設定します。seedを変えると異なる画像が出力されます。 555555 Steps Stable DiffusionのStep数を設定します。 50 Engine 使用するStable Diffusionモデルを設定します。(あくまで推測ですが、GENERATE_512_2_1は解像度512pixelで Stable diffusion ver2.1 を表していると思われます) GENERATE_512_2_1 Sampler Stable DiffusionのSampler(ノイズ除去 アルゴリズム )を設定します。 K_DPMPP_2S_ANCESTRAL 主に出力の品質や、入力のバランス(文章と画像の情報どちらを優先するか)に関するパラメータが設定できます。ここでは、「Init strength」を変更してみます。 「Init strength」を変化させると以下のようになります。 「Init strength」を大きくするほど、Renderingされた情報に準拠するような画像の生成がされました。 一方で、小さくするほどpromptの「An empty park with snow」が重視され、元々置いていたオブジェクトは別のものに解釈される/消えることが確認できました。 ※今回、Renderingからアニメーション生成の手順も実施しましたが、数時間経過しても処理が進まず断念しました。 おわりに 今回はStability for Blender の利用手順とできることを調査しました。 執筆時点でv0.0.16も公開されており、「高解像度化」が新たに機能として追加されるなど、活発に開発が続けられています。今後より使いやすく、かつ機能を拡充していくことでクリエイター支援ツールとして活用されることが期待されます。 AIモデルの3DCGソフトウェアへの組み込みは今後も様々な形で発展していくと思いますので、今後もキャッチアップしていきたいと思います。 ここまでお読みいただきありがとうございました。 現在ISIDは web3領域のグループ横断組織 を立ち上げ、Web3および メタバース 領域のR&Dを行っております(カテゴリー「3DCG」の記事は こちら )。 もし本領域にご興味のある方や、一緒にチャレンジしていきたい方は、ぜひお気軽にご連絡ください! 私たちと同じチームで働いてくれる仲間を、是非お待ちしております! ISID採用ページ 執筆: @wakamoto.ryosuke 、レビュー: @yamada.y ( Shodo で執筆されました )
アバター
こんにちは。ISID 金融ソリューション事業部の若本です。 生成系の画像/ 自然言語処理 AIが盛り上がりを見せる中、既存ソフトウェアへの組み込みや連携も活発に行われるようになってきました。 3DCG制作アプリケーションである Blender でも、アドオンを通じて Blender 内でAIが使いやすくなりつつあります。先日、diffusionが使用できるアドオンである「Stability for Blender 」がリリースされたのもその一例です。 今回はStability for Blender を用いてできることと、その手順をまとめます。 Stability for Blender について Stable Diffusionの開発を行っているStability AI社が提供する、 Blender 用のアドオン※です。 筆者は実施時点で最新であったv0.0.15をインストールして実施しました。v0.0.15時点の機能としては下記の3つがあります。 文章から画像生成 文章からテクスチャを生成する 画像から画像生成 Renderingから画像を生成する テクスチャからテクスチャを生成する 画像からアニメーション生成 Renderingからアニメーションを生成 DreamStudio (β版)に登録し、 API keyを発行する必要があります。 DreamStudioでは登録時に100creditほど使用可能になりますが、画像を生成するたびにcreditを消費していきますのでご注意ください。なお、 API keyとcreditともにDreamStudioのMy Accountから確認可能です。 ※Blender3.0以降がサポートされています。 Stability for blender を使ってみる stability for blender で出力するまでの一連の流れを説明します( Blender そのもののインストールは割愛します)。 公式サイト を参考に実施しました。 事前準備 リリースページ からアドオンのzipファイルをダウンロードします。前述の通り、筆者はv0.0.15をインストールしています。 blender を開き、メニューの「Edit>preferences>add-ons」を開きます。 右上部の「Install...」ボタンを押すとフォルダ エクスプローラ ーが開くので、先ほどダウンロードしたzipファイルを選択します。選択後、以下のような画面になっていればOKです。 画面に「Stability」のタブが表示されていればインストール完了となります。 DreamStudio (β版)に登録し、 API keyを取得します。 「Stability」のタブに API keyを入力すると以下のような画面になります。これで実施する準備が整いました。 文章からテクスチャを生成する Blender 上で与えた文章から画像を生成してみます。 まず、「init Type」の「Text Prompt Only」を選択します。 次に、promptの入力ボックスに欲しい画像を英語で指示します。今回は最初からデフォルトで設定されている下記promptをそのまま使用しました。 A dream of a distant galaxy 後は「Dream」を押下するだけで実行されます。 消費creditも併せて表示されるのは親切ですね。 10秒足らずで画像が生成されました。非常にお手軽です。 もちろん、生成した画像はテクスチャとしてそのまま使用できます。 Renderingから画像を生成する 画像から画像を生成する例として、Renderingの結果から画像を生成してみます。 まずは「init Type」の「Texture」を選択します。 メニューから「Render>Render image」を押下すると、新規ウィンドウでRenderingが実行されます。 カメラを設定している以前の記事のプロジェクトを使用しました。 Rendering画面からStabilityを実行します。 promptは以下としました。 An empty park with snow, concept art, matte painting, HQ, 4k 前述の通り、「Dream」を押下することで画像が生成されます。 Blender 上で見える景色をベースに画像を生成することができました。 ここで、「Stability」タブの「input Options」から各種パラメータを設定できます。 パラメータ名 概要 default Init Strength 入力画像にどれだけ準拠するかを設定します。 0.5 Prompt Strength プロンプトにどれだけ準拠するかを設定します。 7.5 Set seed Stable Diffusionのseedを設定します。seedを変えると異なる画像が出力されます。 555555 Steps Stable DiffusionのStep数を設定します。 50 Engine 使用するStable Diffusionモデルを設定します。(あくまで推測ですが、GENERATE_512_2_1は解像度512pixelで Stable diffusion ver2.1 を表していると思われます) GENERATE_512_2_1 Sampler Stable DiffusionのSampler(ノイズ除去 アルゴリズム )を設定します。 K_DPMPP_2S_ANCESTRAL 主に出力の品質や、入力のバランス(文章と画像の情報どちらを優先するか)に関するパラメータが設定できます。ここでは、「Init strength」を変更してみます。 「Init strength」を変化させると以下のようになります。 「Init strength」を大きくするほど、Renderingされた情報に準拠するような画像の生成がされました。 一方で、小さくするほどpromptの「An empty park with snow」が重視され、元々置いていたオブジェクトは別のものに解釈される/消えることが確認できました。 ※今回、Renderingからアニメーション生成の手順も実施しましたが、数時間経過しても処理が進まず断念しました。 おわりに 今回はStability for Blender の利用手順とできることを調査しました。 執筆時点でv0.0.16も公開されており、「高解像度化」が新たに機能として追加されるなど、活発に開発が続けられています。今後より使いやすく、かつ機能を拡充していくことでクリエイター支援ツールとして活用されることが期待されます。 AIモデルの3DCGソフトウェアへの組み込みは今後も様々な形で発展していくと思いますので、今後もキャッチアップしていきたいと思います。 ここまでお読みいただきありがとうございました。 現在ISIDは web3領域のグループ横断組織 を立ち上げ、Web3および メタバース 領域のR&Dを行っております(カテゴリー「3DCG」の記事は こちら )。 もし本領域にご興味のある方や、一緒にチャレンジしていきたい方は、ぜひお気軽にご連絡ください! 私たちと同じチームで働いてくれる仲間を、是非お待ちしております! ISID採用ページ 執筆: @wakamoto.ryosuke 、レビュー: @yamada.y ( Shodo で執筆されました )
アバター
(画像: Basic Theory of Physically-Based Rendering ) こんにちは!金融ソリューション事業部の山下です。 今回は、近年進化が目覚ましい3DCGグラフィックスのクオリティを支えるPBR(Physical Based Rendering)について紹介します。 本記事では、入門編としてPBRの基礎理論やワークフローを紹介します。 また応用編として、 Substance 3Dや Unreal Engine を用いた制作フローを紹介する記事も別途執筆予定です。 PBRマテリアルの生成事例については、 Substance Samplerを用いたこちらの記事 でも紹介しているので、ぜひご覧ください。 1. PBRとは? 2. PBRの基礎理論 2-1. エネルギー保存の法則:拡散(Diffuse)と鏡面(Specular)反射 2-2. 金属(Metal)と非金属(Non-Metal) 2-3. 吸収(Absorption)と散乱(Scattering) 2-4. フレネル効果(Fresnel Effect) 2-5. マイクロファセット理論 3. PBRにおける主要ワークフロー 3-1. Metal - Roughness 3-2. Specular - Glossiness 4. 各テクスチャマップの概要(Metallic/Roughnessワークフロー) 4-1. BaseColor(Albedo)Map 4-2. Metallic(金属度)Map 4-3. Roughness(粗さ)Map 4-4. Normal(法線)Map 4-5. Ambient Occlusion(環境遮蔽)Map 4-6. Height(高さ)Map 4-7. Specluar Level(鏡面反射レベル)Map まとめ 参考 1. PBRとは? PBR(Physical Based Rendering)とは、現実世界の光の振る舞いを近似させる3DCG レンダリング 手法です。 従来の レンダリング 手法では、物理原則に基づかない比較的シンプルな近似を行う「 Lambert反射モデル 」や「 Blinn–Phong反射モデル 」が採用されていました。 PBRの原理に沿ったマテリアルを使用することにより、リアルな質感や照明をシミュレートしてより正確かつ自然な見た目を実現できます。 PBRの活用は、2000年~2010年代にゲームや映画業界から始まりました。 GPU ハードウェアやGraphic API 、リアルタイム レンダリング 技術の進化に伴い普及が進んだ結果、現在では主要な3Dファイル形式( glTF 、 FBX など)においてもPBRパラメータが採用されています。 一点誤解されやすい点を補足しますと、PBRはトゥーン レンダリング やNPR(非フォトリアル レンダリング )などアニメ調の作品においても有効に機能する技術です。そのため、PBRは Pixar やDisneyの映画でも採用されています。 (画像: SIGGRAPH 2013 Course: Physically Based Shading in Theory and Practice ) 2. PBRの基礎理論 現実世界における光の挙動を再現するための主要な原理/法則について、以下、概要のみ紹介します。 2-1. エネルギー保存の法則 :拡散(Diffuse)と鏡面(Specular)反射 エネルギー保存の法則 は、物理学においてエネルギーが変換される過程でその総量が一定であることを示す基本原則です。 PBRにおいては、光の反射や散乱に関する計算手法( BRDF:Bidirectional Reflectance Distribution Function など)においてこの法則が適用されています。 具体的には、入射光が物体の表面に当たる際、光のエネルギーは以下2つに分散します。 拡散(Diffuse)反射光:物体の内部で散乱され、再び表面から放出される光。物体によって吸収/放出される光の波長が異なる。その結果、物体の色が異なって見える。 鏡面(Specular)反射光:物体の表面から反射される光。完全な平面では入射角と反射角が等しくなる。物体表面が滑らかなほどハイライトは小さく明るくなり、粗いほど大きく暗くなる。 (画像: Basic Theory of Physically-Based Rendering ) この法則に基づき、PBRでは「反射光の総エネルギーは、入射光のエネルギーと等しい」という現実世界の光の挙動を再現しています。 2-2. 金属(Metal)と非金属(Non-Metal) PBRマテリアルにおいて、「金属か非金属か」という観点は非常に重要になります。 表面が金属の場合、鏡面反射が強調されて拡散反射はほとんど存在しません。これにより、金属表面は光沢感が強く、反射が明確に現れます。一方、非金属の場合、鏡面反射は比較的弱くなり、逆に拡散反射の影響が強まります。 また、鏡面反射の色は、金属の場合は金属自体の色で染まります。一方、非金属の場合、鏡面反射はほとんど白に近い色になります。 (画像: THE PBR GUIDE BY ALLEGORITHMIC ) 2-3. 吸収(Absorption)と散乱(Scattering) 吸収は、物体が光を吸収する現象です。吸収された光は一般的には物体内部で熱エネルギーに変換されます。 散乱は、光が物体内部や表面で乱反射される現象です。 半透明な物体では、光が物体の内部で散乱した後に表面から出てくる現象(SSS:Subsurface Scattering)が発生します。特にこの現象は、人肌や大理石、ろうそくや乳製品などで顕著に現れます。 (画像: Wikipedia: Subsurface scattering) ) 2-4. フレネル効果(Fresnel Effect) (画像: Fresnel Reflection and Fresnel Reflection Modes Explained ) フレネル効果は、光が物体の表面と交差する角度によって、その反射率が変化する現象です。 例えば、上記画像のように水面を上から見下ろした際、近い部分(視線と物体表面の角度が大きい)では水面の底が透けて見えます。一方で遠い部分(視線と物体表面の角度が小さい)では、完全に反射光しか見えません。 つまり、視線と物体の表面となす角度が小さいほど(鋭い角度で見るほど)、反射率が高くなります。 このフレネル効果は、水だけでなく布や木などの物体にも全て発生します。 PBRではフレネル効果を考慮することで、物体表面の光沢感や金属質感を表現します。 (参考: THE PBR GUIDE BY ALLEGORITHMIC ) DCCツールにおいては、上記の通り正面から垂直に物体を捉えた点の反射率を「F0」として扱います。このF0は、物体のIOR(屈折率)によって一意に導き出すことができます。 (画像: THE PBR GUIDE BY ALLEGORITHMIC ) また、F0は一般的な非金属で2~5%程度、金属では60~70%程度となっており、いずれも側面における反射率はほぼ100%となります。 2-5. マイクロファセット理論 (画像: THE PBR GUIDE BY ALLEGORITHMIC ) マイクロファセット理論は、物体の表面を無数の微小な平面(マイクロファセット)の集合として扱う理論です。 マイクロファセットはそれぞれ異なる向きを持っているため、光はそれぞれ異なる方向に反射されます。物体表面全体における反射は、各マイクロファセットによる反射の合成として計算されます。 PBRでは、物体表面の粗さ(Roughness)や凹凸(Normal)といったテクスチャマップを用いることで、メッシュよりも細かい単位の光の散乱や反射を計算します。 3. PBRにおける主要ワークフロー PBRマテリアルを作成/利用する場合、Metallic/RoughnessとSpecular/Glossinessという2つのワークフローが主流です。 3-1. Metal - Roughness テクスチャマップによって「金属度」と「粗さ」を制御するワークフローです。 メリット 調整が直感的であり、シンプル。鏡面反射のマップを持たずF0値のデフォルトが設定される為、非金属における反射率の設定破綻がしにくい(物理的にありえない値にはなりにくい) 比較的、テクスチャのメモリ使用量が少ない(1 RGB:Albedo) ほとんどのDCCツールで採用されている デメリット F0値のコン トロール ができない。(※ UEではSpecular Inputが用意されている為デフォルト値からの調整が可能) 金属度マップは原則バイナリ値で表す為、低解像度の場合にテクスチャ補完によってEdge Artifactが発生しやすい 3-2. Specular - Glossiness テクスチャマップで「鏡面反射」と「光沢度」を制御するワークフローです。 メリット Specular MapにてF0値のコン トロール がしやすい 比較的、Edge artifactが発生しにくい デメリット 調整が難しい(F0値が物理法則的に破綻する可能性がある) 比較的、テクスチャのメモリ使用量が多い(2 RGB:Albedo, Specular) どちらのワークフローもそれぞれの利点があり用途や好みに応じて選択されますが、本記事では Unreal Engine でも採用されているMetallic/Roughnessワークフローに沿って説明します。 4. 各テクスチャマップの概要(Metallic/Roughnessワークフロー) PBRワークフローでは、複数の画像素材(テクスチャマップ)を用いてマテリアルを表現します。 各テクスチャ素材をDCCツールや ゲームエンジン において適切に組み合わせることで、PBRの表現が可能になります。 各マップにおけるテクスチャのサンプル画像は、 こちらの記事 にて、 Substance Samplerを用いて生成したこちらのマテリアルを使用します。 マテリアルの完成系は、こちらです。 4-1. BaseColor(Albedo)Map 物体の基本色を表すマップです。RGB( Vector 3)で、0~1の値として表します。 従来のカラーマップとは異なり光の影響や陰影、反射などは含まれていないため、Albedoマップは明るい色調になることが特徴です。 実際のテクスチャ制作ではDCCツールを用いる手法のほか、カメラと偏光フィルターを用いた撮影による制作手法などがあります。 4-2. Metallic(金属度)Map 表面の金属性を表すマップです。 グレースケールで、通常は黒か白かの2値のみで表現します(0が非金属、1が金属)。 今回のサンプル画像は非金属のため、黒一色となります。 白(値が高い)が金属、黒(値が低い)が非金属を示します。 金属マップは、物体の反射特性を制御し、金属質感や非金属質感を区別する役割があります。 4-3. Roughness(粗さ)Map 物体の表面の粗さを表すマップです。0~1のグレースケール値で表します(0がつるつる、1がざらざら)。 粗いほど表面がざらつき、光の散乱が大きくなります。 3Dモデルの表面の粗さを表現します。白(値が高い)は粗い表面、黒(値が低い)は滑らかな表面を示します。 粗さマップは、光の反射や散乱の度合いを制御し、質感や光沢感を調整する役割があります。 4-4. Normal(法線)Map 物体の表面の微細な凹凸を表すマップです。RGB( Vector 3)で表し、RGBがXYZ座標に対応するベクトルとして扱います。 RGB値によって、各 ピクセル の表面法線の向きが定義されています。 法線マップは、モデルのポリゴン数を増やさずにディテールを追加することができ、リアルな質感や陰影を表現する役割があります。これにより、高解像度のジオメトリを持たないモデルでも、細かいディテールを表現できます。 4-5. Ambient Occlusion(環境遮蔽)Map 表面の自然な陰影を表現するマップです。0~1のグレースケール値(0が遮蔽された黒、1が露出していて白)で表します。 表面の凹凸によって遮られる環境光を表現します。これにより、物体同士が接近している部分や凹んでいる部分に影ができ、リアルな陰影が表現されます。 4-6. Height(高さ)Map 物体表面の高低差を表すマップです。0~1のグレイスケール値(0が低く、1が高い)で高さを表します。 レンダリング を行う際に、高さの単位(ユニット)を設定する必要があります。 4-7. Specluar Level(鏡面反射レベル)Map 非金属物体に対する鏡面反射の係数を表すマップです。 UEではデフォルト値が0.5(F0が4%)として設定されていますが、この係数を調整できます。 Specular - GlossinessワークフローにおけるSpecular Mapとは異なる点についてご注意ください。 まとめ いかがでしたでしょうか。 近年では、人肌や大理石など物体表面内部に浸透する光の振る舞いを表現する SSS(サブサーフェススキャタリング) や、幅広いレンジの明るさ情報を用いる HDRI(ハイダイナミックレンジイメージ) など、様々な新しい技術が開発されています。 さらに、Unreal Engine5など ゲームエンジン の進化も伴うことで「現実と見紛う」レベルの3DCGがリアルタイム レンダリング 可能になっており、今後も3DCG技術の進化と ユースケース に目が離せません。 次回からは応用編として、 Substance Designerを用いたPBRマテリアルの制作や、 Unreal Engine における レンダリング 方法について紹介してきたいと思います。 現在ISIDは web3領域のグループ横断組織 を立ち上げ、Web3および メタバース 領域のR&Dを行っております(カテゴリー「3DCG」の記事は こちら )。 もし本領域にご興味のある方や、一緒にチャレンジしていきたい方は、ぜひお気軽にご連絡ください! 私たちと同じチームで働いてくれる仲間を、是非お待ちしております! ISID採用ページ(Web3/メタバース/AI) 参考 Basic Theory of Physically-Based Rendering SIGGRAPH 2013 Course: Physically Based Shading in Theory and Practice THE PBR GUIDE BY ALLEGORITHMIC 執筆: @yamashita.yuki 、レビュー: @wakamoto.ryosuke ( Shodo で執筆されました )
アバター
(画像: Basic Theory of Physically-Based Rendering ) こんにちは!金融ソリューション事業部の山下です。 今回は、近年進化が目覚ましい3DCGグラフィックスのクオリティを支えるPBR(Physical Based Rendering)について紹介します。 本記事では、入門編としてPBRの基礎理論やワークフローを紹介します。 また応用編として、 Substance 3Dや Unreal Engine を用いた制作フローを紹介する記事も別途執筆予定です。 PBRマテリアルの生成事例については、 Substance Samplerを用いたこちらの記事 でも紹介しているので、ぜひご覧ください。 1. PBRとは? 2. PBRの基礎理論 2-1. エネルギー保存の法則:拡散(Diffuse)と鏡面(Specular)反射 2-2. 金属(Metal)と非金属(Non-Metal) 2-3. 吸収(Absorption)と散乱(Scattering) 2-4. フレネル効果(Fresnel Effect) 2-5. マイクロファセット理論 3. PBRにおける主要ワークフロー 3-1. Metal - Roughness 3-2. Specular - Glossiness 4. 各テクスチャマップの概要(Metallic/Roughnessワークフロー) 4-1. BaseColor(Albedo)Map 4-2. Metallic(金属度)Map 4-3. Roughness(粗さ)Map 4-4. Normal(法線)Map 4-5. Ambient Occlusion(環境遮蔽)Map 4-6. Height(高さ)Map 4-7. Specluar Level(鏡面反射レベル)Map まとめ 参考 1. PBRとは? PBR(Physical Based Rendering)とは、現実世界の光の振る舞いを近似させる3DCG レンダリング 手法です。 従来の レンダリング 手法では、物理原則に基づかない比較的シンプルな近似を行う「 Lambert反射モデル 」や「 Blinn–Phong反射モデル 」が採用されていました。 PBRの原理に沿ったマテリアルを使用することにより、リアルな質感や照明をシミュレートしてより正確かつ自然な見た目を実現できます。 PBRの活用は、2000年~2010年代にゲームや映画業界から始まりました。 GPU ハードウェアやGraphic API 、リアルタイム レンダリング 技術の進化に伴い普及が進んだ結果、現在では主要な3Dファイル形式( glTF 、 FBX など)においてもPBRパラメータが採用されています。 一点誤解されやすい点を補足しますと、PBRはトゥーン レンダリング やNPR(非フォトリアル レンダリング )などアニメ調の作品においても有効に機能する技術です。そのため、PBRは Pixar やDisneyの映画でも採用されています。 (画像: SIGGRAPH 2013 Course: Physically Based Shading in Theory and Practice ) 2. PBRの基礎理論 現実世界における光の挙動を再現するための主要な原理/法則について、以下、概要のみ紹介します。 2-1. エネルギー保存の法則 :拡散(Diffuse)と鏡面(Specular)反射 エネルギー保存の法則 は、物理学においてエネルギーが変換される過程でその総量が一定であることを示す基本原則です。 PBRにおいては、光の反射や散乱に関する計算手法( BRDF:Bidirectional Reflectance Distribution Function など)においてこの法則が適用されています。 具体的には、入射光が物体の表面に当たる際、光のエネルギーは以下2つに分散します。 拡散(Diffuse)反射光:物体の内部で散乱され、再び表面から放出される光。物体によって吸収/放出される光の波長が異なる。その結果、物体の色が異なって見える。 鏡面(Specular)反射光:物体の表面から反射される光。完全な平面では入射角と反射角が等しくなる。物体表面が滑らかなほどハイライトは小さく明るくなり、粗いほど大きく暗くなる。 (画像: Basic Theory of Physically-Based Rendering ) この法則に基づき、PBRでは「反射光の総エネルギーは、入射光のエネルギーと等しい」という現実世界の光の挙動を再現しています。 2-2. 金属(Metal)と非金属(Non-Metal) PBRマテリアルにおいて、「金属か非金属か」という観点は非常に重要になります。 表面が金属の場合、鏡面反射が強調されて拡散反射はほとんど存在しません。これにより、金属表面は光沢感が強く、反射が明確に現れます。一方、非金属の場合、鏡面反射は比較的弱くなり、逆に拡散反射の影響が強まります。 また、鏡面反射の色は、金属の場合は金属自体の色で染まります。一方、非金属の場合、鏡面反射はほとんど白に近い色になります。 (画像: THE PBR GUIDE BY ALLEGORITHMIC ) 2-3. 吸収(Absorption)と散乱(Scattering) 吸収は、物体が光を吸収する現象です。吸収された光は一般的には物体内部で熱エネルギーに変換されます。 散乱は、光が物体内部や表面で乱反射される現象です。 半透明な物体では、光が物体の内部で散乱した後に表面から出てくる現象(SSS:Subsurface Scattering)が発生します。特にこの現象は、人肌や大理石、ろうそくや乳製品などで顕著に現れます。 (画像: Wikipedia: Subsurface scattering) ) 2-4. フレネル効果(Fresnel Effect) (画像: Fresnel Reflection and Fresnel Reflection Modes Explained ) フレネル効果は、光が物体の表面と交差する角度によって、その反射率が変化する現象です。 例えば、上記画像のように水面を上から見下ろした際、近い部分(視線と物体表面の角度が大きい)では水面の底が透けて見えます。一方で遠い部分(視線と物体表面の角度が小さい)では、完全に反射光しか見えません。 つまり、視線と物体の表面となす角度が小さいほど(鋭い角度で見るほど)、反射率が高くなります。 このフレネル効果は、水だけでなく布や木などの物体にも全て発生します。 PBRではフレネル効果を考慮することで、物体表面の光沢感や金属質感を表現します。 (参考: THE PBR GUIDE BY ALLEGORITHMIC ) DCCツールにおいては、上記の通り正面から垂直に物体を捉えた点の反射率を「F0」として扱います。このF0は、物体のIOR(屈折率)によって一意に導き出すことができます。 (画像: THE PBR GUIDE BY ALLEGORITHMIC ) また、F0は一般的な非金属で2~5%程度、金属では60~70%程度となっており、いずれも側面における反射率はほぼ100%となります。 2-5. マイクロファセット理論 (画像: THE PBR GUIDE BY ALLEGORITHMIC ) マイクロファセット理論は、物体の表面を無数の微小な平面(マイクロファセット)の集合として扱う理論です。 マイクロファセットはそれぞれ異なる向きを持っているため、光はそれぞれ異なる方向に反射されます。物体表面全体における反射は、各マイクロファセットによる反射の合成として計算されます。 PBRでは、物体表面の粗さ(Roughness)や凹凸(Normal)といったテクスチャマップを用いることで、メッシュよりも細かい単位の光の散乱や反射を計算します。 3. PBRにおける主要ワークフロー PBRマテリアルを作成/利用する場合、Metallic/RoughnessとSpecular/Glossinessという2つのワークフローが主流です。 3-1. Metal - Roughness テクスチャマップによって「金属度」と「粗さ」を制御するワークフローです。 メリット 調整が直感的であり、シンプル。鏡面反射のマップを持たずF0値のデフォルトが設定される為、非金属における反射率の設定破綻がしにくい(物理的にありえない値にはなりにくい) 比較的、テクスチャのメモリ使用量が少ない(1 RGB:Albedo) ほとんどのDCCツールで採用されている デメリット F0値のコン トロール ができない。(※ UEではSpecular Inputが用意されている為デフォルト値からの調整が可能) 金属度マップは原則バイナリ値で表す為、低解像度の場合にテクスチャ補完によってEdge Artifactが発生しやすい 3-2. Specular - Glossiness テクスチャマップで「鏡面反射」と「光沢度」を制御するワークフローです。 メリット Specular MapにてF0値のコン トロール がしやすい 比較的、Edge artifactが発生しにくい デメリット 調整が難しい(F0値が物理法則的に破綻する可能性がある) 比較的、テクスチャのメモリ使用量が多い(2 RGB:Albedo, Specular) どちらのワークフローもそれぞれの利点があり用途や好みに応じて選択されますが、本記事では Unreal Engine でも採用されているMetallic/Roughnessワークフローに沿って説明します。 4. 各テクスチャマップの概要(Metallic/Roughnessワークフロー) PBRワークフローでは、複数の画像素材(テクスチャマップ)を用いてマテリアルを表現します。 各テクスチャ素材をDCCツールや ゲームエンジン において適切に組み合わせることで、PBRの表現が可能になります。 各マップにおけるテクスチャのサンプル画像は、 こちらの記事 にて、 Substance Samplerを用いて生成したこちらのマテリアルを使用します。 マテリアルの完成系は、こちらです。 4-1. BaseColor(Albedo)Map 物体の基本色を表すマップです。RGB( Vector 3)で、0~1の値として表します。 従来のカラーマップとは異なり光の影響や陰影、反射などは含まれていないため、Albedoマップは明るい色調になることが特徴です。 実際のテクスチャ制作ではDCCツールを用いる手法のほか、カメラと偏光フィルターを用いた撮影による制作手法などがあります。 4-2. Metallic(金属度)Map 表面の金属性を表すマップです。 グレースケールで、通常は黒か白かの2値のみで表現します(0が非金属、1が金属)。 今回のサンプル画像は非金属のため、黒一色となります。 白(値が高い)が金属、黒(値が低い)が非金属を示します。 金属マップは、物体の反射特性を制御し、金属質感や非金属質感を区別する役割があります。 4-3. Roughness(粗さ)Map 物体の表面の粗さを表すマップです。0~1のグレースケール値で表します(0がつるつる、1がざらざら)。 粗いほど表面がざらつき、光の散乱が大きくなります。 3Dモデルの表面の粗さを表現します。白(値が高い)は粗い表面、黒(値が低い)は滑らかな表面を示します。 粗さマップは、光の反射や散乱の度合いを制御し、質感や光沢感を調整する役割があります。 4-4. Normal(法線)Map 物体の表面の微細な凹凸を表すマップです。RGB( Vector 3)で表し、RGBがXYZ座標に対応するベクトルとして扱います。 RGB値によって、各 ピクセル の表面法線の向きが定義されています。 法線マップは、モデルのポリゴン数を増やさずにディテールを追加することができ、リアルな質感や陰影を表現する役割があります。これにより、高解像度のジオメトリを持たないモデルでも、細かいディテールを表現できます。 4-5. Ambient Occlusion(環境遮蔽)Map 表面の自然な陰影を表現するマップです。0~1のグレースケール値(0が遮蔽された黒、1が露出していて白)で表します。 表面の凹凸によって遮られる環境光を表現します。これにより、物体同士が接近している部分や凹んでいる部分に影ができ、リアルな陰影が表現されます。 4-6. Height(高さ)Map 物体表面の高低差を表すマップです。0~1のグレイスケール値(0が低く、1が高い)で高さを表します。 レンダリング を行う際に、高さの単位(ユニット)を設定する必要があります。 4-7. Specluar Level(鏡面反射レベル)Map 非金属物体に対する鏡面反射の係数を表すマップです。 UEではデフォルト値が0.5(F0が4%)として設定されていますが、この係数を調整できます。 Specular - GlossinessワークフローにおけるSpecular Mapとは異なる点についてご注意ください。 まとめ いかがでしたでしょうか。 近年では、人肌や大理石など物体表面内部に浸透する光の振る舞いを表現する SSS(サブサーフェススキャタリング) や、幅広いレンジの明るさ情報を用いる HDRI(ハイダイナミックレンジイメージ) など、様々な新しい技術が開発されています。 さらに、Unreal Engine5など ゲームエンジン の進化も伴うことで「現実と見紛う」レベルの3DCGがリアルタイム レンダリング 可能になっており、今後も3DCG技術の進化と ユースケース に目が離せません。 次回からは応用編として、 Substance Designerを用いたPBRマテリアルの制作や、 Unreal Engine における レンダリング 方法について紹介してきたいと思います。 現在ISIDは web3領域のグループ横断組織 を立ち上げ、Web3および メタバース 領域のR&Dを行っております(カテゴリー「3DCG」の記事は こちら )。 もし本領域にご興味のある方や、一緒にチャレンジしていきたい方は、ぜひお気軽にご連絡ください! 私たちと同じチームで働いてくれる仲間を、是非お待ちしております! ISID採用ページ(Web3/メタバース/AI) 参考 Basic Theory of Physically-Based Rendering SIGGRAPH 2013 Course: Physically Based Shading in Theory and Practice THE PBR GUIDE BY ALLEGORITHMIC 執筆: @yamashita.yuki 、レビュー: @wakamoto.ryosuke ( Shodo で執筆されました )
アバター
はいどーもー! 早いもので新卒入社から丸3年、コミュニケーションIT事業部の宮澤響です! 本記事では、 Backlog API を利用した Backlog への課題の登録方法について、私が実際にハマったポイントを交えながらご紹介します。 背景・前提 Backlogとは どうしてAPIで課題登録を? サンプルコードについて 下準備 APIキーの発行 プロジェクトIDの確認 スペースのURLの確認 やってみる 必要なモジュールのインポートと変数の定義 課題の登録〜基本編〜 課題の登録〜カスタム属性編〜 課題の登録〜複数選択編〜 おまけで検証してみた まとめ 背景・前提 Backlogとは Backlogとは、株式会社 ヌーラボ が提供している課題管理・プロジェクト管理のサービスです。 シンプルで直感的に使えるデザインが特長であり、Git リポジトリ や Wiki としての機能も有しています。 どうして API で課題登録を? 弊社では同種のサービスとして Jira が全社展開されています。 そのため、私自身もこれまではJiraの利用経験しかありませんでした。 しかしこの度、チームの都合によりBacklogを利用することになり、利用方法を調査していたところ、BacklogにはJiraのように標準機能で自動化できる項目はあまりないことが分かりました。 そこで、Backlog API を利用することで一部の処理を自動化できないかと考え、手始めに基本となるであろう課題の登録をやってみることにしました。 サンプルコードについて 本記事のサンプルコードには TypeScript と axios を利用しています。 それぞれのインストール方法などについては本記事内では解説していませんので、適宜リンク先をご参照ください。 下準備 まずはBacklog API を利用するための下準備です。 API キーの発行 個人設定 > API から、 API キーを発行します。 必要に応じて メモ 欄に文字列を入力し、 登録 ボタンを押下します。 なお、Backlog API ではOAuth 2.0を利用した認証・認可方式も提供されていますが、Nulabアカウントを作成した上で開発するアプリケーションの登録を行う必要があるため、本記事では事前準備が不要な API キーを利用した方式を採用します。( 参考 ) プロジェクトIDの確認 課題の登録先となるプロジェクトのプロジェクトIDを確認します。 プロジェクトIDは、当該プロジェクトの 課題 ページや、 プロジェクト設定 ページのURLから確認できます。 プロジェクト情報の取得 の API を利用して確認することもできますが、今回は少し楽をしています。 スペースのURLの確認 課題の登録先となるプロジェクトが所属しているスペースのURLを確認します。 スペースやプロジェクトのあらゆる画面のURLの先頭にある https://xx.backlog.jp または https://xx.backlog.com の部分です。 xx の部分にはそれぞれのスペースのスペースIDが入ります。 やってみる 実際に API リク エス トのための ソースコード を記述していきます。 必要なモジュールのインポートと変数の定義 まずは必要なモジュールをインポートするとともに、ここまでに確認してきた内容から以下の変数を定義します。 // 必要なモジュールをインポートします import axios , { AxiosResponse } from "axios" ; // 右辺の""の中に先ほど発行したAPIキーの値を入力します const apiKey = "abcdefghijklmn" ; // 右辺の""の中に先ほど確認したプロジェクトIDの値を入力します const projectId = "123456" ; // 右辺の""の中に先ほど確認したスペースのURLの値の末尾に「/api/v2」を追加したものを入力します const baseUrl = "https://xx.backlog.jp/api/v2" ; なお、本記事では簡素化のために API キーを ソースコード 内に直接記載していますが、実際に運用をする際、特に GitHub などを利用して ソースコード を共有、公開する際は、 API キーのような認証情報は ソースコード 内に直接記載しない ことを強く推奨します。 (対応例: .gitignore で指定した .env ファイルに記載した値を dotenv を利用して読み込む、など) 課題の登録〜基本編〜 課題の追加 の API を利用します。 手始めに、必須とされている以下のパラメータのみを指定して、POSTリク エス トを送信してみます。 パラメータ名 型 内容 projectId 数値 課題を登録するプロジェクトのID summary 文字列 課題の件名 issueTypeId 数値 課題の種別のID priorityId 数値 課題の優先度のID なお、 issueTypeId や priorityId は、登録先のプロジェクトの 課題 ページの 高度な検索 タブや、 プロジェクト設定 の当該種別の編集ページのURLから確認するのが最も簡単です。 もちろん、 課題情報の取得 、 種別一覧の取得 、 優先度一覧の取得 、などの API を利用して確認することも可能です。 注意点として、Backlog API を利用する際は Content-Type が application/x-www-form-urlencoded である必要がある ため、 URLSearchParams を利用します。( 参考 ) const createIssue1 = async () : Promise < AxiosResponse > => { const url = ` ${ baseUrl } /issues?` ; const params = new URLSearchParams ( { apiKey , projectId , summary: "テスト1" , issueTypeId: "123456" , priorityId: "2" , } ); return await axios.post ( url + params ); } ; createIssue1 (); 無事に登録されました。 課題の登録〜カスタム属性編〜 続いて、以下のカスタム属性の値を指定してみます。 カスタム属性名 選択形式 選択肢 単一選択カスタム属性 単一選択(リスト形式) 選択肢1、選択肢2、選択肢3 複数選択カスタム属性 複数選択(リスト形式) 選択肢1、選択肢2、選択肢3 カスタム属性のパラメータ名は customField_xxxxx ( xxxxx はカスタム属性ID)です。 カスタム属性IDの確認方法は、これまでのものと同様、登録先のプロジェクトの 課題 ページの 高度な検索 タブのURL、 プロジェクト設定 の当該カスタム属性の編集ページのURL、 カスタム属性一覧の取得 の API などです。 注意点として、カスタム属性の値は、 選択肢名ではなく選択肢IDで指定 します。 課題の追加 の API リファレンスにはこのことが書かれていないので、若干のハマりポイントです。 const createIssue2 = async () : Promise < AxiosResponse > => { const url = ` ${ baseUrl } /issues?` ; const params = new URLSearchParams ( { apiKey , projectId , summary: "テスト2" , issueTypeId: "123456" , priorityId: "2" , // 「customField_12345: "選択肢1"」とすると400エラーになります customField_12345: "1" , // 同上 customField_67890: "1" , } ); return await axios.post ( url + params ); } ; createIssue2 (); 無事にカスタム属性の値が設定されました。 課題の登録〜複数選択編〜 続いて、複数選択が可能なカスタム属性に複数の値を指定してみます。 イメージとしては以下のような ソースコード なのですが、このままでは customField_67890 に複数の値を指定する部分で コンパイル エラー( Type 'string[]' is not assignable to type 'string'. )が発生してしまいます。 const createIssue3 = async () : Promise < AxiosResponse > => { const url = ` ${ baseUrl } /issues?` ; const params = new URLSearchParams ( { apiKey , projectId , summary: "テスト3" , issueTypeId: "123456" , priorityId: "2" , customField_12345: "1" , // これはコンパイルエラーになります customField_67890: [ "1" , "2" ] , } ); return await axios.post ( url + params ); } ; createIssue3 (); そのため、標準機能で対応する場合には、少し不格好ではありますが、 append() メソッドを利用して、1つ目の選択肢と2つ目の選択肢を分けて指定 します。 const createIssue3 = async () : Promise < AxiosResponse > => { const url = ` ${ baseUrl } /issues?` ; const params = new URLSearchParams ( { apiKey , projectId , summary: "テスト3" , issueTypeId: "123456" , priorityId: "2" , customField_12345: "1" , customField_67890: "1" , } ); params.append ( "customField_67890" , "2" ); return await axios.post ( url + params ); } ; createIssue3 (); 或いは、コンスト ラク タでは値を指定せず、 append() メソッドのみで全ての値を指定することも可能です。 const createIssue3 = async () : Promise < AxiosResponse > => { const url = ` ${ baseUrl } /issues?` ; const params = new URLSearchParams (); params.append ( "apiKey" , apiKey ); params.append ( "projectId" , projectId ); params.append ( "summary" , "テスト3" ); params.append ( "issueTypeId" , "123456" ); params.append ( "priorityId" , "2" ); params.append ( "customField_12345" , "1" ); params.append ( "customField_67890" , "1" ); params.append ( "customField_67890" , "2" ); return await axios.post ( url + params ); } ; createIssue3 (); なお、上述のサンプルコードはいずれも標準機能のみを用いてクエリパラメータを生成していましたが、外部ライブラリを利用すると、カスタム属性に複数の値を指定する部分を一行ですっきり記述できます。 例えば、 qs を利用すると、以下のようになります。 import qs from "qs" ; const createIssue3 = async () : Promise < AxiosResponse > => { const url = ` ${ baseUrl } /issues?` ; const params = qs.stringify ( { apiKey , projectId , summary: "テスト3" , issueTypeId: "123456" , priorityId: "2" , customField_12345: "1" , customField_67890: [ "1" , "2" ] , } , { indices: false } ); return await axios.post ( url + params ); } ; createIssue3 (); 無事に複数の値が設定されました。 これでひとまず課題登録に関する一連の試みは完了です。 おまけで検証してみた ちょっとしたおまけです。 上述のとおり、Backlog API では application/x-www-form-urlencoded でリク エス トを送信しますが、 application/json でのリク エス トに変更したらどうなるのでしょうか。 課題の登録には不要な検証ですが、気になったので試してみました。 const createIssue4 = async () : Promise < AxiosResponse > => { // apiKeyをdataに含めると401エラーになります const url = ` ${ baseUrl } /issues?apiKey= ${ apiKey } ` ; const data = { projectId , summary: "テスト4" , issueTypeId: "123456" , priorityId: "2" , customField_12345: "1" , customField_67890: [ "1" , "2" ] , } ; return await axios.post ( url , data ); } ; createIssue4 (); 結果としては、課題の登録自体はできるものの、カスタム属性の値が反映されませんでした。 (中途半端に成功する理由については不明です…もしご存知の方がいらっしゃれば、ぜひ本記事を引用して記事を執筆してみてください…!笑) まとめ 本記事では、Backlog API を利用したBacklogへの課題の登録方法について、サンプルコードとともにご紹介しました。 その際の主な注意点は以下です。 API キーのような認証情報は ソースコード 内に直接記載しない(Backlog API に限らず) Content-Type は application/x-www-form-urlencoded カスタム属性の値は選択肢名ではなく選択肢IDで指定 標準機能でパラメータに複数の値を指定するには、 append() メソッドで1つ目の選択肢と2つ目の選択肢を分けて指定 少しでもBacklog API の利用を検討している方々の参考になれば幸いです。 最後までお読みいただき、本当にありがとうございました! 私たちは同じ事業部で共に働いていただける仲間を募集しています! 私自身は対顧客のセキュリティに関する業務に従事していますので、そのような業務にご興味がありましたら、応募の際にお問い合わせください! みなさまのご応募、お待ちしています! クラウドアーキテクト アプリケーションアーキテクト 電通グループ向け基幹システムプロジェクトマネージャ 戦略的IT プロジェクトマネージャ/ITコンサルタント 執筆: @miyazawa.hibiki 、レビュー: Ishizawa Kento (@kent) ( Shodo で執筆されました )
アバター
はいどーもー! 早いもので新卒入社から丸3年、コミュニケーションIT事業部の宮澤響です! 本記事では、 Backlog API を利用した Backlog への課題の登録方法について、私が実際にハマったポイントを交えながらご紹介します。 背景・前提 Backlogとは どうしてAPIで課題登録を? サンプルコードについて 下準備 APIキーの発行 プロジェクトIDの確認 スペースのURLの確認 やってみる 必要なモジュールのインポートと変数の定義 課題の登録〜基本編〜 課題の登録〜カスタム属性編〜 課題の登録〜複数選択編〜 おまけで検証してみた おわりに 背景・前提 Backlogとは Backlogとは、株式会社 ヌーラボ が提供している課題管理・プロジェクト管理のサービスです。 シンプルで直感的に使えるデザインが特長であり、Git リポジトリ や Wiki としての機能も有しています。 どうして API で課題登録を? 弊社では同種のサービスとして Jira が全社展開されています。 そのため、私自身もこれまではJiraの利用経験しかありませんでした。 しかしこの度、チームの都合によりBacklogを利用することになり、利用方法を調査していたところ、BacklogにはJiraのように標準機能で自動化できる項目はあまりないことが分かりました。 そこで、Backlog API を利用することで一部の処理を自動化できないかと考え、手始めに基本となるであろう課題の登録をやってみることにしました。 サンプルコードについて 本記事のサンプルコードには TypeScript と axios を利用しています。 それぞれのインストール方法などについては本記事内では解説していませんので、適宜リンク先をご参照ください。 下準備 まずはBacklog API を利用するための下準備です。 API キーの発行 個人設定 > API から、 API キーを発行します。 必要に応じて メモ 欄に文字列を入力し、 登録 ボタンを押下します。 なお、Backlog API ではOAuth 2.0を利用した認証・認可方式も提供されていますが、Nulabアカウントを作成した上で開発するアプリケーションの登録を行う必要があるため、本記事では事前準備が不要な API キーを利用した方式を採用します。( 参考 ) プロジェクトIDの確認 課題の登録先となるプロジェクトのプロジェクトIDを確認します。 プロジェクトIDは、当該プロジェクトの 課題 ページや、 プロジェクト設定 ページのURLから確認できます。 プロジェクト情報の取得 の API を利用して確認することもできますが、今回は少し楽をしています。 スペースのURLの確認 課題の登録先となるプロジェクトが所属しているスペースのURLを確認します。 スペースやプロジェクトのあらゆる画面のURLの先頭にある https://xx.backlog.jp または https://xx.backlog.com の部分です。 xx の部分にはそれぞれのスペースのスペースIDが入ります。 やってみる 実際に API リク エス トのための ソースコード を記述していきます。 必要なモジュールのインポートと変数の定義 まずは必要なモジュールをインポートするとともに、ここまでに確認してきた内容から以下の変数を定義します。 // 必要なモジュールをインポートします import axios , { AxiosResponse } from "axios" ; // 右辺の""の中に先ほど発行したAPIキーの値を入力します const apiKey = "abcdefghijklmn" ; // 右辺の""の中に先ほど確認したプロジェクトIDの値を入力します const projectId = "123456" ; // 右辺の""の中に先ほど確認したスペースのURLの値の末尾に「/api/v2」を追加したものを入力します const baseUrl = "https://xx.backlog.jp/api/v2" ; なお、本記事では簡素化のために API キーを ソースコード 内に直接記載していますが、実際に運用をする際、特に GitHub などを利用して ソースコード を共有、公開する際は、 API キーのような認証情報は ソースコード 内に直接記載しない ことを強く推奨します。 (対応例: .gitignore で指定した .env ファイルに記載した値を dotenv を利用して読み込む、など) 課題の登録〜基本編〜 課題の追加 の API を利用します。 手始めに、必須とされている以下のパラメータのみを指定して、POSTリク エス トを送信してみます。 パラメータ名 型 内容 projectId 数値 課題を登録するプロジェクトのID summary 文字列 課題の件名 issueTypeId 数値 課題の種別のID priorityId 数値 課題の優先度のID なお、 issueTypeId や priorityId は、登録先のプロジェクトの 課題 ページの 高度な検索 タブや、 プロジェクト設定 の当該種別の編集ページのURLから確認するのが最も簡単です。 もちろん、 課題情報の取得 、 種別一覧の取得 、 優先度一覧の取得 、などの API を利用して確認することも可能です。 注意点として、Backlog API を利用する際は Content-Type が application/x-www-form-urlencoded である必要がある ため、 URLSearchParams を利用します。( 参考 ) const createIssue1 = async () : Promise < AxiosResponse > => { const url = ` ${ baseUrl } /issues?` ; const params = new URLSearchParams ( { apiKey , projectId , summary: "テスト1" , issueTypeId: "123456" , priorityId: "2" , } ); return await axios.post ( url + params ); } ; createIssue1 (); 無事に登録されました。 課題の登録〜カスタム属性編〜 続いて、以下のカスタム属性の値を指定してみます。 カスタム属性名 選択形式 選択肢 単一選択カスタム属性 単一選択(リスト形式) 選択肢1、選択肢2、選択肢3 複数選択カスタム属性 複数選択(リスト形式) 選択肢1、選択肢2、選択肢3 カスタム属性のパラメータ名は customField_xxxxx ( xxxxx はカスタム属性ID)です。 カスタム属性IDの確認方法は、これまでのものと同様、登録先のプロジェクトの 課題 ページの 高度な検索 タブのURL、 プロジェクト設定 の当該カスタム属性の編集ページのURL、 カスタム属性一覧の取得 の API などです。 注意点として、カスタム属性の値は、 選択肢名ではなく選択肢IDで指定 します。 課題の追加 の API リファレンスにはこのことが書かれていないので、若干のハマりポイントです。 const createIssue2 = async () : Promise < AxiosResponse > => { const url = ` ${ baseUrl } /issues?` ; const params = new URLSearchParams ( { apiKey , projectId , summary: "テスト2" , issueTypeId: "123456" , priorityId: "2" , // 「customField_12345: "選択肢1"」とすると400エラーになります customField_12345: "1" , // 同上 customField_67890: "1" , } ); return await axios.post ( url + params ); } ; createIssue2 (); 無事にカスタム属性の値が設定されました。 課題の登録〜複数選択編〜 続いて、複数選択が可能なカスタム属性に複数の値を指定してみます。 イメージとしては以下のような ソースコード なのですが、このままでは customField_67890 に複数の値を指定する部分で コンパイル エラー( Type 'string[]' is not assignable to type 'string'. )が発生してしまいます。 const createIssue3 = async () : Promise < AxiosResponse > => { const url = ` ${ baseUrl } /issues?` ; const params = new URLSearchParams ( { apiKey , projectId , summary: "テスト3" , issueTypeId: "123456" , priorityId: "2" , customField_12345: "1" , // これはコンパイルエラーになります customField_67890: [ "1" , "2" ] , } ); return await axios.post ( url + params ); } ; createIssue3 (); そのため、標準機能で対応する場合には、少し不格好ではありますが、 append() メソッドを利用して、1つ目の選択肢と2つ目の選択肢を分けて指定 します。 const createIssue3 = async () : Promise < AxiosResponse > => { const url = ` ${ baseUrl } /issues?` ; const params = new URLSearchParams ( { apiKey , projectId , summary: "テスト3" , issueTypeId: "123456" , priorityId: "2" , customField_12345: "1" , customField_67890: "1" , } ); params.append ( "customField_67890" , "2" ); return await axios.post ( url + params ); } ; createIssue3 (); 或いは、コンスト ラク タでは値を指定せず、 append() メソッドのみで全ての値を指定することも可能です。 const createIssue3 = async () : Promise < AxiosResponse > => { const url = ` ${ baseUrl } /issues?` ; const params = new URLSearchParams (); params.append ( "apiKey" , apiKey ); params.append ( "projectId" , projectId ); params.append ( "summary" , "テスト3" ); params.append ( "issueTypeId" , "123456" ); params.append ( "priorityId" , "2" ); params.append ( "customField_12345" , "1" ); params.append ( "customField_67890" , "1" ); params.append ( "customField_67890" , "2" ); return await axios.post ( url + params ); } ; createIssue3 (); なお、上述のサンプルコードはいずれも標準機能のみを用いてクエリパラメータを生成していましたが、外部ライブラリを利用すると、カスタム属性に複数の値を指定する部分を一行ですっきり記述できます。 例えば、 qs を利用すると、以下のようになります。 import qs from "qs" ; const createIssue3 = async () : Promise < AxiosResponse > => { const url = ` ${ baseUrl } /issues?` ; const params = qs.stringify ( { apiKey , projectId , summary: "テスト3" , issueTypeId: "123456" , priorityId: "2" , customField_12345: "1" , customField_67890: [ "1" , "2" ] , } , { indices: false } ); return await axios.post ( url + params ); } ; createIssue3 (); 無事に複数の値が設定されました。 これでひとまず課題登録に関する一連の試みは完了です。 おまけで検証してみた ちょっとしたおまけです。 上述のとおり、Backlog API では application/x-www-form-urlencoded でリク エス トを送信しますが、 application/json でのリク エス トに変更したらどうなるのでしょうか。 課題の登録には不要な検証ですが、気になったので試してみました。 const createIssue4 = async () : Promise < AxiosResponse > => { // apiKeyをdataに含めると401エラーになります const url = ` ${ baseUrl } /issues?apiKey= ${ apiKey } ` ; const data = { projectId , summary: "テスト4" , issueTypeId: "123456" , priorityId: "2" , customField_12345: "1" , customField_67890: [ "1" , "2" ] , } ; return await axios.post ( url , data ); } ; createIssue4 (); 結果としては、課題の登録自体はできるものの、カスタム属性の値が反映されませんでした。 (中途半端に成功する理由については不明です…もしご存知の方がいらっしゃれば、ぜひ本記事を引用して記事を執筆してみてください…!笑) おわりに 本記事では、Backlog API を利用したBacklogへの課題の登録方法について、サンプルコードとともにご紹介しました。 その際の主な注意点は以下です。 API キーのような認証情報は ソースコード 内に直接記載しない(Backlog API に限らず) Content-Type は application/x-www-form-urlencoded カスタム属性の値は選択肢名ではなく選択肢IDで指定 標準機能でパラメータに複数の値を指定するには、 append() メソッドで1つ目の選択肢と2つ目の選択肢を分けて指定 少しでもBacklog API の利用を検討している方々の参考になれば幸いです。 最後までお読みいただき、本当にありがとうございました! 私たちは同じ事業部で共に働いていただける仲間を募集しています! みなさまのご応募、お待ちしています! <電通×IT>電通グループ基幹システムプロジェクトマネージャー エンタープライズ向けDX推進リーダー/エンジニア <電通×IT>クラウドアーキテクト <電通×IT>アプリケーションアーキテクト 製品・プラットフォーム開発エンジニア 執筆: @miyazawa.hibiki 、レビュー: Ishizawa Kento (@kent) ( Shodo で執筆されました )
アバター