|
shun_iwasawa |
4d2acf |
/*------------------------------------
|
|
shun_iwasawa |
4d2acf |
Iwa_SoapBubbleFx
|
|
shun_iwasawa |
4d2acf |
Generates thin film interference colors from two reference images;
|
|
shun_iwasawa |
4d2acf |
one is for thickness and the other one is for shape or normal vector
|
|
shun_iwasawa |
4d2acf |
distribution of the film.
|
|
shun_iwasawa |
4d2acf |
Inherits Iwa_SpectrumFx.
|
|
shun_iwasawa |
4d2acf |
------------------------------------*/
|
|
shun_iwasawa |
4d2acf |
|
|
shun_iwasawa |
4d2acf |
#include "iwa_soapbubblefx.h"
|
|
shun_iwasawa |
4d2acf |
#include "iwa_cie_d65.h"
|
|
shun_iwasawa |
4d2acf |
#include "iwa_xyz.h"
|
|
shun_iwasawa |
4d2acf |
|
|
shun-iwasawa |
9d0856 |
#include "trop.h"
|
|
shun-iwasawa |
9d0856 |
|
|
shun_iwasawa |
4d2acf |
#include <qlist></qlist>
|
|
shun_iwasawa |
4d2acf |
#include <qpoint></qpoint>
|
|
shun_iwasawa |
4d2acf |
#include <qsize></qsize>
|
|
shun-iwasawa |
9d0856 |
#include <qrect></qrect>
|
|
shun_iwasawa |
4d2acf |
|
|
shun_iwasawa |
4d2acf |
namespace {
|
|
shun_iwasawa |
4d2acf |
const float PI = 3.14159265f;
|
|
shun_iwasawa |
4d2acf |
|
|
shun_iwasawa |
4d2acf |
#define INF 1e20 /* less than FLT_MAX */
|
|
shun_iwasawa |
4d2acf |
|
|
shun_iwasawa |
4d2acf |
/* dt of 1d function using squared distance */
|
|
shun_iwasawa |
4d2acf |
static float* dt(float* f, int n, float a = 1.0f) {
|
|
shun_iwasawa |
4d2acf |
float* d = new float[n];
|
|
shun_iwasawa |
4d2acf |
int* v = new int[n];
|
|
shun_iwasawa |
4d2acf |
float* z = new float[n + 1];
|
|
shun_iwasawa |
4d2acf |
/* index of rightmost parabola in lower envelope */
|
|
shun_iwasawa |
4d2acf |
int k = 0;
|
|
shun_iwasawa |
4d2acf |
/* locations of parabolas in lower envelope */
|
|
shun_iwasawa |
4d2acf |
v[0] = 0;
|
|
shun_iwasawa |
4d2acf |
/* locations of boundaries between parabolas */
|
|
shun_iwasawa |
4d2acf |
z[0] = -INF;
|
|
shun_iwasawa |
4d2acf |
z[1] = +INF;
|
|
shun_iwasawa |
4d2acf |
/* compute lower envelope */
|
|
shun_iwasawa |
4d2acf |
for (int q = 1; q <= n - 1; q++) {
|
|
shun_iwasawa |
4d2acf |
/* compute intersection */
|
|
shun_iwasawa |
4d2acf |
float s =
|
|
shun_iwasawa |
4d2acf |
((f[q] / a + q * q) - (f[v[k]] / a + v[k] * v[k])) / (2 * q - 2 * v[k]);
|
|
shun_iwasawa |
4d2acf |
while (s <= z[k]) {
|
|
shun_iwasawa |
4d2acf |
k--;
|
|
shun_iwasawa |
4d2acf |
s = ((f[q] / a + q * q) - (f[v[k]] / a + v[k] * v[k])) /
|
|
shun_iwasawa |
4d2acf |
(2 * q - 2 * v[k]);
|
|
shun_iwasawa |
4d2acf |
}
|
|
shun_iwasawa |
4d2acf |
k++;
|
|
shun_iwasawa |
4d2acf |
v[k] = q;
|
|
shun_iwasawa |
4d2acf |
z[k] = s;
|
|
shun_iwasawa |
4d2acf |
z[k + 1] = +INF;
|
|
shun_iwasawa |
4d2acf |
}
|
|
shun_iwasawa |
4d2acf |
k = 0;
|
|
shun_iwasawa |
4d2acf |
/* fill in values of distance transform */
|
|
shun_iwasawa |
4d2acf |
for (int q = 0; q <= n - 1; q++) {
|
|
shun_iwasawa |
4d2acf |
while (z[k + 1] < q) k++;
|
|
shun_iwasawa |
4d2acf |
d[q] = a * (q - v[k]) * (q - v[k]) + f[v[k]];
|
|
shun_iwasawa |
4d2acf |
}
|
|
shun_iwasawa |
4d2acf |
|
|
shun_iwasawa |
4d2acf |
delete[] v;
|
|
shun_iwasawa |
4d2acf |
delete[] z;
|
|
shun_iwasawa |
4d2acf |
return d;
|
|
shun_iwasawa |
4d2acf |
}
|
|
shun_iwasawa |
4d2acf |
}
|
|
shun_iwasawa |
4d2acf |
|
|
shun_iwasawa |
4d2acf |
//------------------------------------
|
|
shun_iwasawa |
4d2acf |
|
|
shun_iwasawa |
4d2acf |
Iwa_SoapBubbleFx::Iwa_SoapBubbleFx()
|
|
shun_iwasawa |
4d2acf |
: Iwa_SpectrumFx()
|
|
shun-iwasawa |
9d0856 |
, m_renderMode(new TIntEnumParam(RENDER_MODE_BUBBLE, "Bubble"))
|
|
shun_iwasawa |
4d2acf |
, m_binarize_threshold(0.5)
|
|
shun_iwasawa |
4d2acf |
, m_shape_aspect_ratio(1.0)
|
|
shun_iwasawa |
4d2acf |
, m_blur_radius(5.0)
|
|
shun_iwasawa |
4d2acf |
, m_blur_power(0.5)
|
|
shun-iwasawa |
a1471c |
, m_multi_source(false)
|
|
shun-iwasawa |
9d0856 |
, m_mask_center(false) // obsolete
|
|
shun-iwasawa |
9d0856 |
, m_center_opacity(1.0)
|
|
shun-iwasawa |
9d0856 |
, m_fit_thickness(false)
|
|
shun_iwasawa |
4d2acf |
, m_normal_sample_distance(1)
|
|
shun_iwasawa |
4d2acf |
, m_noise_sub_depth(3)
|
|
shun_iwasawa |
4d2acf |
, m_noise_resolution_s(18.0)
|
|
shun_iwasawa |
4d2acf |
, m_noise_resolution_t(5.0)
|
|
shun_iwasawa |
4d2acf |
, m_noise_sub_composite_ratio(0.5)
|
|
shun_iwasawa |
4d2acf |
, m_noise_evolution(0.0)
|
|
shun_iwasawa |
4d2acf |
, m_noise_depth_mix_ratio(0.05)
|
|
shun_iwasawa |
4d2acf |
, m_noise_thickness_mix_ratio(0.05) {
|
|
shun_iwasawa |
4d2acf |
removeInputPort("Source");
|
|
shun_iwasawa |
4d2acf |
removeInputPort("Light"); /* not used */
|
|
shun_iwasawa |
4d2acf |
addInputPort("Thickness", m_input);
|
|
shun_iwasawa |
4d2acf |
addInputPort("Shape", m_shape);
|
|
shun_iwasawa |
4d2acf |
addInputPort("Depth", m_depth);
|
|
shun_iwasawa |
4d2acf |
|
|
shun-iwasawa |
9d0856 |
bindParam(this, "renderMode", m_renderMode);
|
|
shun-iwasawa |
9d0856 |
m_renderMode->addItem(RENDER_MODE_THICKNESS, "Thickness");
|
|
shun-iwasawa |
9d0856 |
m_renderMode->addItem(RENDER_MODE_DEPTH, "Depth");
|
|
shun-iwasawa |
9d0856 |
|
|
shun_iwasawa |
4d2acf |
bindParam(this, "binarizeThresold", m_binarize_threshold);
|
|
shun_iwasawa |
4d2acf |
bindParam(this, "shapeAspectRatio", m_shape_aspect_ratio);
|
|
shun_iwasawa |
4d2acf |
bindParam(this, "blurRadius", m_blur_radius);
|
|
shun_iwasawa |
4d2acf |
bindParam(this, "blurPower", m_blur_power);
|
|
shun-iwasawa |
a1471c |
bindParam(this, "multiSource", m_multi_source);
|
|
shun-iwasawa |
9d0856 |
bindParam(this, "maskCenter", m_mask_center, false, true); // obsolete
|
|
shun-iwasawa |
9d0856 |
bindParam(this, "centerOpacity", m_center_opacity);
|
|
shun-iwasawa |
9d0856 |
bindParam(this, "fitThickness", m_fit_thickness);
|
|
shun_iwasawa |
4d2acf |
bindParam(this, "normalSampleDistance", m_normal_sample_distance);
|
|
shun_iwasawa |
4d2acf |
bindParam(this, "noiseSubDepth", m_noise_sub_depth);
|
|
shun_iwasawa |
4d2acf |
bindParam(this, "noiseResolutionS", m_noise_resolution_s);
|
|
shun_iwasawa |
4d2acf |
bindParam(this, "noiseResolutionT", m_noise_resolution_t);
|
|
shun_iwasawa |
4d2acf |
bindParam(this, "noiseSubCompositeRatio", m_noise_sub_composite_ratio);
|
|
shun_iwasawa |
4d2acf |
bindParam(this, "noiseEvolution", m_noise_evolution);
|
|
shun_iwasawa |
4d2acf |
bindParam(this, "noiseDepthMixRatio", m_noise_depth_mix_ratio);
|
|
shun_iwasawa |
4d2acf |
bindParam(this, "noiseThicknessMixRatio", m_noise_thickness_mix_ratio);
|
|
shun_iwasawa |
4d2acf |
|
|
shun_iwasawa |
4d2acf |
m_binarize_threshold->setValueRange(0.01, 0.99);
|
|
shun_iwasawa |
4d2acf |
m_shape_aspect_ratio->setValueRange(0.2, 5.0);
|
|
shun_iwasawa |
4d2acf |
m_blur_radius->setMeasureName("fxLength");
|
|
shun_iwasawa |
4d2acf |
m_blur_radius->setValueRange(0.0, 25.0);
|
|
shun_iwasawa |
4d2acf |
m_blur_power->setValueRange(0.01, 5.0);
|
|
shun-iwasawa |
9d0856 |
m_center_opacity->setValueRange(0.0, 1.0);
|
|
shun_iwasawa |
4d2acf |
|
|
shun_iwasawa |
4d2acf |
m_normal_sample_distance->setValueRange(1, 20);
|
|
shun_iwasawa |
4d2acf |
m_noise_sub_depth->setValueRange(1, 5);
|
|
shun_iwasawa |
4d2acf |
m_noise_resolution_s->setValueRange(1.0, 40.0);
|
|
shun_iwasawa |
4d2acf |
m_noise_resolution_t->setValueRange(1.0, 20.0);
|
|
shun_iwasawa |
4d2acf |
m_noise_sub_composite_ratio->setValueRange(0.0, 5.0);
|
|
shun_iwasawa |
4d2acf |
m_noise_depth_mix_ratio->setValueRange(0.0, 1.0);
|
|
shun_iwasawa |
4d2acf |
m_noise_thickness_mix_ratio->setValueRange(0.0, 1.0);
|
|
shun_iwasawa |
4d2acf |
}
|
|
shun_iwasawa |
4d2acf |
|
|
shun_iwasawa |
4d2acf |
//------------------------------------
|
|
shun_iwasawa |
4d2acf |
|
|
shun_iwasawa |
4d2acf |
void Iwa_SoapBubbleFx::doCompute(TTile& tile, double frame,
|
|
shun_iwasawa |
4d2acf |
const TRenderSettings& settings) {
|
|
shun_iwasawa |
4d2acf |
if (!m_input.isConnected()) return;
|
|
shun_iwasawa |
4d2acf |
if (!m_shape.isConnected() && !m_depth.isConnected()) return;
|
|
shun_iwasawa |
4d2acf |
|
|
shun_iwasawa |
4d2acf |
TDimensionI dim(tile.getRaster()->getLx(), tile.getRaster()->getLy());
|
|
shun_iwasawa |
4d2acf |
TRectD bBox(tile.m_pos, TPointD(dim.lx, dim.ly));
|
|
shun-iwasawa |
a1471c |
QList<trastergr8p> allocatedRasList;</trastergr8p>
|
|
shun_iwasawa |
4d2acf |
|
|
shun-iwasawa |
9d0856 |
if (m_renderMode->getValue() == RENDER_MODE_DEPTH && m_depth.isConnected()) {
|
|
shun-iwasawa |
9d0856 |
m_depth->allocateAndCompute(tile, bBox.getP00(), dim, tile.getRaster(),
|
|
shun-iwasawa |
9d0856 |
frame, settings);
|
|
shun-iwasawa |
9d0856 |
return;
|
|
shun-iwasawa |
9d0856 |
}
|
|
shun-iwasawa |
9d0856 |
|
|
shun_iwasawa |
4d2acf |
/* soap bubble color map */
|
|
shun_iwasawa |
4d2acf |
TRasterGR8P bubbleColor_ras(sizeof(float3) * 256 * 256, 1);
|
|
shun_iwasawa |
4d2acf |
bubbleColor_ras->lock();
|
|
shun-iwasawa |
a1471c |
allocatedRasList.append(bubbleColor_ras);
|
|
shun_iwasawa |
4d2acf |
float3* bubbleColor_p = (float3*)bubbleColor_ras->getRawData();
|
|
shun-iwasawa |
9d0856 |
if (m_renderMode->getValue() == RENDER_MODE_BUBBLE)
|
|
shun-iwasawa |
9d0856 |
calcBubbleMap(bubbleColor_p, frame, true);
|
|
shun_iwasawa |
4d2acf |
|
|
shun-iwasawa |
a1471c |
if (checkCancelAndReleaseRaster(allocatedRasList, tile, settings)) return;
|
|
shun-iwasawa |
a1471c |
|
|
shun_iwasawa |
4d2acf |
/* depth map */
|
|
shun_iwasawa |
4d2acf |
TRasterGR8P depth_map_ras(sizeof(float) * dim.lx * dim.ly, 1);
|
|
shun_iwasawa |
4d2acf |
depth_map_ras->lock();
|
|
shun-iwasawa |
a1471c |
allocatedRasList.append(depth_map_ras);
|
|
shun_iwasawa |
4d2acf |
float* depth_map_p = (float*)depth_map_ras->getRawData();
|
|
shun_iwasawa |
4d2acf |
|
|
shun-iwasawa |
a1471c |
/* alpha map */
|
|
shun-iwasawa |
a1471c |
TRasterGR8P alpha_map_ras(sizeof(float) * dim.lx * dim.ly, 1);
|
|
shun-iwasawa |
a1471c |
alpha_map_ras->lock();
|
|
shun-iwasawa |
a1471c |
allocatedRasList.append(alpha_map_ras);
|
|
shun-iwasawa |
a1471c |
float* alpha_map_p = (float*)alpha_map_ras->getRawData();
|
|
shun-iwasawa |
a1471c |
|
|
shun-iwasawa |
9d0856 |
/* region indices */
|
|
shun-iwasawa |
9d0856 |
TRasterGR8P regionIds_ras(sizeof(USHORT) * dim.lx * dim.ly, 1);
|
|
shun-iwasawa |
9d0856 |
regionIds_ras->lock();
|
|
shun-iwasawa |
9d0856 |
regionIds_ras->clear();
|
|
shun-iwasawa |
9d0856 |
allocatedRasList.append(regionIds_ras);
|
|
shun-iwasawa |
9d0856 |
USHORT* regionIds_p = (USHORT*)regionIds_ras->getRawData();
|
|
shun-iwasawa |
9d0856 |
QList<qrect> regionBoundingRects;</qrect>
|
|
shun-iwasawa |
9d0856 |
|
|
shun_iwasawa |
4d2acf |
/* if the depth image is connected, use it */
|
|
shun_iwasawa |
4d2acf |
if (m_depth.isConnected()) {
|
|
shun_iwasawa |
4d2acf |
TTile depth_tile;
|
|
shun_iwasawa |
4d2acf |
m_depth->allocateAndCompute(depth_tile, bBox.getP00(), dim,
|
|
shun_iwasawa |
4d2acf |
tile.getRaster(), frame, settings);
|
|
shun-iwasawa |
a1471c |
|
|
shun-iwasawa |
a1471c |
if (checkCancelAndReleaseRaster(allocatedRasList, tile, settings)) return;
|
|
shun-iwasawa |
a1471c |
|
|
shun_iwasawa |
4d2acf |
TRasterP depthRas = depth_tile.getRaster();
|
|
shun_iwasawa |
4d2acf |
depthRas->lock();
|
|
shun_iwasawa |
4d2acf |
|
|
shun_iwasawa |
4d2acf |
TRaster32P depthRas32 = (TRaster32P)depthRas;
|
|
shun_iwasawa |
4d2acf |
TRaster64P depthRas64 = (TRaster64P)depthRas;
|
|
shun_iwasawa |
4d2acf |
{
|
|
shun_iwasawa |
4d2acf |
if (depthRas32)
|
|
shun-iwasawa |
a1471c |
convertToBrightness<traster32p, tpixel32="">(depthRas32, depth_map_p,</traster32p,>
|
|
shun-iwasawa |
a1471c |
alpha_map_p, dim);
|
|
shun_iwasawa |
4d2acf |
else if (depthRas64)
|
|
shun-iwasawa |
a1471c |
convertToBrightness<traster64p, tpixel64="">(depthRas64, depth_map_p,</traster64p,>
|
|
shun-iwasawa |
a1471c |
alpha_map_p, dim);
|
|
shun_iwasawa |
4d2acf |
}
|
|
shun_iwasawa |
4d2acf |
depthRas->unlock();
|
|
shun-iwasawa |
9d0856 |
|
|
shun-iwasawa |
9d0856 |
// set one region covering whole camera rect
|
|
shun-iwasawa |
9d0856 |
regionBoundingRects.append(QRect(0, 0, dim.lx, dim.ly));
|
|
shun_iwasawa |
4d2acf |
}
|
|
shun_iwasawa |
4d2acf |
/* or, use the shape image to obtain pseudo depth */
|
|
shun_iwasawa |
4d2acf |
else { /* m_shape.isConnected */
|
|
shun_iwasawa |
4d2acf |
/* obtain shape image */
|
|
shun_iwasawa |
4d2acf |
TTile shape_tile;
|
|
shun_iwasawa |
4d2acf |
{
|
|
shun_iwasawa |
4d2acf |
TRaster32P tmp(1, 1);
|
|
shun_iwasawa |
4d2acf |
m_shape->allocateAndCompute(shape_tile, bBox.getP00(), dim, tmp, frame,
|
|
shun_iwasawa |
4d2acf |
settings);
|
|
shun_iwasawa |
4d2acf |
}
|
|
shun-iwasawa |
a1471c |
|
|
shun-iwasawa |
a1471c |
if (checkCancelAndReleaseRaster(allocatedRasList, tile, settings)) return;
|
|
shun-iwasawa |
a1471c |
|
|
shun-iwasawa |
9d0856 |
processShape(frame, shape_tile, depth_map_p, alpha_map_p, regionIds_p,
|
|
shun-iwasawa |
9d0856 |
regionBoundingRects, dim, settings);
|
|
shun_iwasawa |
4d2acf |
}
|
|
shun_iwasawa |
4d2acf |
|
|
shun-iwasawa |
a1471c |
if (checkCancelAndReleaseRaster(allocatedRasList, tile, settings)) return;
|
|
shun-iwasawa |
a1471c |
|
|
shun-iwasawa |
9d0856 |
// conpute thickness
|
|
shun_iwasawa |
4d2acf |
TRasterGR8P thickness_map_ras(sizeof(float) * dim.lx * dim.ly, 1);
|
|
shun_iwasawa |
4d2acf |
thickness_map_ras->lock();
|
|
shun-iwasawa |
a1471c |
allocatedRasList.append(thickness_map_ras);
|
|
shun_iwasawa |
4d2acf |
float* thickness_map_p = (float*)thickness_map_ras->getRawData();
|
|
shun-iwasawa |
9d0856 |
|
|
shun-iwasawa |
9d0856 |
TRasterP tileRas = tile.getRaster();
|
|
shun-iwasawa |
9d0856 |
TRaster32P ras32 = (TRaster32P)tileRas;
|
|
shun-iwasawa |
9d0856 |
TRaster64P ras64 = (TRaster64P)tileRas;
|
|
shun-iwasawa |
9d0856 |
|
|
shun-iwasawa |
9d0856 |
if (m_fit_thickness->getValue()) {
|
|
shun-iwasawa |
9d0856 |
// Get the original bbox of thickness image
|
|
shun-iwasawa |
9d0856 |
TRectD thickBBox;
|
|
shun-iwasawa |
9d0856 |
m_input->getBBox(frame, thickBBox, settings);
|
|
shun-iwasawa |
9d0856 |
if (thickBBox == TConsts::infiniteRectD)
|
|
shun-iwasawa |
9d0856 |
thickBBox = TRectD(tile.m_pos, TDimensionD(tile.getRaster()->getLx(),
|
|
shun-iwasawa |
9d0856 |
tile.getRaster()->getLy()));
|
|
shun-iwasawa |
9d0856 |
// Compute the thickenss tile.
|
|
shun-iwasawa |
9d0856 |
TTile thicknessTile;
|
|
shun-iwasawa |
9d0856 |
TDimension thickDim(static_cast<int>(thickBBox.getLx() + 0.5),</int>
|
|
shun-iwasawa |
9d0856 |
static_cast<int>(thickBBox.getLy() + 0.5));</int>
|
|
shun-iwasawa |
9d0856 |
m_input->allocateAndCompute(thicknessTile, thickBBox.getP00(), thickDim,
|
|
shun-iwasawa |
9d0856 |
tile.getRaster(), frame, settings);
|
|
shun-iwasawa |
9d0856 |
|
|
shun-iwasawa |
9d0856 |
if (checkCancelAndReleaseRaster(allocatedRasList, tile, settings)) return;
|
|
shun-iwasawa |
9d0856 |
|
|
shun-iwasawa |
9d0856 |
TRasterP thickRas = thicknessTile.getRaster();
|
|
shun-iwasawa |
9d0856 |
|
|
shun-iwasawa |
9d0856 |
fitThicknessPatches(thickRas, thickDim, thickness_map_p, dim, regionIds_p,
|
|
shun-iwasawa |
9d0856 |
regionBoundingRects);
|
|
shun-iwasawa |
9d0856 |
} else {
|
|
shun-iwasawa |
9d0856 |
/* compute the thickness input and temporarily store to the tile */
|
|
shun-iwasawa |
9d0856 |
m_input->compute(tile, frame, settings);
|
|
shun-iwasawa |
9d0856 |
|
|
shun-iwasawa |
9d0856 |
if (checkCancelAndReleaseRaster(allocatedRasList, tile, settings)) return;
|
|
shun-iwasawa |
9d0856 |
|
|
shun_iwasawa |
4d2acf |
if (ras32)
|
|
shun-iwasawa |
a1471c |
convertToBrightness<traster32p, tpixel32="">(ras32, thickness_map_p, nullptr,</traster32p,>
|
|
shun-iwasawa |
a1471c |
dim);
|
|
shun_iwasawa |
4d2acf |
else if (ras64)
|
|
shun-iwasawa |
a1471c |
convertToBrightness<traster64p, tpixel64="">(ras64, thickness_map_p, nullptr,</traster64p,>
|
|
shun-iwasawa |
a1471c |
dim);
|
|
shun_iwasawa |
4d2acf |
}
|
|
shun_iwasawa |
4d2acf |
|
|
shun-iwasawa |
a1471c |
if (checkCancelAndReleaseRaster(allocatedRasList, tile, settings)) return;
|
|
shun-iwasawa |
a1471c |
|
|
shun_iwasawa |
4d2acf |
/* process noise */
|
|
shun_iwasawa |
4d2acf |
processNoise(thickness_map_p, depth_map_p, dim, frame, settings);
|
|
shun_iwasawa |
4d2acf |
|
|
shun-iwasawa |
a1471c |
if (checkCancelAndReleaseRaster(allocatedRasList, tile, settings)) return;
|
|
shun-iwasawa |
a1471c |
|
|
shun_iwasawa |
4d2acf |
if (ras32)
|
|
shun_iwasawa |
4d2acf |
convertToRaster<traster32p, tpixel32="">(ras32, thickness_map_p, depth_map_p,</traster32p,>
|
|
shun-iwasawa |
a1471c |
alpha_map_p, dim, bubbleColor_p);
|
|
shun_iwasawa |
4d2acf |
else if (ras64)
|
|
shun_iwasawa |
4d2acf |
convertToRaster<traster64p, tpixel64="">(ras64, thickness_map_p, depth_map_p,</traster64p,>
|
|
shun-iwasawa |
a1471c |
alpha_map_p, dim, bubbleColor_p);
|
|
shun_iwasawa |
4d2acf |
|
|
shun-iwasawa |
a1471c |
for (int i = 0; i < allocatedRasList.size(); i++)
|
|
shun-iwasawa |
a1471c |
allocatedRasList.at(i)->unlock();
|
|
shun_iwasawa |
4d2acf |
}
|
|
shun_iwasawa |
4d2acf |
|
|
shun_iwasawa |
4d2acf |
//------------------------------------
|
|
shun_iwasawa |
4d2acf |
|
|
shun_iwasawa |
4d2acf |
template <typename pixel="" raster,="" typename=""></typename>
|
|
shun_iwasawa |
4d2acf |
void Iwa_SoapBubbleFx::convertToBrightness(const RASTER srcRas, float* dst,
|
|
shun-iwasawa |
a1471c |
float* alpha, TDimensionI dim) {
|
|
shun-iwasawa |
a1471c |
float* dst_p = dst;
|
|
shun-iwasawa |
a1471c |
float* alpha_p = alpha;
|
|
shun_iwasawa |
4d2acf |
for (int j = 0; j < dim.ly; j++) {
|
|
shun_iwasawa |
4d2acf |
PIXEL* pix = srcRas->pixels(j);
|
|
shun_iwasawa |
4d2acf |
for (int i = 0; i < dim.lx; i++, dst_p++, pix++) {
|
|
shun_iwasawa |
4d2acf |
float r = (float)pix->r / (float)PIXEL::maxChannelValue;
|
|
shun_iwasawa |
4d2acf |
float g = (float)pix->g / (float)PIXEL::maxChannelValue;
|
|
shun_iwasawa |
4d2acf |
float b = (float)pix->b / (float)PIXEL::maxChannelValue;
|
|
shun_iwasawa |
4d2acf |
/* brightness */
|
|
shun_iwasawa |
4d2acf |
*dst_p = 0.298912f * r + 0.586611f * g + 0.114478f * b;
|
|
shun-iwasawa |
a1471c |
if (alpha) {
|
|
shun-iwasawa |
a1471c |
*alpha_p = (float)pix->m / (float)PIXEL::maxChannelValue;
|
|
shun-iwasawa |
a1471c |
alpha_p++;
|
|
shun-iwasawa |
a1471c |
}
|
|
shun_iwasawa |
4d2acf |
}
|
|
shun_iwasawa |
4d2acf |
}
|
|
shun_iwasawa |
4d2acf |
}
|
|
shun_iwasawa |
4d2acf |
|
|
shun_iwasawa |
4d2acf |
//------------------------------------
|
|
shun_iwasawa |
4d2acf |
|
|
shun_iwasawa |
4d2acf |
template <typename pixel="" raster,="" typename=""></typename>
|
|
shun_iwasawa |
4d2acf |
void Iwa_SoapBubbleFx::convertToRaster(const RASTER ras, float* thickness_map_p,
|
|
shun-iwasawa |
a1471c |
float* depth_map_p, float* alpha_map_p,
|
|
shun-iwasawa |
a1471c |
TDimensionI dim, float3* bubbleColor_p) {
|
|
shun-iwasawa |
9d0856 |
int renderMode = m_renderMode->getValue();
|
|
shun_iwasawa |
4d2acf |
float* depth_p = depth_map_p;
|
|
shun_iwasawa |
4d2acf |
float* thickness_p = thickness_map_p;
|
|
shun-iwasawa |
a1471c |
float* alpha_p = alpha_map_p;
|
|
shun_iwasawa |
4d2acf |
for (int j = 0; j < dim.ly; j++) {
|
|
shun_iwasawa |
4d2acf |
PIXEL* pix = ras->pixels(j);
|
|
shun-iwasawa |
a1471c |
for (int i = 0; i < dim.lx;
|
|
shun-iwasawa |
a1471c |
i++, depth_p++, thickness_p++, alpha_p++, pix++) {
|
|
shun-iwasawa |
9d0856 |
float alpha = (*alpha_p);
|
|
shun-iwasawa |
9d0856 |
if (!m_fit_thickness->getValue())
|
|
shun-iwasawa |
9d0856 |
alpha *= (float)pix->m / (float)PIXEL::maxChannelValue;
|
|
shun-iwasawa |
a1471c |
if (alpha == 0.0f) { /* no change for the transparent pixels */
|
|
shun-iwasawa |
a1471c |
pix->m = (typename PIXEL::Channel)0;
|
|
shun_iwasawa |
4d2acf |
continue;
|
|
shun-iwasawa |
a1471c |
}
|
|
shun_iwasawa |
4d2acf |
|
|
shun-iwasawa |
9d0856 |
// thickness and depth render mode
|
|
shun-iwasawa |
9d0856 |
if (renderMode != RENDER_MODE_BUBBLE) {
|
|
shun-iwasawa |
9d0856 |
float val = alpha * (float)PIXEL::maxChannelValue + 0.5f;
|
|
shun-iwasawa |
9d0856 |
pix->m = (typename PIXEL::Channel)((val > (float)PIXEL::maxChannelValue)
|
|
shun-iwasawa |
9d0856 |
? (float)PIXEL::maxChannelValue
|
|
shun-iwasawa |
9d0856 |
: val);
|
|
shun-iwasawa |
9d0856 |
float mapVal =
|
|
shun-iwasawa |
9d0856 |
(renderMode == RENDER_MODE_THICKNESS) ? (*thickness_p) : (*depth_p);
|
|
shun-iwasawa |
9d0856 |
val = alpha * mapVal * (float)PIXEL::maxChannelValue + 0.5f;
|
|
shun-iwasawa |
9d0856 |
typename PIXEL::Channel chanVal =
|
|
shun-iwasawa |
9d0856 |
(typename PIXEL::Channel)((val > (float)PIXEL::maxChannelValue)
|
|
shun-iwasawa |
9d0856 |
? (float)PIXEL::maxChannelValue
|
|
shun-iwasawa |
9d0856 |
: val);
|
|
shun-iwasawa |
9d0856 |
pix->r = chanVal;
|
|
shun-iwasawa |
9d0856 |
pix->g = chanVal;
|
|
shun-iwasawa |
9d0856 |
pix->b = chanVal;
|
|
shun-iwasawa |
9d0856 |
continue;
|
|
shun-iwasawa |
9d0856 |
}
|
|
shun-iwasawa |
9d0856 |
|
|
shun_iwasawa |
4d2acf |
float coordinate[2];
|
|
shun_iwasawa |
4d2acf |
coordinate[0] = 256.0f * std::min(1.0f, *depth_p);
|
|
shun_iwasawa |
4d2acf |
coordinate[1] = 256.0f * std::min(1.0f, *thickness_p);
|
|
shun_iwasawa |
4d2acf |
|
|
shun_iwasawa |
4d2acf |
int neighbors[2][2];
|
|
shun_iwasawa |
4d2acf |
|
|
shun_iwasawa |
4d2acf |
/* interpolate sampling */
|
|
shun_iwasawa |
4d2acf |
if (coordinate[0] <= 0.5f)
|
|
shun_iwasawa |
4d2acf |
neighbors[0][0] = 0;
|
|
shun_iwasawa |
4d2acf |
else
|
|
shun_iwasawa |
4d2acf |
neighbors[0][0] = (int)std::floor(coordinate[0] - 0.5f);
|
|
shun_iwasawa |
4d2acf |
if (coordinate[0] >= 255.5f)
|
|
shun_iwasawa |
4d2acf |
neighbors[0][1] = 255;
|
|
shun_iwasawa |
4d2acf |
else
|
|
shun_iwasawa |
4d2acf |
neighbors[0][1] = (int)std::floor(coordinate[0] + 0.5f);
|
|
shun_iwasawa |
4d2acf |
if (coordinate[1] <= 0.5f)
|
|
shun_iwasawa |
4d2acf |
neighbors[1][0] = 0;
|
|
shun_iwasawa |
4d2acf |
else
|
|
shun_iwasawa |
4d2acf |
neighbors[1][0] = (int)std::floor(coordinate[1] - 0.5f);
|
|
shun_iwasawa |
4d2acf |
if (coordinate[1] >= 255.5f)
|
|
shun_iwasawa |
4d2acf |
neighbors[1][1] = 255;
|
|
shun_iwasawa |
4d2acf |
else
|
|
shun_iwasawa |
4d2acf |
neighbors[1][1] = (int)std::floor(coordinate[1] + 0.5f);
|
|
shun_iwasawa |
4d2acf |
|
|
shun_iwasawa |
4d2acf |
float interp_ratio[2];
|
|
shun_iwasawa |
4d2acf |
interp_ratio[0] = coordinate[0] - 0.5f - std::floor(coordinate[0] - 0.5f);
|
|
shun_iwasawa |
4d2acf |
interp_ratio[1] = coordinate[1] - 0.5f - std::floor(coordinate[1] - 0.5f);
|
|
shun_iwasawa |
4d2acf |
|
|
shun_iwasawa |
4d2acf |
float3 nColors[4] = {
|
|
shun_iwasawa |
4d2acf |
bubbleColor_p[neighbors[0][0] * 256 + neighbors[1][0]],
|
|
shun_iwasawa |
4d2acf |
bubbleColor_p[neighbors[0][1] * 256 + neighbors[1][0]],
|
|
shun_iwasawa |
4d2acf |
bubbleColor_p[neighbors[0][0] * 256 + neighbors[1][1]],
|
|
shun_iwasawa |
4d2acf |
bubbleColor_p[neighbors[0][1] * 256 + neighbors[1][1]]};
|
|
shun_iwasawa |
4d2acf |
|
|
shun_iwasawa |
4d2acf |
float3 color =
|
|
shun_iwasawa |
4d2acf |
nColors[0] * (1.0f - interp_ratio[0]) * (1.0f - interp_ratio[1]) +
|
|
shun_iwasawa |
4d2acf |
nColors[1] * interp_ratio[0] * (1.0f - interp_ratio[1]) +
|
|
shun_iwasawa |
4d2acf |
nColors[2] * (1.0f - interp_ratio[0]) * interp_ratio[1] +
|
|
shun_iwasawa |
4d2acf |
nColors[3] * interp_ratio[0] * interp_ratio[1];
|
|
shun_iwasawa |
4d2acf |
|
|
shun_iwasawa |
4d2acf |
/* clamp */
|
|
shun-iwasawa |
a1471c |
float val = alpha * (float)PIXEL::maxChannelValue + 0.5f;
|
|
shun-iwasawa |
a1471c |
pix->m = (typename PIXEL::Channel)((val > (float)PIXEL::maxChannelValue)
|
|
shun-iwasawa |
a1471c |
? (float)PIXEL::maxChannelValue
|
|
shun-iwasawa |
a1471c |
: val);
|
|
shun-iwasawa |
a1471c |
val = alpha * color.x * (float)PIXEL::maxChannelValue + 0.5f;
|
|
shun_iwasawa |
4d2acf |
pix->r = (typename PIXEL::Channel)((val > (float)PIXEL::maxChannelValue)
|
|
shun_iwasawa |
4d2acf |
? (float)PIXEL::maxChannelValue
|
|
shun_iwasawa |
4d2acf |
: val);
|
|
shun-iwasawa |
a1471c |
val = alpha * color.y * (float)PIXEL::maxChannelValue + 0.5f;
|
|
shun_iwasawa |
4d2acf |
pix->g = (typename PIXEL::Channel)((val > (float)PIXEL::maxChannelValue)
|
|
shun_iwasawa |
4d2acf |
? (float)PIXEL::maxChannelValue
|
|
shun_iwasawa |
4d2acf |
: val);
|
|
shun-iwasawa |
a1471c |
val = alpha * color.z * (float)PIXEL::maxChannelValue + 0.5f;
|
|
shun_iwasawa |
4d2acf |
pix->b = (typename PIXEL::Channel)((val > (float)PIXEL::maxChannelValue)
|
|
shun_iwasawa |
4d2acf |
? (float)PIXEL::maxChannelValue
|
|
shun_iwasawa |
4d2acf |
: val);
|
|
shun_iwasawa |
4d2acf |
}
|
|
shun_iwasawa |
4d2acf |
}
|
|
shun_iwasawa |
4d2acf |
}
|
|
shun_iwasawa |
4d2acf |
|
|
shun_iwasawa |
4d2acf |
//------------------------------------
|
|
shun_iwasawa |
4d2acf |
|
|
shun_iwasawa |
4d2acf |
void Iwa_SoapBubbleFx::processShape(double frame, TTile& shape_tile,
|
|
shun-iwasawa |
a1471c |
float* depth_map_p, float* alpha_map_p,
|
|
shun-iwasawa |
9d0856 |
USHORT* regionIds_p,
|
|
shun-iwasawa |
9d0856 |
QList<qrect>& regionBoundingRects,</qrect>
|
|
shun-iwasawa |
a1471c |
TDimensionI dim,
|
|
shun_iwasawa |
4d2acf |
const TRenderSettings& settings) {
|
|
shun_iwasawa |
4d2acf |
TRaster32P shapeRas = shape_tile.getRaster();
|
|
shun_iwasawa |
4d2acf |
shapeRas->lock();
|
|
shun_iwasawa |
4d2acf |
|
|
shun_iwasawa |
4d2acf |
TRasterGR8P distance_ras(sizeof(float) * dim.lx * dim.ly, 1);
|
|
shun_iwasawa |
4d2acf |
distance_ras->lock();
|
|
shun_iwasawa |
4d2acf |
float* distance_p = (float*)distance_ras->getRawData();
|
|
shun_iwasawa |
4d2acf |
|
|
shun_iwasawa |
4d2acf |
float binarize_thres = (float)m_binarize_threshold->getValue(frame);
|
|
shun_iwasawa |
4d2acf |
|
|
shun-iwasawa |
9d0856 |
int regionCount =
|
|
shun-iwasawa |
9d0856 |
do_binarize(shapeRas, regionIds_p, binarize_thres, distance_p,
|
|
shun-iwasawa |
9d0856 |
alpha_map_p, regionBoundingRects, dim);
|
|
shun_iwasawa |
4d2acf |
|
|
shun_iwasawa |
4d2acf |
shapeRas->unlock();
|
|
shun_iwasawa |
4d2acf |
|
|
shun-iwasawa |
a1471c |
if (settings.m_isCanceled && *settings.m_isCanceled) {
|
|
shun-iwasawa |
a1471c |
distance_ras->unlock();
|
|
shun-iwasawa |
a1471c |
return;
|
|
shun-iwasawa |
a1471c |
}
|
|
shun-iwasawa |
a1471c |
|
|
shun-iwasawa |
9d0856 |
do_distance_transform(distance_p, regionIds_p, regionCount, dim, frame);
|
|
shun-iwasawa |
a1471c |
|
|
shun-iwasawa |
a1471c |
if (settings.m_isCanceled && *settings.m_isCanceled) {
|
|
shun-iwasawa |
a1471c |
distance_ras->unlock();
|
|
shun-iwasawa |
a1471c |
return;
|
|
shun-iwasawa |
a1471c |
}
|
|
shun-iwasawa |
a1471c |
|
|
shun-iwasawa |
9d0856 |
float center_opacity = (float)m_center_opacity->getValue(frame);
|
|
shun-iwasawa |
9d0856 |
if (center_opacity != 1.0f)
|
|
shun-iwasawa |
9d0856 |
applyDistanceToAlpha(distance_p, alpha_map_p, dim, center_opacity);
|
|
shun_iwasawa |
4d2acf |
|
|
shun_iwasawa |
4d2acf |
/* create blur filter */
|
|
shun_iwasawa |
4d2acf |
float blur_radius = (float)m_blur_radius->getValue(frame) *
|
|
shun_iwasawa |
4d2acf |
std::sqrt(std::abs((float)settings.m_affine.det()));
|
|
shun_iwasawa |
4d2acf |
|
|
shun_iwasawa |
4d2acf |
/* if blur radius is 0, set the distance image to the depth image as-is */
|
|
shun_iwasawa |
4d2acf |
if (blur_radius == 0.0f) {
|
|
shun_iwasawa |
4d2acf |
float power = (float)m_blur_power->getValue(frame);
|
|
shun_iwasawa |
4d2acf |
float* tmp_depth = depth_map_p;
|
|
shun_iwasawa |
4d2acf |
float* tmp_dist = distance_p;
|
|
shun-iwasawa |
9d0856 |
USHORT* rid_p = regionIds_p;
|
|
shun_iwasawa |
4d2acf |
for (int i = 0; i < dim.lx * dim.ly;
|
|
shun-iwasawa |
9d0856 |
i++, tmp_depth++, tmp_dist++, rid_p++) {
|
|
shun-iwasawa |
9d0856 |
if (*rid_p == 0)
|
|
shun_iwasawa |
4d2acf |
*tmp_depth = 0.0f;
|
|
shun_iwasawa |
4d2acf |
else
|
|
shun_iwasawa |
4d2acf |
*tmp_depth = 1.0f - std::pow(*tmp_dist, power);
|
|
shun_iwasawa |
4d2acf |
}
|
|
shun_iwasawa |
4d2acf |
distance_ras->unlock();
|
|
shun_iwasawa |
4d2acf |
return;
|
|
shun_iwasawa |
4d2acf |
}
|
|
shun_iwasawa |
4d2acf |
|
|
shun_iwasawa |
4d2acf |
int blur_filter_size = (int)std::floor(blur_radius) * 2 + 1;
|
|
shun_iwasawa |
4d2acf |
TRasterGR8P blur_filter_ras(
|
|
shun_iwasawa |
4d2acf |
sizeof(float) * blur_filter_size * blur_filter_size, 1);
|
|
shun_iwasawa |
4d2acf |
blur_filter_ras->lock();
|
|
shun_iwasawa |
4d2acf |
float* blur_filter_p = (float*)blur_filter_ras->getRawData();
|
|
shun_iwasawa |
4d2acf |
|
|
shun_iwasawa |
4d2acf |
do_createBlurFilter(blur_filter_p, blur_filter_size, blur_radius);
|
|
shun_iwasawa |
4d2acf |
|
|
shun-iwasawa |
a1471c |
if (settings.m_isCanceled && *settings.m_isCanceled) {
|
|
shun-iwasawa |
a1471c |
blur_filter_ras->unlock();
|
|
shun-iwasawa |
a1471c |
distance_ras->unlock();
|
|
shun-iwasawa |
a1471c |
return;
|
|
shun-iwasawa |
a1471c |
}
|
|
shun-iwasawa |
a1471c |
|
|
shun_iwasawa |
4d2acf |
/* blur filtering, normarize & power */
|
|
shun-iwasawa |
9d0856 |
do_applyFilter(depth_map_p, dim, distance_p, regionIds_p, blur_filter_p,
|
|
shun-iwasawa |
a1471c |
blur_filter_size, frame, settings);
|
|
shun_iwasawa |
4d2acf |
|
|
shun_iwasawa |
4d2acf |
distance_ras->unlock();
|
|
shun_iwasawa |
4d2acf |
blur_filter_ras->unlock();
|
|
shun_iwasawa |
4d2acf |
}
|
|
shun_iwasawa |
4d2acf |
|
|
shun_iwasawa |
4d2acf |
//------------------------------------
|
|
shun_iwasawa |
4d2acf |
|
|
shun-iwasawa |
a1471c |
int Iwa_SoapBubbleFx::do_binarize(TRaster32P srcRas, USHORT* dst_p, float thres,
|
|
shun-iwasawa |
a1471c |
float* distance_p, float* alpha_map_p,
|
|
shun-iwasawa |
9d0856 |
QList<qrect>& regionBoundingRects,</qrect>
|
|
shun-iwasawa |
a1471c |
TDimensionI dim) {
|
|
shun_iwasawa |
4d2acf |
TPixel32::Channel channelThres =
|
|
shun_iwasawa |
4d2acf |
(TPixel32::Channel)(thres * (float)TPixel32::maxChannelValue);
|
|
shun-iwasawa |
a1471c |
USHORT* tmp_p = dst_p;
|
|
shun_iwasawa |
4d2acf |
float* tmp_dist = distance_p;
|
|
shun-iwasawa |
a1471c |
float* alpha_p = alpha_map_p;
|
|
shun_iwasawa |
4d2acf |
for (int j = 0; j < dim.ly; j++) {
|
|
shun_iwasawa |
4d2acf |
TPixel32* pix = srcRas->pixels(j);
|
|
shun-iwasawa |
a1471c |
for (int i = 0; i < dim.lx; i++, pix++, tmp_p++, tmp_dist++, alpha_p++) {
|
|
shun_iwasawa |
4d2acf |
(*tmp_p) = (pix->m > channelThres) ? 1 : 0;
|
|
shun_iwasawa |
4d2acf |
(*tmp_dist) = (*tmp_p == 1) ? INF : 0.0f;
|
|
shun-iwasawa |
a1471c |
*alpha_p = (float)pix->m / (float)TPixel32::maxChannelValue;
|
|
shun_iwasawa |
4d2acf |
}
|
|
shun_iwasawa |
4d2acf |
}
|
|
shun-iwasawa |
a1471c |
|
|
shun-iwasawa |
a1471c |
// label regions when multi bubble option is on
|
|
shun-iwasawa |
9d0856 |
if (!m_multi_source->getValue()) {
|
|
shun-iwasawa |
9d0856 |
if (m_fit_thickness->getValue()) {
|
|
shun-iwasawa |
9d0856 |
regionBoundingRects.append(QRect());
|
|
shun-iwasawa |
9d0856 |
// calc boundingRect of the bubble
|
|
shun-iwasawa |
9d0856 |
QPoint topLeft(dim.lx, dim.ly);
|
|
shun-iwasawa |
9d0856 |
QPoint bottomRight(0, 0);
|
|
shun-iwasawa |
9d0856 |
USHORT* tmp_p = dst_p;
|
|
shun-iwasawa |
9d0856 |
for (int j = 0; j < dim.ly; j++) {
|
|
shun-iwasawa |
9d0856 |
for (int i = 0; i < dim.lx; i++, tmp_p++) {
|
|
shun-iwasawa |
9d0856 |
if ((*tmp_p) == 0) continue;
|
|
shun-iwasawa |
9d0856 |
if (topLeft.x() > i) topLeft.setX(i);
|
|
shun-iwasawa |
9d0856 |
if (bottomRight.x() < i) bottomRight.setX(i);
|
|
shun-iwasawa |
9d0856 |
if (topLeft.y() > j) topLeft.setY(j);
|
|
shun-iwasawa |
9d0856 |
if (bottomRight.y() < j) bottomRight.setY(j);
|
|
shun-iwasawa |
9d0856 |
}
|
|
shun-iwasawa |
9d0856 |
}
|
|
shun-iwasawa |
9d0856 |
regionBoundingRects.append(QRect(topLeft, bottomRight));
|
|
shun-iwasawa |
9d0856 |
}
|
|
shun-iwasawa |
9d0856 |
|
|
shun-iwasawa |
9d0856 |
return 1;
|
|
shun-iwasawa |
9d0856 |
}
|
|
shun-iwasawa |
a1471c |
|
|
shun-iwasawa |
a1471c |
QList<int> lut;</int>
|
|
shun-iwasawa |
a1471c |
for (int i = 0; i < 65536; i++) lut.append(i);
|
|
shun-iwasawa |
a1471c |
tmp_p = dst_p;
|
|
shun-iwasawa |
a1471c |
int regionCount = 0;
|
|
shun-iwasawa |
a1471c |
for (int j = 0; j < dim.ly; j++) {
|
|
shun-iwasawa |
a1471c |
for (int i = 0; i < dim.lx; i++, tmp_p++) {
|
|
shun-iwasawa |
a1471c |
if ((*tmp_p) == 1) {
|
|
shun-iwasawa |
a1471c |
int up = (j == 0) ? 0 : *(tmp_p - dim.lx);
|
|
shun-iwasawa |
a1471c |
int left = (i == 0) ? 0 : *(tmp_p - 1);
|
|
shun-iwasawa |
a1471c |
assert(up >= 0 && left >= 0);
|
|
shun-iwasawa |
a1471c |
if (!up && !left) {
|
|
shun-iwasawa |
a1471c |
if (regionCount < 65535) regionCount++;
|
|
shun-iwasawa |
a1471c |
(*tmp_p) = regionCount;
|
|
shun-iwasawa |
a1471c |
} else if (up && !left)
|
|
shun-iwasawa |
a1471c |
(*tmp_p) = up;
|
|
shun-iwasawa |
a1471c |
else if (!up && left)
|
|
shun-iwasawa |
a1471c |
(*tmp_p) = left;
|
|
shun-iwasawa |
a1471c |
else if (up == left)
|
|
shun-iwasawa |
a1471c |
(*tmp_p) = up;
|
|
shun-iwasawa |
a1471c |
else if (up > left) {
|
|
shun-iwasawa |
a1471c |
(*tmp_p) = left;
|
|
shun-iwasawa |
a1471c |
lut[up] = left;
|
|
shun-iwasawa |
a1471c |
} else {
|
|
shun-iwasawa |
a1471c |
(*tmp_p) = up;
|
|
shun-iwasawa |
a1471c |
lut[left] = up;
|
|
shun-iwasawa |
a1471c |
}
|
|
shun-iwasawa |
a1471c |
}
|
|
shun-iwasawa |
a1471c |
}
|
|
shun-iwasawa |
a1471c |
}
|
|
shun-iwasawa |
a1471c |
|
|
shun-iwasawa |
a1471c |
// organize lut
|
|
shun-iwasawa |
a1471c |
QList<int> convIndex;</int>
|
|
shun-iwasawa |
a1471c |
int currentIndex = 0;
|
|
shun-iwasawa |
a1471c |
for (int i = 0; i < 65536; i++) {
|
|
shun-iwasawa |
a1471c |
if (lut.at(i) == i) {
|
|
shun-iwasawa |
a1471c |
lut[i] = currentIndex;
|
|
shun-iwasawa |
a1471c |
currentIndex++;
|
|
shun-iwasawa |
a1471c |
} else
|
|
shun-iwasawa |
a1471c |
convIndex.append(i);
|
|
shun-iwasawa |
a1471c |
}
|
|
shun-iwasawa |
a1471c |
for (int i = 0; i < convIndex.count(); i++)
|
|
shun-iwasawa |
a1471c |
lut[convIndex.at(i)] = lut.at(lut.at(convIndex.at(i)));
|
|
shun-iwasawa |
a1471c |
|
|
shun-iwasawa |
a1471c |
// apply lut
|
|
shun-iwasawa |
9d0856 |
int maxRegionIndex = 0;
|
|
shun-iwasawa |
9d0856 |
tmp_p = dst_p;
|
|
shun-iwasawa |
a1471c |
for (int j = 0; j < dim.ly; j++) {
|
|
shun-iwasawa |
a1471c |
for (int i = 0; i < dim.lx; i++, tmp_p++) {
|
|
shun-iwasawa |
9d0856 |
(*tmp_p) = lut[*tmp_p];
|
|
shun-iwasawa |
9d0856 |
if (maxRegionIndex < (*tmp_p)) maxRegionIndex = (*tmp_p);
|
|
shun-iwasawa |
9d0856 |
}
|
|
shun-iwasawa |
9d0856 |
}
|
|
shun-iwasawa |
9d0856 |
|
|
shun-iwasawa |
9d0856 |
// compute bounding boxes of each bubble
|
|
shun-iwasawa |
9d0856 |
if (m_fit_thickness->getValue()) {
|
|
shun-iwasawa |
9d0856 |
regionBoundingRects.append(QRect());
|
|
shun-iwasawa |
9d0856 |
USHORT* tmp_p = dst_p;
|
|
shun-iwasawa |
9d0856 |
for (int j = 0; j < dim.ly; j++) {
|
|
shun-iwasawa |
9d0856 |
for (int i = 0; i < dim.lx; i++, tmp_p++) {
|
|
shun-iwasawa |
9d0856 |
int rId = (*tmp_p);
|
|
shun-iwasawa |
9d0856 |
if (rId == 0) continue;
|
|
shun-iwasawa |
9d0856 |
while (regionBoundingRects.size() <= rId)
|
|
shun-iwasawa |
9d0856 |
regionBoundingRects.append(QRect());
|
|
shun-iwasawa |
9d0856 |
|
|
shun-iwasawa |
9d0856 |
if (regionBoundingRects.at(rId).isNull())
|
|
shun-iwasawa |
9d0856 |
regionBoundingRects[rId].setRect(i, j, 1, 1);
|
|
shun-iwasawa |
9d0856 |
else {
|
|
shun-iwasawa |
9d0856 |
if (regionBoundingRects[rId].left() > i)
|
|
shun-iwasawa |
9d0856 |
regionBoundingRects[rId].setLeft(i);
|
|
shun-iwasawa |
9d0856 |
if (regionBoundingRects[rId].right() < i)
|
|
shun-iwasawa |
9d0856 |
regionBoundingRects[rId].setRight(i);
|
|
shun-iwasawa |
9d0856 |
if (regionBoundingRects[rId].top() > j)
|
|
shun-iwasawa |
9d0856 |
regionBoundingRects[rId].setTop(j);
|
|
shun-iwasawa |
9d0856 |
if (regionBoundingRects[rId].bottom() < j)
|
|
shun-iwasawa |
9d0856 |
regionBoundingRects[rId].setBottom(j);
|
|
shun-iwasawa |
9d0856 |
}
|
|
shun-iwasawa |
9d0856 |
}
|
|
shun-iwasawa |
a1471c |
}
|
|
shun-iwasawa |
a1471c |
}
|
|
shun-iwasawa |
9d0856 |
|
|
shun-iwasawa |
9d0856 |
return maxRegionIndex;
|
|
shun_iwasawa |
4d2acf |
}
|
|
shun_iwasawa |
4d2acf |
|
|
shun_iwasawa |
4d2acf |
//------------------------------------
|
|
shun_iwasawa |
4d2acf |
|
|
shun_iwasawa |
4d2acf |
void Iwa_SoapBubbleFx::do_createBlurFilter(float* dst_p, int size,
|
|
shun_iwasawa |
4d2acf |
float radius) {
|
|
shun_iwasawa |
4d2acf |
float radius2 = radius * radius;
|
|
shun_iwasawa |
4d2acf |
float* tmp_p = dst_p;
|
|
shun_iwasawa |
4d2acf |
float sum = 0.0f;
|
|
shun_iwasawa |
4d2acf |
int rad = (size - 1) / 2;
|
|
shun_iwasawa |
4d2acf |
for (int j = -rad; j <= rad; j++) {
|
|
shun_iwasawa |
4d2acf |
for (int i = -rad; i <= rad; i++, tmp_p++) {
|
|
shun_iwasawa |
4d2acf |
float length2 = (float)i * (float)i + (float)j * (float)j;
|
|
shun_iwasawa |
4d2acf |
/* out of range */
|
|
shun_iwasawa |
4d2acf |
if (length2 >= radius2)
|
|
shun_iwasawa |
4d2acf |
*tmp_p = 0.0f;
|
|
shun_iwasawa |
4d2acf |
else {
|
|
shun_iwasawa |
4d2acf |
/* normalize distace from the filter center, to 0-1 */
|
|
shun_iwasawa |
4d2acf |
*tmp_p = 1.0f - std::sqrt(length2) / radius;
|
|
shun_iwasawa |
4d2acf |
sum += *tmp_p;
|
|
shun_iwasawa |
4d2acf |
}
|
|
shun_iwasawa |
4d2acf |
}
|
|
shun_iwasawa |
4d2acf |
}
|
|
shun_iwasawa |
4d2acf |
/* normalize */
|
|
shun_iwasawa |
4d2acf |
tmp_p = dst_p;
|
|
shun_iwasawa |
4d2acf |
for (int i = 0; i < size * size; i++, tmp_p++) {
|
|
shun_iwasawa |
4d2acf |
*tmp_p /= sum;
|
|
shun_iwasawa |
4d2acf |
}
|
|
shun_iwasawa |
4d2acf |
}
|
|
shun_iwasawa |
4d2acf |
//------------------------------------
|
|
shun_iwasawa |
4d2acf |
|
|
shun_iwasawa |
4d2acf |
void Iwa_SoapBubbleFx::do_applyFilter(float* depth_map_p, TDimensionI dim,
|
|
shun-iwasawa |
a1471c |
float* distance_p, USHORT* binarized_p,
|
|
shun_iwasawa |
4d2acf |
float* blur_filter_p,
|
|
shun-iwasawa |
a1471c |
int blur_filter_size, double frame,
|
|
shun-iwasawa |
a1471c |
const TRenderSettings& settings) {
|
|
shun_iwasawa |
4d2acf |
float power = (float)m_blur_power->getValue(frame);
|
|
shun_iwasawa |
4d2acf |
|
|
shun_iwasawa |
4d2acf |
memset(depth_map_p, 0, sizeof(float) * dim.lx * dim.ly);
|
|
shun_iwasawa |
4d2acf |
|
|
shun_iwasawa |
4d2acf |
int fil_margin = (blur_filter_size - 1) / 2;
|
|
shun_iwasawa |
4d2acf |
float* dst_p = depth_map_p;
|
|
shun-iwasawa |
a1471c |
USHORT* bin_p = binarized_p;
|
|
shun_iwasawa |
4d2acf |
for (int j = 0; j < dim.ly; j++) {
|
|
shun_iwasawa |
4d2acf |
for (int i = 0; i < dim.lx; i++, dst_p++, bin_p++) {
|
|
shun_iwasawa |
4d2acf |
if (*bin_p == 0) continue;
|
|
shun_iwasawa |
4d2acf |
|
|
shun_iwasawa |
4d2acf |
float* fil_p = blur_filter_p;
|
|
shun_iwasawa |
4d2acf |
for (int fy = j - fil_margin; fy <= j + fil_margin; fy++) {
|
|
shun_iwasawa |
4d2acf |
if (fy < 0 || fy >= dim.ly) {
|
|
shun_iwasawa |
4d2acf |
fil_p += blur_filter_size;
|
|
shun_iwasawa |
4d2acf |
continue;
|
|
shun_iwasawa |
4d2acf |
}
|
|
shun_iwasawa |
4d2acf |
for (int fx = i - fil_margin; fx <= i + fil_margin; fx++, fil_p++) {
|
|
shun_iwasawa |
4d2acf |
if (fx < 0 || fx >= dim.lx) continue;
|
|
shun_iwasawa |
4d2acf |
|
|
shun_iwasawa |
4d2acf |
*dst_p += *fil_p * distance_p[fy * dim.lx + fx];
|
|
shun_iwasawa |
4d2acf |
}
|
|
shun_iwasawa |
4d2acf |
}
|
|
shun_iwasawa |
4d2acf |
/* power the value */
|
|
shun_iwasawa |
4d2acf |
*dst_p = 1.0f - std::pow(*dst_p, power);
|
|
shun_iwasawa |
4d2acf |
}
|
|
shun-iwasawa |
a1471c |
if (settings.m_isCanceled && *settings.m_isCanceled) return;
|
|
shun_iwasawa |
4d2acf |
}
|
|
shun_iwasawa |
4d2acf |
}
|
|
shun_iwasawa |
4d2acf |
|
|
shun_iwasawa |
4d2acf |
//------------------------------------
|
|
shun_iwasawa |
4d2acf |
|
|
shun_iwasawa |
4d2acf |
void Iwa_SoapBubbleFx::processNoise(float* thickness_map_p, float* depth_map_p,
|
|
shun_iwasawa |
4d2acf |
TDimensionI dim, double frame,
|
|
shun_iwasawa |
4d2acf |
const TRenderSettings& settings) {
|
|
shun_iwasawa |
4d2acf |
float noise_depth_mix_ratio = (float)m_noise_depth_mix_ratio->getValue(frame);
|
|
shun_iwasawa |
4d2acf |
float noise_thickness_mix_ratio =
|
|
shun_iwasawa |
4d2acf |
(float)m_noise_thickness_mix_ratio->getValue(frame);
|
|
shun_iwasawa |
4d2acf |
|
|
shun_iwasawa |
4d2acf |
/* If the noise ratio is 0, do nothing and return */
|
|
shun_iwasawa |
4d2acf |
if (noise_depth_mix_ratio == 0.0f && noise_thickness_mix_ratio == 0.0f)
|
|
shun_iwasawa |
4d2acf |
return;
|
|
shun_iwasawa |
4d2acf |
|
|
shun_iwasawa |
4d2acf |
int noise_sub_depth = m_noise_sub_depth->getValue();
|
|
shun_iwasawa |
4d2acf |
int noise_resolution_s = (int)m_noise_resolution_s->getValue(frame);
|
|
shun_iwasawa |
4d2acf |
int noise_resolution_t = (int)m_noise_resolution_t->getValue(frame);
|
|
shun_iwasawa |
4d2acf |
float noise_composite_ratio =
|
|
shun_iwasawa |
4d2acf |
(float)m_noise_sub_composite_ratio->getValue(frame);
|
|
shun_iwasawa |
4d2acf |
float noise_evolution = (float)m_noise_evolution->getValue(frame);
|
|
shun_iwasawa |
4d2acf |
|
|
shun_iwasawa |
4d2acf |
/* initialize the phase map */
|
|
shun_iwasawa |
4d2acf |
QList<int> noise_amount;</int>
|
|
shun_iwasawa |
4d2acf |
QList<qsize> noise_base_resolution;</qsize>
|
|
shun_iwasawa |
4d2acf |
int whole_noise_amount = 0;
|
|
shun_iwasawa |
4d2acf |
|
|
shun_iwasawa |
4d2acf |
for (int layer = 0; layer < noise_sub_depth; layer++) {
|
|
shun_iwasawa |
4d2acf |
/* noise resolution */
|
|
shun_iwasawa |
4d2acf |
/* width: circumferential direction height:distal direction */
|
|
shun_iwasawa |
4d2acf |
QSize size;
|
|
shun_iwasawa |
4d2acf |
size.setWidth(std::pow(2, layer) * noise_resolution_s);
|
|
shun_iwasawa |
4d2acf |
size.setHeight(std::pow(2, layer) * noise_resolution_t + 1);
|
|
shun_iwasawa |
4d2acf |
noise_base_resolution.append(size);
|
|
shun_iwasawa |
4d2acf |
int amount = size.width() * size.height();
|
|
shun_iwasawa |
4d2acf |
noise_amount.append(amount);
|
|
shun_iwasawa |
4d2acf |
whole_noise_amount += amount;
|
|
shun_iwasawa |
4d2acf |
}
|
|
shun_iwasawa |
4d2acf |
|
|
shun_iwasawa |
4d2acf |
float* noise_phases = new float[whole_noise_amount];
|
|
shun_iwasawa |
4d2acf |
float* ph_p = noise_phases;
|
|
shun_iwasawa |
4d2acf |
|
|
shun_iwasawa |
4d2acf |
srand(0);
|
|
romeojulietthotel |
12386f |
/* Set the phase differences (0-2) */
|
|
shun_iwasawa |
4d2acf |
for (int i = 0; i < whole_noise_amount; i++, ph_p++) {
|
|
shun_iwasawa |
4d2acf |
*ph_p = (float)rand() / (float)RAND_MAX * 2.0f * PI;
|
|
shun_iwasawa |
4d2acf |
}
|
|
shun_iwasawa |
4d2acf |
|
|
shun_iwasawa |
4d2acf |
/* make noise base */
|
|
shun_iwasawa |
4d2acf |
/* compute composite ratio of each layer */
|
|
shun_iwasawa |
4d2acf |
QList<float> comp_ratios;</float>
|
|
shun_iwasawa |
4d2acf |
comp_ratios.append(10.0f);
|
|
shun_iwasawa |
4d2acf |
float ratio_sum = 10.0f;
|
|
shun_iwasawa |
4d2acf |
for (int i = 1; i < noise_sub_depth; i++) {
|
|
shun_iwasawa |
4d2acf |
comp_ratios.append(comp_ratios.last() * noise_composite_ratio);
|
|
shun_iwasawa |
4d2acf |
ratio_sum += comp_ratios.last();
|
|
shun_iwasawa |
4d2acf |
}
|
|
shun_iwasawa |
4d2acf |
/* normalize */
|
|
shun_iwasawa |
4d2acf |
for (int i = 0; i < noise_sub_depth; i++) comp_ratios[i] /= ratio_sum;
|
|
shun_iwasawa |
4d2acf |
|
|
shun_iwasawa |
4d2acf |
float* noise_base = new float[whole_noise_amount];
|
|
shun_iwasawa |
4d2acf |
|
|
shun_iwasawa |
4d2acf |
float* nb_p = noise_base;
|
|
shun_iwasawa |
4d2acf |
ph_p = noise_phases;
|
|
shun_iwasawa |
4d2acf |
|
|
shun_iwasawa |
4d2acf |
/* for each sub-noise layer */
|
|
shun_iwasawa |
4d2acf |
for (int layer = 0; layer < noise_sub_depth; layer++) {
|
|
shun_iwasawa |
4d2acf |
float tmp_evolution = noise_evolution * (float)(layer + 1);
|
|
shun_iwasawa |
4d2acf |
for (int i = 0; i < noise_amount[layer]; i++, nb_p++, ph_p++) {
|
|
shun_iwasawa |
4d2acf |
*nb_p = comp_ratios[layer] * (cosf(tmp_evolution + *ph_p) / 2.0f + 0.5f);
|
|
shun_iwasawa |
4d2acf |
}
|
|
shun_iwasawa |
4d2acf |
}
|
|
shun_iwasawa |
4d2acf |
delete[] noise_phases;
|
|
shun_iwasawa |
4d2acf |
|
|
shun_iwasawa |
4d2acf |
TRasterGR8P norm_angle_ras(sizeof(float) * dim.lx * dim.ly, 1);
|
|
shun_iwasawa |
4d2acf |
norm_angle_ras->lock();
|
|
shun_iwasawa |
4d2acf |
float* norm_angle_p = (float*)norm_angle_ras->getRawData();
|
|
shun_iwasawa |
4d2acf |
|
|
shun_iwasawa |
4d2acf |
calc_norm_angle(norm_angle_p, depth_map_p, dim, settings.m_shrinkX);
|
|
shun_iwasawa |
4d2acf |
|
|
shun_iwasawa |
4d2acf |
TRasterGR8P noise_map_ras(sizeof(float) * dim.lx * dim.ly, 1);
|
|
shun_iwasawa |
4d2acf |
noise_map_ras->lock();
|
|
shun_iwasawa |
4d2acf |
float* noise_map_p = (float*)noise_map_ras->getRawData();
|
|
shun_iwasawa |
4d2acf |
|
|
shun_iwasawa |
4d2acf |
make_noise_map(noise_map_p, depth_map_p, norm_angle_p, dim, noise_amount,
|
|
shun_iwasawa |
4d2acf |
noise_base_resolution, noise_sub_depth, noise_base);
|
|
shun_iwasawa |
4d2acf |
|
|
shun_iwasawa |
4d2acf |
norm_angle_ras->unlock();
|
|
shun_iwasawa |
4d2acf |
delete[] noise_base;
|
|
shun_iwasawa |
4d2acf |
|
|
shun_iwasawa |
4d2acf |
/* composite with perlin noise */
|
|
shun_iwasawa |
4d2acf |
add_noise(thickness_map_p, depth_map_p, dim, noise_map_p,
|
|
shun_iwasawa |
4d2acf |
noise_thickness_mix_ratio, noise_depth_mix_ratio);
|
|
shun_iwasawa |
4d2acf |
|
|
shun_iwasawa |
4d2acf |
noise_map_ras->unlock();
|
|
shun_iwasawa |
4d2acf |
}
|
|
shun_iwasawa |
4d2acf |
|
|
shun_iwasawa |
4d2acf |
//------------------------------------
|
|
shun_iwasawa |
4d2acf |
|
|
shun_iwasawa |
4d2acf |
void Iwa_SoapBubbleFx::calc_norm_angle(float* norm_angle_p, float* depth_map_p,
|
|
shun_iwasawa |
4d2acf |
TDimensionI dim, int shrink) {
|
|
shun_iwasawa |
4d2acf |
struct Locals {
|
|
shun_iwasawa |
4d2acf |
TDimensionI _dim;
|
|
shun_iwasawa |
4d2acf |
const float* _depth_p;
|
|
shun_iwasawa |
4d2acf |
float data(int x, int y) {
|
|
shun_iwasawa |
4d2acf |
if (x < 0 || _dim.lx <= x || y < 0 || _dim.ly <= y) return 0.0f;
|
|
shun_iwasawa |
4d2acf |
return _depth_p[y * _dim.lx + x];
|
|
shun_iwasawa |
4d2acf |
}
|
|
shun_iwasawa |
4d2acf |
} locals = {dim, depth_map_p};
|
|
shun_iwasawa |
4d2acf |
|
|
shun_iwasawa |
4d2acf |
int sampleDistance =
|
|
shun_iwasawa |
4d2acf |
std::max(1, m_normal_sample_distance->getValue() / shrink);
|
|
shun_iwasawa |
4d2acf |
float* dst_p = norm_angle_p;
|
|
shun_iwasawa |
4d2acf |
|
|
shun_iwasawa |
4d2acf |
for (int j = 0; j < dim.ly; j++) {
|
|
shun_iwasawa |
4d2acf |
int sample_y[2] = {j - sampleDistance, j + sampleDistance};
|
|
shun_iwasawa |
4d2acf |
if (sample_y[0] < 0) sample_y[0] = 0;
|
|
shun_iwasawa |
4d2acf |
if (sample_y[1] >= dim.ly) sample_y[1] = dim.ly - 1;
|
|
shun_iwasawa |
4d2acf |
|
|
shun_iwasawa |
4d2acf |
for (int i = 0; i < dim.lx; i++, norm_angle_p++) {
|
|
shun_iwasawa |
4d2acf |
int sample_x[2] = {i - sampleDistance, i + sampleDistance};
|
|
shun_iwasawa |
4d2acf |
if (sample_x[1] >= dim.lx) sample_x[1] = dim.lx - 1;
|
|
shun_iwasawa |
4d2acf |
if (sample_x[0] < 0) sample_x[0] = 0;
|
|
shun_iwasawa |
4d2acf |
|
|
shun_iwasawa |
4d2acf |
float gradient[2];
|
|
shun_iwasawa |
4d2acf |
gradient[0] =
|
|
shun_iwasawa |
4d2acf |
(locals.data(sample_x[0], j) - locals.data(sample_x[1], j)) /
|
|
shun_iwasawa |
4d2acf |
(float)(sample_x[0] - sample_x[1]);
|
|
shun_iwasawa |
4d2acf |
gradient[1] =
|
|
shun_iwasawa |
4d2acf |
(locals.data(i, sample_y[0]) - locals.data(i, sample_y[1])) /
|
|
shun_iwasawa |
4d2acf |
(float)(sample_y[0] - sample_y[1]);
|
|
shun_iwasawa |
4d2acf |
|
|
shun_iwasawa |
4d2acf |
if (gradient[0] == 0.0f && gradient[1] == 0.0f)
|
|
shun_iwasawa |
4d2acf |
*norm_angle_p = 0.0f;
|
|
shun_iwasawa |
4d2acf |
else /* normalize value range to 0-1 */
|
|
shun_iwasawa |
4d2acf |
*norm_angle_p =
|
|
shun_iwasawa |
4d2acf |
0.5f + std::atan2(gradient[0], gradient[1]) / (2.0f * PI);
|
|
shun_iwasawa |
4d2acf |
}
|
|
shun_iwasawa |
4d2acf |
}
|
|
shun_iwasawa |
4d2acf |
}
|
|
shun_iwasawa |
4d2acf |
|
|
shun_iwasawa |
4d2acf |
//------------------------------------
|
|
shun_iwasawa |
4d2acf |
|
|
shun_iwasawa |
4d2acf |
void Iwa_SoapBubbleFx::make_noise_map(float* noise_map_p, float* depth_map_p,
|
|
shun_iwasawa |
4d2acf |
float* norm_angle_p, TDimensionI dim,
|
|
shun_iwasawa |
4d2acf |
const QList<int>& noise_amount,</int>
|
|
shun_iwasawa |
4d2acf |
const QList<qsize>& noise_base_resolution,</qsize>
|
|
shun_iwasawa |
4d2acf |
int noise_sub_depth, float* noise_base) {
|
|
shun_iwasawa |
4d2acf |
float* dst_p = noise_map_p;
|
|
shun_iwasawa |
4d2acf |
float* depth_p = depth_map_p;
|
|
shun_iwasawa |
4d2acf |
float* norm_p = norm_angle_p;
|
|
shun_iwasawa |
4d2acf |
|
|
shun_iwasawa |
4d2acf |
for (int j = 0; j < dim.ly; j++) {
|
|
shun_iwasawa |
4d2acf |
for (int i = 0; i < dim.lx; i++, dst_p++, depth_p++, norm_p++) {
|
|
shun_iwasawa |
4d2acf |
/* Obtain coordinate */
|
|
shun_iwasawa |
4d2acf |
/* circumferential direction */
|
|
shun_iwasawa |
4d2acf |
float tmp_s = (*norm_p);
|
|
shun_iwasawa |
4d2acf |
/* distal direction */
|
|
shun_iwasawa |
4d2acf |
float tmp_t = std::min(1.0f, *depth_p);
|
|
shun_iwasawa |
4d2acf |
|
|
shun_iwasawa |
4d2acf |
/* accumulate noise values */
|
|
shun_iwasawa |
4d2acf |
*dst_p = 0.0f;
|
|
shun_iwasawa |
4d2acf |
float* noise_layer_base = noise_base;
|
|
shun_iwasawa |
4d2acf |
for (int layer = 0; layer < noise_sub_depth; layer++) {
|
|
shun_iwasawa |
4d2acf |
/* obtain pseudo polar coords */
|
|
shun_iwasawa |
4d2acf |
QSize reso = noise_base_resolution.at(layer);
|
|
shun_iwasawa |
4d2acf |
float polar_s =
|
|
shun_iwasawa |
4d2acf |
tmp_s * (float)(reso.width()); /* because it is circumferential */
|
|
shun_iwasawa |
4d2acf |
float polar_t = tmp_t * (float)(reso.height() - 1);
|
|
shun_iwasawa |
4d2acf |
|
|
shun_iwasawa |
4d2acf |
/* first, compute circumferential position and ratio */
|
|
shun_iwasawa |
4d2acf |
int neighbor_s[2];
|
|
shun_iwasawa |
4d2acf |
neighbor_s[0] = (int)std::floor(polar_s);
|
|
shun_iwasawa |
4d2acf |
neighbor_s[1] = neighbor_s[0] + 1;
|
|
shun_iwasawa |
4d2acf |
if (neighbor_s[0] == reso.width()) neighbor_s[0] = 0;
|
|
shun_iwasawa |
4d2acf |
if (neighbor_s[1] >= reso.width()) neighbor_s[1] = 0;
|
|
shun_iwasawa |
4d2acf |
float ratio_s = polar_s - std::floor(polar_s);
|
|
shun_iwasawa |
4d2acf |
|
|
shun_iwasawa |
4d2acf |
/* second, compute distal position and ratio */
|
|
shun_iwasawa |
4d2acf |
int neighbor_t[2];
|
|
shun_iwasawa |
4d2acf |
neighbor_t[0] = (int)std::floor(polar_t);
|
|
shun_iwasawa |
4d2acf |
neighbor_t[1] = neighbor_t[0] + 1;
|
|
shun_iwasawa |
4d2acf |
if (neighbor_t[1] == reso.height()) neighbor_t[1] -= 1;
|
|
shun_iwasawa |
4d2acf |
float ratio_t = polar_t - std::floor(polar_t);
|
|
shun_iwasawa |
4d2acf |
|
|
shun_iwasawa |
4d2acf |
*dst_p += noise_interp(neighbor_s[0], neighbor_s[1], neighbor_t[0],
|
|
shun_iwasawa |
4d2acf |
neighbor_t[1], ratio_s, ratio_t,
|
|
shun_iwasawa |
4d2acf |
noise_layer_base, reso.width());
|
|
shun_iwasawa |
4d2acf |
|
|
shun_iwasawa |
4d2acf |
/* offset noise pointer */
|
|
shun_iwasawa |
4d2acf |
noise_layer_base += noise_amount[layer];
|
|
shun_iwasawa |
4d2acf |
}
|
|
shun_iwasawa |
4d2acf |
}
|
|
shun_iwasawa |
4d2acf |
}
|
|
shun_iwasawa |
4d2acf |
}
|
|
shun_iwasawa |
4d2acf |
|
|
shun_iwasawa |
4d2acf |
//------------------------------------
|
|
shun_iwasawa |
4d2acf |
|
|
shun_iwasawa |
4d2acf |
float Iwa_SoapBubbleFx::noise_interp(int left, int right, int bottom, int top,
|
|
shun_iwasawa |
4d2acf |
float ratio_s, float ratio_t,
|
|
shun_iwasawa |
4d2acf |
float* noise_layer_base, int noise_dim_x) {
|
|
shun_iwasawa |
4d2acf |
struct Locals {
|
|
shun_iwasawa |
4d2acf |
int _dim_x;
|
|
shun_iwasawa |
4d2acf |
const float* _noise_p;
|
|
shun_iwasawa |
4d2acf |
float data(int x, int y) { return _noise_p[y * _dim_x + x]; }
|
|
shun_iwasawa |
4d2acf |
} locals = {noise_dim_x, noise_layer_base};
|
|
shun_iwasawa |
4d2acf |
|
|
shun_iwasawa |
4d2acf |
float c_ratio_s = (1.0f - cosf(ratio_s * PI)) * 0.5f;
|
|
shun_iwasawa |
4d2acf |
float c_ratio_t = (1.0f - cosf(ratio_t * PI)) * 0.5f;
|
|
shun_iwasawa |
4d2acf |
|
|
shun_iwasawa |
4d2acf |
return locals.data(left, bottom) * (1.0f - c_ratio_s) * (1.0f - c_ratio_t) +
|
|
shun_iwasawa |
4d2acf |
locals.data(right, bottom) * c_ratio_s * (1.0f - c_ratio_t) +
|
|
shun_iwasawa |
4d2acf |
locals.data(left, top) * (1.0f - c_ratio_s) * c_ratio_t +
|
|
shun_iwasawa |
4d2acf |
locals.data(right, top) * c_ratio_s * c_ratio_t;
|
|
shun_iwasawa |
4d2acf |
}
|
|
shun_iwasawa |
4d2acf |
|
|
shun_iwasawa |
4d2acf |
//------------------------------------
|
|
shun_iwasawa |
4d2acf |
|
|
shun_iwasawa |
4d2acf |
void Iwa_SoapBubbleFx::add_noise(float* thickness_map_p, float* depth_map_p,
|
|
shun_iwasawa |
4d2acf |
TDimensionI dim, float* noise_map_p,
|
|
shun_iwasawa |
4d2acf |
float noise_thickness_mix_ratio,
|
|
shun_iwasawa |
4d2acf |
float noise_depth_mix_ratio) {
|
|
shun_iwasawa |
4d2acf |
float one_minus_thickness_ratio = 1.0f - noise_thickness_mix_ratio;
|
|
shun_iwasawa |
4d2acf |
float one_minus_depth_ratio = 1.0f - noise_depth_mix_ratio;
|
|
shun_iwasawa |
4d2acf |
float* tmp_thickness = thickness_map_p;
|
|
shun_iwasawa |
4d2acf |
float* tmp_depth = depth_map_p;
|
|
shun_iwasawa |
4d2acf |
float* tmp_noise = noise_map_p;
|
|
shun_iwasawa |
4d2acf |
|
|
shun_iwasawa |
4d2acf |
for (int j = 0; j < dim.ly; j++) {
|
|
shun_iwasawa |
4d2acf |
for (int i = 0; i < dim.lx;
|
|
shun_iwasawa |
4d2acf |
i++, tmp_thickness++, tmp_depth++, tmp_noise++) {
|
|
shun_iwasawa |
4d2acf |
*tmp_thickness = *tmp_noise * noise_thickness_mix_ratio +
|
|
shun_iwasawa |
4d2acf |
*tmp_thickness * one_minus_thickness_ratio;
|
|
shun_iwasawa |
4d2acf |
*tmp_depth = *tmp_noise * noise_depth_mix_ratio +
|
|
shun_iwasawa |
4d2acf |
*tmp_depth * one_minus_depth_ratio;
|
|
shun_iwasawa |
4d2acf |
}
|
|
shun_iwasawa |
4d2acf |
}
|
|
shun_iwasawa |
4d2acf |
}
|
|
shun_iwasawa |
4d2acf |
//------------------------------------
|
|
shun_iwasawa |
4d2acf |
|
|
shun-iwasawa |
a1471c |
void Iwa_SoapBubbleFx::do_distance_transform(float* dst_p, USHORT* binarized_p,
|
|
shun-iwasawa |
a1471c |
int regionCount, TDimensionI dim,
|
|
shun_iwasawa |
4d2acf |
double frame) {
|
|
shun_iwasawa |
4d2acf |
float ar = (float)m_shape_aspect_ratio->getValue(frame);
|
|
shun_iwasawa |
4d2acf |
|
|
shun_iwasawa |
4d2acf |
float* f = new float[std::max(dim.lx, dim.ly)];
|
|
shun_iwasawa |
4d2acf |
|
|
shun-iwasawa |
a1471c |
QList<float> max_val;</float>
|
|
shun-iwasawa |
a1471c |
for (int r = 0; r <= regionCount; r++) max_val.append(0.0f);
|
|
shun_iwasawa |
4d2acf |
|
|
shun_iwasawa |
4d2acf |
float* tmp_dst = dst_p;
|
|
shun_iwasawa |
4d2acf |
/* transform along rows */
|
|
shun_iwasawa |
4d2acf |
for (int j = 0; j < dim.ly; j++) {
|
|
Rozhuk Ivan |
823a31 |
for (int i = 0; i < dim.lx; i++, tmp_dst++) {
|
|
shun_iwasawa |
4d2acf |
f[i] = *tmp_dst;
|
|
shun_iwasawa |
4d2acf |
}
|
|
shun_iwasawa |
4d2acf |
|
|
shun_iwasawa |
4d2acf |
tmp_dst -= dim.lx;
|
|
shun_iwasawa |
4d2acf |
|
|
shun_iwasawa |
4d2acf |
float* d = dt(f, dim.lx);
|
|
shun_iwasawa |
4d2acf |
for (int i = 0; i < dim.lx; i++, tmp_dst++) {
|
|
shun_iwasawa |
4d2acf |
*tmp_dst = d[i];
|
|
shun_iwasawa |
4d2acf |
}
|
|
shun_iwasawa |
4d2acf |
delete[] d;
|
|
shun_iwasawa |
4d2acf |
}
|
|
shun_iwasawa |
4d2acf |
/* transform along columns */
|
|
shun_iwasawa |
4d2acf |
for (int i = 0; i < dim.lx; i++) {
|
|
shun_iwasawa |
4d2acf |
for (int j = 0; j < dim.ly; j++) {
|
|
shun_iwasawa |
4d2acf |
f[j] = dst_p[j * dim.lx + i];
|
|
shun_iwasawa |
4d2acf |
}
|
|
shun_iwasawa |
4d2acf |
float* d =
|
|
shun_iwasawa |
4d2acf |
dt(f, dim.ly,
|
|
shun_iwasawa |
4d2acf |
ar); /* ar : taking account of the aspect ratio of the shape */
|
|
shun_iwasawa |
4d2acf |
for (int j = 0; j < dim.ly; j++) {
|
|
shun-iwasawa |
a1471c |
dst_p[j * dim.lx + i] = d[j];
|
|
shun-iwasawa |
a1471c |
int regionId = binarized_p[j * dim.lx + i];
|
|
shun-iwasawa |
a1471c |
if (d[j] > max_val[regionId]) max_val[regionId] = d[j];
|
|
shun_iwasawa |
4d2acf |
}
|
|
shun_iwasawa |
4d2acf |
delete[] d;
|
|
shun_iwasawa |
4d2acf |
}
|
|
shun_iwasawa |
4d2acf |
|
|
shun_iwasawa |
4d2acf |
tmp_dst = dst_p;
|
|
shun-iwasawa |
a1471c |
for (int r = 0; r <= regionCount; r++) max_val[r] = std::sqrt(max_val[r]);
|
|
shun_iwasawa |
4d2acf |
|
|
shun_iwasawa |
4d2acf |
/* square root and normalize */
|
|
shun-iwasawa |
a1471c |
USHORT* region_p = binarized_p;
|
|
Rozhuk Ivan |
823a31 |
for (int i = 0; i < dim.lx * dim.ly; i++, tmp_dst++, region_p++) {
|
|
shun-iwasawa |
a1471c |
if (max_val[*region_p] > 0)
|
|
shun-iwasawa |
a1471c |
*tmp_dst = std::sqrt(*tmp_dst) / max_val[*region_p];
|
|
shun_iwasawa |
4d2acf |
}
|
|
shun_iwasawa |
4d2acf |
}
|
|
shun-iwasawa |
a1471c |
//------------------------------------
|
|
shun-iwasawa |
a1471c |
|
|
shun-iwasawa |
a1471c |
bool Iwa_SoapBubbleFx::checkCancelAndReleaseRaster(
|
|
shun-iwasawa |
a1471c |
const QList<trastergr8p>& allocatedRasList, TTile& tile,</trastergr8p>
|
|
shun-iwasawa |
a1471c |
const TRenderSettings& settings) {
|
|
shun-iwasawa |
a1471c |
if (settings.m_isCanceled && *settings.m_isCanceled) {
|
|
shun-iwasawa |
a1471c |
for (int i = 0; i < allocatedRasList.size(); i++)
|
|
shun-iwasawa |
a1471c |
allocatedRasList.at(i)->unlock();
|
|
shun-iwasawa |
a1471c |
tile.getRaster()->clear();
|
|
shun-iwasawa |
a1471c |
return true;
|
|
shun-iwasawa |
a1471c |
} else
|
|
shun-iwasawa |
a1471c |
return false;
|
|
shun-iwasawa |
a1471c |
}
|
|
shun-iwasawa |
a1471c |
//------------------------------------
|
|
shun-iwasawa |
a1471c |
|
|
shun-iwasawa |
a1471c |
void Iwa_SoapBubbleFx::applyDistanceToAlpha(float* distance_p,
|
|
shun-iwasawa |
9d0856 |
float* alpha_map_p, TDimensionI dim,
|
|
shun-iwasawa |
9d0856 |
float center_opacity) {
|
|
shun-iwasawa |
9d0856 |
float da = 1.0f - center_opacity;
|
|
shun-iwasawa |
a1471c |
float* d_p = distance_p;
|
|
shun-iwasawa |
a1471c |
float* a_p = alpha_map_p;
|
|
shun-iwasawa |
9d0856 |
for (int i = 0; i < dim.lx * dim.ly; i++, d_p++, a_p++) {
|
|
shun-iwasawa |
9d0856 |
(*a_p) *= 1.0f - (*d_p) * da;
|
|
shun-iwasawa |
9d0856 |
}
|
|
shun-iwasawa |
9d0856 |
}
|
|
shun-iwasawa |
9d0856 |
|
|
shun-iwasawa |
9d0856 |
//------------------------------------
|
|
shun-iwasawa |
9d0856 |
// This will be called in TFx::loadData when obsolete "mask center" value is
|
|
shun-iwasawa |
9d0856 |
// loaded
|
|
shun-iwasawa |
9d0856 |
void Iwa_SoapBubbleFx::onObsoleteParamLoaded(const std::string& paramName) {
|
|
shun-iwasawa |
9d0856 |
if (paramName != "maskCenter") return;
|
|
shun-iwasawa |
9d0856 |
// if "mask center" was ON, set a key frame to the center opacity in order to
|
|
shun-iwasawa |
9d0856 |
// get the same result.
|
|
shun-iwasawa |
9d0856 |
if (m_mask_center->getValue()) m_center_opacity->setValue(0.0, 0.0);
|
|
shun-iwasawa |
9d0856 |
}
|
|
shun-iwasawa |
9d0856 |
|
|
shun-iwasawa |
9d0856 |
//------------------------------------
|
|
shun-iwasawa |
9d0856 |
// patch the thickness images to each bounding box of the bubble
|
|
shun-iwasawa |
9d0856 |
void Iwa_SoapBubbleFx::fitThicknessPatches(TRasterP thickRas,
|
|
shun-iwasawa |
9d0856 |
TDimensionI thickDim,
|
|
shun-iwasawa |
9d0856 |
float* thickness_map_p,
|
|
shun-iwasawa |
9d0856 |
TDimensionI dim, USHORT* regionIds_p,
|
|
shun-iwasawa |
9d0856 |
QList<qrect>& regionBoundingRects) {</qrect>
|
|
shun-iwasawa |
9d0856 |
int regionCount = regionBoundingRects.size() - 1;
|
|
shun-iwasawa |
9d0856 |
|
|
shun-iwasawa |
9d0856 |
// compute resized thickness rasters
|
|
shun-iwasawa |
9d0856 |
QList<trastergr16p> resizedThicks;</trastergr16p>
|
|
shun-iwasawa |
9d0856 |
resizedThicks.append(TRasterGR16P());
|
|
shun-iwasawa |
9d0856 |
for (int r = 1; r <= regionCount; r++) {
|
|
shun-iwasawa |
9d0856 |
QRect regionRect = regionBoundingRects.at(r);
|
|
shun-iwasawa |
9d0856 |
TRaster64P resizedThickness(
|
|
shun-iwasawa |
9d0856 |
TDimension(regionRect.width(), regionRect.height()));
|
|
shun-iwasawa |
9d0856 |
resizedThickness->lock();
|
|
shun-iwasawa |
9d0856 |
|
|
shun-iwasawa |
9d0856 |
TAffine aff = TScale((double)regionRect.width() / (double)thickDim.lx,
|
|
shun-iwasawa |
9d0856 |
(double)regionRect.height() / (double)thickDim.ly);
|
|
shun-iwasawa |
9d0856 |
|
|
shun-iwasawa |
9d0856 |
// resample the thickenss
|
|
shun-iwasawa |
9d0856 |
TRop::resample(resizedThickness, thickRas, aff);
|
|
shun-iwasawa |
9d0856 |
|
|
shun-iwasawa |
9d0856 |
for (int ry = 0; ry < regionRect.height(); ry++) {
|
|
shun-iwasawa |
9d0856 |
TPixel64* p = resizedThickness->pixels(ry);
|
|
shun-iwasawa |
9d0856 |
for (int rx = 0; rx < regionRect.width(); rx++, p++) {
|
|
shun-iwasawa |
9d0856 |
double val = (double)((*p).r) / (double)(TPixel64::maxChannelValue);
|
|
shun-iwasawa |
9d0856 |
}
|
|
shun-iwasawa |
9d0856 |
}
|
|
shun-iwasawa |
9d0856 |
|
|
shun-iwasawa |
9d0856 |
TRasterGR16P thickRas_gray(
|
|
shun-iwasawa |
9d0856 |
TDimension(regionRect.width(), regionRect.height()));
|
|
shun-iwasawa |
9d0856 |
thickRas_gray->lock();
|
|
shun-iwasawa |
9d0856 |
TRop::convert(thickRas_gray, resizedThickness);
|
|
shun-iwasawa |
9d0856 |
|
|
shun-iwasawa |
9d0856 |
resizedThickness->unlock();
|
|
shun-iwasawa |
9d0856 |
resizedThicks.append(thickRas_gray);
|
|
shun-iwasawa |
9d0856 |
}
|
|
shun-iwasawa |
9d0856 |
|
|
shun-iwasawa |
9d0856 |
float* out_p = thickness_map_p;
|
|
shun-iwasawa |
9d0856 |
USHORT* rId_p = regionIds_p;
|
|
shun-iwasawa |
9d0856 |
for (int j = 0; j < dim.ly; j++) {
|
|
shun-iwasawa |
9d0856 |
for (int i = 0; i < dim.lx; i++, out_p++, rId_p++) {
|
|
shun-iwasawa |
9d0856 |
if ((*rId_p) == 0) {
|
|
shun-iwasawa |
9d0856 |
(*out_p) = 0.0f;
|
|
shun-iwasawa |
9d0856 |
continue;
|
|
shun-iwasawa |
9d0856 |
}
|
|
shun-iwasawa |
9d0856 |
QRect regionBBox = regionBoundingRects.at((int)(*rId_p));
|
|
shun-iwasawa |
9d0856 |
QPoint coordInRegion(i - regionBBox.left(), j - regionBBox.top());
|
|
shun-iwasawa |
9d0856 |
TPixelGR16 pix = resizedThicks.at((int)(*rId_p))
|
|
shun-iwasawa |
9d0856 |
->pixels(coordInRegion.y())[coordInRegion.x()];
|
|
shun-iwasawa |
9d0856 |
(*out_p) = (float)pix.value / (float)TPixelGR16::maxChannelValue;
|
|
shun-iwasawa |
9d0856 |
}
|
|
shun-iwasawa |
9d0856 |
}
|
|
shun-iwasawa |
9d0856 |
|
|
shun-iwasawa |
9d0856 |
for (int r = 1; r <= regionCount; r++) resizedThicks.at(r)->unlock();
|
|
shun-iwasawa |
a1471c |
}
|
|
shun_iwasawa |
4d2acf |
|
|
shun_iwasawa |
4d2acf |
//==============================================================================
|
|
shun_iwasawa |
4d2acf |
|
|
romeojulietthotel |
12386f |
FX_PLUGIN_IDENTIFIER(Iwa_SoapBubbleFx, "iwa_SoapBubbleFx");
|