絵文字を扱う上で最も重要なことは、絵文字が使えるフォントを指定する点。ただしサンプルで使用しているseguiemj.ttfはアルファベットは使えるが日本語が使えないので、実用的な事を言えば絵文字と絵文字以外でフォントを切り替える必要がある。
あと、UTF32で文字を指定しないと失敗するように思う。
#pragma once #include<cstdio> #include <bitset> //! @brief PBM(1byte,テキスト)を書き込む void pbmP1_Write(const char* const fname, const int width, const int height, const unsigned char* const p) { // PPM ASCII FILE* fp = fopen(fname, "wb"); fprintf(fp, "P1\n%d\n%d\n", width, height); size_t k = 0; for (size_t i = 0; i < (size_t)height; i++) { for (size_t j = 0; j < (size_t)width; j++) { fprintf(fp, "%d ", p[k] ? 0 : 1); k++; } fprintf(fp, "\n"); } fclose(fp); } //! @brief PGM(1byte,テキスト)を書き込む void pgmP2_Write( const char* const fname, const int width, const int height, const unsigned char* const p ) { // PPM ASCII FILE* fp = fopen(fname, "wb"); fprintf(fp, "P2\n%d %d\n255\n", width, height); size_t k = 0; for (size_t i = 0; i < (size_t)height; i++) { for (size_t j = 0; j < (size_t)width; j++) { fprintf(fp, "%d ", p[k]); k++; } fprintf(fp, "\n"); } fclose(fp); } //! @brief PPM(1byte,テキスト)を書き込む void ppmP3_Write( const char* const fname, const int width, const int height, const unsigned char* const p ) { FILE* fp = fopen(fname, "wb"); fprintf(fp, "P3\n%d %d\n255\n", width, height); size_t k = 0; for (size_t i = 0; i < (size_t)height; i++) { for (size_t j = 0; j < (size_t)width; j++) { //RGBAなので、* 3でなく* 4にしている fprintf(fp, "%d %d %d ", p[k * 4 + 2], p[k * 4 + 1], p[k * 4 + 0]); k++; } fprintf(fp, "\n"); } fclose(fp); }
#include <ft2build.h> #include FT_FREETYPE_H // MONO変換用 #include FT_BITMAP_H #pragma warning(disable:4996) #pragma comment(lib,"freetype.lib") #include "pnmwrite.hpp" int main() { FT_Library library; // handle to library FT_Error error; error = FT_Init_FreeType(&library); if (error) return -1; FT_Face face; // フォントファイル読み込み error = FT_New_Face( library, "C:\\Windows\\Fonts\\seguiemj.ttf", // 絵文字が使えるフォントを指定 0, &face ); //文字コード指定 error = FT_Select_Charmap( face, // target face object FT_ENCODING_UNICODE // エンコード指定 ); if (error == FT_Err_Unknown_File_Format) return -1; else if (error) return -1; //この二つの値でフォントサイズ調整 FT_F26Dot6 fontsize = 16 * 64 * 2; FT_UInt CHAR_RESOLUTION = 300; error = FT_Set_Char_Size( face, // handle to face object 0, // char_width in 1/64th of points fontsize, // char_height in 1/64th of points CHAR_RESOLUTION, // horizontal device resolution CHAR_RESOLUTION); // vertical device resolution // 文字の取得 FT_ULong character = U'😀'; // UTF32で文字を指定 FT_UInt char_index = FT_Get_Char_Index(face, character); //モノクロ error = FT_Load_Glyph(face, char_index, FT_LOAD_RENDER | FT_LOAD_MONOCHROME); //グレイスケール //error = FT_Load_Glyph(face, char_index, FT_LOAD_RENDER ); //カラー //error = FT_Load_Glyph(face, char_index, FT_LOAD_RENDER | FT_LOAD_COLOR); if (error) return -1; // ignore errors int Width = face->glyph->bitmap.width; int Height = face->glyph->bitmap.rows; switch (face->glyph->bitmap.pixel_mode) { case FT_PIXEL_MODE_NONE: printf("FT_PIXEL_MODE_NONE"); break;
case FT_PIXEL_MODE_MONO: printf("FT_PIXEL_MODE_MONO"); { FT_Bitmap glyphbitmap; FT_Bitmap_Init(&glyphbitmap); FT_Bitmap_Convert(library, &face->glyph->bitmap, &glyphbitmap, 1); FT_Render_Glyph(face->glyph, FT_RENDER_MODE_MONO); pbmP1_Write( "C:\\test\\freetypetest.pbm", Width, Height, glyphbitmap.buffer ); } break;
case FT_PIXEL_MODE_GRAY: printf("FT_PIXEL_MODE_GRAY"); pgmP2_Write( "C:\\test\\freetypetest.pgm", Width, Height, face->glyph->bitmap.buffer ); break;
case FT_PIXEL_MODE_GRAY2: printf("FT_PIXEL_MODE_GRAY2"); break; case FT_PIXEL_MODE_GRAY4: printf("FT_PIXEL_MODE_GRAY4"); break; case FT_PIXEL_MODE_LCD: printf("FT_PIXEL_MODE_LCD"); break; case FT_PIXEL_MODE_LCD_V: printf("FT_PIXEL_MODE_LCD_V"); break;
case FT_PIXEL_MODE_BGRA: printf("FT_PIXEL_MODE_BGRA"); ppmP3_Write( "C:\\test\\freetypetest.ppm", Width, Height, face->glyph->bitmap.buffer ); break;
} // FreeType2の解放 FT_Done_Face(face); FT_Done_FreeType(library); }
Normal MapのBakeをやったのでついでにHeight MapのBakeを調べた。
端的に言えばモデルを作り、そのマテリアルにGeometryのPositionをSeparateでZだけ取り出してEmissonのColorとして繋げたものを繋いでやればいい(らしい)。
あとはベイク時の設定、UV展開やBake Typeなどをやっておく必要がある。
テクスチャペイントでテクスチャデータに画像を書き込んでいく。
一言でいえば、Blender内で新しいテクスチャをnewし、マテリアルに指定しておく。
テクスチャファイルを読み込む

特殊キー+右ボタンドラッグで画像の変形、左ドラッグでテクスチャに画像を書き込む

Making this beautiful castle scene in blender 2.81のチュートリアルの一部を試す のチュートリアル中なのだがこれだけ別エントリにしておきたい。
法線マップをベイクする方法。特に、モデルにMultiresモディファイアを使い、Sculptingでメッシュに凹凸を付けた場合。
Multiresでメッシュに凹凸を付けた場合のみ、気をつけなければいけないのは設定のLevel viewportを小さくしておかなければならないこと。この数字がSculptやRenderと同じように大きいと欲しい結果が得られない。
あとは普通のNormal MapのBakeの設定と同じ。
① UV展開をする

② マテリアルにImage Textureノードを追加し、新規画像を作成する
③ Image Textureノードをクリックして強調状態にしておく
④ Cyclesに切り替える
⑤ Multiresを使っている場合は、Bake→Bake from Multiresにチェックを付ける
⑥ Bake→Bake TypeをNormalに設定
⑦ Bakeボタンを押す
⑧ Untitled画像を確認するとNormal mapがbakeされている。ちょっとした要因で消えるらしいので急いでファイルに保存する(Image→Save As)。
このチュートリアルの冒頭の地形の部分だけを試す。
multiresolutionモディファイアを追加し、Subdivideを数回クリックし5まで上げる。
Sculptモードへ移行し、Clay Stripsを選択。
Texture Propertiesへ行き、ペンとなる画像を選択する。
画像はGimpで適当に作成した。
その他にScriptの設定として、
Stroke→Stroke MethodをAnchored
Texture→MappingをView Plane
にする。

BlenderのSaplingで葉にオブジェクトを指定したとき、元のオブジェクトが葉とリンクしたまま残ってしまうので、どうやって消すかという話。
① SaplingでLeavesをDupliFacesにする
② 葉を選択
③ Object → Apply → Make Instances Real を選択
④ 元になったオブジェクトを選択
⑤ [x]→Delete
#include <iostream> #include <Windows.h> #include <gl/GL.h> #include <gl/GLU.h> #include <gl/freeglut.h> //ウィンドウの幅と高さ int width, height;
void draw() { double v = 0.7; glBegin(GL_QUADS); glColor3d(0, 0, 1); glVertex2d(-v, -v); glColor3d(1, 0, 1); glVertex2d(v, -v); glColor3d(1, 1, 1); glVertex2d(v, v); glColor3d(0, 1, 1); glVertex2d(-v, v); glEnd(); }
//描画関数 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); glPolygonMode(GL_FRONT, GL_LINE);//ワイヤーフレーム描画に設定 draw(); glPolygonMode(GL_FRONT, GL_FILL);//塗りつぶし描画に戻す glFlush(); }
//ウィンドウサイズの変化時に呼び出される void reshape(int w, int h) { width = w; height = h; disp(); } //エントリポイント int main(int argc, char** argv) { glutInit(&argc, argv); glutInitWindowPosition(100, 50); glutInitWindowSize(500, 500); glutInitDisplayMode(GLUT_SINGLE | GLUT_RGBA); glutCreateWindow("sample"); glutDisplayFunc(disp); glutReshapeFunc(reshape); glutMainLoop(); return 0; }
Shroomは、円を元に適当に作成する。
また、上記中Emptyは[Shift+A]→[Empty]→[Sphere]で導入する
Suzanneに対してGeometry Node Editorを開く。NewするとGroup InputとGroup Outputがあるので、この間にノードを追加していく。
ノードを追加していく
ここまでの結果
Geometry Nodeの使い方が全くと言っていいほどわからなかったので調べた。
Geometry Node Editor からオブジェクトに対してジオメトリノードツリーを作成するとノードベースのモデリングが可能。
まずCubeに対してPoint Distributeを使ってみる。とりあえずGroup InputとGroup Outputの間にPoint Distributeを挟んでみると、形状の表面に点が散布される。しかしこのままレンダリングしても何も表示されない。Point Instanceを繋げば表示されるが今はその前にこの散布された点について確認しておきたい。
Attributeは属性のことで、つまり「それ」がどんな性質を持っているかという事で、別の表現をするならパラメータとかになると思う。Point Distributeで生成された点はそれぞれにAttribute(=属性)を持っている。どんな属性を持っているかというと「Built-In Attributes」と呼ばれている属性一覧がある。
以下、Blender 3.0 Manual Attributes
https://docs.blender.org/manual/en/dev/modeling/geometry_nodes/attributes_reference.html
|
Name |
Type |
Domain |
Notes |
|---|---|---|---|
|
position |
Vector |
Point |
モディファイヤオブジェクトの変換空間で、頂点またはポイントの位置を記述する組み込み属性。ポイントの位置を変更するノードは、TransformノードやPoint Translateノードのように、この属性を調整します。 |
|
radius |
Float |
Point |
Point Distributeノードによって作成されたポイントクラウドデータの組み込み属性ビューポート内のポイントのサイズを設定するために使用されます。 |
|
material_index |
Integer |
Face |
メッシュ内のすべての面のマテリアルスロットを指定するために使用されます。 |
|
crease |
Float |
Edge |
サブディビジョンサーフェスノードとモディファイヤによって使用されるエッジ属性。値は0から1の範囲に制限されています。 |
|
normal |
Vector |
Face |
faceの法線。これは、変更できないという点で他の組み込み属性とは少し異なります。メッシュから自動的に派生します。この属性が非点ドメインでアクセスされる場合、隣接する面の法線から補間されるため、正規化されない可能性があります。 |
|
shade_smooth |
Boolean |
Face |
faceでスムーズシェーディングを有効にするかどうかを決定する属性。 |
Point Distributeにはradiusがあるらしいので、これを変更してみる。値を変更するにはAttribute Mathなどを使えばいい。
Point Distributeで生成されるのは点である。点はAttributeを持ってはいるが形状を持っていないのでそのままでは表示できない。Point Instanceを使えば点のpositionにObjectを配置できる。ただしこうするとradiusでサイズ指定ができない(次項)。
ノードによってNaming Conventionsを使用できる。Point Instanceノードではscaleを使用できる。
|
Name |
Type |
Notes |
|---|---|---|
|
rotation |
Vector |
インスタンス化されたオブジェクトまたはコレクションの回転を制御するために、Point Instance Nodeで使用されます。Point Rotate NodeとAlignRotation to VectorNodeによって調整されます。 |
|
scale |
Vector |
インスタンスのスケールを制御するためにPoint Distribute Nodeで使用されます。Point Scale Nodeまたは他の属性ノードによって調整されます。 |
|
id |
Integer |
入力メッシュの形状が変化したときに安定性を提供するために、Point Distribute Nodeによって作成されます。値は大きく、順序はありません。属性値は、Attribute Randomize Nodeなど、ランダム性を生成するノードによって使用されます。 |
radiusをscaleに変換すれば、サイズの変更ができる。
scaleを変えるだけなら、scaleを直接いじったほうがいいかもしれない。