Skip to content

Commit 8eba4c9

Browse files
committed
pull ditt, resolve conflicts
2 parents 95246c4 + 0c03e2f commit 8eba4c9

File tree

7 files changed

+84
-46
lines changed

7 files changed

+84
-46
lines changed

CONTRIBUTING.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ Thank you for your interest in contributing to the Nabla Engine! Nabla is a high
44

55
## Table of Contents
66

7+
<<<<<<< HEAD
78
- [How Can I Contribute?](#how-can-i-contribute)
89
- [Reporting Bugs](#reporting-bugs)
910
- [Suggesting Enhancements](#suggesting-enhancements)
@@ -12,6 +13,9 @@ Thank you for your interest in contributing to the Nabla Engine! Nabla is a high
1213
- [Pull Request Process](#pull-request-process)
1314
- [Connect with Other Project Contributors](#connect-with-other-project-contributors)
1415
- [License](#license)
16+
=======
17+
https://github.com/Devsh-Graphics-Programming/Nabla/issues
18+
>>>>>>> 0c03e2f7517c6cd8cfff2dfb5c874a3da41c27e7
1519
1620
## How Can I Contribute?
1721

ci

Submodule ci updated 37 files

include/nbl/builtin/glsl/ies/functions.glsl

Lines changed: 22 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -6,25 +6,33 @@
66

77
#include <nbl/builtin/glsl/math/constants.glsl>
88

9-
// TODO: implement proper mirroing
10-
// MIRROR_180_BITS = 0b001, Last Angle is 180, so map V slightly differently
11-
// MIRROR_90_BITS = 0b010, Last Angle is 90, so map both U and V slightly differently
12-
// ISOTROPIC_BITS = 0b011, texture to sample is Nx1, pretend v=middle always
13-
// FULL_THETA_BIT = 0b100, handle extended domain and rotate by 45 degrees for anisotropic
14-
15-
vec2 nbl_glsl_IES_convert_dir_to_uv(vec3 dir) {
16-
float sum = dot(vec3(1.0f), abs(dir));
9+
// TODO: when rewriting to HLSL this is not IES namespace or folder, this should be octahedral mapping sitting somewhere where the spherical/polar sits
10+
// NOTE: I changed it to return NDC [-1,1]^2 instead of UV coords [0,1]^2
11+
vec2 nbl_glsl_TODOnamespace_octahedral_mapping(vec3 dir)
12+
{
13+
float sum = dot(vec3(1.0f), abs(dir));
1714
vec3 s = dir / sum;
1815

19-
if(s.z < 0.0f) {
20-
s.xy = sign(s.xy) * (1.0f - abs(s.yx));
16+
if(s.z < 0.0f)
17+
{
18+
const uvec2 flipSignMask = floatBitsToUint(s.xy)&0x80000000u;
19+
s.xy = uintBitsToFloat(floatBitsToUint(1.0f - abs(s.yx))^flipSignMask);
2120
}
2221

23-
return s.xy * 0.5f + 0.5f;
22+
return s.xy;
2423
}
2524

26-
// vec2 nbl_glsl_IES_convert_dir_to_uv(vec3 dir) {
27-
// return vec2((atan(dir.x, dir.y) + nbl_glsl_PI) / (2.0*nbl_glsl_PI), acos(dir.z) / nbl_glsl_PI);
28-
// }
25+
// TODO: implement proper mirroing
26+
// MIRROR_180_BITS = 0b001, Last Angle is 180, so map V with MIRROR and corner sampling off
27+
// MIRROR_90_BITS = 0b010, Last Angle is 90, so map both U and V with MIRROR and corner sampling off
28+
// ISOTROPIC_BITS = 0b011, texture to sample is Nx1, pretend v=middle always , and make u REPEAT or CLAMP_TO_BORDER
29+
// FULL_THETA_BIT = 0b100, handle truncated domain and rotate by 45 degrees for anisotropic
30+
// (certain combos wont work like 90 degree 2 symmetry domain & half theta), it really needs to be an 8 case label thing explicitly enumerated
31+
vec2 nbl_glsl_IES_convert_dir_to_uv(vec3 dir, vec2 halfMinusHalfPixel)
32+
{
33+
// halfMinusHalfPixel = 0.5-0.5/texSize
34+
// believe it or not, cornerSampled(NDC*0.5+0.5) = NDC*0.5*(1-1/texSize)+0.5
35+
return nbl_glsl_TODOnamespace_octahedral_mapping(dir)*halfMinusHalfPixel+0.5;
36+
}
2937

3038
#endif

include/nbl/builtin/glsl/material_compiler/common.glsl

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -601,7 +601,8 @@ vec3 nbl_glsl_MC_oriented_material_t_getEmissive(in nbl_glsl_MC_oriented_materia
601601
if ((floatBitsToInt(emitter.orientation[0])&1u) != 1u) {
602602
right *= -1;
603603
}
604-
return emissive * nbl_glsl_vTextureGrad(emitter.emissionProfile, nbl_glsl_IES_convert_dir_to_uv(mat3(right, up, view)*dir), mat2(0.0)).r;
604+
vec2 halfMinusHalfPixel = vec2(0.5)-vec2(0.5)/vec2(nbl_glsl_unpackSize(emitter.emissionProfile));
605+
return emissive * nbl_glsl_vTextureGrad(emitter.emissionProfile, nbl_glsl_IES_convert_dir_to_uv(mat3(right, up, view)*dir,halfMinusHalfPixel), mat2(0.0)).r;
605606
}
606607
#endif
607608
return emissive;

src/nbl/asset/utils/CIESProfile.cpp

Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -88,8 +88,8 @@ inline core::vectorSIMDf CIESProfile::octahdronUVToDir(const float& u, const flo
8888
float abs_x = core::abs(pos.x), abs_y = core::abs(pos.y);
8989
pos.z = 1.0 - abs_x - abs_y;
9090
if (pos.z < 0.0) {
91-
pos.x = core::sign(pos.x) * (1.0 - abs_y);
92-
pos.y = core::sign(pos.y) * (1.0 - abs_x);
91+
pos.x = (pos.x<0.f ? (-1.f):1.f) * (1.0 - abs_y);
92+
pos.y = (pos.y<0.f ? (-1.f):1.f) * (1.0 - abs_x);
9393
}
9494

9595
return core::normalize(pos);
@@ -116,6 +116,13 @@ core::smart_refctd_ptr<asset::ICPUImageView> CIESProfile::createIESTexture(Execu
116116
if (height > CDC_MAX_TEXTURE_HEIGHT)
117117
height = CDC_MAX_TEXTURE_HEIGHT;
118118

119+
// TODO: If no symmetry (no folding in half and abuse of mirror sampler) make dimensions odd-sized so middle texel taps the south pole
120+
121+
// TODO: This is hack because the mitsuba loader and its material compiler use Virtual Texturing, and there's some bug with IES not sampling sub 128x128 mip levels
122+
// don't want to spend time to fix this since we'll be using descriptor indexing for the next iteration
123+
width = core::max(width,128);
124+
height = core::max(height,128);
125+
119126
asset::ICPUImage::SCreationParams imgInfo;
120127
imgInfo.type = asset::ICPUImage::ET_2D;
121128
imgInfo.extent.width = width;
@@ -164,15 +171,19 @@ core::smart_refctd_ptr<asset::ICPUImageView> CIESProfile::createIESTexture(Execu
164171
const double maxValue = getMaxCandelaValue();
165172
const double maxValueRecip = 1.0 / maxValue;
166173

167-
const double vertInv = 1.0 / height;
168-
const double horiInv = 1.0 / width;
174+
// There is one huge issue, the IES files love to give us values for degrees 0, 90, 180 an 360
175+
// So standard octahedral mapping won't work, because for above data points you need corner sampled images.
176+
const float vertInv = 1.0 / (height-1);
177+
const float horiInv = 1.0 / (width-1);
169178

170179
const double flattenTarget = getAvgEmmision(fullDomainFlatten);
171180
const double domainLo = core::radians(vAngles.front());
172181
const double domainHi = core::radians(vAngles.back());
173182
auto fill = [&](uint32_t blockArrayOffset, core::vectorSIMDu32 position) -> void
174183
{
175-
const auto dir = octahdronUVToDir(((float)position.x + 0.5) * vertInv, ((float)position.y + 0.5) * horiInv);
184+
// We don't currently support generating IES images that exploit symmetries or reduced domains, all are full octahederal mappings of a sphere.
185+
// If we did, we'd rely on MIRROR and CLAMP samplers to do some of the work for us while handling the discontinuity due to corner sampling.
186+
const auto dir = octahdronUVToDir(position.x * vertInv, position.y * horiInv);
176187
const auto [theta, phi] = sphericalDirToRadians(dir);
177188
const auto intensity = sample(theta, phi);
178189

src/nbl/asset/utils/CIESProfile.h

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,12 @@ namespace nbl
7171
inline IES_STORAGE_FORMAT getAvgEmmision(const bool fullDomain=false) const
7272
{
7373
if (fullDomain)
74-
return totalEmissionIntegral*0.25/core::radians(vAngles.back()-vAngles.front());
74+
{
75+
const float cosLo = std::cos(core::radians(vAngles.front()));
76+
const float cosHi = std::cos(core::radians<float>(vAngles.back()));
77+
const float dsinTheta = cosLo - cosHi;
78+
return totalEmissionIntegral*(0.5/core::PI<float>())/dsinTheta;
79+
}
7580
return avgEmmision;
7681
}
7782

src/nbl/asset/utils/CIESProfileParser.cpp

Lines changed: 33 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -106,12 +106,6 @@ bool CIESProfileParser::parse(CIESProfile& result)
106106
if (vSize < 2)
107107
return false;
108108

109-
{
110-
const uint32_t maxDimMeasureSize = core::max(hSize, vSize);
111-
result.optimalIESResolution = decltype(result.optimalIESResolution){ maxDimMeasureSize, maxDimMeasureSize };
112-
result.optimalIESResolution *= 2u; // safe bias for our bilinear interpolation to work nicely and increase resolution of a profile
113-
}
114-
115109
auto& vAngles = result.vAngles;
116110
for (int i = 0; i < vSize; i++) {
117111
vAngles[i] = getDouble("vertical angle truncated");
@@ -180,15 +174,29 @@ bool CIESProfileParser::parse(CIESProfile& result)
180174
float totalEmissionIntegral = 0.0, nonZeroEmissionDomainSize = 0.0;
181175
constexpr auto FULL_SOLID_ANGLE = 4.0f * core::PI<float>();
182176

177+
// TODO: this code could have two separate inner for loops for `result.symmetry != CIESProfile::ISOTROPIC` cases
183178
const auto H_ANGLES_I_RANGE = result.symmetry != CIESProfile::ISOTROPIC ? result.hAngles.size() - 1 : 1;
184179
const auto V_ANGLES_I_RANGE = result.vAngles.size() - 1;
185180

186-
for (size_t i = 0; i < H_ANGLES_I_RANGE; i++)
181+
float smallestRangeSolidAngle = FULL_SOLID_ANGLE;
182+
for (size_t j = 0; j < V_ANGLES_I_RANGE; j++)
187183
{
188-
const float dPhiRad = result.symmetry != CIESProfile::ISOTROPIC ? (hAngles[i + 1] - hAngles[i]) : core::PI<float>() * 2.0f;
189-
190-
for (size_t j = 0; j < V_ANGLES_I_RANGE; j++)
184+
const float thetaRad = core::radians<float>(result.vAngles[j]);
185+
const float cosLo = std::cos(thetaRad);
186+
const float cosHi = std::cos(core::radians<float>(result.vAngles[j+1]));
187+
const float dsinTheta = cosLo - cosHi;
188+
189+
float stripIntegral = 0.f;
190+
float nonZeroStripDomain = 0.f;
191+
for (size_t i = 0; i < H_ANGLES_I_RANGE; i++)
191192
{
193+
const float dPhiRad = result.symmetry != CIESProfile::ISOTROPIC ? core::radians<float>(hAngles[i + 1] - hAngles[i]) : (core::PI<float>() * 2.0f);
194+
// TODO: in reality one should transform the 4 vertices (or 3) into octahedral map, work out the dUV/dPhi and dUV/dTheta vectors as-if for Anisotropic Filtering
195+
// then choose the minor axis length, and use that as a pixel size (since looking for smallest thing, dont have to worry about handling discont)
196+
const float solidAngle = dsinTheta * dPhiRad;
197+
if (solidAngle<smallestRangeSolidAngle)
198+
smallestRangeSolidAngle = solidAngle;
199+
192200
const auto candelaValue = result.getCandelaValue(i, j);
193201

194202
// interpolate candela value spanned onto a solid angle
@@ -199,23 +207,24 @@ bool CIESProfileParser::parse(CIESProfile& result)
199207
if (result.maxCandelaValue < candelaValue)
200208
result.maxCandelaValue = candelaValue;
201209

202-
const float thetaRad = core::radians<float>(result.vAngles[j]);
203-
const float cosLo = std::cos(core::radians<float>(result.vAngles[j]));
204-
const float cosHi = std::cos(core::radians<float>(result.vAngles[j + 1]));
205-
206-
const auto differentialSolidAngle = dPhiRad*(cosLo - cosHi);
207-
const auto integralV = candelaAverage * differentialSolidAngle;
208-
209-
if (integralV > 0.0)
210-
{
211-
totalEmissionIntegral += integralV;
212-
nonZeroEmissionDomainSize += differentialSolidAngle;
213-
}
210+
stripIntegral += candelaAverage*dPhiRad;
211+
if (candelaAverage>0.f)
212+
nonZeroStripDomain += dPhiRad;
214213
}
214+
totalEmissionIntegral += stripIntegral*dsinTheta;
215+
nonZeroEmissionDomainSize += nonZeroStripDomain*dsinTheta;
216+
}
217+
218+
// assuming octahedral map
219+
{
220+
const uint32_t maxDimMeasureSize = core::sqrt(FULL_SOLID_ANGLE/smallestRangeSolidAngle);
221+
result.optimalIESResolution = decltype(result.optimalIESResolution){ maxDimMeasureSize, maxDimMeasureSize };
222+
result.optimalIESResolution *= 2u; // safe bias for our bilinear interpolation to work nicely and increase resolution of a profile
215223
}
216224

217-
nonZeroEmissionDomainSize = std::clamp<float>(nonZeroEmissionDomainSize, 0.0, FULL_SOLID_ANGLE);
218-
if (nonZeroEmissionDomainSize <= 0) // protect us from division by 0 (just in case, we should never hit it)
225+
assert(nonZeroEmissionDomainSize >= 0.f);
226+
//assert(nonZeroEmissionDomainSize*fluxMultiplier =approx= 2.f*(cosBack-cosFront)*PI);
227+
if (nonZeroEmissionDomainSize <= std::numeric_limits<float>::min()) // protect us from division by small numbers (just in case, we should never hit it)
219228
return false;
220229

221230
result.avgEmmision = totalEmissionIntegral / static_cast<decltype(totalEmissionIntegral)>(nonZeroEmissionDomainSize);

0 commit comments

Comments
 (0)