Optimized the area of interest of the lensdistortion node.
authorJeroen Bakker <j.bakker@atmind.nl>
Tue, 3 Jul 2012 09:05:19 +0000 (09:05 +0000)
committerJeroen Bakker <j.bakker@atmind.nl>
Tue, 3 Jul 2012 09:05:19 +0000 (09:05 +0000)
This will have faster feedback to the user, as lensdistortion is mostly
a node that is located at the end of a composite

source/blender/compositor/nodes/COM_LensDistortionNode.cpp
source/blender/compositor/operations/COM_ScreenLensDistortionOperation.cpp
source/blender/compositor/operations/COM_ScreenLensDistortionOperation.h

index 0319e66ee22610af6324ea73a6e914bcd0543189..bb431f86897181c25acf9d8da16701acfbdbee14 100644 (file)
@@ -48,13 +48,21 @@ void LensDistortionNode::convertToOperations(ExecutionSystem *graph, CompositorC
        }
        else {
                ScreenLensDistortionOperation *operation = new ScreenLensDistortionOperation();
+               operation->setData(data);
+               if (!(this->getInputSocket(1)->isConnected() || this->getInputSocket(2)->isConnected())) 
+               {
+                       // no nodes connected to the distortion and dispersion. We can precalculate some values
+                       float distortion = ((const bNodeSocketValueFloat *)this->getInputSocket(1)->getbNodeSocket()->default_value)->value;
+                       float dispersion = ((const bNodeSocketValueFloat *)this->getInputSocket(2)->getbNodeSocket()->default_value)->value;
+                       operation->setDistortionAndDispersion(distortion, dispersion);
+               }
 
                this->getInputSocket(0)->relinkConnections(operation->getInputSocket(0), 0, graph);
                this->getInputSocket(1)->relinkConnections(operation->getInputSocket(1), 1, graph);
                this->getInputSocket(2)->relinkConnections(operation->getInputSocket(2), 2, graph);
+
                this->getOutputSocket(0)->relinkConnections(operation->getOutputSocket(0));
 
-               operation->setData(data);
                graph->addOperation(operation);
        }
 
index e3abf2aa70b6232a38b14519348efc7c10a185f5..ea8483734d3452b79f4ec982c088b843b7db0b71 100644 (file)
@@ -42,6 +42,10 @@ ScreenLensDistortionOperation::ScreenLensDistortionOperation() : NodeOperation()
 void ScreenLensDistortionOperation::initExecution()
 {
        this->m_inputProgram = this->getInputSocketReader(0);
+       this->initMutex();
+       this->m_cx = 0.5f * (float)getWidth();
+       this->m_cy = 0.5f * (float)getHeight();
+       
 }
 
 void *ScreenLensDistortionOperation::initializeTileData(rcti *rect, MemoryBuffer **memoryBuffers)
@@ -139,52 +143,192 @@ void ScreenLensDistortionOperation::executePixel(float *outputColor, int x, int
 
 void ScreenLensDistortionOperation::deinitExecution()
 {
+       this->deinitMutex();
        this->m_inputProgram = NULL;
 }
 
-void ScreenLensDistortionOperation::determineUV(float result[2], float x, float y) const
+void ScreenLensDistortionOperation::determineUV(float result[4], float x, float y, float distortion, float dispersion) 
+{
+       if (!this->m_valuesAvailable) {
+               updateVariables(distortion, dispersion);
+       }
+       determineUV(result, x, y);
+}
+
+void ScreenLensDistortionOperation::determineUV(float result[4], float x, float y) const
 {
+       const float height = this->getHeight();
+       const float width = this->getWidth();
+       
+       float d, t, ln[6] = {0, 0, 0, 0, 0, 0};
        const float v = this->m_sc * ((y + 0.5f) - this->m_cy) / this->m_cy;
        const float u = this->m_sc * ((x + 0.5f) - this->m_cx) / this->m_cx;
-       const float t = ABS(MIN3(this->m_kr, this->m_kg, this->m_kb) * 4);
-       float d = 1.f / (1.f + sqrtf(t));
-       result[0] = (u * d + 0.5f) * getWidth() - 0.5f;
-       result[1] = (v * d + 0.5f) * getHeight() - 0.5f;
+       const float uv_dot = u * u + v * v;
+
+       if ((t = 1.f - this->m_kr4 * uv_dot) >= 0.f) {
+               d = 1.f / (1.f + sqrtf(t));
+               ln[0] = (u * d + 0.5f) * width - 0.5f, ln[1] = (v * d + 0.5f) * height - 0.5f;
+       }
+       if ((t = 1.f - this->m_kg4 * uv_dot) >= 0.f) {
+               d = 1.f / (1.f + sqrtf(t));
+               ln[2] = (u * d + 0.5f) * width - 0.5f, ln[3] = (v * d + 0.5f) * height - 0.5f;
+       }
+       if ((t = 1.f - this->m_kb4 * uv_dot) >= 0.f) {
+               d = 1.f / (1.f + sqrtf(t));
+               ln[4] = (u * d + 0.5f) * width - 0.5f, ln[5] = (v * d + 0.5f) * height - 0.5f;
+       }
+
+       float jit = this->m_data->jit;
+       float z;
+       {
+               // RG
+               const int dx = ln[2] - ln[0], dy = ln[3] - ln[1];
+               const float dsf = sqrtf((float)dx * dx + dy * dy) + 1.f;
+               const int ds = (int)(jit ? ((dsf < 4.f) ? 2.f : sqrtf(dsf)) : dsf);
+               const float sd = 1.f / (float)ds;
+
+               z = ds;
+               const float tz = ((float)z + (1.0f)) * sd;
+               t = 1.0f - (this->m_kr4 + tz * this->m_drg) * uv_dot;
+               d = 1.0f / (1.f + sqrtf(t));
+               const float nx = (u * d + 0.5f) * width - 0.5f;
+               const float ny = (v * d + 0.5f) * height - 0.5f;
+               result[0] = nx;
+               result[1] = ny;
+       }
+       {
+               // GB
+               const int dx = ln[4] - ln[2], dy = ln[5] - ln[3];
+               const float dsf = sqrtf((float)dx * dx + dy * dy) + 1.f;
+               const int ds = (int)(jit ? ((dsf < 4.f) ? 2.f : sqrtf(dsf)) : dsf);
+               const float sd = 1.f / (float)ds;
+
+               z = ds;
+               const float tz = ((float)z + (1.0f)) * sd;
+               t = 1.f - (this->m_kg4 + tz * this->m_dgb) * uv_dot;
+               d = 1.f / (1.f + sqrtf(t));
+               const float nx = (u * d + 0.5f) * width - 0.5f;
+               const float ny = (v * d + 0.5f) * height - 0.5f;
+               result[2] = nx;
+               result[3] = ny;
+       }
 }
 
 bool ScreenLensDistortionOperation::determineDependingAreaOfInterest(rcti *input, ReadBufferOperation *readOperation, rcti *output)
 {
+       rcti newInputValue;
+       newInputValue.xmin = 0;
+       newInputValue.ymin = 0;
+       newInputValue.xmax = 2;
+       newInputValue.ymax = 2;
+       
+       NodeOperation *operation = getInputOperation(1);
+       if (operation->determineDependingAreaOfInterest(&newInputValue, readOperation, output) ) {
+               return true;
+       }
+
+       operation = getInputOperation(2);
+       if (operation->determineDependingAreaOfInterest(&newInputValue, readOperation, output) ) {
+               return true;
+       }
+
+#define MARGIN 64
+
+#define UPDATE_INPUT \
+               newInput.xmin = MIN3(newInput.xmin, coords[0], coords[2]); \
+               newInput.ymin = MIN3(newInput.ymin, coords[1], coords[3]); \
+               newInput.xmax = MAX3(newInput.xmax, coords[0], coords[2]); \
+               newInput.ymax = MAX3(newInput.ymax, coords[1], coords[3]);
+       
        rcti newInput;
-       newInput.xmin = 0;
-       newInput.ymin = 0;
-       newInput.ymax = this->m_inputProgram->getHeight();
-       newInput.xmax = this->m_inputProgram->getWidth();
-       return NodeOperation::determineDependingAreaOfInterest(&newInput, readOperation, output);
+       float margin;
+       float coords[4];
+       if (m_valuesAvailable) {
+               determineUV(coords, input->xmin, input->ymin);
+               newInput.xmin = coords[0];
+               newInput.ymin = coords[1];
+               newInput.xmax = coords[0];
+               newInput.ymax = coords[1];
+               UPDATE_INPUT;
+               determineUV(coords, input->xmin, input->ymax);
+               UPDATE_INPUT;
+               determineUV(coords, input->xmax, input->ymax);
+               UPDATE_INPUT;
+               determineUV(coords, input->xmax, input->ymin);
+               UPDATE_INPUT;
+               margin = (ABS(this->m_distortion)+this->m_dispersion)*MARGIN;
+       } 
+       else 
+       {
+               determineUV(coords, input->xmin, input->ymin, 1.0f, 1.0f);
+               newInput.xmin = coords[0];
+               newInput.ymin = coords[1];
+               newInput.xmax = coords[0];
+               newInput.ymax = coords[1];
+               UPDATE_INPUT;
+               determineUV(coords, input->xmin, input->ymin, -1.0f, 1.0f);
+               UPDATE_INPUT;
+               
+               determineUV(coords, input->xmin, input->ymax, -1.0f, 1.0f);
+               UPDATE_INPUT;
+               determineUV(coords, input->xmin, input->ymax, 1.0f, 1.0f);
+               UPDATE_INPUT;
+               
+               determineUV(coords, input->xmax, input->ymax, -1.0f, 1.0f);
+               UPDATE_INPUT;
+               determineUV(coords, input->xmax, input->ymax, 1.0f, 1.0f);
+               UPDATE_INPUT;
+               
+               determineUV(coords, input->xmax, input->ymin, -1.0f, 1.0f);
+               UPDATE_INPUT;
+               determineUV(coords, input->xmax, input->ymin, 1.0f, 1.0f);
+               UPDATE_INPUT;
+               margin=MARGIN;
+       }
+
+#undef UPDATE_INPUT
+       newInput.xmin -= margin;
+       newInput.ymin -= margin;
+       newInput.xmax += margin;
+       newInput.ymax += margin;
+
+       operation = getInputOperation(0);
+       if (operation->determineDependingAreaOfInterest(&newInput, readOperation, output) ) {
+               return true;
+       }
+       return false;
+}
+
+void ScreenLensDistortionOperation::updateVariables(float distortion, float dispersion)
+{
+       this->m_kg = MAX2(MIN2(distortion, 1.f), -0.999f);
+       // smaller dispersion range for somewhat more control
+       const float d = 0.25f * MAX2(MIN2(dispersion, 1.f), 0.f);
+       this->m_kr = MAX2(MIN2((this->m_kg + d), 1.0f), -0.999f);
+       this->m_kb = MAX2(MIN2((this->m_kg - d), 1.0f), -0.999f);
+       this->m_maxk = MAX3(this->m_kr, this->m_kg, this->m_kb);
+       this->m_sc = (this->m_data->fit && (this->m_maxk > 0.f)) ? (1.f / (1.f + 2.f * this->m_maxk)) : (1.f / (1.f + this->m_maxk));
+       this->m_drg = 4.f * (this->m_kg - this->m_kr);
+       this->m_dgb = 4.f * (this->m_kb - this->m_kg);
+
+       this->m_kr4 = this->m_kr * 4.0f;
+       this->m_kg4 = this->m_kg * 4.0f;
+       this->m_kb4 = this->m_kb * 4.0f;        
 }
 
 void ScreenLensDistortionOperation::updateDispersionAndDistortion(MemoryBuffer **inputBuffers)
 {
+       if (this->m_valuesAvailable) return;
+       
+       this->lockMutex();
        if (!this->m_valuesAvailable) {
                float result[4];
                this->getInputSocketReader(1)->read(result, 0, 0, COM_PS_NEAREST, inputBuffers);
                this->m_distortion = result[0];
                this->getInputSocketReader(2)->read(result, 0, 0, COM_PS_NEAREST, inputBuffers);
                this->m_dispersion = result[0];
-               this->m_kg = MAX2(MIN2(this->m_distortion, 1.f), -0.999f);
-               // smaller dispersion range for somewhat more control
-               const float d = 0.25f * MAX2(MIN2(this->m_dispersion, 1.f), 0.f);
-               this->m_kr = MAX2(MIN2((this->m_kg + d), 1.0f), -0.999f);
-               this->m_kb = MAX2(MIN2((this->m_kg - d), 1.0f), -0.999f);
-               this->m_maxk = MAX3(this->m_kr, this->m_kg, this->m_kb);
-               this->m_sc = (this->m_data->fit && (this->m_maxk > 0.f)) ? (1.f / (1.f + 2.f * this->m_maxk)) : (1.f / (1.f + this->m_maxk));
-               this->m_drg = 4.f * (this->m_kg - this->m_kr);
-               this->m_dgb = 4.f * (this->m_kb - this->m_kg);
-       
-               this->m_kr4 = this->m_kr * 4.0f;
-               this->m_kg4 = this->m_kg * 4.0f;
-               this->m_kb4 = this->m_kb * 4.0f;
-               this->m_cx = 0.5f * (float)getWidth();
-               this->m_cy = 0.5f * (float)getHeight();
+               updateVariables(this->m_distortion, this->m_dispersion);
                this->m_valuesAvailable = true;
        }
+       this->unlockMutex();
 }
index 7e4fda0f7556aa3071f28b9820312662a1a4df27..f80b938818c16d862229834e534d7842633c3597 100644 (file)
@@ -66,9 +66,23 @@ public:
        
        bool determineDependingAreaOfInterest(rcti *input, ReadBufferOperation *readOperation, rcti *output);
 
+       /**
+        * @brief Set the distortion and dispersion and precalc some values
+        * @param distortion
+        * @param dispersion
+        */
+       void setDistortionAndDispersion(float distortion, float dispersion) {
+               this->m_distortion = distortion;
+               this->m_dispersion = dispersion;
+               updateVariables(distortion, dispersion);
+               this->m_valuesAvailable = true;
+       }
+
 private:
-       void determineUV(float *result, float x, float y) const;
+       void determineUV(float result[4], float x, float y) const;
+       void determineUV(float result[4], float x, float y, float distortion, float dispersion);
        void updateDispersionAndDistortion(MemoryBuffer **inputBuffers);
+       void updateVariables(float distortion, float dispersion);
 
 };
 #endif