カメラ ノード

以下に、カスタムの歪みと周辺減光を設定した単純なパース カメラ ノードのソース コードを示します。

mycamera.cpp

#include <ai.h>
#include <string.h>

AI_CAMERA_NODE_EXPORT_METHODS(MyCameraMethods)

enum
{
   p_fov
};

struct MyCameraData
{
   float tan_fov;
};

node_parameters
{
   AiParameterFlt("fov", 60.0f);
}

node_initialize
{
   AiCameraInitialize(node);
   AiNodeSetLocalData(node, new MyCameraData());
}

node_update
{
   MyCameraData* data = (MyCameraData*)AiNodeGetLocalData(node);
   data->tan_fov = tanf(AiNodeGetFlt(node, AtString("fov")) * AI_DTOR / 2);
   AiCameraUpdate(node, false);
}

node_finish
{
   MyCameraData* data = (MyCameraData*)AiNodeGetLocalData(node);
   delete data;
}

camera_create_ray
{
   const MyCameraData* data = (MyCameraData*)AiNodeGetLocalData(node);
   const AtVector p(input.sx * data->tan_fov, input.sy * data->tan_fov, 1);

   // warp ray origin with a noise vector
   AtVector noise_point(input.sx, input.sy, 0.5f);
   noise_point *= 5;
   AtVector noise_vector = AiVNoise3(noise_point, 1, 0.f, 1.92f);
   output.origin = noise_vector * 0.04f;
   output.dir = AiV3Normalize(p - output.origin);

   // vignetting
   const float dist2 = input.sx * input.sx + input.sy * input.sy;
   output.weight = 1 - dist2;

   // now looking down -Z
   output.dir.z *= -1;
}

camera_reverse_ray
{
   const MyCameraData* data = (MyCameraData*)AiNodeGetLocalData(node);

   // Note: we ignore distortion to compute the screen projection
   // compute projection factor: avoid divide by zero and flips when crossing the camera plane
   float coeff = 1 / AiMax(fabsf(Po.z * data->tan_fov), 1e-3f);
   Ps.x = Po.x * coeff;
   Ps.y = Po.y * coeff;
   return true;
}

node_loader
{
   if (i != 0) return false;
   node->methods     = MyCameraMethods;
   node->output_type = AI_TYPE_UNDEFINED;
   node->name        = "mycamera";
   node->node_type   = AI_NODE_CAMERA;
   strcpy(node->version, AI_VERSION);
   return true;
} 

camera_create_ray では、方向と位置の微分係数も計算できます。これは、正しいフィルタリングのために重要です。ただし、これらのフィールドを既定値の 0.0 に設定されたままにしておくと、Arnold に自動的に微分を計算させることができます。

次の例では、パース カメラのカメラ ノードで微分係数を計算する方法を示しています。この場合、レイの原点は常に同じですが、方向はピクセルごとに変わります。パース カメラの微分係数を計算するには、いくつかのサンプル コードを実行します(uv ノイズは考慮しません)。

   float fov = data->fov;
   fov *= (float) (AI_DTOR * 0.5);
   float tan_fov = tanf(fov);

   ...
   // scale derivatives
   float dsx = input.dsx * tan_fov;
   float dsy = input.dsy * tan_fov;
   ...

   AtVector d = p;  // direction vector == point on the image plane
   double d_dot_d = AiV3Dot(d, d);
   double temp = 1.0 / sqrt(d_dot_d * d_dot_d * d_dot_d);

   // already initialized to 0's, only compute the non zero coordinates
   output.dDdx.x = (d_dot_d * dsx - (d.x * dsx) * d.x) * temp;
   output.dDdx.y = (              - (d.x * dsx) * d.y) * temp;
   output.dDdx.z = (              - (d.x * dsx) * d.z) * temp;
   output.dDdy.x = (              - (d.y * dsy) * d.x) * temp;
   output.dDdy.y = (d_dot_d * dsy - (d.y * dsy) * d.y) * temp;
   output.dDdy.z = (              - (d.y * dsy) * d.z) * temp;

   // output.dOd* is also initialized to 0s, the correct value 

次の .ass ファイルは、このページの上部と同じようなイメージを生成します。

mycamera.ass

options
{
 xres 1024
 yres 1024
 AA_samples 6
 camera "mycamera"
 GI_diffuse_depth 4
 GI_specular_depth 4
}

mycamera
{
 name mycamera
 position 0 1 4
 look_at 0 -0.2 0
 up 0 1 0
}

skydome_light
{
 name myskydome
 intensity 1
 color 1 1 1
 camera 0.0
}

standard_surface
{
 name mystd
 base_color 0.4 0.8 0.4
}

sphere
{
 shader mystd
 matrix
  1 0 0 0
  0 1 0 0
  0 0 1 0
  -1.5 0 0 0
}

sphere
{
 shader mystd
 matrix
  1 0 0 0
  0 1 0 0
  0 0 1 0
  0 0 0 0
}

sphere
{
 shader mystd
 matrix
  1 0 0 0
  0 1 0 0
  0 0 1 0
  1.5 0 0 0
}

standard_surface
{
 name myfloor
 base_color 0.2 0.2 0.2
 specular 0
}

plane
{
 name myplane
 normal 0 1 0
 point 0 -0.5 0
 shader myfloor
}