Blender  V3.3
COM_KeyingOperation.cc
Go to the documentation of this file.
1 /* SPDX-License-Identifier: GPL-2.0-or-later
2  * Copyright 2012 Blender Foundation. */
3 
4 #include "COM_KeyingOperation.h"
5 
6 namespace blender::compositor {
7 
8 static float get_pixel_saturation(const float pixel_color[4],
9  float screen_balance,
10  int primary_channel)
11 {
12  const int other_1 = (primary_channel + 1) % 3;
13  const int other_2 = (primary_channel + 2) % 3;
14 
15  const int min_channel = MIN2(other_1, other_2);
16  const int max_channel = MAX2(other_1, other_2);
17 
18  const float val = screen_balance * pixel_color[min_channel] +
19  (1.0f - screen_balance) * pixel_color[max_channel];
20 
21  return (pixel_color[primary_channel] - val) * fabsf(1.0f - val);
22 }
23 
25 {
29 
30  screen_balance_ = 0.5f;
31 
32  pixel_reader_ = nullptr;
33  screen_reader_ = nullptr;
34 }
35 
37 {
40 }
41 
43 {
44  pixel_reader_ = nullptr;
45  screen_reader_ = nullptr;
46 }
47 
49  float x,
50  float y,
52 {
53  float pixel_color[4];
54  float screen_color[4];
55 
56  pixel_reader_->read_sampled(pixel_color, x, y, sampler);
57  screen_reader_->read_sampled(screen_color, x, y, sampler);
58 
59  const int primary_channel = max_axis_v3(screen_color);
60  const float min_pixel_color = min_fff(pixel_color[0], pixel_color[1], pixel_color[2]);
61 
62  if (min_pixel_color > 1.0f) {
63  /* overexposure doesn't happen on screen itself and usually happens
64  * on light sources in the shot, this need to be checked separately
65  * because saturation and falloff calculation is based on the fact
66  * that pixels are not overexposed
67  */
68  output[0] = 1.0f;
69  }
70  else {
71  float saturation = get_pixel_saturation(pixel_color, screen_balance_, primary_channel);
72  float screen_saturation = get_pixel_saturation(screen_color, screen_balance_, primary_channel);
73 
74  if (saturation < 0) {
75  /* means main channel of pixel is different from screen,
76  * assume this is completely a foreground
77  */
78  output[0] = 1.0f;
79  }
80  else if (saturation >= screen_saturation) {
81  /* matched main channels and higher saturation on pixel
82  * is treated as completely background
83  */
84  output[0] = 0.0f;
85  }
86  else {
87  /* nice alpha falloff on edges */
88  float distance = 1.0f - saturation / screen_saturation;
89 
90  output[0] = distance;
91  }
92  }
93 }
94 
96  const rcti &area,
98 {
99  for (BuffersIterator<float> it = output->iterate_with(inputs, area); !it.is_end(); ++it) {
100  const float *pixel_color = it.in(0);
101  const float *screen_color = it.in(1);
102 
103  const int primary_channel = max_axis_v3(screen_color);
104  const float min_pixel_color = min_fff(pixel_color[0], pixel_color[1], pixel_color[2]);
105 
106  if (min_pixel_color > 1.0f) {
107  /* Overexposure doesn't happen on screen itself and usually happens
108  * on light sources in the shot, this need to be checked separately
109  * because saturation and falloff calculation is based on the fact
110  * that pixels are not overexposed.
111  */
112  it.out[0] = 1.0f;
113  }
114  else {
115  const float saturation = get_pixel_saturation(pixel_color, screen_balance_, primary_channel);
116  const float screen_saturation = get_pixel_saturation(
117  screen_color, screen_balance_, primary_channel);
118 
119  if (saturation < 0) {
120  /* Means main channel of pixel is different from screen,
121  * assume this is completely a foreground.
122  */
123  it.out[0] = 1.0f;
124  }
125  else if (saturation >= screen_saturation) {
126  /* Matched main channels and higher saturation on pixel
127  * is treated as completely background.
128  */
129  it.out[0] = 0.0f;
130  }
131  else {
132  /* Nice alpha falloff on edges. */
133  const float distance = 1.0f - saturation / screen_saturation;
134  it.out[0] = distance;
135  }
136  }
137  }
138 }
139 
140 } // namespace blender::compositor
MINLINE float min_fff(float a, float b, float c)
MINLINE int max_axis_v3(const float vec[3])
#define MAX2(a, b)
#define MIN2(a, b)
_GL_VOID GLfloat value _GL_VOID_RET _GL_VOID const GLuint GLboolean *residences _GL_BOOL_RET _GL_VOID GLsizei GLfloat GLfloat GLfloat GLfloat const GLubyte *bitmap _GL_VOID_RET _GL_VOID GLenum const void *lists _GL_VOID_RET _GL_VOID const GLdouble *equation _GL_VOID_RET _GL_VOID GLdouble GLdouble blue _GL_VOID_RET _GL_VOID GLfloat GLfloat blue _GL_VOID_RET _GL_VOID GLint GLint blue _GL_VOID_RET _GL_VOID GLshort GLshort blue _GL_VOID_RET _GL_VOID GLubyte GLubyte blue _GL_VOID_RET _GL_VOID GLuint GLuint blue _GL_VOID_RET _GL_VOID GLushort GLushort blue _GL_VOID_RET _GL_VOID GLbyte GLbyte GLbyte alpha _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble alpha _GL_VOID_RET _GL_VOID GLfloat GLfloat GLfloat alpha _GL_VOID_RET _GL_VOID GLint GLint GLint alpha _GL_VOID_RET _GL_VOID GLshort GLshort GLshort alpha _GL_VOID_RET _GL_VOID GLubyte GLubyte GLubyte alpha _GL_VOID_RET _GL_VOID GLuint GLuint GLuint alpha _GL_VOID_RET _GL_VOID GLushort GLushort GLushort alpha _GL_VOID_RET _GL_VOID GLenum mode _GL_VOID_RET _GL_VOID GLint y
in reality light always falls off quadratically Particle Retrieve the data of the particle that spawned the object for example to give variation to multiple instances of an object Point Retrieve information about points in a point cloud Retrieve the edges of an object as it appears to Cycles topology will always appear triangulated Convert a blackbody temperature to an RGB value Normal Generate a perturbed normal from an RGB normal map image Typically used for faking highly detailed surfaces Generate an OSL shader from a file or text data block Image Sample an image file as a texture Sky Generate a procedural sky texture Noise Generate fractal Perlin noise Wave Generate procedural bands or rings with noise Voronoi Generate Worley noise based on the distance to random points Typically used to generate textures such as or biological cells Brick Generate a procedural texture producing bricks Texture Retrieve multiple types of texture coordinates nTypically used as inputs for texture nodes Vector Convert a or normal between and object coordinate space Combine Create a color from its saturation
void update_memory_buffer_partial(MemoryBuffer *output, const rcti &area, Span< MemoryBuffer * > inputs) override
void execute_pixel_sampled(float output[4], float x, float y, PixelSampler sampler) override
calculate a single pixel
a MemoryBuffer contains access to the data of a chunk
void add_output_socket(DataType datatype)
SocketReader * get_input_socket_reader(unsigned int index)
void read_sampled(float result[4], float x, float y, PixelSampler sampler)
void add_input_socket(DataType datatype, ResizeMode resize_mode=ResizeMode::Center)
depth_tx sampler(1, ImageType::FLOAT_2D, "combined_tx") .sampler(2
ccl_global KernelShaderEvalInput ccl_global float * output
#define fabsf(x)
Definition: metal/compat.h:219
static void area(int d1, int d2, int e1, int e2, float weights[2])
typename BuffersIteratorBuilder< T >::Iterator BuffersIterator
static float get_pixel_saturation(const float pixel_color[4], float screen_balance, int primary_channel)
T distance(const T &a, const T &b)
static bNodeSocketTemplate inputs[]