多分まだ上げてなかったと思う。タイトルはif-elifとしてあるけれど個人的な好みでSwitch / Caseにしてある。
以下のように、Switch< /* .... */ >::type とし、typeを決定する。
そのtypeは、Case<条件 , 型 > とし、条件がtrueの時の型とする。
条件は再起で上から順番に評価していて、trueが見つかった時点で探索をやめるので、複数あると先に書いた方が採用される。
#include "pch.h" #include <iostream>
/////////////////////////////////////////////////////// // Switch / Case
template<bool BOOL, typename Second> struct Case { static constexpr bool TBOOL = BOOL; using TSecond = Second; }; template<class Head, class... Tail> struct Switch { using type = typename std::conditional< Head::TBOOL, typename Head::TSecond, // trueの時 typename Switch<Tail...>::type //falseの時 >::type; }; //再起終端用特殊化 template<class Head> struct Switch<Head> { using type = typename std::conditional< Head::TBOOL, typename Head::TSecond, // trueの時 void >::type; };
/////////////////////////////////////////////////////// // 動作テスト用クラスstruct forInt {void disp() {std::cout << "int" << std::endl;}}; struct forFloat {void disp() {std::cout << "float" << std::endl;}}; struct forChar {void disp() {std::cout << "char" << std::endl;}};//動作テスト用関数 template<typename T> void disp_type(T val) { // 型 T によってDispTypeが変わる using DispType = typename Switch< Case<std::is_same<int, T>::value, forInt>, Case<std::is_same<float, T>::value, forFloat>, Case<std::is_same<char, T>::value, forChar> >::type; DispType tmp; tmp.disp(); }int main() { char value = 10; disp_type(value); }
C++には T[N] 形式の他に、
・std::array
・std::vector
・std::valarray
等の配列の形式がある。このうちstdの<type_traits>で判別できるのはT[N]型か否かを判別するstd::is_arrayしか用意されていないようなので、その他を判別するテンプレートを用意する。
#include <iostream> #include<vector> #include<array> #include<valarray> int primarray[10]; std::array<int, 10> stdarray; std::vector<int> vectordata; std::valarray<int> valarraydata; namespace CheckPrimitiveArray { // type_traits内に同様のものがある
template<class> struct is_array :std::false_type {}; template<class T> struct is_array<T[]> : std::true_type {}; template<class T, std::size_t N> struct is_array<T[N]> : std::true_type {};
void example() { std::cout << std::endl; std::cout << "--- is_array" << std::endl; std::cout << "primitive:" << is_array<decltype(primarray)>::value << std::endl; std::cout << "stdarray :" << is_array<decltype(stdarray)>::value << std::endl; std::cout << "vector :" << is_array<decltype(vectordata)>::value << std::endl; std::cout << "valarray :" << is_array<decltype(valarraydata)>::value << std::endl; } } namespace CheckVectorArray {
template<class> struct is_vector : std::false_type {};
template<class T, class ALLOCATOR> struct is_vector<std::vector<T, ALLOCATOR>> : std::true_type {};
void example() { std::cout << std::endl; std::cout << "--- is_vector" << std::endl; std::cout << "primitive:" << is_vector<decltype(primarray)>::value << std::endl; std::cout << "stdarray :" << is_vector<decltype(stdarray)>::value << std::endl; std::cout << "vector :" << is_vector<decltype(vectordata)>::value << std::endl; std::cout << "valarray :" << is_vector<decltype(valarraydata)>::value << std::endl; } } namespace CheckStdArray {
template<class> struct is_stdarray :std::false_type {}; template<class T, std::size_t N> struct is_stdarray<std::array<T, N>> :std::true_type {};
void example() { std::cout << std::endl; std::cout << "--- is_stdarray" << std::endl; std::cout << "primitive:" << is_stdarray<decltype(primarray)>::value << std::endl; std::cout << "stdarray :" << is_stdarray<decltype(stdarray)>::value << std::endl; std::cout << "vector :" << is_stdarray<decltype(vectordata)>::value << std::endl; std::cout << "valarray :" << is_stdarray<decltype(valarraydata)>::value << std::endl; } } namespace CheckValArray {
template<class> struct is_valarray : std::false_type {};
template<class T> struct is_valarray<std::valarray<T>> : std::true_type {};
void example() { std::cout << std::endl; std::cout << "--- is_valarray" << std::endl; std::cout << "primitive:" << is_valarray<decltype(primarray)>::value << std::endl; std::cout << "stdarray :" << is_valarray<decltype(stdarray)>::value << std::endl; std::cout << "vector :" << is_valarray<decltype(vectordata)>::value << std::endl; std::cout << "valarray :" << is_valarray<decltype(valarraydata)>::value << std::endl; } } int main() { CheckPrimitiveArray::example(); CheckStdArray::example(); CheckVectorArray::example(); CheckValArray::example(); getchar(); }
--- is_array
primitive:1
stdarray :0
vector :0
valarray :0
--- is_stdarray
primitive:0
stdarray :1
vector :0
valarray :0
--- is_vector
primitive:0
stdarray :0
vector :1
valarray :0
--- is_valarray
primitive:0
stdarray :0
vector :0
valarray :1

以下のようにCtrl+Gでノードグループとしてひとまとめにし、NormalのdotをFacにしてオブジェクトの本来のマテリアルとミックスすれば、オブジェクトの色と雪の色を分離できる。



いつの間にかCyclesにWhite Noise Textureが入っていた。確認しているバージョンは2.83,2.90。確か2.7系には無かった気がする。Blender Renderが廃止された?時に移行があったのかもしれない。
そのままだとあまりにもわかりにくいので、vector mathでsnapを設定する。
SkyTextureは便利だが水平面より下にも色がついている。これを編集し水平面には色がつかないようにする。

Worldで以下のようにノードを設定する。
そしてSkyTextureとMixRGBでMultiplyする
応用で、空の部分だけを星空にする。

星空のチュートリアルで比較的短い物。
ざっくりいうとBackgroundを以下のノードで設定する。
⑥のFrom Minを0に近づけると明るくなる。
EEVEEの場合レンダリング結果に直接Bloomがかかるのでわかりやすいが、Cyclesの場合は後からcompositorで設定しなければならない。
compositorで設定する。
色々と加工してみた例。
1bit単位の処理が必要になったので、charの各ビットに[]でアクセスできるクラスを書いた。
今見たら、クラス名iteratorはおかしい。まあいいか。
#include <iostream> #include <bitset>
//! @brief 1ビットにoperator=を提供するためのクラス class bititerator_t { unsigned char* m_c; int m_index; public: bititerator_t(unsigned char* c, const int index) { m_c = c; m_index = 7-index; } void operator=(const int value) { unsigned char mask = (1 << m_index); if (value) { *m_c |= mask; } else { *m_c &= ~mask; } } operator unsigned char() { unsigned char mask = (1 << m_index); return (*m_c & mask) ? 1 : 0; } };
//! @brief ビットを配列のようにアクセスするクラス class BitArray { unsigned char c; public: BitArray() :c(0) {} //! @brief 各ビットへ[]でアクセスする bititerator_t operator[](const int i) { return bititerator_t(&c, i); } operator unsigned char(){ return c; } //内部のunsigned charデータへ書き込む unsigned char operator=(const unsigned char value) { c = value; return c; } };
int main() { BitArray bit; bit[0] = 1; bit[1] = 0; bit[2] = 1; bit[3] = 1; bit[4] = 0; bit[5] = 0; bit[6] = 0; bit[7] = 0; std::cout << (unsigned int)bit << " " << std::bitset<8>(bit) << std::endl; int i; std::cin >> i; }
176 10110000
この図では三角形を2枚書いて、IBOを使わない場合、定義しなければいけない頂点数は6となる。
IBOを使うと共通に使用する頂点をまとめて4個にできる。

基本は以下と同じ:
GLSLを試す (1)
注目すべき点は、
・頂点バッファの定義は普通と同じ形式で良い
・IBOを使うからと言って、バーテクスシェーダ、フラグメントシェーダに変更を加える必要は無い
・頂点バッファなどを準備する時に、一緒にGL_ELEMENT_ARRAY_BUFFERでIBOを作成する
・glDrawArraysではなくglDrawElementsを使用する
// バッファとデータ typedef GLfloat points_t[3]; GLuint vertexbuffer;//バッファのIDを格納する変数 GLuint colorbuffer;//バッファのIDを格納する変数 GLuint indexbuffer;//三角形を頂点IDで表現するバッファのIDを格納する変数 //////////////////////////////////////////////////
// データの準備
void prepare_buffers() { points_t position[4]; points_t color[4]; //頂点座標 position[0][0] = 0; position[0][1] = 0.5; position[0][2] = 0; position[1][0] = 0.5; position[1][1] = -0.5; position[1][2] = 0; position[2][0] = -0.5; position[2][1] = -0.5; position[2][2] = 0; position[3][0] = 0; position[3][1] = -1.0; position[3][2] = 0; //色 color[0][0] = 1.0; color[0][1] = 0.0; color[0][2] = 0.0; color[1][0] = 0.0; color[1][1] = 1.0; color[1][2] = 0.0; color[2][0] = 0.0; color[2][1] = 0.0; color[2][2] = 1.0; color[3][0] = 1.0; color[3][1] = 1.0; color[3][2] = 1.0; //頂点座標のバッファ glGenBuffers(1, &vertexbuffer); glBindBuffer(GL_ARRAY_BUFFER, vertexbuffer); glBufferData( GL_ARRAY_BUFFER, 4 * 3 * sizeof(GLfloat), position, GL_STATIC_DRAW); //頂点カラーのバッファ glGenBuffers(1, &colorbuffer); glBindBuffer(GL_ARRAY_BUFFER, colorbuffer); glBufferData( GL_ARRAY_BUFFER, 4 * 3 * sizeof(GLfloat), color, GL_STATIC_DRAW);
//頂点Indexで表現した三角形一覧 // △012,△213 の二つを定義 GLuint triangle_elements[] = { 0,1,2 , 2,1,3 }; //三角形の頂点IDのバッファ const size_t triangle_elements_memsize = sizeof(triangle_elements);
glGenBuffers(1, &indexbuffer); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexbuffer); glBufferData( GL_ELEMENT_ARRAY_BUFFER, triangle_elements_memsize, // バッファのメモリ上のバイト数を求める triangle_elements, //バッファへのポインタ GL_STATIC_DRAW ); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
}
void display(void) { glClearColor(0, 0, 0, 1); glClear(GL_COLOR_BUFFER_BIT); // シェーダを使う glUseProgram(ProgramID); // 頂点バッファ:頂点 glEnableVertexAttribArray(0); glBindBuffer(GL_ARRAY_BUFFER, vertexbuffer); glVertexAttribPointer( 0, // シェーダ内のlayoutとあわせる 3, // 1要素の要素数(x,y,z)で3要素 GL_FLOAT, // タイプ GL_FALSE, // 正規化しない(データが整数型の時) 0, // ストライド (void*)0 // 配列バッファオフセット ); // カラーバッファを有効にする glEnableVertexAttribArray(1); glBindBuffer(GL_ARRAY_BUFFER, colorbuffer); glVertexAttribPointer( 1, // シェーダ内のlayoutとあわせる 3, // 1要素の要素数(r,g,b)で3要素 GL_FLOAT, // タイプ GL_FALSE, // 正規化しない(データが整数型の時) 0, // ストライド (void*)0 // 配列バッファオフセット );
// 三角形を描きます! glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexbuffer); //int size; //glGetBufferParameteriv(GL_ELEMENT_ARRAY_BUFFER, GL_BUFFER_SIZE, &size); glDrawElements( GL_TRIANGLES, 6, // 頂点数。size / sizeof(GLuint) の式でも頂点数を算出できる。 GL_UNSIGNED_INT, 0 );
glDisableVertexAttribArray(0);//バッファを無効にする glDisableVertexAttribArray(1); glFlush(); }
各シェーダはIBOの使用の有無で書き換える必要は無い。
#version 460 core layout (location = 0) in vec3 aPos; layout (location = 1) in vec3 incolor; out vec4 vertexColor; void main() { gl_Position = vec4(aPos, 1.0); vertexColor = vec4(incolor, 1.0); }
#version 460 core out vec4 FragColor; in vec4 vertexColor; void main() { FragColor = vertexColor; }
import bpy msh = bpy.context.active_object fname = 'C:/test/' + msh.name + '.xyz' with open(fname, 'w') as myf: for vt in msh.data.vertices: print(vt.co[0],vt.co[1],vt.co[2] ,file=myf ) #頂点座標出力
//! @brief separator区切りの実数の一覧を読み込む //! @details xyzフォーマットは正式な規格として存在しないらしいので、ある程度の柔軟性を持たせる //! @param [out] ret 結果を格納する配列の配列 //! @param [in] filename ファイル名 //! @param [in] separator 区切り文字 //! @return なし template<typename scalar_t> void read_xyz(std::vector<std::vector<scalar_t> >& ret,const char* filename, const char separator) { std::ifstream ifs(filename); std::string str; while (std::getline(ifs, str)) { std::stringstream line{ str }; std::string value; std::vector<scalar_t> tmp; while (getline(line, value, separator)){ tmp.push_back(std::atof(value.c_str())); } ret.push_back(tmp); } }