キーボードやマウスの入力を拾うにはレベルブループリントを使う。
「レベル」とはマップの事で、つまりマップにI/Oの処理を書く事になる(多分)
この設定でマウス入力はできるようになるがあくまでレベルでクリックを検出できるようになるだけで、アクタをクリックされたら何かすると言う事はできない。それは次回やる。
① 前回と同じ方法でSphereを追加し、ブループリントクラスに変換する
② 同様にCubeを追加し、Cube_Blueprintクラスに変換する
ただスポーンさせたいだけなら、例えば以下のように設定する。Sphere BlueprintのBeginPlayにSpawnActorを接続すれば、Sphereが生成された瞬間にCubeをSpawnできる。
上記の例はあまりにも地味なので、前回の方法でSphereのOn Component Hitを有効にした上で、Sphere Blueprintに以下のようなノードを設定する
破棄はDestroyActorで行う。以下では、上記、SphereのOn Component Hit時に生成されたCubeの、生成時に走るBeginPlay後、0.5秒のdelayの後self(=Cube)をDestroyActorする。
UE4のブループリントに少し触れたい。
今回はアクタ(3Dのオブジェクト)が落下して何かに衝突したら文字列を表示させてみる。
UE4のブループリントはイベントドリブン型みたいな感じで、アクタに対してイベントが起こるとOn Compornent Hit イベントハンドラが呼び出されるので、そこに処理の内容を書く、と考えるとわかりやすい。
① アクタを追加して高い位置に移動
② アクタが重力の影響を受けるように設定、On Comprnent Hitを処理できるように設定
③ アクタをブループリントクラスに変換
④ ビューポートでオブジェクトを選択、On Compornent Hit イベントを追加
⑤ On Compornent Hit に Print Textを接続
⑥ コンパイル→プレイ
改めてみると間違っていた気がするのでここに修正版を置く。
あと確認のためにBlenderのスクリプトを組んで確認した。
このd1,d2を、最初の②の式に代入する。
import bpy import mathutils
def _nearestLineLinePoints3_(A,B,C,D): AC = C-A n1 = B-A n1.normalize() n2 = D-C n2.normalize() AmC=A-C CmA=C-A ############################################### numerator = n2.dot(AmC) + n2.dot(n1) * ( n1.dot(CmA) / n1.dot(n1) ) denominator = n2.dot(n2) - n1.dot(n2)**2 / n1.dot(n1) d2 = numerator / denominator ############################################### numerator = n1.dot(CmA) + n1.dot(n2) * d2 denominator = n1.dot(n1) d1 = numerator / denominator ############################################### dn1 = n1 * d1 _PAB = A + dn1 dn2 = n2 * d2 _PCD = C + dn2 return _PAB,_PCD
A = mathutils.Vector((0.390268,-0.093855,-0.48373)) B = mathutils.Vector((-0.401277 ,0.95607,-0.045612)) C = mathutils.Vector((-0.475275 ,-0.448733 ,0.344921)) D = mathutils.Vector((0.231105 ,0.937974 ,-0.776157)) PAB = mathutils.Vector((0,0,0)) PCD = mathutils.Vector((0,0,0)) ret = _nearestLineLinePoints3_(A,B,C,D) PAB = ret[0] PCD = ret[1]
############################################# print( PAB,PCD) #頂点定義 verts = [] verts.append( A ) verts.append( B ) verts.append( C ) verts.append( D ) verts.append( PAB ) verts.append( PCD ) #面を、それを構成する頂点番号で定義 edges =[] edges.append( [0,1] ) edges.append( [2,3] ) edges.append( [4,5] ) #頂点と頂点番号からメッシュを作成 mymesh = bpy.data.meshes.new("mymesh") mymesh.from_pydata(verts,edges,[]) #作成部分 mymesh.update() #オブジェクトを作成し、メッシュを登録 obj = bpy.data.objects.new("My_Object", mymesh) #オブジェクトのマテリアルを作成 mat = bpy.data.materials.new("Mat1") mat.diffuse_color = (0.3,0.7,0.5,1.0) obj.active_material = mat #オブジェクトを登録 bpy.context.scene.collection.objects.link(obj)
レンダラはCyclesを使用する。
1.1 [Shift+A] → [Mesh]→ Ico Sphereを追加し、[S][Z]でZ軸方向に拡大する
1.2 Decimateモディファイアを追加し、CollapseでRatio=0.4706に設定する
1.3 Shift+Dで複製し、外側の透明な部分と内側の色を付ける部分を別に作成する。
内側のみ、Bevelモディファイアを追加する
Areaランプを追加し、Strength=500とする
テクスチャでグリッドを描く。
Planeを一枚追加し、マテリアルでX方向とY方向のWave Textureを追加。
両方のテクスチャをGreaterThanで一定値以下を0,それ以外を1にして、Multiplyする。
Texture CoordinateのObjectから、座標をMultiplyし、Wave Textureに繋げる。
最後に、今作ったテクスチャをMix ShaderのFacに繋げる。
例えばsumの場合、以下のように書ける。
転載元:http://yohshiy.blog.fc2.com/blog-entry-300.html
// 末端 isum inline int isum() { return 0; } // 再帰呼び出し isum template<typename First, typename... Rest> int isum(const First& first, const Rest&... rest) { return first + isum(rest...); }
+や*の場合は交換法則が成り立つ。つまり、
(a+(b+(c+d))) == (((a+b)+c)+d)
だ。しかし、例えば/の場合、交換法則が成り立たない
(a/(b/(c/d))) != (((a/b)/c)/d)
ではどうすればいいか。
// 再起の最後 template<typename First, typename Second> inline auto div(const First& first, const Second& second) { return first / second; } // 連続で割り算を行う関数 template<typename First, typename Second, typename... Rest> inline auto div(const First& first, const Second& second, const Rest& ... rest) { return div( div(first , second) , rest...); }
#include <iostream>
////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////// // 再起の最後 template<typename First, typename Second> inline auto div(const First& first, const Second& second) { return first / second; } // 連続で割り算を行う関数 template<typename First, typename Second, typename... Rest> inline auto div(const First& first, const Second& second, const Rest& ... rest) { return div(div(first, second), rest...); }
////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////// // 後ろから計算する場合 // 再起の最後 inline auto backDIV() { return 1.0; } // 連続で割り算を行う関数 template<typename First, typename... Rest> inline auto backDIV(const First& first, const Rest& ... rest) { return first / backDIV(rest...) ; }
////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////// int main() { std::cout << "普通計算:"; double k1 = 5.0 / 8.0 / 2.0; std::cout << k1; std::cout << std::endl; std::cout << "再帰(前方):"; double k2 = div(5.0, 8.0, 2.0); std::cout << k2; std::cout << std::endl; std::cout << "再帰(後方):"; double k3 = backDIV(5.0, 8.0, 2.0); std::cout << k3; int i; std::cin >> i; }
普通計算:0.3125 再帰(前方):0.3125 再帰(後方):1.25
DAZ Importer 1.4でBlenderへExportした結果のマテリアルがある。
これのテクスチャノードが、Bump用なのか、あるいはDiffuse用なのか...を知りたい。
import bpy
# @brief 与えられたCyclesのノードツリーの中のImage Textureノードを全て取得して返す # @param [in] nodetree Cyclesのノードツリー # @return Image Textureノードの一覧 def get_all_textures(nodetree): nodes = nodetree.nodes texturenodelist = [] for node in nodes: if node.type == 'TEX_IMAGE': texturenodelist.append(node) return texturenodelist
# @brief ノードのto_nodeを辿り、特定のノードが見つかるまで再帰的に検索する # @param [in] node Cyclesのノード # @return 見つかったノード # @retval None 見つからなかった場合 def get_input_to(node): if node.type == 'BUMP': return node if node.type == 'NORMAL_MAP': return node elif node.type == 'BSDF_DIFFUSE': return node elif node.type == 'BSDF_GLOSSY': return node elif node.type == 'BSDF_PRINCIPLED': return node for output in node.outputs: for link in output.links: return get_input_to(link.to_node)# 目的のノード出ないなら再帰呼び出し return None
# @brief テクスチャノードから、そのノードが繋がっているノードを探す # @param [in] texnode CyclesのImage Textureノード # @return 見つかったBump,Normalまたは各種BSDFノード # @retval None 見つからなかった def get_tex_input_to(texnode): for link in texnode.outputs["Color"].links:# テクスチャノードの"Color"に接続されたノードを探す prevnode = link.to_node tonode = get_input_to(prevnode) if tonode is not None: return tonode return None
# @brief マテリアルスロット内の全てのマテリアルについて、テクスチャノードの接続先を検索する # @param [in] slots マテリアルスロット # @return なし def about_all_material(slots): for slot in slots: texturenodelist=[] material = slot.material nodetree = material.node_tree print("------" , material.name , "-------") texturenodelist = get_all_textures(nodetree) for texnode in texturenodelist: inputto = get_tex_input_to(texnode) print( texnode.name , inputto )
print("---------------") print("---------------") print("---------------") # 呼び出し about_all_material(bpy.context.active_object.material_slots)
------ Torso-1 ------- Acicia_NM_1002 <bpy_struct, ShaderNodeNormalMap("Normal Map")> Acicia_B_1002 <bpy_struct, ShaderNodeBump("Bump")> Acicia_1002 Base <bpy_struct, ShaderNodeBsdfPrincipled("Principled BSDF")> Acicia_1002_SSS <bpy_struct, ShaderNodeBsdfPrincipled("Principled BSDF")> Acicia_Torso_Ref_1002 <bpy_struct, ShaderNodeBsdfPrincipled("Principled BSDF")> ------ Face-1 ------- Acicia_NM_1001 <bpy_struct, ShaderNodeNormalMap("Normal Map")> Acicia_B_1001 <bpy_struct, ShaderNodeBump("Bump")> Acicia_1001 Shadow 07 <bpy_struct, ShaderNodeBsdfDiffuse("Diffuse BSDF")> Acicia_1001_SSS Default None Acicia_1001_Spec None ------ Lips-1 ------- Acicia_NM_1001 <bpy_struct, ShaderNodeNormalMap("Normal Map")> Acicia_B_1001 <bpy_struct, ShaderNodeBump("Bump")> Acicia 1001 Lip 02 <bpy_struct, ShaderNodeBsdfDiffuse("Diffuse BSDF")> Acicia_1001_SSS Lip 02 None Acicia_1001_Spec None Acicia_Spc_1001 <bpy_struct, ShaderNodeBsdfGlossy("Glossy BSDF")> ------ Teeth-1 ------- Acicia_MouthNM_1005 <bpy_struct, ShaderNodeNormalMap("Normal Map")> Acicia_MouthB_1005 <bpy_struct, ShaderNodeBump("Bump")> Acicia_1005 <bpy_struct, ShaderNodeBsdfDiffuse("Diffuse BSDF")> ------ Ears-1 ------- Acicia_NM_1001 <bpy_struct, ShaderNodeNormalMap("Normal Map")> Acicia_B_1001 <bpy_struct, ShaderNodeBump("Bump")> Acicia_1001 Shadow 07 <bpy_struct, ShaderNodeBsdfDiffuse("Diffuse BSDF")> Acicia_1001_SSS Default None Acicia_1001_Spec None ------ Legs-1 ------- Acicia_NM_1003 <bpy_struct, ShaderNodeNormalMap("Normal Map")> Acicia_B_1003 <bpy_struct, ShaderNodeBump("Bump")> Acicia_1003 Base <bpy_struct, ShaderNodeBsdfPrincipled("Principled BSDF")> Acicia_1003_SSS <bpy_struct, ShaderNodeBsdfPrincipled("Principled BSDF")> Acicia_Rh_1003 <bpy_struct, ShaderNodeBsdfPrincipled("Principled BSDF")> ------ EyeSocket-1 ------- Acicia_B_1001 <bpy_struct, ShaderNodeBump("Bump")> Acicia_1001 Shadow 07 <bpy_struct, ShaderNodeBsdfDiffuse("Diffuse BSDF")> Acicia_1001_SSS Default None Acicia_1001_Spec None Acicia_NM_1001 <bpy_struct, ShaderNodeNormalMap("Normal Map")> ------ Mouth-1 ------- Acicia_MouthNM_1005 <bpy_struct, ShaderNodeNormalMap("Normal Map")> Acicia_MouthB_1005 <bpy_struct, ShaderNodeBump("Bump")> Acicia_1005 <bpy_struct, ShaderNodeBsdfDiffuse("Diffuse BSDF")> ------ Arms-1 ------- Acicia_NM_1004 <bpy_struct, ShaderNodeNormalMap("Normal Map")> Acicia_B_1004 <bpy_struct, ShaderNodeBump("Bump")> Acicia_1004 Base <bpy_struct, ShaderNodeBsdfPrincipled("Principled BSDF")> Acicia_1004_SSS <bpy_struct, ShaderNodeBsdfPrincipled("Principled BSDF")> Acicia_Rh_1004 <bpy_struct, ShaderNodeBsdfPrincipled("Principled BSDF")> ------ Pupils-1 ------- ------ EyeMoisture-2 ------- ------ Fingernails-1 ------- Acicia_NM_1004 <bpy_struct, ShaderNodeNormalMap("Normal Map")> Acicia_B_1004 <bpy_struct, ShaderNodeBump("Bump")> Acicia_1004 Base <bpy_struct, ShaderNodeBsdfPrincipled("Principled BSDF")> Acicia_1004_SSS <bpy_struct, ShaderNodeBsdfPrincipled("Principled BSDF")> Acicia_Rh_1004 <bpy_struct, ShaderNodeBsdfPrincipled("Principled BSDF")> ------ Cornea-1 ------- ------ Irises-1 ------- Acicia_EyesNM_1006 <bpy_struct, ShaderNodeNormalMap("Normal Map")> Acicia_EyesB_1006 <bpy_struct, ShaderNodeBump("Bump")> Acacia Eyes Color Red 02 <bpy_struct, ShaderNodeBsdfDiffuse("Diffuse BSDF")> ------ Sclera-1 ------- Acicia_1006 <bpy_struct, ShaderNodeBsdfPrincipled("Principled BSDF")> ------ Toenails-1 ------- Acicia_NM_1003 <bpy_struct, ShaderNodeNormalMap("Normal Map")> Acicia_B_1003 <bpy_struct, ShaderNodeBump("Bump")> Acicia_1003 Base <bpy_struct, ShaderNodeBsdfPrincipled("Principled BSDF")> Acicia_1003_SSS <bpy_struct, ShaderNodeBsdfPrincipled("Principled BSDF")> Acicia_Rh_1003 <bpy_struct, ShaderNodeBsdfPrincipled("Principled BSDF")>
特定できなかった物はNoneが入っている
FTGLを使うと日本語を出力できる。
#include <iostream> #include <Windows.h> #include <gl/GL.h> #include <gl/GLU.h> #include <gl/freeglut.h> #include <FTGL/ftgl.h> #pragma comment(lib,"opengl32.lib") #pragma comment(lib,"freeglut.lib") #pragma comment(lib,"ftgl.lib") #pragma warning(disable:4996) // freeglut: // http://freeglut.sourceforge.net/ // freetype2: // https://www.freetype.org/ //FTGL // https://sourceforge.net/projects/ftgl/ // 参考サイト FTGLの使い方 // http://slis.tsukuba.ac.jp/~fujisawa.makoto.fu/lecture/iml/text/screen_character.html //ウィンドウの幅と高さ int width, height;
struct CFtglObject { const char* FONT_PATHNAME = "C:\\Windows\\Fonts\\msgothic.ttc"; FTPixmapFont* g_pFont; unsigned long g_ulFontSize; // フォントサイズ ~CFtglObject() { delete g_pFont; }
// フォントの初期化 void init(const unsigned long fontsize) { g_ulFontSize = fontsize; if (!g_pFont) { g_pFont = new FTPixmapFont(FONT_PATHNAME); if (g_pFont->Error()) { delete g_pFont; g_pFont = nullptr; } else { g_pFont->FaceSize(g_ulFontSize); } } }
// FTGLで文字列を描画 void print(const std::wstring& wstr,float x, float y) { if (g_pFont) { glRasterPos2f(x, y); g_pFont->Render(wstr.c_str()); } }
};
CFtglObject ftglo; static int rot = 0; //描画関数 void disp(void) { glViewport(0, 0, width, height); glClearColor(0.2, 0.2, 0.2, 1); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glLoadIdentity(); glScaled(0.5, 0.5, 0.5); glRotatef(rot, 1, 1, 1); rot++; glDisable(GL_CULL_FACE); double v = 0.7; glBegin(GL_QUADS); glColor3d(1, 0, 0); glVertex2d(-v, -v); glColor3d(0, 1, 0); glVertex2d(v, -v); glColor3d(0, 0, 1); glVertex2d(v, v); glColor3d(1, 1, 1); glVertex2d(-v, v); glEnd();
glColor3d(1, 1, 0); wchar_t text[1000]; swprintf(text, L"赤 %0.3lf %0.3lf",-v, -v); ftglo.print(text, -v, -v ); swprintf(text, L"緑 %0.3lf %0.3lf", v, -v); ftglo.print(text, v, -v); swprintf(text, L"青 %0.3lf %0.3lf", v, v); ftglo.print(text, v, v); swprintf(text, L"白 %0.3lf %0.3lf",-v, v); ftglo.print(text, -v, v);
glFlush(); } //ウィンドウサイズの変化時に呼び出される void reshape(int w, int h) { width = w; height = h; disp(); } //ドラッグ void motion(int x, int y) { disp(); } //エントリポイント int main(int argc, char** argv) { glutInit(&argc, argv); glutInitWindowPosition(100, 50); glutInitWindowSize(500, 500); glutInitDisplayMode(GLUT_SINGLE | GLUT_RGBA);
//FTGL使用クラスの初期設定 ftglo.init(25); glutCreateWindow("sample"); glutDisplayFunc(disp); glutReshapeFunc(reshape); glutMotionFunc(motion); glutMainLoop(); return 0; }
https://sourceforge.net/projects/ftgl/
CMakeの必要はない。
vc8 (Visual Studio 2005)と、vc71(Visual Studio 2003)のソリューションが用意されているので、2005用slnを開いてVC++2019に変換する
ftgl-2.1.3~rc5\msvc\vc8\ftgl.sln
freetype2のincludeとlibディレクトリを設定してビルドする
ビルド済みバイナリ・・・ ftgl-2.1.3-rc5\msvc\Build
includeファイル群・・・ ftgl-2.1.3-rc5\src
をそれぞれ使いやすい場所に移動する。