久しぶりにCUDAを勉強しようと思ったら忘れていたので、block,gridの設定がカーネル内でどうなるかを確認するプログラムを書いた。
#include "cuda_runtime.h"
#include "device_launch_parameters.h" #include <stdio.h> #include <stdlib.h>
/////////////////////////////////////////////// // GPU側 ////////////////////////////////////// __global__ void threadpos( unsigned char* c, const int width, const int height) { //アクセス法 //このスレッドが担当する画素の位置を二次元座標で求める size_t xpos = blockIdx.x * blockDim.x + threadIdx.x; size_t ypos = blockIdx.y * blockDim.y + threadIdx.y; if (xpos >= width || ypos >= height)return; int pos = ypos * width + xpos; c[pos * 6 + 0] = blockIdx.x; c[pos * 6 + 1] = blockIdx.y; c[pos * 6 + 2] = threadIdx.x; c[pos * 6 + 3] = threadIdx.y; c[pos * 6 + 4] = xpos; c[pos * 6 + 5] = ypos; } /////
int main() { int width = 10; int height = 10; int item = 6; // 最小単位 合計で512未満 //5×5の領域に分けて計算する dim3 block(5, 5); //グリッド数 dim3 grid(2, 2); unsigned char* p_cpu = new unsigned char[width*height*item]; for (int i = 0; i < width*height*item; i++) { p_cpu[i] = 0; } unsigned char* p_gpu;//GPU側メモリ確保 cudaMalloc((void**)&p_gpu, width*height * item); threadpos << <grid, block >> > (p_gpu, width,height); //GPU→CPU側へメモリコピー cudaMemcpy(p_cpu, p_gpu, width*height * item, cudaMemcpyDeviceToHost); cudaFree(p_gpu); /////////////////////////////////////////////// // 結果出力 FILE* fpblock = fopen("block.txt", "w"); FILE* fpthread = fopen("thread.txt", "w"); FILE* fpxy = fopen("xy.txt", "w"); for (size_t y = 0; y < height; y++) { for (size_t x = 0; x < width; x++) { int pos = y * width + x; fprintf(fpblock,"[%2d %2d]", p_cpu[pos * item + 0], p_cpu[pos * item + 1] ); fprintf(fpthread, "[%2d %2d]", p_cpu[pos * item + 2], p_cpu[pos * item + 3] ); fprintf(fpxy, "(%2d %2d)", p_cpu[pos * item + 4], p_cpu[pos * item + 5] ); } fprintf(fpblock,"\n"); fprintf(fpthread, "\n"); fprintf(fpxy, "\n"); } fclose(fpblock); fclose(fpthread); fclose(fpxy); delete[] p_cpu; return 0; }
OrbitControls.jsを使うとかなり簡単にマウスドラッグでカメラ回転がで着るようになる。
以下より、three.js-master.zipをダウンロードし展開する。
以下サイトのCubeを表示するHTML+JavaScripファイルを作り.htmlファイルで保存する。
https://ics.media/tutorial-three/camera_orbitcontrols/
そのままコピペすると以下のエラーが出る。
恐らく原因は、three.jsはweb上の指定バージョンの物を使っているのに、OrbitControls.jsはダウンロードした最新バージョンを使っていて、かつ、自分で書いたスクリプトの部分が古いバージョンに対応したコードになっているから。
<html> <head> <meta charset="utf-8" /> <script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/110/three.min.js"></script> <script src="js/controls/OrbitControls.js"></script> <script> // ...
// カメラコントローラーを作成 const controls = new THREE.OrbitControls(camera); // ...
</script> </head> <body> <canvas id="myCanvas"></canvas> </body> </html>
なのでthree.jsもダウンロードしてorbitcontrols.js共にローカルのファイルを使用して、スクリプト本体もdomElement指定を追加してやる。
<html> <head> <meta charset="utf-8" /> <script src="three.js-master/build/three.min.js"></script> <script src="three.js-master/examples/js/controls/OrbitControls.js"></script> <script> // ...
// カメラコントローラーを作成 const controls = new THREE.OrbitControls(camera,renderer.domElement); // ...
</script> </head> <body> <canvas id="myCanvas"></canvas> </body> </html>
上にも書いたが、domElementを渡していないソースコードが多いが、最新のバージョンではこれが必須になっているらしい。
<html> <head> <meta charset="utf-8" /> <script src="three.js-master/build/three.min.js"></script> <script src="three.js-master/examples/js/controls/OrbitControls.js"></script> <script> // ページの読み込みを待つ window.addEventListener('load', init); function init() { // サイズを指定 const width = 960; const height = 540; // レンダラーを作成 const renderer = new THREE.WebGLRenderer({ canvas: document.querySelector('#myCanvas') }); renderer.setSize(width, height); // シーンを作成 const scene = new THREE.Scene(); // カメラを作成 const camera = new THREE.PerspectiveCamera(45, width / height); // カメラの初期座標を設定 camera.position.set(0, 0, 1000); // カメラコントローラーを作成 const controls = new THREE.OrbitControls(camera,renderer.domElement); // 形状とマテリアルからメッシュを作成します const mesh = new THREE.Mesh( new THREE.BoxGeometry(300, 300, 300), new THREE.MeshNormalMaterial() ); scene.add(mesh); tick(); // 毎フレーム時に実行されるループイベントです function tick() { // レンダリング renderer.render(scene, camera); requestAnimationFrame(tick); } } </script> </head> <body> <canvas id="myCanvas"></canvas> </body> </html>
このディレクトリに保存したブラシファイルがブラシとして認識される。
画像を上記ディレクトリに拡張子.gbrでExportする。
ブラシ一覧の下にある「Refresh Brushes」をクリックするとブラシファイルが読み込まれる。
画像をグレースケールモードで.gbr保存すれば色が使える。黒がパレットの色、白が透明となる。
注意 ブラシを作ったままだとGrayscaleモードになっているので色が出ない。RGBに戻すことを忘れないようにする。
LandscapeでLakeのPresetを選択し池を作る
① Blender標準でRealSnowアドオンが入っているので有効化する。
② 適当になにかモデル(ICO Sphereなど)を追加し、RealSnowを適用
③ 地形を選択し、RealSnowで作成されたマテリアルを設定
④ Sphereと雪のオブジェクトはいらない(欲しいのはMaterialだけ)ので削除する
背景画像を以下からダウンロードしてWorldに設定
https://hdrihaven.com/hdri/?h=lakes
絵文字を扱う上で最も重要なことは、絵文字が使えるフォントを指定する点。ただしサンプルで使用している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
にする。