| |
| |
| |
| |
| |
| #include "iwa_pnperspectivefx.h" |
| |
| #include "trop.h" |
| #include "tparamuiconcept.h" |
| |
| #include "iwa_fresnel.h" |
| #include "iwa_simplexnoise.h" |
| #include "iwa_noise1234.h" |
| |
| #include <vector> |
| |
| namespace { |
| #ifndef M_PI |
| const double M_PI = 3.1415926535897932384626433832795; |
| #endif |
| |
| |
| inline float dot(float3 a, float3 b) { |
| return a.x * b.x + a.y * b.y + a.z * b.z; |
| } |
| |
| |
| inline float3 cross(float3 a, float3 b) { |
| float3 ret = {a.y * b.z - a.z * b.y, a.z * b.x - a.x * b.z, |
| a.x * b.y - a.y * b.x}; |
| return ret; |
| } |
| |
| |
| inline float3 normalize(float3 v) { |
| float length = sqrtf(v.x * v.x + v.y * v.y + v.z * v.z); |
| float3 ret = {v.x / length, v.y / length, v.z / length}; |
| return ret; |
| } |
| } |
| |
| |
| |
| |
| |
| template <typename RASTER, typename PIXEL> |
| void Iwa_PNPerspectiveFx::setOutputRaster(float4 *srcMem, const RASTER dstRas, |
| TDimensionI dim, int drawLevel, |
| const bool alp_rend_sw) { |
| typename PIXEL::Channel halfChan = |
| (typename PIXEL::Channel)(PIXEL::maxChannelValue / 2); |
| |
| if (alp_rend_sw) |
| dstRas->fill(PIXEL(halfChan, halfChan, halfChan, halfChan)); |
| else |
| dstRas->fill(PIXEL(halfChan, halfChan, halfChan)); |
| float4 *chan_p = srcMem; |
| for (int j = 0; j < drawLevel; j++) { |
| PIXEL *pix = dstRas->pixels(j); |
| for (int i = 0; i < dstRas->getLx(); i++, chan_p++, pix++) { |
| float val; |
| val = (*chan_p).x * (float)PIXEL::maxChannelValue + 0.5f; |
| pix->r = (typename PIXEL::Channel)((val > (float)PIXEL::maxChannelValue) |
| ? (float)PIXEL::maxChannelValue |
| : val); |
| val = (*chan_p).y * (float)PIXEL::maxChannelValue + 0.5f; |
| pix->g = (typename PIXEL::Channel)((val > (float)PIXEL::maxChannelValue) |
| ? (float)PIXEL::maxChannelValue |
| : val); |
| val = (*chan_p).z * (float)PIXEL::maxChannelValue + 0.5f; |
| pix->b = (typename PIXEL::Channel)((val > (float)PIXEL::maxChannelValue) |
| ? (float)PIXEL::maxChannelValue |
| : val); |
| val = (*chan_p).w * (float)PIXEL::maxChannelValue + 0.5f; |
| pix->m = (typename PIXEL::Channel)((val > (float)PIXEL::maxChannelValue) |
| ? (float)PIXEL::maxChannelValue |
| : val); |
| } |
| } |
| } |
| |
| |
| |
| |
| void Iwa_PNPerspectiveFx::getPNParameters(TTile &tile, double frame, |
| const TRenderSettings &settings, |
| PN_Params ¶ms, |
| TDimensionI &dimOut) { |
| |
| params.renderMode = m_renderMode->getValue(); |
| params.noiseType = m_noiseType->getValue(); |
| params.size = (float)m_size->getValue(frame); |
| |
| if (params.noiseType == 1) params.size *= 1.41421356f; |
| params.octaves = m_octaves->getValue() + 1; |
| params.offset = float2{(float)m_offset->getValue(frame).x, |
| (float)m_offset->getValue(frame).y}; |
| params.p_intensity = (float)m_persistance_intensity->getValue(frame); |
| params.p_size = (float)m_persistance_size->getValue(frame); |
| params.p_offset = (float)m_persistance_offset->getValue(frame); |
| TPointD _eyeLevel = m_eyeLevel->getValue(frame); |
| params.eyeLevel = float2{(float)_eyeLevel.x, (float)_eyeLevel.y}; |
| params.alp_rend_sw = m_alpha_rendering->getValue(); |
| params.waveHeight = (float)m_waveHeight->getValue(frame); |
| |
| const float fov = (float)m_fov->getValue(frame); |
| |
| TAffine aff = settings.m_affine; |
| const double scale = 1.0 / sqrt(fabs(aff.det())); |
| TAffine aff_pn = TScale(scale) * TTranslation(tile.m_pos); |
| |
| params.a11 = aff_pn.a11; |
| params.a12 = aff_pn.a12; |
| params.a13 = aff_pn.a13; |
| params.a21 = aff_pn.a21; |
| params.a22 = aff_pn.a22; |
| params.a23 = aff_pn.a23; |
| |
| params.time = (float)m_evolution->getValue(frame) * 0.05; |
| params.p_evolution = (float)m_persistance_evolution->getValue(frame); |
| |
| TPointD eyePoint = |
| aff * _eyeLevel - (tile.m_pos + tile.getRaster()->getCenterD()); |
| const float eyeHeight = (float)eyePoint.y; |
| |
| params.drawLevel = (int)((float)dimOut.ly / 2.0f + eyeHeight); |
| if (params.drawLevel > dimOut.ly) params.drawLevel = dimOut.ly; |
| |
| |
| |
| |
| int camHeight = settings.m_cameraBox.getLy(); |
| TPointD vec_p0p1((double)camHeight * aff_pn.a12, |
| (double)camHeight * aff_pn.a22); |
| params.fy_2 = sqrtf(vec_p0p1.x * vec_p0p1.x + vec_p0p1.y * vec_p0p1.y) / 2.0f; |
| |
| float fov_radian_2 = (fov / 2.0f) * float(M_PI_180); |
| |
| |
| float D = params.fy_2 / tanf(fov_radian_2); |
| |
| params.A = sqrtf(params.eyeLevel.y * params.eyeLevel.y + D * D); |
| |
| |
| float theta = fov_radian_2 + asinf(params.eyeLevel.y / params.A); |
| |
| float M = params.fy_2 / sinf(fov_radian_2); |
| |
| params.cam_pos = float3{0.0f, -M * cosf(theta), M * sinf(theta)}; |
| |
| |
| params.base_fresnel_ref = 0.0f; |
| float phi = 90.0f - theta * 180.0f / M_PI; |
| if (phi >= 0.0f && phi < 90.0f) { |
| int index = (int)phi; |
| float ratio = phi - (float)index; |
| params.base_fresnel_ref = |
| fresnel[index] * (1.0f - ratio) + fresnel[index + 1] * ratio; |
| } |
| |
| |
| float intensity = 2.0f; |
| params.int_sum = 0.0f; |
| for (int o = 0; o < params.octaves; o++) { |
| params.int_sum += intensity; |
| intensity *= params.p_intensity; |
| } |
| } |
| |
| |
| |
| Iwa_PNPerspectiveFx::Iwa_PNPerspectiveFx() |
| : m_renderMode(new TIntEnumParam(0, "Noise")) |
| , m_noiseType(new TIntEnumParam(0, "Perlin Noise")) |
| , m_size(10.0) |
| , m_evolution(0.0) |
| , m_octaves(new TIntEnumParam(0, "1")) |
| , m_offset(TPointD(0, 0)) |
| , m_persistance_intensity(0.5) |
| , m_persistance_size(0.5) |
| , m_persistance_evolution(0.5) |
| , m_persistance_offset(0.5) |
| , m_fov(30) |
| , m_eyeLevel(TPointD(0, 0)) |
| , m_alpha_rendering(true) |
| , m_waveHeight(10.0) { |
| bindParam(this, "renderMode", m_renderMode); |
| bindParam(this, "noiseType", m_noiseType); |
| bindParam(this, "size", m_size); |
| bindParam(this, "evolution", m_evolution); |
| bindParam(this, "octaves", m_octaves); |
| bindParam(this, "offset", m_offset); |
| bindParam(this, "persistance_intensity", m_persistance_intensity); |
| bindParam(this, "persistance_size", m_persistance_size); |
| bindParam(this, "persistance_evolution", m_persistance_evolution); |
| bindParam(this, "persistance_offset", m_persistance_offset); |
| bindParam(this, "fov", m_fov); |
| bindParam(this, "eyeLevel", m_eyeLevel); |
| bindParam(this, "alpha_rendering", m_alpha_rendering); |
| bindParam(this, "waveHeight", m_waveHeight); |
| |
| m_noiseType->addItem(1, "Simplex Noise"); |
| |
| m_renderMode->addItem(1, "Noise (no resampled)"); |
| m_renderMode->addItem(2, "Warp HV offset"); |
| m_renderMode->addItem(4, "Warp HV offset 2"); |
| m_renderMode->addItem(3, "Fresnel reflectivity"); |
| |
| m_size->setMeasureName("fxLength"); |
| m_size->setValueRange(0.0, 1000.0); |
| |
| m_octaves->addItem(1, "2"); |
| m_octaves->addItem(2, "3"); |
| m_octaves->addItem(3, "4"); |
| m_octaves->addItem(4, "5"); |
| m_octaves->addItem(5, "6"); |
| m_octaves->addItem(6, "7"); |
| m_octaves->addItem(7, "8"); |
| m_octaves->addItem(8, "9"); |
| m_octaves->addItem(9, "10"); |
| |
| m_persistance_intensity->setValueRange(0.1, 2.0); |
| m_persistance_size->setValueRange(0.1, 2.0); |
| m_persistance_evolution->setValueRange(0.1, 2.0); |
| m_persistance_offset->setValueRange(0.1, 2.0); |
| |
| m_fov->setValueRange(10, 90); |
| |
| m_eyeLevel->getX()->setMeasureName("fxLength"); |
| m_eyeLevel->getY()->setMeasureName("fxLength"); |
| |
| m_waveHeight->setMeasureName("fxLength"); |
| m_waveHeight->setValueRange(1.0, 100.0); |
| } |
| |
| |
| |
| bool Iwa_PNPerspectiveFx::doGetBBox(double frame, TRectD &bBox, |
| const TRenderSettings &info) { |
| bBox = TConsts::infiniteRectD; |
| return true; |
| } |
| |
| |
| |
| bool Iwa_PNPerspectiveFx::canHandle(const TRenderSettings &info, double frame) { |
| return false; |
| } |
| |
| |
| |
| void Iwa_PNPerspectiveFx::doCompute(TTile &tile, double frame, |
| const TRenderSettings &settings) { |
| |
| if (!((TRaster32P)tile.getRaster()) && !((TRaster64P)tile.getRaster())) { |
| throw TRopException("unsupported input pixel type"); |
| } |
| |
| TDimensionI dimOut(tile.getRaster()->getLx(), tile.getRaster()->getLy()); |
| |
| |
| PN_Params pnParams; |
| getPNParameters(tile, frame, settings, pnParams, dimOut); |
| |
| |
| if (pnParams.drawLevel < 0) { |
| tile.getRaster()->clear(); |
| return; |
| } |
| |
| const float evolution = (float)m_evolution->getValue(frame); |
| const float p_evolution = (float)m_persistance_evolution->getValue(frame); |
| |
| float4 *out_host; |
| |
| TRasterGR8P out_host_ras(sizeof(float4) * dimOut.lx, pnParams.drawLevel); |
| out_host_ras->lock(); |
| out_host = (float4 *)out_host_ras->getRawData(); |
| |
| doCompute_CPU(tile, frame, settings, out_host, dimOut, pnParams); |
| |
| |
| tile.getRaster()->clear(); |
| TRaster32P outRas32 = (TRaster32P)tile.getRaster(); |
| TRaster64P outRas64 = (TRaster64P)tile.getRaster(); |
| if (outRas32) |
| setOutputRaster<TRaster32P, TPixel32>( |
| out_host, outRas32, dimOut, pnParams.drawLevel, pnParams.alp_rend_sw); |
| else if (outRas64) |
| setOutputRaster<TRaster64P, TPixel64>( |
| out_host, outRas64, dimOut, pnParams.drawLevel, pnParams.alp_rend_sw); |
| |
| out_host_ras->unlock(); |
| } |
| |
| |
| void Iwa_PNPerspectiveFx::doCompute_CPU(TTile &tile, double frame, |
| const TRenderSettings &settings, |
| float4 *out_host, TDimensionI &dimOut, |
| PN_Params &pnParams) { |
| |
| if (pnParams.renderMode == 0 || pnParams.renderMode == 1) { |
| calcPerinNoise_CPU(out_host, dimOut, pnParams, |
| (bool)(pnParams.renderMode == 0)); |
| } else if (pnParams.renderMode == 2 || pnParams.renderMode == 3 || |
| pnParams.renderMode == 4) { |
| calcPNNormal_CPU(out_host, dimOut, pnParams); |
| if (pnParams.renderMode == 4) { |
| calcPNNormal_CPU(out_host, dimOut, pnParams, true); |
| } |
| } |
| } |
| |
| |
| |
| |
| void Iwa_PNPerspectiveFx::calcPerinNoise_CPU(float4 *out_host, |
| TDimensionI &dimOut, PN_Params &p, |
| bool doResample) { |
| int reso = (doResample) ? 10 : 1; |
| |
| float4 *out_p = out_host; |
| |
| for (int yy = 0; yy < p.drawLevel; yy++) { |
| for (int xx = 0; xx < dimOut.lx; xx++, out_p++) { |
| float val_sum = 0.0f; |
| int count = 0; |
| |
| for (int tt = 0; tt < reso; tt++) { |
| for (int ss = 0; ss < reso; ss++) { |
| float2 tmpPixPos = { |
| (float)xx - 0.5f + ((float)ss + 0.5f) / (float)reso, |
| (float)yy - 0.5f + ((float)tt + 0.5f) / (float)reso}; |
| float2 screenPos = { |
| tmpPixPos.x * p.a11 + tmpPixPos.y * p.a12 + p.a13, |
| tmpPixPos.x * p.a21 + tmpPixPos.y * p.a22 + p.a23}; |
| |
| float2 noisePos; |
| noisePos.x = -(p.eyeLevel.y + p.fy_2) * (screenPos.x - p.eyeLevel.x) / |
| (screenPos.y - p.eyeLevel.y) + |
| p.eyeLevel.x; |
| noisePos.y = |
| (p.fy_2 + screenPos.y) * p.A / (p.eyeLevel.y - screenPos.y); |
| float tmpVal = 0.5f; |
| float currentSize = p.size; |
| float2 currentOffset = p.offset; |
| float currentIntensity = 1.0f; |
| |
| |
| float currentEvolution = p.time; |
| |
| |
| for (int o = 0; o < p.octaves; o++) { |
| float2 currentNoisePos = { |
| (noisePos.x - currentOffset.x) / currentSize, |
| (noisePos.y - currentOffset.y) / currentSize}; |
| |
| if (p.noiseType == 0) { |
| tmpVal += currentIntensity * |
| Noise1234::noise(currentNoisePos.x, currentNoisePos.y, |
| currentEvolution) / |
| p.int_sum; |
| } else { |
| tmpVal += |
| currentIntensity * |
| SimplexNoise::noise(currentNoisePos.x, currentNoisePos.y, |
| currentEvolution) / |
| p.int_sum; |
| } |
| |
| currentSize *= p.p_size; |
| currentOffset.x *= p.p_offset; |
| currentOffset.y *= p.p_offset; |
| currentIntensity *= p.p_intensity; |
| currentEvolution *= p.p_evolution; |
| } |
| val_sum += tmpVal; |
| count += 1; |
| } |
| } |
| |
| float val = val_sum / (float)count; |
| |
| |
| val = (val < 0.0f) ? 0.0f : ((val > 1.0f) ? 1.0f : val); |
| |
| (*out_p).x = val; |
| (*out_p).y = val; |
| (*out_p).z = val; |
| (*out_p).w = (p.alp_rend_sw) ? val : 1.0f; |
| } |
| } |
| } |
| |
| |
| |
| |
| void Iwa_PNPerspectiveFx::calcPNNormal_CPU(float4 *out_host, |
| TDimensionI &dimOut, PN_Params &p, |
| bool isSubWave) { |
| |
| float4 *out_p = out_host; |
| |
| for (int yy = 0; yy < p.drawLevel; yy++) { |
| for (int xx = 0; xx < dimOut.lx; xx++, out_p++) { |
| float2 screenPos = {(float)xx * p.a11 + (float)yy * p.a12 + p.a13, |
| (float)xx * p.a21 + (float)yy * p.a22 + p.a23}; |
| |
| |
| float2 noisePos; |
| |
| noisePos.x = -(p.eyeLevel.y + p.fy_2) * (screenPos.x - p.eyeLevel.x) / |
| (screenPos.y - p.eyeLevel.y) + |
| p.eyeLevel.x; |
| |
| noisePos.y = (p.fy_2 + screenPos.y) * p.A / (p.eyeLevel.y - screenPos.y); |
| |
| float gradient[2]; |
| |
| float delta = 0.001f; |
| |
| |
| for (int yokoTate = 0; yokoTate < 2; yokoTate++) { |
| |
| gradient[yokoTate] = 0.0f; |
| |
| |
| float2 kinbouNoisePos[2] = { |
| float2{noisePos.x - ((yokoTate == 0) ? delta : 0.0f), |
| noisePos.y - ((yokoTate == 0) ? 0.0f : delta)}, |
| float2{noisePos.x + ((yokoTate == 0) ? delta : 0.0f), |
| noisePos.y + ((yokoTate == 0) ? 0.0f : delta)}}; |
| float currentSize = p.size; |
| float2 currentOffset = p.offset; |
| float currentIntensity = 1.0f; |
| |
| float currentEvolution = (isSubWave) ? p.time + 100.0f : p.time; |
| |
| for (int o = 0; o < p.octaves; o++, currentSize *= p.p_size, |
| currentOffset.x *= p.p_offset, currentOffset.y *= p.p_offset, |
| currentIntensity *= p.p_intensity) { |
| |
| float2 currentOffsetNoisePos[2]; |
| for (int mp = 0; mp < 2; mp++) |
| currentOffsetNoisePos[mp] = |
| float2{(kinbouNoisePos[mp].x - currentOffset.x) / currentSize, |
| (kinbouNoisePos[mp].y - currentOffset.y) / currentSize}; |
| |
| |
| float noiseDiff; |
| |
| if (p.noiseType == 0) { |
| noiseDiff = |
| Noise1234::noise(currentOffsetNoisePos[1].x, |
| currentOffsetNoisePos[1].y, currentEvolution) - |
| Noise1234::noise(currentOffsetNoisePos[0].x, |
| currentOffsetNoisePos[0].y, currentEvolution); |
| } else { |
| |
| |
| CellIds kinbouIds[2] = { |
| SimplexNoise::getCellIds(currentOffsetNoisePos[0].x, |
| currentOffsetNoisePos[0].y, |
| currentEvolution), |
| SimplexNoise::getCellIds(currentOffsetNoisePos[1].x, |
| currentOffsetNoisePos[1].y, |
| currentEvolution)}; |
| |
| if (kinbouIds[0] == kinbouIds[1]) { |
| noiseDiff = SimplexNoise::noise(currentOffsetNoisePos[1].x, |
| currentOffsetNoisePos[1].y, |
| currentEvolution) - |
| SimplexNoise::noise(currentOffsetNoisePos[0].x, |
| currentOffsetNoisePos[0].y, |
| currentEvolution); |
| } |
| |
| else { |
| float2 currentCenterNoisePos = { |
| (noisePos.x - currentOffset.x) / currentSize, |
| (noisePos.y - currentOffset.y) / currentSize}; |
| CellIds centerIds = SimplexNoise::getCellIds( |
| currentCenterNoisePos.x, currentCenterNoisePos.y, |
| currentEvolution); |
| if (kinbouIds[0] == centerIds) { |
| noiseDiff = SimplexNoise::noise(currentCenterNoisePos.x, |
| currentCenterNoisePos.y, |
| currentEvolution) - |
| SimplexNoise::noise(currentOffsetNoisePos[0].x, |
| currentOffsetNoisePos[0].y, |
| currentEvolution); |
| } else |
| { |
| noiseDiff = SimplexNoise::noise(currentOffsetNoisePos[1].x, |
| currentOffsetNoisePos[1].y, |
| currentEvolution) - |
| SimplexNoise::noise(currentCenterNoisePos.x, |
| currentCenterNoisePos.y, |
| currentEvolution); |
| } |
| |
| |
| noiseDiff *= 2.0f; |
| } |
| } |
| |
| gradient[yokoTate] += currentIntensity * noiseDiff / p.int_sum; |
| |
| currentEvolution *= p.p_evolution; |
| } |
| } |
| |
| |
| float3 vec_x = {delta * 2, 0.0f, gradient[0] * p.waveHeight}; |
| float3 vec_y = {0.0f, delta * 2, gradient[1] * p.waveHeight}; |
| float3 normal = normalize(cross(vec_x, vec_y)); |
| |
| |
| float3 cam_vec = {noisePos.x - p.cam_pos.x, noisePos.y - p.cam_pos.y, |
| -p.cam_pos.z}; |
| cam_vec = normalize(cam_vec); |
| |
| if (p.renderMode == 2 || p.renderMode == 4) { |
| |
| float alpha = dot(normal, cam_vec); |
| float3 reflect_cam = { |
| 2.0f * alpha * normal.x - cam_vec.x, |
| 2.0f * alpha * normal.y - cam_vec.y, |
| 2.0f * alpha * normal.z - cam_vec.z}; |
| |
| float3 reflect_cam_mirror = {cam_vec.x, cam_vec.y, -cam_vec.z}; |
| |
| |
| float angle_h = atanf(reflect_cam.x / reflect_cam.y) - |
| atanf(reflect_cam_mirror.x / reflect_cam_mirror.y); |
| float angle_v = atanf(reflect_cam.z / reflect_cam.y) - |
| atanf(reflect_cam_mirror.z / reflect_cam_mirror.y); |
| |
| |
| angle_h = 0.5f + angle_h / 0.5236f; |
| angle_v = 0.5f - angle_v / 0.5236f; |
| |
| |
| angle_h = (angle_h < 0.0f) ? 0.0f : ((angle_h > 1.0f) ? 1.0f : angle_h); |
| angle_v = (angle_v < 0.0f) ? 0.0f : ((angle_v > 1.0f) ? 1.0f : angle_v); |
| |
| if (p.renderMode == 2) { |
| (*out_p).x = angle_h; |
| (*out_p).y = angle_v; |
| (*out_p).z = 0.0f; |
| (*out_p).w = 1.0f; |
| } else |
| { |
| if (!isSubWave) { |
| (*out_p).y = angle_v; |
| (*out_p).z = 0.0f; |
| (*out_p).w = 1.0f; |
| } else |
| (*out_p).x = angle_v; |
| } |
| } |
| |
| else if (p.renderMode == 3) { |
| cam_vec.x *= -1; |
| cam_vec.y *= -1; |
| cam_vec.z *= -1; |
| float diffuse_angle = acosf(dot(normal, cam_vec)) * 180.0f / 3.14159f; |
| float ref = 0.0f; |
| if (diffuse_angle >= 0.0f && diffuse_angle < 90.0f) { |
| int index = (int)diffuse_angle; |
| float ratio = diffuse_angle - (float)index; |
| float fresnel_ref = |
| fresnel[index] * (1.0f - ratio) + fresnel[index + 1] * ratio; |
| ref = |
| (fresnel_ref - p.base_fresnel_ref) / (1.0f - p.base_fresnel_ref); |
| } else if (diffuse_angle >= 90.0f) |
| ref = 1.0f; |
| |
| |
| ref = (ref < 0.0f) ? 0.0f : ((ref > 1.0f) ? 1.0f : ref); |
| (*out_p).x = ref; |
| (*out_p).y = ref; |
| (*out_p).z = ref; |
| (*out_p).w = (p.alp_rend_sw) ? ref : 1.0f; |
| } |
| } |
| } |
| } |
| |
| |
| |
| void Iwa_PNPerspectiveFx::getParamUIs(TParamUIConcept *&concepts, int &length) { |
| concepts = new TParamUIConcept[length = 1]; |
| |
| concepts[0].m_type = TParamUIConcept::POINT; |
| concepts[0].m_label = "Eye Level"; |
| concepts[0].m_params.push_back(m_eyeLevel); |
| } |
| |
| FX_PLUGIN_IDENTIFIER(Iwa_PNPerspectiveFx, "iwa_PNPerspectiveFx"); |