普通、光は水に入ると次第に減衰していく。だから極めて浅いところでは色がなく、浅いところでは明るい色になり、深いところでは暗い色になる。
ところがCyclesのGlassは光の減衰を再現してくれないらしい。だから薄く色を付けたGlassのオブジェクトを使うと沼みたいになる。
仕方がないのでVolumeを使用。表面には別に半透明なマテリアルを指定し、Voronoiで波を再現して貼り付けている。
C++のDLLの中に、関数ポインタを取る関数が外部に公開されている。
これをC#から使いたい。
どういうわけか、以下コードのCallFunctionに渡す関数ポインタの型をtypedefした関数ポインタ型(CallFP)にしたところランタイムエラーが起こる。
仕方がないので、void*で受け取って呼び出し直前にキャストするようにしたところうまくいった。今のところ、意味が分からない。
ちなみに、DLLDefs.hはDLL作成時に使用するヘッダで使っているもの。
dlltest.h
#include "DLLDefs.h" #include <cstdint> /////////////////////////////////// /// C++側 (ヘッダ) ///////////////// /////////////////////////////////// int APIENTRY DllMain(HINSTANCE hInstance, DWORD dwReason, LPVOID lpReserved); typedef void(WINAPI *CallFP)(std::int32_t a, std::int32_t b); __DLL_PORT void WINAPI CallFunction(void* p,std::int32_t in1,std::int32_t in2);
dlltest.cpp
#include <Windows.h> #include "dlltest.h" /////////////////////////////////// /// C++側 (cpp) ///////////////// /////////////////////////////////// int APIENTRY DllMain(HINSTANCE hInstance, DWORD dwReason, LPVOID lpReserved) { switch (dwReason) { case DLL_PROCESS_ATTACH: //初期処理 break; case DLL_PROCESS_DETACH: //終了処理 break; } return 1; // OK }; void WINAPI CallFunction(void* p, std::int32_t in1, std::int32_t in2) { CallFP cp = static_cast<CallFP>(p); (*cp)(in1, in2); }
using System; using System.Runtime.InteropServices;//Marshal用 /////////////////////////////////// /// C#側 (呼び出し)///////////////// /////////////////////////////////// namespace ConsoleApplication1 { //コールバック関数の型を宣言 [UnmanagedFunctionPointer(CallingConvention.StdCall)] delegate void TypeOfCallBack_t(System.Int32 a, System.Int32 b); class Program { //DLLの中の関数を宣言 [DllImport("Project1.dll",EntryPoint = "CallFunction") ] public static extern void CallFunction(IntPtr callbk,Int32 in1,Int32 in2); //コールバック関数本体。この関数がDLL経由で呼び出される static public void CallBackMain(Int32 a, Int32 b) { Console.Write(a + b + "\n"); } static TypeOfCallBack_t delgobj; static GCHandle gch; //エントリポイント public static void Main(string[] args) { delgobj = CallBackMain; IntPtr ptr = System.Runtime.InteropServices.Marshal.GetFunctionPointerForDelegate( delgobj ); gch = GCHandle.Alloc(delgobj); //関数を呼び出す CallFunction( ptr ,10,15); Console.Read(); gch.Free(); } } }
DLLを扱う際にimport,exportを分けるファイル。
DLLを作るプロジェクトへ読み込んだ場合は、プロジェクトの設定などでDLL_EXPORT_DOを定義しておけば、関数宣言時に__DLL_PORTを付けると公開関数となる
DLLを使うプロジェクトへ読み込んだ場合は、libをリンクするだけで関数を使えるようになる。
#ifdef DLL_EXPORT_DO /* DLLを作る場合 */ #define __DLL_PORT extern "C" __declspec(dllexport) #else /* DLLを使う場合 */ #define __DLL_PORT extern "C" __declspec(dllimport) #endif
もうすぐ冬なので雪を作りたい。
だがなかなかわかりやすいCyclesのノード構成図が見当たらない。
この絵の床は
https://www.packtpub.com/books/content/creating-ice-and-snow-materials
のiceを途中までやったのだがテクスチャが必要と言われ断念。
ゆきだるまのほうは自前で何かしらやった結果。
てか、iceこれで十分じゃね?(ちょっと変えてある)
template<typename T> struct coord { T x; T y; T z; coord() {} coord(const T _x, const T _y, const T _z) { x = _x; y = _y; z = _z; } template<typename U> coord<T>& operator=(const coord<U>& src) { x = src.x; y = src.y; z = src.z; return *this; } };
このような構造体があったとして、こいつにoperatorを定義するときにいつも悩むのが戻り値の型である。
template<typename T, typename U> double operator-(const coord<T>& s, U v) { typedef decltype(s.x - v) Type; return coord< Type >( static_cast<Type>(s.x - v), static_cast<Type>(s.y - v), static_cast<Type>(s.z - v) ); }
このように型を決め打ちしてしまうと、TもUもintなのにdoubleが返ってくることになったり、long doubleが入ってきたりすると潰れてしまう。
BoostにはBOOST::TYPEOFなるものがあるらしいが、このためにBoostを使うのは論外だ。
Boostにあるということはメタメタすればいけるんだろうが、これもやりたくない。
ここで思い出したのだが、今は仕事でもVC++2015を使っている。こいつのC++11対応はMicrosoftにしては良い線行っている。
autoとdecltypeを使えば、以下のように書ける。
template<typename T, typename U> auto operator-(const coord<T>& s, U v) { typedef decltype(s.x - v) Type; return coord< Type >( static_cast<Type>( s.x-v ), static_cast<Type>( s.y-v ), static_cast<Type>( s.z-v ) ); }
やはり、ターゲットプラットフォームに問題がないなら、Visual C++のバージョンは2015以降を使うことを人類の義務にすべきだ。トランプよ法律作れ。