float3 Camera::transform_raster_to_world(float raster_x, float raster_y) { float3 D, P; if(type == CAMERA_PERSPECTIVE) { D = transform_perspective(&rastertocamera, make_float3(raster_x, raster_y, 0.0f)); float3 Pclip = normalize(D); P = make_float3(0.0f, 0.0f, 0.0f); /* TODO(sergey): Aperture support? */ P = transform_point(&cameratoworld, P); D = normalize(transform_direction(&cameratoworld, D)); /* TODO(sergey): Clipping is conditional in kernel, and hence it could * be mistakes in here, currently leading to wrong camera-in-volume * detection. */ P += nearclip * D / Pclip.z; } else if(type == CAMERA_ORTHOGRAPHIC) { D = make_float3(0.0f, 0.0f, 1.0f); /* TODO(sergey): Aperture support? */ P = transform_perspective(&rastertocamera, make_float3(raster_x, raster_y, 0.0f)); P = transform_point(&cameratoworld, P); D = normalize(transform_direction(&cameratoworld, D)); } else { assert(!"unsupported camera type"); } return P; }
float Camera::world_to_raster_size(float3 P) { if(type == CAMERA_ORTHOGRAPHIC) { return min(len(full_dx), len(full_dy)); } else if(type == CAMERA_PERSPECTIVE) { /* Calculate as if point is directly ahead of the camera. */ float3 raster = make_float3(0.5f*width, 0.5f*height, 0.0f); float3 Pcamera = transform_perspective(&rastertocamera, raster); /* dDdx */ float3 Ddiff = transform_direction(&cameratoworld, Pcamera); float3 dx = len_squared(full_dx) < len_squared(full_dy) ? full_dx : full_dy; float3 dDdx = normalize(Ddiff + dx) - normalize(Ddiff); /* dPdx */ float dist = len(transform_point(&worldtocamera, P)); float3 D = normalize(Ddiff); return len(dist*dDdx - dot(dist*dDdx, D)*D); } else { // TODO(mai): implement for CAMERA_PANORAMA assert(!"pixel width calculation for panoramic projection not implemented yet"); } return 1.0f; }
float3 DiagSplit::project(Patch *patch, float2 uv) { float3 P; patch->eval(&P, NULL, NULL, uv.x, uv.y); if(params.camera) P = transform_perspective(¶ms.camera->worldtoraster, P); return P; }
void Camera::update() { if(!need_update) return; /* Full viewport to camera border in the viewport. */ Transform fulltoborder = transform_from_viewplane(viewport_camera_border); Transform bordertofull = transform_inverse(fulltoborder); /* ndc to raster */ Transform screentocamera; Transform ndctoraster = transform_scale(width, height, 1.0f) * bordertofull; /* raster to screen */ Transform screentondc = fulltoborder * transform_from_viewplane(viewplane); Transform screentoraster = ndctoraster * screentondc; Transform rastertoscreen = transform_inverse(screentoraster); /* screen to camera */ if(type == CAMERA_PERSPECTIVE) screentocamera = transform_inverse(transform_perspective(fov, nearclip, farclip)); else if(type == CAMERA_ORTHOGRAPHIC) screentocamera = transform_inverse(transform_orthographic(nearclip, farclip)); else screentocamera = transform_identity(); Transform cameratoscreen = transform_inverse(screentocamera); rastertocamera = screentocamera * rastertoscreen; cameratoraster = screentoraster * cameratoscreen; cameratoworld = matrix; screentoworld = cameratoworld * screentocamera; rastertoworld = cameratoworld * rastertocamera; ndctoworld = rastertoworld * ndctoraster; /* note we recompose matrices instead of taking inverses of the above, this * is needed to avoid inverting near degenerate matrices that happen due to * precision issues with large scenes */ worldtocamera = transform_inverse(matrix); worldtoscreen = cameratoscreen * worldtocamera; worldtondc = screentondc * worldtoscreen; worldtoraster = ndctoraster * worldtondc; /* differentials */ if(type == CAMERA_ORTHOGRAPHIC) { dx = transform_direction(&rastertocamera, make_float3(1, 0, 0)); dy = transform_direction(&rastertocamera, make_float3(0, 1, 0)); } else if(type == CAMERA_PERSPECTIVE) { dx = transform_perspective(&rastertocamera, make_float3(1, 0, 0)) - transform_perspective(&rastertocamera, make_float3(0, 0, 0)); dy = transform_perspective(&rastertocamera, make_float3(0, 1, 0)) - transform_perspective(&rastertocamera, make_float3(0, 0, 0)); } else { dx = make_float3(0.0f, 0.0f, 0.0f); dy = make_float3(0.0f, 0.0f, 0.0f); } dx = transform_direction(&cameratoworld, dx); dy = transform_direction(&cameratoworld, dy); need_update = false; need_device_update = true; need_flags_update = true; }