以下のようなコードがある。vec_tは三次元のベクトル型で、lengthはその長さを計算する
#pragma oncestruct vec_t { double x, y, z; };double length(const vec_t& v) { return sqrt( v.x * v.x + v.y * v.y + v.z * v.z ); }
#include <iostream> #include "len.hpp" int main() { vec_t vv; vv.x = 1; vv.y = 1; vv.z = 1; double dbl = length(vv); std::cout << dbl << std::endl; int i; std::cin >>i; }
lengthはシンプルで可読性が高いが、移植性には欠ける。
具体的にはvec_tにしか対応していない。(故に読みやすいのだが。)
length関数をテンプレート化する
#pragma oncestruct vec_t { double x, y, z; };template<typename T> double length(const T& v) { return sqrt( v.x * v.x + v.y * v.y + v.z * v.z ); }
これでx,y,zというメンバ変数がpublicにあればコンパイルできる。
#include <iostream> #include "len.hpp"struct xyz_t { double x, y, z; };int main() { double L; vec_t vv; vv.x = 1; vv.y = 1; vv.z = 1; L = length(vv); std::cout << L << std::endl; xyz_t xyz; xyz.x = 1; xyz.y = 1; xyz.z = 1; L = length(xyz); std::cout << L << std::endl; int i; std::cin >>i; }
ではx,y,zがないときはどうすればいいのか。
#pragma once//デフォルトの型 struct vec_t { double x, y, z; };//プライマリテンプレート template<typename T> struct GETTER;//特殊化1(デフォルトの型) template<> struct GETTER<vec_t> { using arg_t = vec_t; using carg_t = const vec_t; static inline double& X(arg_t& v) { return v.x; } static inline double& Y(arg_t& v) { return v.y; } static inline double& Z(arg_t& v) { return v.z; } static inline const double& X(carg_t& v) { return v.x; } static inline const double& Y(carg_t& v) { return v.y; } static inline const double& Z(carg_t& v) { return v.z; } };template< typename T, class G = GETTER<T> > double length(const T & v) { return sqrt( G::X(v) * G::X(v) + G::Y(v) * G::Y(v) + G::Z(v) * G::Z(v) ); }
#include <iostream> #include "len.hpp" //自作の型 struct XYZ_t { double X, Y, Z; };
//特殊化2(自作の型用) template<> struct GETTER<XYZ_t> { using arg_t = XYZ_t; using carg_t = const XYZ_t; static inline double& X(arg_t& v) { return v.X; } static inline double& Y(arg_t& v) { return v.Y; } static inline double& Z(arg_t& v) { return v.Z; } static inline const double& X(carg_t& v) { return v.X; } static inline const double& Y(carg_t& v) { return v.Y; } static inline const double& Z(carg_t& v) { return v.Z; } };//エントリポイント int main() { double L; vec_t vv; vv.x = 1; vv.y = 1; vv.z = 1; L = length(vv); std::cout << L << std::endl; XYZ_t xyz; xyz.X = 1; xyz.X = 1; xyz.X = 1; L = length(xyz); std::cout << L << std::endl; int i; std::cin >> i; }
これでGETTERを定義すればどんな型でも使える。
続く...
https://github.com/HowardHinnant/hash_append/issues/7
最新のC++にはBoostから正式に仕様に含められたhashが「unordered_map」という名前で入っているが、hash_combineは取り入れられていないらしい。なので自分で作る必要がある。
この時、多くはBoostを参考にすると思うのだが、Boostの中のマジックナンバーがどうやら32bitのもので、64bit版の場合、この数字はどうなるんだ?というのが上記サイトの議論の内容となっている。
そもそもこの数字はTEAアルゴリズムというものが根拠らしく、64bitの場合と、さらに128bitの場合の値が上げられている。
ビット数 | 16進数表記の値 |
---|---|
8 | 0x9e |
16 | 0x9e37 |
32 | 0x9e3779b9 |
64 | 0x9e3779b97f4a7c15 |
128 | 0x9e3779b97f4a7c15f39cc0605d396154 |
そして64bitは32bitの二倍なので、シフト量も二倍にする。
↓
なおこの(Boostの)HashCombineはさして優れているわけでは無いと言うことで、別の方法があるならそれを使うべきと言うような主張をちらほら見かける。
CityHashはGoogleが考案したハッシュアルゴリズムで、MITライセンス(らしい)。そこから転用したコードが紹介されている。
template <class T> inline void hash_combine(std::size_t& seed, const T& v) { std::hash<T> hasher; const std::size_t kMul = 0x9ddfea08eb382d69ULL; std::size_t a = (hasher(v) ^ seed) * kMul; a ^= (a >> 47); std::size_t b = (seed ^ a) * kMul; b ^= (b >> 47); seed = b * kMul; }
(このスニペットは、CityHashコードの「実質的な部分」を構成するものではないため、ここや他の場所に複製しても問題ないと思いますが、CityHashのソースとライセンス契約を確認して、自分で決めてください)
(Google翻訳)
c2220 警告をエラーとして扱いました。'object' ファイルは生成されません。
Open3DのCMakeを試していたのだけれど、VC++2017でC2220が大量発生した。関連するプロジェクトが無数にある場合で、一つ一つプロパティを開くのは避けたい場合、王道な方法が見つからなかったのでCMakeList.txtを編集して対処した。
単体のプロジェクトなら、以下のように /WX オプションを解除することで対処できる。
CMakeLists.txtをテキストエディタで開き、中の「/WX」という部分を削除する。
https://github.com/nigels-com/glew#copyright-and-licensing
GLEW is originally derived from the EXTGL project by Lev Povalahev. The source code is licensed under the Modified BSD License, the Mesa 3-D License (MIT) and the Khronos License (MIT).
The automatic code generation scripts are released under the GNU GPL.
glewはBSD LicenseかMITライセンス。普通誰も気にしないが、気に入らない場合は使用できない。
けれどやっていることはヘッダファイル側で定数を#defineしているのと、dll側でwglGetProcAddressしているだけ(多分)なので、必要な部分だけ自前で書くことも不可能ではない。
#pragma once #include <gl/GL.h> typedef ptrdiff_t GLsizeiptr; typedef char GLchar; //サンプルのコンパイルに必要なものだけを取り出したもの // 関数ポインタ型 using PFNGLGENBUFFERSPROC = void(_stdcall*) (GLsizei n, GLuint* buffers); using PFNGLBINDBUFFERPROC = void(_stdcall*) (GLenum target, GLuint buffer); using PFNGLBUFFERDATAPROC = void(_stdcall*) (GLenum target, GLsizeiptr size, const void* data, GLenum usage); using PFNGLCREATESHADERPROC = GLuint(_stdcall*) (GLenum type); using PFNGLSHADERSOURCEPROC = void(_stdcall*) (GLuint shader, GLsizei count, const GLchar* const* string, const GLint* length); using PFNGLCOMPILESHADERPROC = void(_stdcall*) (GLuint shader); using PFNGLGETSHADERIVPROC = void(_stdcall*) (GLuint shader, GLenum pname, GLint* param); using PFNGLGETSHADERINFOLOGPROC = void(_stdcall*) (GLuint shader, GLsizei bufSize, GLsizei* length, GLchar* infoLog); using PFNGLCREATEPROGRAMPROC = GLuint(_stdcall*) (void); using PFNGLATTACHSHADERPROC = void(_stdcall*) (GLuint program, GLuint shader); using PFNGLLINKPROGRAMPROC = void(_stdcall*) (GLuint program); using PFNGLGETPROGRAMIVPROC = void(_stdcall*) (GLuint program, GLenum pname, GLint* param); using PFNGLGETPROGRAMINFOLOGPROC = void(_stdcall*) (GLuint program, GLsizei bufSize, GLsizei* length, GLchar* infoLog); using PFNGLUSEPROGRAMPROC = void(_stdcall*) (GLuint program); using PFNGLENABLEVERTEXATTRIBARRAYPROC = void(_stdcall*) (GLuint index); using PFNGLVERTEXATTRIBPOINTERPROC = void(_stdcall*) (GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const void* pointer); using PFNGLDISABLEVERTEXATTRIBARRAYPROC = void(_stdcall*) (GLuint index); // 定数 #define GL_ARRAY_BUFFER 0x8892 #define GL_STATIC_DRAW 0x88E4 #define GL_VERTEX_SHADER 0x8B31 #define GL_COMPILE_STATUS 0x8B81 #define GL_INFO_LOG_LENGTH 0x8B84 #define GL_FRAGMENT_SHADER 0x8B30 #define GL_LINK_STATUS 0x8B82 // wglGetProcAddressで取得したアドレスを格納する変数(グローバル) PFNGLGENBUFFERSPROC glGenBuffers; PFNGLBINDBUFFERPROC glBindBuffer; PFNGLBUFFERDATAPROC glBufferData; PFNGLCREATESHADERPROC glCreateShader; PFNGLSHADERSOURCEPROC glShaderSource; PFNGLCOMPILESHADERPROC glCompileShader; PFNGLGETSHADERIVPROC glGetShaderiv; PFNGLGETSHADERINFOLOGPROC glGetShaderInfoLog; PFNGLCREATEPROGRAMPROC glCreateProgram; PFNGLATTACHSHADERPROC glAttachShader; PFNGLLINKPROGRAMPROC glLinkProgram; PFNGLGETPROGRAMIVPROC glGetProgramiv; PFNGLGETPROGRAMINFOLOGPROC glGetProgramInfoLog; PFNGLUSEPROGRAMPROC glUseProgram; PFNGLENABLEVERTEXATTRIBARRAYPROC glEnableVertexAttribArray; PFNGLVERTEXATTRIBPOINTERPROC glVertexAttribPointer; PFNGLDISABLEVERTEXATTRIBARRAYPROC glDisableVertexAttribArray; //関数のアドレスを取得 inline void myglinit() { glAttachShader = (PFNGLATTACHSHADERPROC)wglGetProcAddress("glAttachShader"); glBindBuffer = (PFNGLBINDBUFFERPROC)wglGetProcAddress("glBindBuffer"); glBufferData = (PFNGLBUFFERDATAPROC)wglGetProcAddress("glBufferData"); glCompileShader = (PFNGLCOMPILESHADERPROC)wglGetProcAddress("glCompileShader"); glCreateProgram = (PFNGLCREATEPROGRAMPROC)wglGetProcAddress("glCreateProgram"); glCreateShader = (PFNGLCREATESHADERPROC)wglGetProcAddress("glCreateShader"); glDisableVertexAttribArray = (PFNGLDISABLEVERTEXATTRIBARRAYPROC)wglGetProcAddress("glDisableVertexAttribArray"); glEnableVertexAttribArray = (PFNGLENABLEVERTEXATTRIBARRAYPROC)wglGetProcAddress("glEnableVertexAttribArray"); glGenBuffers = (PFNGLGENBUFFERSPROC)wglGetProcAddress("glGenBuffers"); glGetProgramInfoLog = (PFNGLGETPROGRAMINFOLOGPROC)wglGetProcAddress("glGetProgramInfoLog"); glGetProgramiv = (PFNGLGETPROGRAMIVPROC)wglGetProcAddress("glGetProgramiv"); glGetShaderInfoLog = (PFNGLGETSHADERINFOLOGPROC)wglGetProcAddress("glGetShaderInfoLog"); glGetShaderiv = (PFNGLGETSHADERIVPROC)wglGetProcAddress("glGetShaderiv"); glLinkProgram = (PFNGLLINKPROGRAMPROC)wglGetProcAddress("glLinkProgram"); glShaderSource = (PFNGLSHADERSOURCEPROC)wglGetProcAddress("glShaderSource"); glUseProgram = (PFNGLUSEPROGRAMPROC)wglGetProcAddress("glUseProgram"); glVertexAttribPointer = (PFNGLVERTEXATTRIBPOINTERPROC)wglGetProcAddress("glVertexAttribPointer"); }
元のソースコード
#include <iostream> #pragma warning(disable:4996) //#pragma comment(lib,"glew32.lib") --- しない //#include <gl/glew.h> --- しない #include <Windows.h> #include <GL/glut.h> #include <fstream> #include <sstream> #include <vector> #include <algorithm> #include "myglinit.hpp" void init(void); void display(void); void link_program(); void prepare_buffers(); void prepare_vertex_shader(); void prepare_fragment_shader(); int main(int argc, char *argv[]) { glutInit(&argc, argv); glutInitDisplayMode(GLUT_RGBA); glutCreateWindow(argv[0]); glutDisplayFunc(display); //■ glewInit(); // glewの初期化 --- しない myglinit();// glewInit()関数の代わり init(); glutMainLoop(); return 0; } void init(void) { //頂点データと色情報の作成 prepare_buffers(); //頂点シェーダの準備 prepare_vertex_shader(); //フラグメントシェーダの準備 prepare_fragment_shader(); //プログラムのリンク link_program(); } //バッファとデータ typedef GLfloat points_t[3]; GLuint vertexbuffer;//バッファのIDを格納する変数 GLuint colorbuffer;//バッファのIDを格納する変数 points_t position[3]; points_t color[3]; ////////////////////////////////////////////////// void prepare_buffers() { //頂点座標 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; //色 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; glGenBuffers(1, &vertexbuffer); glBindBuffer(GL_ARRAY_BUFFER, vertexbuffer); glBufferData( GL_ARRAY_BUFFER, 3 * 3 * sizeof(GLfloat), position, GL_STATIC_DRAW); glGenBuffers(1, &colorbuffer); glBindBuffer(GL_ARRAY_BUFFER, colorbuffer); glBufferData( GL_ARRAY_BUFFER, 3 * 3 * sizeof(GLfloat), color, GL_STATIC_DRAW); } GLuint VertexShaderID; void prepare_vertex_shader() { ////////////////////////////////////////////// // シェーダを作ります // (作るといっても宣言みたいなもの) VertexShaderID = glCreateShader(GL_VERTEX_SHADER); //////////////////////////////////////////// // ファイルから頂点シェーダを読み込みます。 // 注意 ここはSTLのifstreamとかstringstreamの使い方の話で、 // OpenGL命令は一つも無い。 const char * vertex_file_path = ".\\verts.sh"; std::string VertexShaderCode; std::ifstream VertexShaderStream(vertex_file_path, std::ios::in); if (VertexShaderStream.is_open()) { std::stringstream sstr; sstr << VertexShaderStream.rdbuf(); VertexShaderCode = sstr.str(); VertexShaderStream.close(); } //////////////////////////////////////////// // 頂点シェーダをコンパイルします。 printf("Compiling shader : %s\n", vertex_file_path); char const * VertexSourcePointer = VertexShaderCode.c_str(); glShaderSource(VertexShaderID, 1, &VertexSourcePointer, NULL); glCompileShader(VertexShaderID); //////////////////////////////////////////// // エラーチェック GLint Result = GL_FALSE; int InfoLogLength; // 頂点シェーダをチェックします。 glGetShaderiv(VertexShaderID, GL_COMPILE_STATUS, &Result); glGetShaderiv(VertexShaderID, GL_INFO_LOG_LENGTH, &InfoLogLength); if (Result == FALSE) { std::vector<char> VertexShaderErrorMessage(InfoLogLength); glGetShaderInfoLog(VertexShaderID, InfoLogLength, NULL, &VertexShaderErrorMessage[0]); fprintf(stdout, "%s\n", &VertexShaderErrorMessage[0]); } } GLuint FragmentShaderID; void prepare_fragment_shader() { ///////////////////////////////////////////// // シェーダを作ります。 FragmentShaderID = glCreateShader(GL_FRAGMENT_SHADER); ///////////////////////////////////////////// // ファイルからフラグメントシェーダを読み込みます。 const char * fragment_file_path = ".\\frags.sh"; std::string FragmentShaderCode; std::ifstream FragmentShaderStream(fragment_file_path, std::ios::in); if (FragmentShaderStream.is_open()) { std::stringstream sstr; sstr << FragmentShaderStream.rdbuf(); FragmentShaderCode = sstr.str(); FragmentShaderStream.close(); } ///////////////////////////////////////////// // フラグメントシェーダをコンパイルします。 printf("Compiling shader : %s\n", fragment_file_path); char const * FragmentSourcePointer = FragmentShaderCode.c_str(); glShaderSource(FragmentShaderID, 1, &FragmentSourcePointer, NULL); glCompileShader(FragmentShaderID); GLint Result = GL_FALSE; int InfoLogLength; ///////////////////////////////////////////// // フラグメントシェーダをチェックします。 glGetShaderiv(FragmentShaderID, GL_COMPILE_STATUS, &Result); glGetShaderiv(FragmentShaderID, GL_INFO_LOG_LENGTH, &InfoLogLength); if (Result == GL_FALSE) { std::vector<char> FragmentShaderErrorMessage(InfoLogLength); glGetShaderInfoLog(FragmentShaderID, InfoLogLength, NULL, &FragmentShaderErrorMessage[0]); fprintf(stdout, "%s\n", &FragmentShaderErrorMessage[0]); } } GLuint ProgramID; void link_program() { GLint Result = GL_FALSE; int InfoLogLength; //////////////////////////////////////// // プログラムをリンクします。 fprintf(stdout, "Linking program\n"); ProgramID = glCreateProgram(); glAttachShader(ProgramID, VertexShaderID); glAttachShader(ProgramID, FragmentShaderID); glLinkProgram(ProgramID); //////////////////////////////////////// // プログラムをチェックします。 glGetProgramiv(ProgramID, GL_LINK_STATUS, &Result); glGetProgramiv(ProgramID, GL_INFO_LOG_LENGTH, &InfoLogLength); std::vector<char> ProgramErrorMessage((std::max)(InfoLogLength, int(1))); glGetProgramInfoLog(ProgramID, InfoLogLength, NULL, &ProgramErrorMessage[0]); fprintf(stdout, "%s\n", &ProgramErrorMessage[0]); } void display(void) { glClearColor(0, 0, 0, 1); glClear(GL_COLOR_BUFFER_BIT); glLoadIdentity(); glTranslated(0.5, 0.0, 0.0);//平行移動 // シェーダを使う 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 // 配列バッファオフセット ); // 三角形を描きます! glDrawArrays(GL_TRIANGLES, 0, 3); glDisableVertexAttribArray(0);//バッファを無効にする glDisableVertexAttribArray(1); glFlush(); }
他にもリンクしちゃいけないときとかもこの方法をとることになると思う。ただその場合はglext.hを使えば自分で#define やtypedefを並べたりしなくて良くなる・・・のか?
「MIT Licenseを気にする状況ってどんな状況?」とか言う人がいそうなのだけれど、個人でならともかく業務でやっていると、自分より上の層で「俺が理解できないものは低品質なガラクタ」とか「俺の知らないものは使えないゴミ」等の謎理論で意味不明な利用制限がかかったりするので、できるかできないかぐらいは把握しておいた方がいい。後は、そういう契約になってるんだ!とか後から言われたり。しないかな?しないよね。
・ビットシフト(>>)には算術シフトと論理シフトがある。
・算術シフトは負数をシフトすると左側が1で埋まる (Arithmetic shift)
・論理シフトは負数をシフトすると左側が0で埋まる (Logical shift)
・どちらの挙動をするかは処理系依存
ということで、強制的に論理シフトしたい時は工夫する必要がある。
unsignedにキャストする。以下C++のコード。
#include <iostream> //表示のためにbitsetを使う #include <bitset> int main() { char val = -40; char S = val; char A = val >> 2;//処理系依存 VC++2019では算術シフト char L = static_cast<unsigned char>(val) >> 2;//論理シフト std::bitset<8> Sdisp(S); std::bitset<8> Adisp(A); std::bitset<8> Ldisp(L); std::cout << "source : " << Sdisp << " == " << static_cast<int>(S) << '\n'; std::cout << "not cast and >>2 : " << Adisp << " == " << static_cast<int>(A) << '\n'; std::cout << "cast to unsigned and >>2 : " << Ldisp << " == " << static_cast<int>(L) << '\n'; getchar(); return 0; }
同じ事を関数化するなら以下のような感じになる。
#include <iostream> #include<type_traits>
//! @brief 論理右シフト //! @param [in] val 右シフトする値 //! @param [in] shift 右シフトするビット数 //! @return val >> shift template<typename T> inline auto logical_right_shift(const T val,const int shift) { return static_cast< typename std::make_unsigned<T>::type>(val) >> shift; }
int main() { char val = -40; char S = val; char A = val >> 2;//処理系依存 VC++2019では算術シフト char L = logical_right_shift(val, 2);//論理シフト std::bitset<8> Sdisp(S); std::bitset<8> Adisp(A); std::bitset<8> Ldisp(L); std::cout << "source : " << Sdisp << " == " << static_cast<int>(S) << '\n'; std::cout << "not cast and >>2 : " << Adisp << " == " << static_cast<int>(A) << '\n'; std::cout << "logicalrightshift 2 : " << Ldisp << " == " << static_cast<int>(L) << '\n'; getchar(); }
負数の算術シフトが処理系依存とは。流石Cと言わざるを得ない。
import bpy from mathutils import Vector surface_data = bpy.data.curves.new('wook', 'SURFACE') surface_data.dimensions = '3D' # 16 coordinates, set points per segments (U * V) points = [ Vector((-1.5, -1.5, 0.0, 1.0)), Vector((-1.5, -0.5, 0.0, 1.0)), # 0, 0, 1 / 0, 1, 0 Vector((-1.5, 0.5, 0.0, 1.0)), Vector((-1.5, 1.5, 0.0, 1.0)), # 0, 1, 1 / 1, 0, 0 Vector((-0.5, -1.5, 0.0, 1.0)), Vector((-0.5, -0.5, 1.0, 1.0)), # 1, 0, 1 / 1, 1, 0 Vector((-0.5, 0.5, 1.0, 1.0)), Vector((-0.5, 1.5, 0.0, 1.0)), # 1, 1, 1 / 0, 0, 0 Vector((0.5, -1.5, 0.0, 1.0)), Vector((0.5, -0.5, 1.0, 1.0)), # 0.0, 0,0, 0.5 / 0.0, 0,5, 0.0 Vector((0.5, 0.5, 1.0, 1.0)), Vector((0.5, 1.5, 0.0, 1.0)), # 0.0, 0.5, 0.5 / 0.5, 0.0, 0.0 Vector((1.5, -1.5, 0.0, 1.0)), Vector((1.5, -0.5, 0.0, 1.0)), # 0.5, 0.0, 0.5 / 0.5, 0.5, 0.0 Vector((1.5, 0.5, 0.0, 1.0)), Vector((1.5, 1.5, 0.0, 1.0)) # 0.5, 0.5, 0.5 / 1.0, 0.2, 0.2 ] for i in range(0, 16, 4): spline = surface_data.splines.new(type='NURBS') spline.points.add(3) # already has a default zero vector for p, new_co in zip(spline.points, points[i:i+4]): p.co = new_co surface_object = bpy.data.objects.new('NURBS_OBJ', surface_data) splines = surface_object.data.splines for s in splines: for p in s.points: p.select = True ####################################### ####################################### # 新しいCollrectionを作成 newCol = bpy.data.collections.new('Collection 1') # 現在のシーンにコレクションをリンク bpy.context.scene.collection.children.link(newCol) # コレクションにオブジェクトをリンク newCol.objects.link(surface_object) ####################################### ####################################### bpy.context.view_layer.objects.active = surface_object bpy.ops.object.mode_set(mode='EDIT') bpy.ops.curve.make_segment() #https://blender.stackexchange.com/questions/126577/blender-2-8-api-python-set-active-object
https://blender.stackexchange.com/questions/126577/blender-2-8-api-python-set-active-object
import bpy
curvedata = bpy.data.curves.new("my curve", type='CURVE')
curvedata.dimensions = '3D'
polyline = curvedata.splines.new('BEZIER')
polyline.bezier_points.add(2) # 制御点数ー1個
polyline.bezier_points[0].co = 0,0,0
polyline.bezier_points[0].handle_left = -1,0,0
polyline.bezier_points[0].handle_right = 1,0,0
polyline.bezier_points[1].co = 2,0,1
polyline.bezier_points[1].handle_left = 1,0,1
polyline.bezier_points[1].handle_right = 3,0,1
polyline.bezier_points[2].co = 4,0,0
polyline.bezier_points[2].handle_left = 3,0,0
polyline.bezier_points[2].handle_right = 5,0,0
obj = bpy.data.objects.new("my bezier", curvedata)
# 新しいCollrectionを作成
newCol = bpy.data.collections.new('Collection 1')
# 現在のシーンにコレクションをリンク
bpy.context.scene.collection.children.link(newCol)
# コレクションにオブジェクトをリンク
newCol.objects.link(obj)
import bpy
#############################################################
#############################################################
# メタボール(一つ目)
# add metaball object
mball = bpy.data.metaballs.new("MyBall")
mball.resolution = 0.15 # View resolution
#mball.render_resolution
ele = mball.elements.new()
ele.co = (0.0, 0.0, 0.0)
ele.use_negative = False
ele.radius = 2.0
# create meta ball
obj1 = bpy.data.objects.new("MyBallObjectK", mball)
#############################################################
#############################################################
# メタボール(二つ目)
mball = bpy.data.metaballs.new("MyBall") mball.resolution = 0.15 # View resolution ele = mball.elements.new() ele.co = (1.0, 1.0, 1.0) ele.use_negative = False ele.radius = 2.0 # create meta ball obj2 = bpy.data.objects.new("MyBallObjectK", mball)
# 名前を同じにすることで MyBallObjectK.001 のような名前にする
#############################################################
#############################################################
# 新しいCollrectionを作成
newCol = bpy.data.collections.new('Collection 1')
# 現在のシーンにコレクションをリンク
bpy.context.scene.collection.children.link(newCol)
newCol.objects.link(obj1)
newCol.objects.link(obj2)
#https://developer.blender.org/T33455
Blender Pythonでメタボールを作ろうとして、以下の問題に遭遇した。
つまり、メタボールのオブジェクトを二つ作ったが中身が表示されなかった。
メタボールの挙動は、オブジェクト名に依存する。
メタボールは、オブジェクト名が数字で終わらないものをmotherとし、それ以外の、同じ名前 + . + 数字のオブジェクト同士が結合する
・Kball / Mball ... 名前が違うと独立する
・Mball2 ... 名前の最後が数字だと表示されない
・Kball / Kball2 ... 名前が同じでも、単純に後ろに数字を付けるだけでは表示されない
・Kball / Kball.001 ... 同じ名前.数字 の組み合わせで初めてくっつく
libpngで8bit,16bit以外のビット深度のグレイスケール画像を読み込むと、メモリ上には1bit,2bit,4bitなどごとにデータが格納されているので、1byteごとデータを取り出すような簡単な処理で取得できない。
ちょっと調べた限りでは画素値を素直に取り出す関数などが見当たらなかった(あるかもしれない)のでとりあえず適当に作ることにした。
例えば、bit depth==4で
10101011 , 01001110 , 10000101 というデータがあったら、
1010,1011,0100,1110,1000,0101
と分割する
対象が1bit,2bit,4bitの時は、以下のような感じで、該当部分のビット列だけを抜き出して右にシフトする。
対象が8bitの時はデータをそのままunsigned char型の配列として扱う。
対象が16bitの時はデータをそのままunsigned short型の配列として扱い、取得した2byteの前後をswapする。
//! @file CGetGrayBits.hpp //! @brief 1bit,2bit,4bit,8bit,16bitごとに納められたデータを取得する #pragma once //! @class CGetGrayBits //! @brief 配列上のx番目の画素値を取得するクラス class CGetGrayBits { unsigned char* m_p; //!< 画素へのポインタ int m_depth; //!< ビット深度 unsigned char m_mask = 0; //!< depth8未満の時のビットマスク public:
//! @brief コンストラクタ //! @param [in] p 画素配列へのポインタ //! @param [in] depth ビット深度。1画素が何ビットで表現されているか CGetGrayBits( const void* const p, const int depth) : m_p(static_cast<unsigned char*>(const_cast<void*>(p))), m_depth(depth) { //ビット深度が8未満の時に使用するマスクを作成 if (m_depth < 8) { for (int i = 0; i < m_depth; i++) m_mask = (m_mask << 1) | 1; } }
//! @brief 指定した番号の画素を取得 //! @param [in] x 画素番号 //! @return 画素値 int operator[](const std::size_t x) { switch (m_depth) { case 1: case 2: case 4: return getgrayLess8(x); break; case 8: return getgray8(x); break; case 16: return getgray16(x); break; } return -1; }
//! @brief 指定した番号の画素を取得(ビット深度==8の時) //! @param [in] x 画素番号 //! @return 画素値をintで表現したもの inline int getgray8(const std::size_t x)const { return static_cast<int>(m_p[x]); }
//! @brief 指定した番号の画素を取得(ビット深度==16の時) //! @param [in] x 画素番号 //! @return 画素値をintで表現したもの inline int getgray16(const std::size_t x)const { unsigned short t = reinterpret_cast<unsigned short*>(m_p)[x]; std::swap( reinterpret_cast<unsigned char*>(&t)[0], reinterpret_cast<unsigned char*>(&t)[1]); return t; }
//! @brief 指定した番号の画素を取得(ビット深度<8の時) //! @param [in] x 画素番号 //! @return 画素値をintで表現したもの inline int getgrayLess8(const std::size_t x)const { // x ドットが何バイト目かを算出 (0開始) std::size_t byte = x / (8 / m_depth); unsigned char c = m_p[byte]; std::size_t pos = x % (8 / m_depth); int shift = 8 - m_depth - pos * m_depth; unsigned char mask1 = m_mask << shift; unsigned int val = (c & mask1) >> shift; return val; }
};
#pragma once #include <cstdlib> #include <iostream> #include <vector> #include <bitset> #include <png.h> #include <algorithm> #include "CGetGrayBits.hpp" #pragma comment(lib,"libpng16.lib") void out_to_ppm( const char* outpath, const int width, const int height, const std::vector<int>& pixels );
//エラーの時強制終了 void abort_(const char* c) { printf(c); abort(); } //! @brief pngファイル読み込み関数 //! @param [in] file_name ファイル名 //! @param [out] width 画像幅(ピクセル) //! @param [out] height 画像高さ(ピクセル) //! @param [out] color_type RGBかRGBAか...等 //! @param [out] bit_depth チャンネルのビット数 //! @param [out] row_pointers 画像データへのポインタのポインタ //! @param [out] palette パレット //! @param [out] palette_num パレット色の個数 void read_png( const char* file_name, int* width, int* height, png_byte* color_type, png_byte* bit_depth, png_bytep** row_pointers, png_colorp* palette, int* palette_num ) { png_byte header[8]; // 8 is the maximum size that can be checked FILE* fp = fopen(file_name, "rb"); if (!fp) { abort_("[read_png_file] File could not be opened for reading"); } fread(header, 1, 8, fp); if (png_sig_cmp(header, 0, 8)) { abort_("[read_png_file] File is not recognized as a PNG file"); } png_structp png_ptr; png_infop info_ptr; /* initialize stuff */ png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); if (!png_ptr) abort_("[read_png_file] png_create_read_struct failed"); info_ptr = png_create_info_struct(png_ptr); if (!info_ptr) abort_("[read_png_file] png_create_info_struct failed"); if (setjmp(png_jmpbuf(png_ptr))) abort_("[read_png_file] Error during init_io"); png_init_io(png_ptr, fp); png_set_sig_bytes(png_ptr, 8); png_read_info(png_ptr, info_ptr); ///////////////////////////////////////// // 画像情報の取得 *width = png_get_image_width(png_ptr, info_ptr); *height = png_get_image_height(png_ptr, info_ptr); *color_type = png_get_color_type(png_ptr, info_ptr); *bit_depth = png_get_bit_depth(png_ptr, info_ptr); // ///////////////////////////////////////// ///////////////////////////////////////// // パレットの取得 if (*color_type & PNG_COLOR_TYPE_PALETTE) { png_get_PLTE(png_ptr, info_ptr, palette, palette_num); } // ///////////////////////////////////////// int number_of_passes; number_of_passes = png_set_interlace_handling(png_ptr); png_read_update_info(png_ptr, info_ptr); /* read file */ if (setjmp(png_jmpbuf(png_ptr))) abort_("[read_png_file] Error during read_image"); ///////////////////////////////////////// // 画像の読み込み *row_pointers = (png_bytep*)malloc(sizeof(png_bytep) * *height); for (int y = 0; y < *height; y++) (*row_pointers)[y] = (png_byte*)malloc(png_get_rowbytes(png_ptr, info_ptr)); png_read_image(png_ptr, *row_pointers); // ///////////////////////////////////////// fclose(fp); }
int main() { int width; int height; png_byte color_type; png_byte bit_depth; png_bytep* row_pointers; png_colorp palette; int palette_num; //////////////////////////////// // 画像読み込み read_png( R"(c:\test\data\snail2.png)", &width, &height, &color_type, &bit_depth, &row_pointers, &palette, &palette_num ); // //////////////////////////////// std::cout << "width : " << width << std::endl; std::cout << "height: " << height << std::endl; std::cout << "colortype: " << (int)color_type << std::endl; std::cout << "bitdepth: " << (int)bit_depth << std::endl; //////////////////////////////// //グレイスケール画像だけを対象とする if (color_type != (PNG_COLOR_TYPE_GRAY )){ std::cout << "not support" << std::endl; int i; std::cin >> i; return -1; } // ////////////////////////////////
//////////////////////////////// // 内容を取得 std::vector<int> imgvec; for (int y = 0; y < height; y++) { png_bytep yhead = row_pointers[y]; // 画像の横一列の先頭を取得 CGetGrayBits g(yhead, bit_depth); // 画素取得の準備 for (int x = 0; x < width; x++) { int index = g[x]; // x番目の画素値をintで取得 imgvec.push_back( index ); // 画素値を保存 } } // ///////////////////////////////////////////////
/////////////////////////////////////////////// // 画像として保存 char outpath[1024]; sprintf(outpath, R"(C:\test\out-%d-palette.ppm)",bit_depth); out_to_ppm(outpath, width, height, imgvec); // /////////////////////////////////////////////// /////////////////////////////////////////////// // メモリの解放 for (size_t i = 0; i < (size_t)height; i++) { png_bytep yhead = row_pointers[i]; free(yhead); } free(row_pointers); // /////////////////////////////////////////////// int i; std::cin >> i; } void out_to_ppm(const char* outpath,const int width, const int height, const std::vector<int>& pixels) { int pixmax = *std::max_element(pixels.begin(), pixels.end()); FILE* fp = fopen(outpath, "wb"); fprintf(fp, "P3\n%d %d\n%d\n", width, height, 255); for (size_t y = 0; y < (size_t)height; y++) { for (size_t x = 0; x < (size_t)width; x++) { int index = y * width + x; unsigned char c = pixels[index] / (double)pixmax * 255; fprintf(fp, "%d %d %d ", c, c, c); } fprintf(fp, "\n"); } fclose(fp); }
前回ImageMagickで作成したデータを用いる。