テクスチャペイントでテクスチャデータに画像を書き込んでいく。
一言でいえば、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にマテリアルを追加し、Emissionを設定する。
ShroomにParticleを設定する。
Shroomのマテリアルをもう一度いじる
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を直接いじったほうがいいかもしれない。
#pragma once #include <Windows.h> #include <gl/GL.h> #include <vector> #include <cstdio> #pragma warning(disable:4996)
//画像の上下を反転する void reverse_Y(const int width, const int height, unsigned char* p) { int WidthByte = width * 3; size_t HalfHEIGHT = height / 2; for (int ha = 0; ha < HalfHEIGHT; ha++) { int hb = (height - ha) - 1; unsigned char* pha = p + ha * WidthByte; unsigned char* phb = p + hb * WidthByte; if (ha != hb) { for (size_t i = 0; i < WidthByte; i++) { std::swap(pha[i], phb[i]); } } } }
//! @brief PPM(RGB各1byte,カラー,テキスト)を書き込む //! @param [in] fname ファイル名 //! @param [in] vmax 全てのRGBの中の最大値 //! @param [in] width 画像の幅 //! @param [in] height 画像の高さ //! @param [in] p 画像のメモリへのアドレス //! @details RGBRGBRGB....のメモリを渡すと、RGBテキストでファイル名fnameで書き込む void pnmP3_Write(const char* const fname, const int vmax, const int width, const int height, const unsigned char* const p) { // PPM ASCII FILE* fp = fopen(fname, "w"); fprintf(fp, "P3\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 %d %d ", p[k * 3 + 0], p[k * 3 + 1], p[k * 3 + 2]); k++; } fprintf(fp, "\n"); } fclose(fp); }
//! @brief OpenGLの画面を画像に保存 //! @param [in] width 画像幅ピクセル数 //! @param [in] height 画像高さピクセル数 //! @param [in] pathname ファイル名 void saveGLtoPPM(const int width, const int height, const char* pathname) { //メモリ確保 std::vector<GLubyte> buffer; buffer.resize(width*height * 3); //画像取得 glReadBuffer(GL_FRONT); glReadPixels(0, 0, width, height, GL_RGB, GL_UNSIGNED_BYTE, buffer.data()); //上下反転 reverse_Y(width, height, buffer.data()); pnmP3_Write( pathname, 255, width, height, buffer.data()); // PPM ASCII }
#include <iostream> #include <Windows.h> #include "prepare_shader.hpp" #include <gl/GL.h> #include <gl/GLU.h> #include <gl/freeglut.h> #include <fstream> #include "saveGLtoPPM.hpp" #pragma comment(lib,"glew32.lib") //ウィンドウの幅と高さ int Width, Height; GLuint buf_points; GLuint buf_colors; GLfloat mproj[16]; GLfloat mmodel[16]; GLuint programID; // シェーダとデータの設定 void init() { std::vector<GLfloat> colors; std::vector<GLfloat> points; GLfloat v = 0.8; push_3(colors, 0, 0, 1);//色 RGB push_3(points, 0, 0, 0);//座標 XYZ push_3(colors, 0, 1, 0); push_3(points, 0, v, 0); push_3(colors, 1, 0, 0); push_3(points, v, 0, 0); prepare_buffer(&buf_points, points.data(), points.size() * sizeof(GLfloat), GL_STATIC_DRAW); prepare_buffer(&buf_colors, colors.data(), colors.size() * sizeof(GLfloat), GL_STATIC_DRAW); GLuint vtxShader; GLuint flagShader; const char* vtxfile = "default.vert"; const char* fragfile = "default.frag"; std::string verr; std::string ferr; prepare_shader_byfile(&vtxShader, GL_VERTEX_SHADER, vtxfile, &verr); prepare_shader_byfile(&flagShader, GL_FRAGMENT_SHADER, fragfile, &ferr); std::cout << verr << std::endl; std::cout << ferr << std::endl; std::string linkerr; link_program(&programID, { vtxShader ,flagShader }, nullptr, &linkerr); loadidentity44(mproj); loadidentity44(mmodel); } //描画関数 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); glUseProgram(programID); GLuint loc_ModelViewMatrix = glGetUniformLocation(programID, "ModelViewMatrix"); GLuint loc_ProjectionMatrix = glGetUniformLocation(programID, "ProjectionMatrix"); glUniformMatrix4fv(loc_ModelViewMatrix, 1, GL_FALSE, mmodel); glUniformMatrix4fv(loc_ProjectionMatrix, 1, GL_FALSE, mproj); { auto bindbufP = EnableAndBindFArrayBuffer(0, buf_points, 3, GL_FLOAT); auto bindbufC = EnableAndBindFArrayBuffer(1, buf_colors, 3, GL_FLOAT); glDrawArrays(GL_TRIANGLES, 0, 3); } glFlush(); } //ウィンドウサイズの変化時に呼び出される void reshape(int w, int h) { Width = w; Height = h; disp(); }
// クリックでファイルに保存 void mouse(int button, int state, int x, int y) {
saveGLtoPPM( Width, Height, R"(C:\test\a.ppm)");
} //エントリポイント 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); glutMouseFunc(mouse); glewInit(); init(); glutMainLoop(); return 0; }
#include <iostream> #include <Windows.h> #include "prepare_shader.hpp" #include <gl/GL.h> #include <gl/GLU.h> #include <gl/freeglut.h> #pragma comment(lib,"glew32.lib") //ウィンドウの幅と高さ int width, height; GLuint buf_points; GLuint buf_tcoord; GLuint textureID22; GLuint textureID44; GLfloat mproj[16]; GLfloat mmodel[16]; GLuint programID;
void texture_setting(GLuint* texid, std::vector < GLubyte >& texdata, int TEXWIDTH, int TEXHEIGHT) { glGenTextures(1, texid); glBindTexture(GL_TEXTURE_2D, *texid); glPixelStorei(GL_UNPACK_ALIGNMENT, 1); // テクスチャの割り当て glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, TEXWIDTH, TEXHEIGHT, 0, GL_RGB, GL_UNSIGNED_BYTE, texdata.data()); // テクスチャを拡大・縮小する方法の指定 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); } // テクスチャ作成 void create_texture_22() {
std::vector < GLubyte > texdata;
push_3(texdata, 255, 0, 0); push_3(texdata, 0, 255, 0); push_3(texdata, 255, 255, 255); push_3(texdata, 0, 255, 255); texture_setting(&textureID22, texdata, 2, 2); texdata.clear(); } void create_texture_44() { std::vector < GLubyte > texdata;
push_3(texdata, 255, 0, 0); push_3(texdata, 0, 0, 0); push_3(texdata, 255, 0, 0); push_3(texdata, 0, 0, 0); push_3(texdata, 0, 0, 0); push_3(texdata, 255, 0, 0); push_3(texdata, 0, 0, 0); push_3(texdata, 255, 0, 0); push_3(texdata, 255, 0, 0); push_3(texdata, 0, 0, 0); push_3(texdata, 255, 0, 0); push_3(texdata, 0, 0, 0); push_3(texdata, 0, 0, 0); push_3(texdata, 255, 0, 0); push_3(texdata, 0, 0, 0); push_3(texdata, 255, 0, 0); texture_setting(&textureID44, texdata, 4, 4); texdata.clear(); }
// シェーダとデータの設定 void init() { ///////////////////////////////////////////// std::vector<GLfloat> points; GLfloat v = 0.8; push_3(points, -v , -v , 0); push_3(points, v , -v , 0); push_3(points, -v , v , 0); push_3(points, v , v , 0); prepare_buffer(&buf_points, points.data(), points.size() * sizeof(GLfloat), GL_STATIC_DRAW); ///////////////////////////////////////////// // テクスチャ座標 std::vector<GLfloat> texcoord; push_2(texcoord, 0, 0); push_2(texcoord, 1, 0); push_2(texcoord, 0, 1); push_2(texcoord, 1, 1); prepare_buffer(&buf_tcoord, texcoord.data(), texcoord.size() * sizeof(GLfloat), GL_STATIC_DRAW); ///////////////////////////////////////////// //テクスチャ(画像)作成 create_texture_22(); create_texture_44(); ///////////////////////////////////////////// GLuint vtxShader; GLuint flagShaderR; const char* vtxfile = "default.vert"; const char* fragfileR = "default.frag"; std::string verr; std::string ferr; prepare_shader_byfile(&vtxShader, GL_VERTEX_SHADER, vtxfile, &verr); prepare_shader_byfile(&flagShaderR, GL_FRAGMENT_SHADER, fragfileR, &ferr); std::cout << verr << std::endl; std::cout << ferr << std::endl; std::string linkerr; link_program(&programID, { vtxShader ,flagShaderR }, nullptr, &linkerr); loadidentity44(mproj); loadidentity44(mmodel); }
//描画関数 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); glUseProgram(programID); GLuint loc_ModelViewMatrix = glGetUniformLocation(programID, "ModelViewMatrix"); GLuint loc_ProjectionMatrix = glGetUniformLocation(programID, "ProjectionMatrix"); glUniformMatrix4fv(loc_ModelViewMatrix, 1, GL_FALSE, mmodel); glUniformMatrix4fv(loc_ProjectionMatrix, 1, GL_FALSE, mproj);
GLint loc_tex22 = glGetUniformLocation(programID, "Tex22"); glUniform1i(loc_tex22, 0);// Texture unit 0 glActiveTexture(GL_TEXTURE0 + 0); // Texture unit 0 glBindTexture(GL_TEXTURE_2D, textureID22); GLint loc_tex44 = glGetUniformLocation(programID, "Tex44"); glUniform1i(loc_tex44, 1);// Texture unit 1 glActiveTexture(GL_TEXTURE0 + 1); // Texture unit 1 glBindTexture(GL_TEXTURE_2D, textureID44);
{ auto bind_points = EnableAndBindFArrayBuffer(0, buf_points, 3, GL_FLOAT); auto bind_tcoord = EnableAndBindFArrayBuffer(1, buf_tcoord, 2, GL_FLOAT); glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); } glUseProgram(0); 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); glewInit(); init(); glutMainLoop(); return 0; }
#version 460 core layout (location = 0) in vec3 aPos;//ポリゴンの頂点座標 layout (location = 1) in vec2 texcd;//座標に対応するテクスチャ座標 out vec2 vTexCoord;//テクスチャ座標の出力先 uniform mat4 gl_ModelViewMatrix; uniform mat4 gl_ProjectionMatrix; void main() { gl_Position = gl_ProjectionMatrix * gl_ModelViewMatrix * vec4(aPos, 1.0); vTexCoord = texcd;//フラグメントシェーダへテクスチャ座標を渡す }
#version 460 core out vec4 FragColor;//色の出力先 uniform sampler2D Tex22; uniform sampler2D Tex44; in vec2 vTexCoord;//頂点シェーダから渡されたテクスチャ座標 void main() { //テクスチャデータとテクスチャ座標から色を決定 vec4 c22 = texture(Tex22,vTexCoord); vec4 c44 = texture(Tex44,vTexCoord); //合成したテクスチャの色を作成 vec4 crr; crr.x = c44.x * c22.x; crr.y = c44.x * c22.y; crr.z = c44.x * c22.z; FragColor = crr; }