svn merge ^/trunk/blender -r49520:49531
[blender.git] / source / blender / compositor / operations / COM_ConvertDepthToRadiusOperation.cpp
1 /*
2  * Copyright 2011, Blender Foundation.
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License
6  * as published by the Free Software Foundation; either version 2
7  * of the License, or (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software Foundation,
16  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17  *
18  * Contributor: 
19  *              Jeroen Bakker 
20  *              Monique Dewanchand
21  */
22
23 #include "COM_ConvertDepthToRadiusOperation.h"
24 #include "BLI_math.h"
25 #include "DNA_camera_types.h"
26
27 ConvertDepthToRadiusOperation::ConvertDepthToRadiusOperation() : NodeOperation()
28 {
29         this->addInputSocket(COM_DT_VALUE);
30         this->addOutputSocket(COM_DT_VALUE);
31         this->m_inputOperation = NULL;
32         this->m_fStop = 128.0f;
33         this->m_cameraObject = NULL;
34         this->m_maxRadius = 32.0f;
35         this->m_blurPostOperation = NULL;
36 }
37
38 float ConvertDepthToRadiusOperation::determineFocalDistance()
39 {
40
41         if (this->m_cameraObject == NULL || this->m_cameraObject->type != OB_CAMERA) {
42                 return 10.0f;
43         }
44         else {
45                 Camera *camera = (Camera *)this->m_cameraObject->data;
46                 this->m_cam_lens = camera->lens;
47                 if (camera->dof_ob) {
48                         /* too simple, better to return the distance on the view axis only
49                          * return len_v3v3(ob->obmat[3], cam->dof_ob->obmat[3]); */
50                         float mat[4][4], imat[4][4], obmat[4][4];
51
52                         copy_m4_m4(obmat, this->m_cameraObject->obmat);
53                         normalize_m4(obmat);
54                         invert_m4_m4(imat, obmat);
55                         mult_m4_m4m4(mat, imat, camera->dof_ob->obmat);
56                         return (float)fabs(mat[3][2]);
57                 }
58                 return camera->YF_dofdist;
59         }
60 }
61
62 void ConvertDepthToRadiusOperation::initExecution()
63 {
64         this->m_inputOperation = this->getInputSocketReader(0);
65         float focalDistance = determineFocalDistance();
66         if (focalDistance == 0.0f) focalDistance = 1e10f;  /* if the dof is 0.0 then set it be be far away */
67         this->m_inverseFocalDistance = 1.f / focalDistance;
68         this->m_aspect = (this->getWidth() > this->getHeight()) ? (this->getHeight() / (float)this->getWidth()) : (this->getWidth() / (float)this->getHeight());
69         this->m_aperture = 0.5f * (this->m_cam_lens / (this->m_aspect * 32.0f)) / this->m_fStop;
70         float minsz = MIN2(getWidth(), getHeight());
71         this->m_dof_sp = (float)minsz / (16.f / this->m_cam_lens);    // <- == aspect * MIN2(img->x, img->y) / tan(0.5f * fov);
72         
73         if (this->m_blurPostOperation) {
74                 m_blurPostOperation->setSigma(m_aperture * 128.0f);
75         }
76 }
77
78 void ConvertDepthToRadiusOperation::executePixel(float *outputValue, float x, float y, PixelSampler sampler)
79 {
80         float inputValue[4];
81         float z;
82         float radius;
83         this->m_inputOperation->read(inputValue, x, y, sampler);
84         z = inputValue[0];
85         if (z != 0.f) {
86                 float iZ = (1.f / z);
87                 
88                 // bug #6656 part 2b, do not rescale
89 #if 0
90                 bcrad = 0.5f * fabs(aperture * (dof_sp * (cam_invfdist - iZ) - 1.0f));
91                 // scale crad back to original maximum and blend
92                 crad->rect[px] = bcrad + wts->rect[px] * (scf * crad->rect[px] - bcrad);
93 #endif
94                 radius = 0.5f * fabsf(this->m_aperture * (this->m_dof_sp * (this->m_inverseFocalDistance - iZ) - 1.f));
95                 // 'bug' #6615, limit minimum radius to 1 pixel, not really a solution, but somewhat mitigates the problem
96                 if (radius < 0.0f) radius = 0.0f;
97                 if (radius > this->m_maxRadius) {
98                         radius = this->m_maxRadius;
99                 }
100                 outputValue[0] = radius;
101         }
102         else outputValue[0] = 0.0f;
103 }
104
105 void ConvertDepthToRadiusOperation::deinitExecution()
106 {
107         this->m_inputOperation = NULL;
108 }