25:20~
1.別のレイヤーに移動してあるSmall Petalを選択する
この時Editモードへ行き、[U]→UnwrapでUVマップを作成する
2.まずBig Petalとマテリアルを共有し、[2]を押して共有を解除し個別のマテリアルにする。
3.Big PetalからコピーしたSmall Petalの以下の2色を修正する
リアルにするためにBig Petalの数を減らす。
花の中心のオブジェクトを選択し、Particle Systemのpetals_outerのNumberを70→50に変更
1.レンダリングのために配置換えを行う。
この時、花を回転するとHairが歪んでしまうが、確定すると元に戻る。
2.カメラの位置とパラメータを以下のように設定。ただし※の値はカメラの視線の上の+印が花の中央に来るように設定する
1.User PreferencesからImport Images as Planesアドオンを設定し、テクスチャ画像を指定すると同時にPlaneが作成されるようにする
Images as Planesによって、
[Shift+A]→[Mesh]→Images as Planesで画像を読み込める
2.Images as PlanesでできたPlaneを以下のように配置
なお今回使用する画像は
ライトやオブジェクトの位置は詳細がわからないので明るくなるように調整する必要がある。
Blender – Detailed Flower のチュートリアルを試す(1)
Blender – Detailed Flower のチュートリアルを試す(2)
Blender – Detailed Flower のチュートリアルを試す(3)
13:30
1.デフォルトのライトをSunに設定し、Strengthを2.0に設定する。
2.Backgroundに、動画ではHDR画像を使っているらしいが、どのようなものか不明なため似たような効果を得られるものをノードで設定する。
さらにその上で、Render→Film→Transparentをonにする
3.Ctrl+Bで左ドラッグし、3Dのシェーディングを行う範囲を限定する
※解除はCtrl+Alt+Bで行う
1.花の中心のオブジェクトを選択し、マテリアルを以下のように設定する
なお動画ではNode Wranglerを使っているのでCtrl+Shift+左クリックでプレビューを更新できる。使うのであればUser Preferences→Add-onsから追加する。
1.別のレイヤーに移動してあるBig Petalを選択する
この時Editモードへ行き、[U]→UnwrapでUVマップを作成する
2.花全体に戻り、マテリアルを追加し、マテリアル名を"petal"とし以下のように設定
なお使用しているテクスチャは
https://www.textures.com/download/plasterdirty0073/72072
https://www.textures.com/download/woodfine0010/19679
ただし、plasterdirty0073のほうは、動画ではtiledというのがあるのだがtextures.comの中には見当たらないので、配信者が自作した可能性がある。要は花にしたときに模様がリング状になることを目的としているので(動画22:25前後)、それに合わせてgimpなどで編集するといいかもしれない。
続く
Blender – Detailed Flower のチュートリアルを試す(1)
Blender – Detailed Flower のチュートリアルを試す(2)
Blender – Detailed Flower のチュートリアルを試す(3)
09:15
petals_outerのHairのNumberを70にする
1.Particle Systemを追加し、petals_smallと名前を付ける
2.[Z]キーを押してワイヤフレーム表示にして、[G][Z]で花の中心の一番上の点を0.050だけ移動する
3.petal_smallを生やすためのVertexGroupを作成するため、花の中心の中心付近の頂点を選択する。なお、動画でやっているようにShift+Altで選択範囲を調整すると余計な部分まで選択されるが動画では気にしていない。
4.新たにVertexGroupを作成し、名前をpetals_innerとして上で選択した頂点をassignする。
5.petals_smallの設定に戻り、VertexGroupにpetals_innerを設定する
6.調整のため選択してある点群の一番内側の円をループ選択し、Weight=0でAssignする。なお、VertexGroupを編集してもParticle Systemは自動で更新されないので、Numberを変えるなどして更新のきっかけを与えてやらないといけない。
7.さらに調整として、petal_smallが多すぎるので304まで減らす。
マテリアルに入る前に花弁をさらに編集する
12:15~
以下、数値が一切示されていないので全て目分量で編集する
続く
Blender – Detailed Flower のチュートリアルを試す(1)
Blender – Detailed Flower のチュートリアルを試す(2)
Blender – Detailed Flower のチュートリアルを試す(3)
04:30~
1.花の中心のEditモードへ行き、切り口の部分の頂点を一つ選択し、[Alt+右クリック]でループ選択する。
そして[E][Z]でZ方向に-0.196(目分量)だけエッジをコピー→押し出しを行う。
2.そのまま[A]で全頂点を選択し、[S][Z]でZ方向に0.563(目分量)縮小する
04:45
1.花の中心にHairを設定する
この時に、各花びらをpetal_big,petal_smallという名前に変更する
2.上記Hairの範囲を限定するためのVertexGroupを追加(petals_outer)する
3.上記VertexGroupに頂点を割り当てる。花の中心の一点からAlt+右クリックでループ選択し、Ctrl+Num"+"で範囲拡大し、petals_outerにAssignする
4.Hairの設定に戻り、Vertex Groupsの設定のDensityにpetals_outerを設定する
5.Hairの設定を以下のように修正
6.petal_big,petal_smallを選択し、[M]で別のレイヤーに移動する
08:30~
1.花の中心の内側から5個目のループをAlt+右クリックでループ選択し、[S]で1.102拡大する
2.内側から4番目のループを選択し、[S]で1.098拡大する
3.縁のリングをループ選択し、[S]で1.082拡大する
4.最後に、HairのRandom Sizeを0.275に設定
続く
Blender – Detailed Flower のチュートリアルを試す(1)
Blender – Detailed Flower のチュートリアルを試す(2)
Blender – Detailed Flower のチュートリアルを試す(3)
0:22~
1.デフォルトのキューブを削除する
2.[Shift+A]→[Mesh]→[UV Sphere]で球を作成する
3.Propotional Editing modeをonにして、UVSphereの上の頂点を下へ0.482(目分量)移動する。
0:50~
4.UVSphereの下の頂点を選択し、Ctrl+[Num +]で選択範囲を拡大し、Z=0.0以下の頂点を全て削除する
5.スムーズシェーディングに設定する
01:20~
1.[Shift+A]→[Mesh]→[Plane]でPlaneを追加
2.Editモードへ行き、X方向に0.253(目分量)まで縮小する
3.Editモードで2頂点選択し、Y方向に0.833 (目分量) 移動する
4.先の2頂点を今度はX方向に0.519 (目分量) 縮小する
5.反対側の2頂点を選択し、[E]で複製、[Y]でY方向に0.896(目分量)移動する
6.先の2頂点を0.813(目分量)縮小する
7.先の2頂点を[E]で複製し、Y方向に0.318移動する
8.先の2点を[S]でX方向に0.675縮小する。ただしこの時Proportional Editingをonにしているため、その手前の2点も若干縮小する
9. Proportional Editing をRootに設定し、先の2頂点をZ方向に約-0.404ぐらい移動する
10.中央の一番長いエッジを選択し、Z方向に約-0.066ぐらい移動する
03:00
11.Object Modeへ移動し、Solidifyモディファイアを追加する
12.続けて、そのすぐ下のSubdivision Surfaceを追加する
13.各モディファイアを以下のように設定
13.作った花弁を[D]でコピーする
14.太い方からエッジ三本を選択し、Y方向に-0.810移動する
15.同じ場所を[S]で0.734だけ縮小する。この時、 Proportional Editing がonかつRootのままなので、先頭のほうにも影響が出る。
16.中央の四角形部分だけを選択し、[S][X]でX方向だけに1.266だけ拡大する
17.一番右側のエッジを選択し、 [S]で0.339に縮小する(0.444倍→0.764 倍 なので0.444×0.764)
18. [Ctrl+E]→Edge Slideを選択し、Factor=-0.361だけ左にスライドする
19.上記エッジを[S]で1.511拡大する
20.上記エッジを[G]でY方向に0.099移動する
21.上記、小さい方の花弁のSubdivide SurfaceモディファイアのRenderとViewのパラメータを2に落とす
続く
Blender – Detailed Flower のチュートリアルを試す(1)
Blender – Detailed Flower のチュートリアルを試す(2)
Blender – Detailed Flower のチュートリアルを試す(3)
この二つは行列が単純すぎて別記事にする気にならないのでまとめてやる。
namespace nu { typedef float real_t; inline real_t to_radian(real_t degree) { return degree * (real_t)3.14159265358979 / (real_t)180.0; } void mytranslate( real_t* m, real_t x, real_t y, real_t z ) { m[0] = 1.0; m[1] = 0.0; m[2] = 0.0; m[3] = 0.0; m[4] = 0.0; m[5] = 1.0; m[6] = 0.0; m[7] = 0.0; m[8] = 0.0; m[9] = 0.0; m[10] = 1.0; m[11] = 0.0; m[12] = x; m[13] = y; m[14] = z; m[15] = 1.0; } void myscale( real_t* m, real_t sx, real_t sy, real_t sz ) { m[0] = sx; m[1] = 0.0; m[2] = 0.0; m[3] = 0.0; m[4] = 0.0; m[5] = sy; m[6] = 0.0; m[7] = 0.0; m[8] = 0.0; m[9] = 0.0; m[10] = sz; m[11] = 0.0; m[12] = 0.0; m[13] = 0.0; m[14] = 0.0; m[15] = 1.0; } }
#include <windows.h> #include <gl/GLU.h> #include <gl/freeglut.h> #include <cstdio> #include <cmath> //検証用 #include <cassert> //自前実装版glTranslate* / glScale* #include "mytranslatescale.h" #pragma comment(lib,"opengl32.lib") #pragma comment(lib,"glu32.lib") #pragma comment(lib,"freeglut.lib") void display(void) { GLfloat glmat[16]; //gl関数で生成 GLfloat mymat[16]; //自分関数で生成 //gltranslate,mytranslateへの入力の値を色々変える static int i = 0; i++; GLfloat x = 1.0+i; GLfloat y = 1.0 * (i * 0.1); GLfloat z = 1.0 * (i / 0.2); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); //openglで計算 glTranslatef( x, y, z); glGetFloatv(GL_MODELVIEW_MATRIX, glmat); //自前計算 nu::mytranslate(mymat,x,y,z); puts("----------------------------------------------"); printf("** %d :: %lf %lf %lf\n", i,x,y,z); for (int k = 0; k < 16; k++) { //比較 printf("m[%2d] %+5.10lf %+5.10lf \n", k, glmat[k], mymat[k]); //自前計算とgltranslate計算の値があまりにかけ離れていたらassertで落ちる assert(std::abs(glmat[k] - mymat[k]) < 0.0001); } puts("----------------------------------------------"); } void mouse(int button, int state, int x, int y) { display(); } int main(int argc, char* argv[]) { glutInit(&argc, argv); glutInitDisplayMode(GLUT_RGBA); glutCreateWindow(argv[0]); glutInitWindowPosition(0, 0); glutInitWindowSize(100,100); glutDisplayFunc(display); glutMouseFunc(mouse); glutMainLoop(); return 0; }
#include <windows.h> #include <gl/GLU.h> #include <gl/freeglut.h> #include <cstdio> #include <cmath> //検証用 #include <cassert> //自前実装版glTranslate* / glScale* #include "mytranslatescale.h" #pragma comment(lib,"opengl32.lib") #pragma comment(lib,"glu32.lib") #pragma comment(lib,"freeglut.lib") void display(void) { GLfloat glmat[16]; //gl関数で生成 GLfloat mymat[16]; //自分関数で生成 //glscalef,myscaleへの入力の値を色々変える static int i = 0; i++; GLfloat x = 1.0+i; GLfloat y = 1.0 * (i * 0.1); GLfloat z = 1.0 * (i / 0.2); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); //openglで計算 glScalef( x, y, z); glGetFloatv(GL_MODELVIEW_MATRIX, glmat); //自前計算 nu::myscale(mymat,x,y,z); puts("----------------------------------------------"); printf("** %d :: %lf %lf %lf\n", i,x,y,z); for (int k = 0; k < 16; k++) { //比較 printf("m[%2d] %+5.10lf %+5.10lf \n", k, glmat[k], mymat[k]); //自前計算とglScalef計算の値があまりにかけ離れていたらassertで落ちる assert(std::abs(glmat[k] - mymat[k]) < 0.0001); } puts("----------------------------------------------"); } void mouse(int button, int state, int x, int y) { display(); } int main(int argc, char* argv[]) { glutInit(&argc, argv); glutInitDisplayMode(GLUT_RGBA); glutCreateWindow(argv[0]); glutInitWindowPosition(0, 0); glutInitWindowSize(100,100); glutDisplayFunc(display); glutMouseFunc(mouse); glutMainLoop(); return 0; }
#include <cmath> namespace nu { typedef float real_t; inline real_t to_radian(real_t degree) { return degree * (real_t)3.14159265358979 / (real_t)180.0; } //! @brief 回転行列作成 //! @param [out] m 結果を格納する要素数16の配列 //! @param [in] angle_degree 回転角を度で指定 //! @param [in] x 回転軸のX成分 //! @param [in] y 回転軸のY成分 //! @param [in] z 回転軸のZ成分 //! @return なし void myrotate( real_t* m, real_t angle_degree, real_t x, real_t y, real_t z) { //len(x y z) != 0ならnormalizeする real_t len = sqrt(x * x + y * y + z * z); if (abs(1.0 - len) > 0.000001) { x = x / len; y = y / len; z = z / len; } real_t angle_rad = to_radian(angle_degree); real_t c = std::cos(angle_rad); real_t s = std::sin(angle_rad); m[0] = x * x * (1 - c) + c; m[1] = y * x * (1 - c) + z * s; m[2] = x * z * (1 - c) - y * s; m[3] = 0.0; m[4] = x * y * (1 - c) - z * s; m[5] = y * y * (1 - c) + c; m[6] = y * z * (1 - c) + x * s; m[7] = 0.0; m[8] = x * z * (1 - c) + y * s; m[9] = y * z * (1 - c) - x * s; m[10] = z * z * (1 - c) + c; m[11] = 0.0; m[12] = 0.0; m[13] = 0.0; m[14] = 0.0; m[15] = 1.0; } }
#include <windows.h> #include <gl/GLU.h> #include <gl/freeglut.h> #include <cstdio> //検証用 #include <cassert> //自前実装版glRotate #include "myrotate.h" #pragma comment(lib,"opengl32.lib") #pragma comment(lib,"glu32.lib") #pragma comment(lib,"freeglut.lib") void display(void) { GLfloat glrmat[16]; //gl関数で生成 GLfloat myrmat[16]; //自分関数で生成 //glRotate,myrotateへの入力の値を色々変える static int i = 0; i++; GLfloat x = 1.0+i; GLfloat y = 1.0 * (i * 0.1); GLfloat z = 1.0 * (i / 0.2); GLfloat angle=i+25; glMatrixMode(GL_MODELVIEW); glLoadIdentity(); //openglで計算 glRotatef(angle, x, y, z); glGetFloatv(GL_MODELVIEW_MATRIX, glrmat); //自前計算 nu::myrotate(myrmat,angle,x,y,z); puts("----------------------------------------------"); printf("** %d :: %lf %lf %lf %lf\n", i,angle,x,y,z); for (int k = 0; k < 16; k++) { //比較 printf("m[%2d] %+5.10lf %+5.10lf \n", k, glrmat[k], myrmat[k]); //自前計算とglRotate計算の値があまりにかけ離れていたらassertで落ちる assert(abs(glrmat[k] - myrmat[k]) < 0.0001); } puts("----------------------------------------------"); } void mouse(int button, int state, int x, int y) { display(); } int main(int argc, char* argv[]) { glutInit(&argc, argv); glutInitDisplayMode(GLUT_RGBA); glutCreateWindow(argv[0]); glutInitWindowPosition(0, 0); glutInitWindowSize(100,100); glutDisplayFunc(display); glutMouseFunc(mouse); glutMainLoop(); return 0; }
#include <cmath> namespace nu { typedef float real_t; //! @brief 平行投影行列を作成する //! @param [out] m 作成した行列を格納する要素数16の配列 //! @return なし inline void myortho( real_t* m, real_t left, real_t right, real_t bottom, real_t top, real_t znear, real_t zfar) { real_t tx = -(right + left) / (right - left); real_t ty = -(top + bottom) / (top - bottom); real_t tz = -(zfar + znear) / (zfar - znear); //infが出たときは単位行列を返す模様 if (std::isinf(tx) || std::isinf(ty) || std::isinf(tz)) { m[0] = m[5] = m[10] = m[15] = (real_t)1.0; m[1] = m[2] = m[3] = m[4] = m[6] = m[7] = m[8] = m[9] = m[11] = (real_t)0.0; m[12] = m[13] = m[14] = (real_t)0.0; return; } m[0] = (real_t)2.0 / (right - left); m[1] = 0.0; m[2] = 0.0; m[3] = 0.0; m[4] = 0.0; m[5] = (real_t)2.0 / (top - bottom); m[6] = 0.0; m[7] = 0.0; m[8] = 0.0; m[9] = 0.0; m[10] = (real_t)-2.0/(zfar-znear); m[11] = 0.0; m[12] = tx; m[13] = ty; m[14] = tz; m[15] = 1.0; } }
//検証用 #include <cassert> //自前実装版glortho #include "myortho.h" #pragma comment(lib,"opengl32.lib") #pragma comment(lib,"glu32.lib") #pragma comment(lib,"freeglut.lib") void display(void) { GLfloat glomat[16]; //glu関数で生成 GLfloat myomat[16]; //自分関数で生成 //glOrtho,myorthoへの入力の値を色々変える static int i = 0; static float j = 0.0f; GLdouble left=-10+i; GLdouble right=+23 + i*1.5; GLdouble bottom=-10 - i / 2.0; GLdouble top=10 - i; GLdouble znear=5+j; GLdouble zfar=30+j*2; i++; j += 0.01; glMatrixMode(GL_PROJECTION); glLoadIdentity(); //openglで計算 glOrtho(left, right, bottom, top, znear, zfar); glGetFloatv(GL_PROJECTION_MATRIX, glomat); //自前計算 nu::myortho(myomat,left, right, bottom, top, znear, zfar); puts("----------------------------------------------"); printf("** %d \n", i); for (int k = 0; k < 16; k++) { //比較 printf("m[%2d] %+5.10lf %+5.10lf \n", k,glomat[k], myomat[k]); //自前計算とglOrtho計算の値があまりにかけ離れていたらassertで落ちる assert(abs(glomat[k] - myomat[k]) < 0.00001); } puts("----------------------------------------------"); } void mouse(int button, int state, int x, int y) { display(); } int main(int argc, char* argv[]) { glutInit(&argc, argv); glutInitDisplayMode(GLUT_RGBA); glutCreateWindow(argv[0]); glutInitWindowPosition(0, 0); glutInitWindowSize(100,100); glutDisplayFunc(display); glutMouseFunc(mouse); glutMainLoop(); return 0; }
参考:https://manpag.es/RHEL5/3+gluPerspective
#include <cmath> namespace nu { typedef float real_t; inline real_t cot(real_t theta) { return (real_t)1.0 / tan(theta); } inline real_t to_radian(real_t degree) { return degree * (real_t)3.14159265358979 / (real_t)180.0; } //! @brief 透視投影行列の作成 (視野角で指定) //! @param [out] m 結果の4x4行列 //! @param [in] fovy_degree 視野角 //! @param [in] aspect アスペクト比 //! @param [in] zNear 一番近いz位置 //! @param [in] zFar 一番遠いz位置 //! @return なし inline void myPerspective( real_t* m, real_t fovy_degree, real_t aspect, real_t zNear, real_t zFar) { real_t fovy_rad = to_radian(fovy_degree); real_t f = cot(fovy_rad / (real_t)2.0); m[0] = f / aspect; m[1] = 0.0; m[2] = 0.0; m[3] = 0.0; m[4] = 0.0; m[5] = f; m[6] = 0.0; m[7] = 0.0; m[8] = 0.0; m[9] = 0.0; m[10] = (zFar + zNear) / (zNear - zFar); m[11] = -1.0; m[12] = 0.0; m[13] = 0.0; m[14] = (2 * zFar * zNear) / (zNear - zFar); m[15] = 0.0; } }
gluPerspectiveの結果はgluPerspectiveを呼び出した後でglGetFloatvで取得する。
#include <windows.h> #include <gl/GLU.h> #include <gl/freeglut.h> #include <cstdio> //検証用 #include <cassert> //自前実装版gluPerspective #include "myperspective.h" #pragma comment(lib,"opengl32.lib") #pragma comment(lib,"glu32.lib") #pragma comment(lib,"freeglut.lib") void display(void) { GLfloat glumat[16]; //glu関数で生成 GLfloat mypmat[16]; //自分関数で生成 //gluPerpsective,myPerspectiveへの入力の値を色々変える static int i = 0; static float j = 0.0f; GLfloat fovy=45.0f + i; GLfloat aspect=0.2f + j; GLfloat zNear=0.1f + j; GLfloat zFar=10.0f + j*2; i++; j += 0.01; glMatrixMode(GL_PROJECTION); glLoadIdentity(); //gluで計算 gluPerspective(fovy, aspect, zNear, zFar); glGetFloatv(GL_PROJECTION_MATRIX, glumat); //自前計算 nu::myPerspective(mypmat, fovy, aspect, zNear, zFar); puts("----------------------------------------------"); for (int k = 0; k < 16; k++) { //自前計算 printf("m[%2d] %+5.5lf %+5.5lf \n", k,glumat[k], mypmat[k]); //自前計算とgluPerspective計算の値があまりにかけ離れていたらassertで落ちる assert(abs(glumat[k] - mypmat[k]) < 0.00001); } puts("----------------------------------------------"); } void mouse(int button, int state, int x, int y) { display(); } int main(int argc, char* argv[]) { glutInit(&argc, argv); glutInitDisplayMode(GLUT_RGBA); glutCreateWindow(argv[0]); glutInitWindowPosition(0, 0); glutInitWindowSize(100,100); glutDisplayFunc(display); glutMouseFunc(mouse); glutMainLoop(); return 0; }
template<int I, typename Head, typename... T> struct Tget { using type_t = typename Tget<I - 1, T...> ::type_t; }; template<typename Head, typename... T> struct Tget<0, Head, T...> { using type_t = Head; }; int main() { using t1 = Tget<2, char, int, double>::type_t; std::cout << "sizeof " << sizeof( t1 ) << std::endl; int i; std::cin >> i; return 0; }