レンダラは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
をそれぞれ使いやすい場所に移動する。
このように、CyclesでImage Textureノードを追加し、画像を設定した上でノードを選択状態にしておき、スクリプトを走らせると、
Vrayのノードとして追加される。
import bpy # vray for blenderに必要 from vb30.lib import LibUtils from vb30.lib import BlenderUtils from vb30.nodes import tree_defaults
# 選択したノードを取得する # Cycles側でImageTextureノードを特定するコードを書いても良いが # ImageTextureノードを追加して選択した上でこれを呼び出した方が多分単純なのでこれを使う # CyclesのImage Textureノードを取得できれば何でも良い def get_selected_node(material): node_tree = material.node_tree sel = [x for x in node_tree.nodes if x.select] return sel[0]
# 追加した Vray ノードを接続する # _VrayImageNode は _vrayNodeTree から探すこともできるけれど # せっかく特定できているので引数で渡す def connect_image_and_material(_vrayNodeTree,_VrayImageNode): # vrayのStandard Materiahを取得。デフォルトで存在しているはず matStandard = None for v in _vrayNodeTree.nodes: if v.name == 'Standard Material': matStandard = v vstand = matStandard vstand.location.x = -250 vstand.location.y = 0 vtex = _VrayImageNode vtex.location.x = vstand.location.x - vstand.width - 50 vtex.location.y = 0 # ノードを接続 _vrayNodeTree.links.new( vtex.outputs['Color'] , vstand.inputs['Diffuse'] )
# マテリアルからImage Textureノードを特定し、Vrayのノードを追加する def set_vray_image_node(mat): # Image Textureノードがマウスで選択されている事が前提 CyclesNode = get_selected_node(mat) # Vrayに切り替え bpy.context.scene.render.engine = "VRAY_RENDER_RT" # vray用のマテリアル追加 tree_defaults.AddMaterialNodeTree(mat) mat.vray.ntree.name = mat.name + '-vray' # vrayのテクスチャノード追加 VrayImageNode = mat.vray.ntree.nodes.new(type='VRayNodeMetaImageTexture')
# vrayのテクスチャノードにテクスチャを指定。 VrayImageNode.texture.image = bpy.data.images[CyclesNode.image.name]
# ノードを繋ぎレンダリングできるようにする connect_image_and_material(mat.vray.ntree,VrayImageNode)
material = bpy.data.materials['Material'] set_vray_image_node(material)
文字列を画像として出力する。
仕組みとしては、画像と高さ、幅情報、移動量情報を全て配列にし、一行分描画してから高さ計算を行う。
#pragma once #include <ft2build.h> #include FT_FREETYPE_H #include <freetype/ftbitmap.h> #include <vector>
// 人文字の画像とサイズ・位置の情報 struct charpict { std::vector<char> m_pic; int width; int height; int left; int top; int advancex; int advancey; };
// 文字列をラスタライズするクラス class SingleLineText { std::vector<charpict> m_pict; int imageWidth; //!< 結果画像の幅 int imageHeight;//!< 結果画像の高さ std::vector<unsigned char> m_image;//!< 結果画像 FT_Library* m_plib; FT_Face face; // handle to face object
//! @brief m_imageに書き込むための座標計算関数 //! @param [in] x 二次元座標のx //! @param [in] y 二次元座標のy //! @return 一次元配列のindex int pixel_pos(const int x, const int y) { return y * imageWidth + x; }
//! @brief 作成済みの一文字の画像を全体画像に書き込む //! @param [in] index m_pictのindex。何文字目をレンダリングするか //! @param [in] pen_x この文字のm_image上の描画開始位置 //! @param [in] maxtop 全ての文字の中の高さの最大値 //! @return なし void draw_single_character(const int index, const int pen_x, const int maxtop) { char* buffer = &m_pict[index].m_pic[0]; int Width = m_pict[index].width; int Height = m_pict[index].height; int startx = pen_x + m_pict[index].left; int starty = -m_pict[index].top + maxtop; for (size_t y = 0; y < Height; y++) { for (size_t x = 0; x < Width; x++) { int xx = startx + x; int yy = starty + y; if (xx < 0)continue; if (yy < 0)continue; if (xx >= imageWidth)continue; if (yy >= imageHeight)continue; if (buffer[y * Width + x]) { m_image[pixel_pos(xx, yy)] = buffer[y * Width + x]; } } } }
//! @brief 全ての文字を結果に書き込む //! @param [in] maxtop 全ての文字の中の高さの最大値 //! @return なし void characters_to_image(const int maxtop) { int pen_x = 0; for (size_t i = 0; i < m_pict.size(); i++) { if (m_pict[i].m_pic.size()) { // 画像書き込み draw_single_character(i, pen_x,maxtop); } // 描画位置を更新 pen_x += m_pict[i].advancex; } }
public:
//! @brief コンストラクタ //! @param [in] ftLib FreeTypeライブラリオブジェクトへのポインタ //! @param [in] fontfilename フォントファイル名 SingleLineText(FT_Library* ftLib,const char* fontfilename) { m_plib = ftLib; FT_Error error; // フォントファイル読み込み error = FT_New_Face( *m_plib, fontfilename, 0, &face ); //文字コード指定 error = FT_Select_Charmap( face, // target face object FT_ENCODING_UNICODE // エンコード指定 ); if (error == FT_Err_Unknown_File_Format) { throw "FT_Err_Unknown_File_Format"; } else if (error) { throw "FT_Err"; } }
//! @brief ラスタライズ
//! @param [in] text 元のテキスト
//! @param [in] pixel_size_y 文字サイズ
//! @return なし
void rasterize(std::wstring text,const int pixel_size_y) {
FT_Error error;
error = FT_Set_Pixel_Sizes(
face, // handle to face object
0, // pixel_width
pixel_size_y); // pixel_height
int maxtop = INT_MIN;
imageHeight = INT_MIN;
imageWidth = 0;
m_pict.clear();
//textの各文字について画像を作成
for (size_t k = 0; k < text.size(); k++) {
// 文字の取得
FT_ULong character = text[k];
FT_UInt char_index = FT_Get_Char_Index(face, character);
// グリフ(字の形状)読込
//FT_LOAD_COLOR
error = FT_Load_Glyph(face, char_index, FT_LOAD_RENDER | FT_LOAD_COLOR);
if (error)
return; // ignore errors
// 文字を画像化
//FT_RENDER_MODE_MONO
//FT_RENDER_MODE_NORMAL
FT_Render_Glyph(face->glyph, FT_RENDER_MODE_NORMAL);
//データを8bit画像にする
FT_Bitmap tmpbmp;
FT_Bitmap_Init(&tmpbmp);
FT_Bitmap_Convert(*m_plib, &face->glyph->bitmap, &tmpbmp, 1);
m_pict.emplace_back();
////////////////////////////////////////
//画像を配列に保存
const int Width = tmpbmp.width;
const int Height = tmpbmp.rows;
for (size_t y = 0; y < Height; y++) {
for (size_t x = 0; x < Width; x++) {
m_pict.back().m_pic.push_back(tmpbmp.buffer[y * Width + x]);
}
}
FT_Bitmap_Done(*m_plib, &tmpbmp);
m_pict.back().width = Width;
m_pict.back().height = Height;
m_pict.back().left = face->glyph->bitmap_left;
m_pict.back().top = face->glyph->bitmap_top;
m_pict.back().advancex = face->glyph->advance.x >> 6;
m_pict.back().advancey = face->glyph->advance.y >> 6;
////////////////////////////////////////
maxtop = (std::max)(maxtop, m_pict.back().top);
imageHeight = (std::max)(
imageHeight,
-m_pict[k].top + maxtop + m_pict[k].height
);
imageWidth += m_pict.back().advancex;
}
//結果画像のメモリ確保
m_image.resize(imageWidth * imageHeight, 0);
//画像に全ての文字を書き込む
characters_to_image(maxtop);
}
void done_face() { FT_Done_Face(face); }
int ImageWidth() { return imageWidth; } int ImageHeight() { return imageHeight; } const unsigned char* image()const { return &m_image[0]; } };
#include <string> #include <array> #include "SingleLineText.hpp" #include "pnm_rw.hpp" #pragma warning(disable:4996) #pragma comment(lib,"freetyped.lib") int main() { FT_Library library; // handle to library FT_Error error; error = FT_Init_FreeType(&library); if (error) return -1; ////msgothic.ttc //meiryo SingleLineText slt(&library, "C:\\Windows\\Fonts\\msgothic.ttc"); int pixel_size_y = 24; std::wstring chars = L"いろ は。にほへと,abc d"; slt.rasterize(chars, pixel_size_y);//画像の作成 //ファイル出力 write_pnm( "C:\\test\\text.pgm", slt.image(), slt.ImageWidth(), slt.ImageHeight(), PNM_TYPE::P2 ); slt.done_face(); // FreeType2の解放 FT_Done_FreeType(library); }
#include <ft2build.h> #include FT_FREETYPE_H //FT_Bitmap_Convert #include <freetype/ftbitmap.h> #pragma warning(disable:4996) #pragma comment(lib,"freetype.lib")
//! @brief PGM(1byte,テキスト)を書き込む //! @param [in] fname ファイル名 //! @param [in] width 画像の幅 //! @param [in] height 画像の高さ //! @param [in] p 画像のメモリへのアドレス //! @details 1画素1Byteのメモリを渡すと、テキストでファイル名fnameで書き込む void pgmP2_Write(const char* const fname, const int width, const int height,const int vmax, const unsigned char* const p) { // PPM ASCII FILE* fp = fopen(fname, "wb"); fprintf(fp, "P2\n%d %d\n%d\n", width, height,vmax); 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); }
int main() { FT_Library library; // handle to library FT_Error error; error = FT_Init_FreeType(&library); if (error) return -1; FT_Face face; // handle to face object //msgothic.ttc //meiryo.ttc // フォントファイル読み込み error = FT_New_Face( library, "C:\\Windows\\Fonts\\msgothic.ttc", 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; int pixel_heigth = 32; //この二つの値でフォントサイズ調整 FT_Set_Pixel_Sizes( face, // handle to face object 0, // pixel_width pixel_heigth // pixel_height ); // 文字の取得 FT_ULong character = wchar_t(L'あ'); FT_UInt char_index = FT_Get_Char_Index(face, character);
// グリフ(字の形状)読込 error = FT_Load_Glyph(face, char_index, FT_LOAD_RENDER | FT_LOAD_COLOR); if (error) return -1; // ignore errors
// 文字を画像化 FT_Render_Glyph(face->glyph, FT_RENDER_MODE_NORMAL); FT_Bitmap glyphbitmap; FT_Bitmap_Convert(library, &face->glyph->bitmap, &glyphbitmap, 1); int Width = glyphbitmap.width; int Height = glyphbitmap.rows; pgmP2_Write(// ファイル保存 "C:\\test\\freetypetest.pbm", Width, Height, 255, glyphbitmap.buffer ); // FreeType2の解放 FT_Done_Face(face); FT_Done_FreeType(library); }
//! @brief PBM(1byte,テキスト)を書き込む //! @param [in] fname ファイル名 //! @param [in] width 画像の幅 //! @param [in] height 画像の高さ //! @param [in] p 画像のメモリへのアドレス //! @details 1画素1Byteのメモリを渡すと、0,1テキストでファイル名fnameで書き込む 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); }
この時、以下のコードで、以下のpixel_heightで出力すると、正常に出力されない。文字サイズが小さすぎると結果が壊れる。
#include <ft2build.h> #include FT_FREETYPE_H #pragma warning(disable:4996) #pragma comment(lib,"freetype.lib") int main() { FT_Library library; // handle to library FT_Error error; error = FT_Init_FreeType(&library); if (error) return -1; FT_Face face; // handle to face object //msgothic.ttc //meiryo.ttc // フォントファイル読み込み error = FT_New_Face( library, "C:\\Windows\\Fonts\\msgothic.ttc", 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;
int pixel_heigth =16;
//この二つの値でフォントサイズ調整 FT_Set_Pixel_Sizes( face, // handle to face object 0, // pixel_width pixel_heigth // pixel_height ); // 文字の取得 FT_ULong character = wchar_t(L'あ'); FT_UInt char_index = FT_Get_Char_Index(face, character); // グリフ(字の形状)読込 error = FT_Load_Glyph(face, char_index, FT_LOAD_RENDER); if (error) return -1; // ignore errors // 文字を画像化 FT_Render_Glyph(face->glyph, FT_RENDER_MODE_NORMAL); FT_Bitmap& glyphbitmap = face->glyph->bitmap; int Width = glyphbitmap.width; int Height = glyphbitmap.rows; pbmP1_Write(// ファイル保存 "C:\\test\\freetypetest.pbm", Width, Height, glyphbitmap.buffer ); // FreeType2の解放 FT_Done_Face(face); FT_Done_FreeType(library); }
これは(多分)、フォントサイズが小さいときはビットマップフォントが使われ、pixel_typeが変わってしまっているから。
FT_Bitmap_Convertで画像データを変換すれば、取り出したフォントの形式にかかわらず、8bppにできる。
FT_Bitmap glyphbitmap;// 新しい画像データ FT_Bitmap_Init(&glyphbitmap);// 新しい画像データの初期化 FT_Bitmap_Convert(library, &face->glyph->bitmap, &glyphbitmap, 1);// 文字画像を8bppに変換 int Width = glyphbitmap.width; int Height = glyphbitmap.rows; pgmP2_Write(// ファイル保存 "C:\\test\\freetypetest.pbm", Width, Height, 255, glyphbitmap.buffer ); FT_Bitmap_Done(library, &glyphbitmap);// 文字画像を解放
int main() { FT_Library library; // handle to library FT_Error error; error = FT_Init_FreeType(&library); if (error) return -1; FT_Face face; // handle to face object //msgothic.ttc //meiryo.ttc // フォントファイル読み込み error = FT_New_Face( library, "C:\\Windows\\Fonts\\msgothic.ttc", 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; int pixel_heigth = 16; //この二つの値でフォントサイズ調整 FT_Set_Pixel_Sizes( face, // handle to face object 0, // pixel_width pixel_heigth // pixel_height ); // 文字の取得 FT_ULong character = wchar_t(L'あ'); FT_UInt char_index = FT_Get_Char_Index(face, character); // グリフ(字の形状)読込 error = FT_Load_Glyph(face, char_index, FT_LOAD_RENDER | FT_LOAD_COLOR); if (error) return -1; // ignore errors // 文字を画像化 FT_Render_Glyph(face->glyph, FT_RENDER_MODE_NORMAL);
FT_Bitmap glyphbitmap; FT_Bitmap_Init(&glyphbitmap); FT_Bitmap_Convert(library, &face->glyph->bitmap, &glyphbitmap, 1); int Width = glyphbitmap.width; int Height = glyphbitmap.rows; pgmP2_Write(// ファイル保存 "C:\\test\\freetypetest.pbm", Width, Height, 255, glyphbitmap.buffer ); FT_Bitmap_Done(library, &glyphbitmap);
// FreeType2の解放 FT_Done_Face(face); FT_Done_FreeType(library); }
フォントサイズによってpixel_modeが違うことがある。以下のコードで確認する。
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"); break; case FT_PIXEL_MODE_GRAY: printf("FT_PIXEL_MODE_GRAY"); 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"); break; } getchar();
pixel height | pixel_mode |
---|---|
16 | FT_PIXEL_MODE_MONO |
32 | FT_PIXEL_MODE_GRAY |