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