Skip to content

Commit 85a36e6

Browse files
Merge pull request #104 from Devsh-Graphics-Programming/iesFeatures
New IES plotter
2 parents da9305f + 6ed94b0 commit 85a36e6

File tree

5 files changed

+943
-153
lines changed

5 files changed

+943
-153
lines changed

50.IESProfileTest/compute/cdc.comp

Lines changed: 260 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,260 @@
1+
#version 430 core
2+
3+
// Copyright (C) 2018-2024 - DevSH Graphics Programming Sp. z O.O.
4+
// This file is part of the "Nabla Engine".
5+
// For conditions of distribution and use, see copyright notice in nabla.h
6+
7+
#include "common.h"
8+
9+
layout(local_size_x = WORKGROUP_DIMENSION, local_size_y = WORKGROUP_DIMENSION) in;
10+
11+
layout(set = 0, binding = 0, r16) restrict uniform image2D outIESCandelaImage;
12+
layout(set = 0, binding = 1, rg32f) restrict uniform image2D outSphericalCoordinatesImage;
13+
layout(set = 0, binding = 2, rgba32f) restrict uniform image2D outOUVProjectionDirectionImage;
14+
layout(set = 0, binding = 3, rg8) restrict uniform image2D outPassTMask;
15+
16+
layout(std430, set = 0, binding = 4) readonly buffer HorizontalAngles
17+
{
18+
double hAngles[];
19+
};
20+
21+
layout(std430, set = 0, binding = 5) readonly buffer VerticalAngles
22+
{
23+
double vAngles[];
24+
};
25+
26+
layout(std430, set = 0, binding = 6) readonly buffer Data
27+
{
28+
double data[];
29+
};
30+
31+
layout(push_constant) uniform PushConstants
32+
{
33+
float maxIValue;
34+
float zAngleDegreeRotation;
35+
uint mode;
36+
uint dummy;
37+
} pc;
38+
39+
vec3 octahedronUVToDir(vec2 uv)
40+
{
41+
vec3 position = vec3((uv * 2.0 - 1.0).xy, 0.0);
42+
vec2 absP = vec2(abs(position.x), abs(position.y));
43+
44+
position.z = 1.0 - absP.x - absP.y;
45+
46+
if (position.z < 0.0)
47+
{
48+
position.x = sign(position.x) * (1.0 - absP.y);
49+
position.y = sign(position.y) * (1.0 - absP.x);
50+
}
51+
52+
// rotate position vector around Z-axis with "pc.zAngleDegreeRotation"
53+
if(pc.zAngleDegreeRotation != 0.0)
54+
{
55+
float rDegree = pc.zAngleDegreeRotation;
56+
57+
const float zAngleRadians = float(rDegree * M_PI / 180.0);
58+
const float cosineV = cos(zAngleRadians);
59+
const float sineV = sin(zAngleRadians);
60+
61+
position = vec3(cosineV * position.x - cosineV * position.y, sineV * position.x + sineV * position.y, position.z);
62+
//position = vec3((cosineV * position.x) - (sineV * position.y), (cosineV * position.x) + (sineV * position.y), position.z);
63+
}
64+
65+
return normalize(position);
66+
}
67+
68+
//! Returns spherical coordinates with physics convention in radians
69+
/*
70+
https://en.wikipedia.org/wiki/Spherical_coordinate_system#/media/File:3D_Spherical.svg
71+
Retval.x is "theta" polar angle in range [0, PI] & Retval.y "phi" is azimuthal angle
72+
in range [-PI, PI] range
73+
*/
74+
75+
vec2 sphericalDirToRadians(vec3 direction)
76+
{
77+
double theta = acos(clamp(direction.z/length(direction), -1.0, 1.0));
78+
double phi = atan(direction.y, direction.x);
79+
80+
return vec2(theta, phi);
81+
}
82+
83+
uint implGetVUB(const float angle)
84+
{
85+
const uint len = vAngles.length();
86+
87+
for(uint i = 0; i < len; ++i)
88+
if(vAngles[i] > angle)
89+
return i;
90+
91+
return len;
92+
}
93+
94+
uint implGetHUB(const float angle)
95+
{
96+
const uint len = hAngles.length();
97+
98+
for(uint i = 0; i < len; ++i)
99+
if(hAngles[i] > angle)
100+
return i;
101+
102+
return len;
103+
}
104+
105+
uint getVLB(const float angle)
106+
{
107+
return uint(max(int(implGetVUB(angle)) - 1, 0));
108+
}
109+
110+
uint getHLB(const float angle)
111+
{
112+
return uint(max(int(implGetHUB(angle)) - 1, 0));
113+
}
114+
115+
uint getVUB(const float angle)
116+
{
117+
return uint(min(int(implGetVUB(angle)), int(vAngles.length()) - 1));
118+
}
119+
120+
uint getHUB(const float angle)
121+
{
122+
return uint(min(int(implGetHUB(angle)), int(hAngles.length()) - 1));
123+
}
124+
125+
double getValue(uint i, uint j)
126+
{
127+
return data[vAngles.length() * i + j];
128+
}
129+
130+
// symmetry
131+
#define ISOTROPIC 0u
132+
#define QUAD_SYMETRIC 1u
133+
#define HALF_SYMETRIC 2u
134+
#define NO_LATERAL_SYMMET 3u
135+
136+
uint getSymmetry() // TODO: to reduce check time we could pass it with PCs
137+
{
138+
const uint hALength = hAngles.length();
139+
if(hALength < 2) // careful here, somebody can break it by feeding us with too much data by mistake
140+
return ISOTROPIC;
141+
142+
const double hABack = hAngles[hALength - 1];
143+
144+
if(hABack == 90)
145+
return QUAD_SYMETRIC;
146+
else if(hABack == 180) // note that OTHER_HALF_SYMMETRIC = HALF_SYMETRIC here
147+
return HALF_SYMETRIC;
148+
else
149+
return NO_LATERAL_SYMMET;
150+
}
151+
152+
float wrapPhi(const float phi, const uint symmetry) //! wrap phi spherical coordinate compoment to range defined by symmetry
153+
{
154+
switch (symmetry)
155+
{
156+
case ISOTROPIC:
157+
return 0.0;
158+
case QUAD_SYMETRIC: //! phi MIRROR_REPEAT wrap onto [0, 90] degrees range
159+
{
160+
float wrapPhi = abs(phi); //! first MIRROR
161+
162+
if(wrapPhi > M_HALF_PI) //! then REPEAT
163+
wrapPhi = clamp(M_HALF_PI - (wrapPhi - M_HALF_PI), 0, M_HALF_PI);
164+
165+
return wrapPhi; //! eg. maps (in degrees) 91,269,271 -> 89 and 179,181,359 -> 1
166+
}
167+
case HALF_SYMETRIC: //! phi MIRROR wrap onto [0, 180] degrees range
168+
return abs(phi); //! eg. maps (in degress) 181 -> 179 or 359 -> 1
169+
case NO_LATERAL_SYMMET:
170+
{
171+
if(phi < 0)
172+
return phi + 2.0 * M_PI;
173+
else
174+
return phi;
175+
}
176+
}
177+
178+
return 69;
179+
}
180+
181+
double sampleI(const vec2 sphericalCoordinates, const uint symmetry)
182+
{
183+
const float vAngle = degrees(sphericalCoordinates.x), hAngle = degrees(wrapPhi(sphericalCoordinates.y, symmetry));
184+
185+
double vABack = vAngles[vAngles.length() - 1];
186+
double hABack = hAngles[hAngles.length() - 1];
187+
188+
if (vAngle > vABack)
189+
return 0.0;
190+
191+
// bilinear interpolation
192+
uint j0 = getVLB(vAngle);
193+
uint j1 = getVUB(vAngle);
194+
uint i0 = symmetry == ISOTROPIC ? 0 : getHLB(hAngle);
195+
uint i1 = symmetry == ISOTROPIC ? 0 : getHUB(hAngle);
196+
197+
double uReciprocal = i1 == i0 ? 1.0 : 1.0 / (hAngles[i1] - hAngles[i0]);
198+
double vReciprocal = j1 == j0 ? 1.0 : 1.0 / (vAngles[j1] - vAngles[j0]);
199+
200+
double u = (hAngle - hAngles[i0]) * uReciprocal;
201+
double v = (vAngle - vAngles[j0]) * vReciprocal;
202+
203+
double s0 = getValue(i0, j0) * (1.0 - v) + getValue(i0, j1) * (v);
204+
double s1 = getValue(i1, j0) * (1.0 - v) + getValue(i1, j1) * (v);
205+
206+
return s0 * (1.0 - u) + s1 * u;
207+
}
208+
209+
//! Checks if (x,y) /in [0,PI] x [-PI,PI] product
210+
/*
211+
IES vertical range is [0, 180] degrees
212+
and horizontal range is [0, 360] degrees
213+
but for easier computations (MIRROR & MIRROW_REPEAT operations)
214+
we represent horizontal range as [-180, 180] given spherical coordinates
215+
*/
216+
217+
bool isWithinSCDomain(vec2 point)
218+
{
219+
const vec2 lb = vec2(0, -M_PI);
220+
const vec2 ub = vec2(M_PI, M_PI);
221+
222+
return all(lessThanEqual(lb, point)) && all(lessThanEqual(point, ub));
223+
}
224+
225+
void main()
226+
{
227+
const float VERTICAL_INVERSE = 1.0f / TEXTURE_SIZE;
228+
const float HORIZONTAL_INVERSE = 1.0f / TEXTURE_SIZE;
229+
230+
const ivec2 pixelCoordinates = ivec2(gl_GlobalInvocationID.xy);
231+
const ivec2 destinationSize = imageSize(outIESCandelaImage);
232+
233+
if (all(lessThan(pixelCoordinates, destinationSize)))
234+
{
235+
const vec2 uv = vec2((float(pixelCoordinates.x) + 0.5) * VERTICAL_INVERSE, (float(pixelCoordinates.y) + 0.5) * HORIZONTAL_INVERSE);
236+
const vec3 direction = octahedronUVToDir(uv);
237+
const vec2 sphericalCoordinates = sphericalDirToRadians(direction); // third radius spherical compoment is normalized and skipped
238+
239+
const double intensity = sampleI(sphericalCoordinates, getSymmetry());
240+
const vec4 value = vec4(intensity / pc.maxIValue, 0, 0, 0);
241+
242+
const double normD = length(direction);
243+
vec2 mask;
244+
245+
if(1.0 - QUANT_ERROR_ADMISSIBLE <= normD && normD <= 1.0 + QUANT_ERROR_ADMISSIBLE)
246+
mask.x = 1.0; // pass
247+
else
248+
mask.x = 0;
249+
250+
if(isWithinSCDomain(sphericalCoordinates))
251+
mask.y = 1.0; // pass
252+
else
253+
mask.y = 0;
254+
255+
imageStore(outIESCandelaImage, pixelCoordinates, value);
256+
imageStore(outSphericalCoordinatesImage, pixelCoordinates, vec4(sphericalCoordinates, 0, 1));
257+
imageStore(outOUVProjectionDirectionImage, pixelCoordinates, vec4(direction.xyz, 1));
258+
imageStore(outPassTMask, pixelCoordinates, vec4(mask.xy, 1, 1));
259+
}
260+
}

50.IESProfileTest/compute/common.h

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
#ifndef _COMMON_INCLUDED_
2+
#define _COMMON_INCLUDED_
3+
4+
#ifndef UINT16_MAX
5+
#define UINT16_MAX 65535u // would be cool if we have this define somewhere or GLSL do
6+
#endif
7+
#define M_PI 3.1415926535897932384626433832795f // would be cool if we have this define somewhere or GLSL do
8+
#define M_HALF_PI M_PI/2.0f // would be cool if we have this define somewhere or GLSL do
9+
#define QUANT_ERROR_ADMISSIBLE 1/1024
10+
11+
#define TEXTURE_SIZE 1024u
12+
#define WORKGROUP_SIZE 256u
13+
#define WORKGROUP_DIMENSION 16u
14+
15+
#endif // _COMMON_INCLUDED_

0 commit comments

Comments
 (0)