Skip to content

Commit 4258fec

Browse files
committed
Alternate hash function using pcg3d
1 parent 9ec1d89 commit 4258fec

File tree

2 files changed

+53
-28
lines changed

2 files changed

+53
-28
lines changed

src/ImageCanvas.cpp

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -560,9 +560,14 @@ Vector3f ImageCanvas::applyTonemap(const Vector3f& value, float gamma, ETonemap
560560
}
561561
case ETonemap::Hash:
562562
{
563-
static const auto fract = [](float x){ return x - floor(x); };
564-
Vector3f mixed = abs(fract(dot(value, Vector3f{115.191742f, 64.0546951f, 124.512291f})) - 0.5f) * Vector3f{1368.46143f, 1523.2019f, 1034.50476f};
565-
result = {2.0f * abs(fract(mixed.x()) - 0.5f), 2.0f * abs(fract(mixed.y()) - 0.5f), 2.0f * abs(fract(mixed.z()) - 0.5f)};
563+
// See 'Hash Functions for GPU Rendering' (https://jcgt.org/published/0009/03/02/)
564+
uint32_t vX = std::bit_cast<uint32_t>(value.x()) * 1664525u + 1013904223u;
565+
uint32_t vY = std::bit_cast<uint32_t>(value.y()) * 1664525u + 1013904223u;
566+
uint32_t vZ = std::bit_cast<uint32_t>(value.z()) * 1664525u + 1013904223u;
567+
vX += vY * vZ; vY += vZ * vX; vZ += vX * vY;
568+
vX ^= vX >> 16u; vY ^= vY >> 16u; vZ ^= vZ >> 16u;
569+
vX += vY * vZ; vY += vZ * vX; vZ += vX * vY;
570+
result = {vX * (1.0f / 4294967295.0f), vY * (1.0f / 4294967295.0f), vZ * (1.0f / 4294967295.0f)};
566571
break;
567572
}
568573
default:

src/UberShader.cpp

Lines changed: 45 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -14,11 +14,12 @@ UberShader::UberShader(RenderPass* renderPass) {
1414
#if defined(NANOGUI_USE_OPENGL) || defined(NANOGUI_USE_GLES)
1515
# if defined(NANOGUI_USE_OPENGL)
1616
std::string preamble =
17-
R"(#version 110)";
17+
R"(#version 330)";
1818
# elif defined(NANOGUI_USE_GLES)
1919
std::string preamble =
20-
R"(#version 100
21-
precision highp float;)";
20+
R"(#version 300 es
21+
precision highp float;
22+
precision highp int;)";
2223
# endif
2324
auto vertexShader = preamble +
2425
R"glsl(
@@ -31,11 +32,11 @@ UberShader::UberShader(RenderPass* renderPass) {
3132
uniform vec2 referenceScale;
3233
uniform vec2 referenceOffset;
3334
34-
attribute vec2 position;
35+
in vec2 position;
3536
36-
varying vec2 checkerUv;
37-
varying vec2 imageUv;
38-
varying vec2 referenceUv;
37+
out vec2 checkerUv;
38+
out vec2 imageUv;
39+
out vec2 referenceUv;
3940
4041
void main() {
4142
checkerUv = position / (pixelSize * checkerSize);
@@ -79,9 +80,11 @@ UberShader::UberShader(RenderPass* renderPass) {
7980
8081
uniform vec4 bgColor;
8182
82-
varying vec2 checkerUv;
83-
varying vec2 imageUv;
84-
varying vec2 referenceUv;
83+
in vec2 checkerUv;
84+
in vec2 imageUv;
85+
in vec2 referenceUv;
86+
87+
layout(location = 0) out vec4 fragColor;
8588
8689
float average(vec3 col) {
8790
return (col.r + col.g + col.b) / 3.0;
@@ -118,8 +121,19 @@ UberShader::UberShader(RenderPass* renderPass) {
118121
}
119122
}
120123
121-
vec3 hash(vec3 co){
122-
return 2.0 * abs(fract(abs(fract(dot(co, vec3(115.191742, 64.0546951, 124.512291))) - 0.5) * vec3(1368.46143, 1523.2019, 1034.50476)) - 0.5);
124+
vec3 hash(vec3 col) {
125+
uvec3 v = floatBitsToUint(col);
126+
// See 'Hash Functions for GPU Rendering' (https://jcgt.org/published/0009/03/02/)
127+
// pcg3d is MIT licensed (https://github.com/markjarzynski/PCG3D/commit/684c5da):
128+
// Copyright 2020 Mark Jarzynski & Marc Olano
129+
// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
130+
// The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
131+
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
132+
v = v * 1664525u + 1013904223u;
133+
v.x += v.y * v.z; v.y += v.z * v.x; v.z += v.x * v.y;
134+
v ^= v >> 16u;
135+
v.x += v.y * v.z; v.y += v.z * v.x; v.z += v.x * v.y;
136+
return vec3(v) * vec3(1.0 / 4294967295.0);
123137
}
124138
125139
vec3 applyTonemap(vec3 col, vec4 background) {
@@ -155,7 +169,7 @@ UberShader::UberShader(RenderPass* renderPass) {
155169
return vec3(0.0);
156170
}
157171
158-
vec4 sample(sampler2D sampler, vec2 uv) {
172+
vec4 sampleImage(sampler2D sampler, vec2 uv) {
159173
vec4 color = texture2D(sampler, uv);
160174
if (uv.x < 0.0 || uv.x > 1.0 || uv.y < 0.0 || uv.y > 1.0) {
161175
color = vec4(0.0);
@@ -170,35 +184,35 @@ UberShader::UberShader(RenderPass* renderPass) {
170184
vec3 checker = abs(mod(floor(checkerUv.x) + floor(checkerUv.y), 2.0)) < 0.5 ? darkGray : lightGray;
171185
checker = bgColor.rgb * bgColor.a + checker * (1.0 - bgColor.a);
172186
if (!hasImage) {
173-
gl_FragColor = vec4(checker, 1.0);
187+
fragColor = vec4(checker, 1.0);
174188
return;
175189
}
176190
177191
float cropAlpha =
178192
imageUv.x < cropMin.x || imageUv.x > cropMax.x || imageUv.y < cropMin.y || imageUv.y > cropMax.y ? 0.3 : 1.0;
179193
180-
vec4 imageVal = sample(image, imageUv);
194+
vec4 imageVal = sampleImage(image, imageUv);
181195
imageVal.a *= cropAlpha;
182196
if (!hasReference) {
183-
gl_FragColor = vec4(
197+
fragColor = vec4(
184198
applyTonemap(applyExposureAndOffset(imageVal.rgb), vec4(checker, 1.0 - imageVal.a)),
185199
1.0
186200
);
187-
gl_FragColor.rgb = clamp(gl_FragColor.rgb, clipToLdr ? 0.0 : -64.0, clipToLdr ? 1.0 : 64.0);
201+
fragColor.rgb = clamp(fragColor.rgb, clipToLdr ? 0.0 : -64.0, clipToLdr ? 1.0 : 64.0);
188202
return;
189203
}
190204
191-
vec4 referenceVal = sample(reference, referenceUv);
205+
vec4 referenceVal = sampleImage(reference, referenceUv);
192206
referenceVal.a *= cropAlpha;
193207
194208
vec3 difference = imageVal.rgb - referenceVal.rgb;
195209
float alpha = (imageVal.a + referenceVal.a) * 0.5;
196-
gl_FragColor = vec4(
210+
fragColor = vec4(
197211
applyTonemap(applyExposureAndOffset(applyMetric(difference, referenceVal.rgb)), vec4(checker, 1.0 - alpha)),
198212
1.0
199213
);
200214
201-
gl_FragColor.rgb = clamp(gl_FragColor.rgb, clipToLdr ? 0.0 : -64.0, clipToLdr ? 1.0 : 64.0);
215+
fragColor.rgb = clamp(fragColor.rgb, clipToLdr ? 0.0 : -64.0, clipToLdr ? 1.0 : 64.0);
202216
})glsl";
203217
#elif defined(NANOGUI_USE_METAL)
204218
auto vertexShader =
@@ -280,8 +294,14 @@ UberShader::UberShader(RenderPass* renderPass) {
280294
}
281295
}
282296
283-
float3 hash(float3 co){
284-
return 2.0f * abs(fract(abs(fract(dot(co.xyz, float3(115.191742f, 64.0546951f, 124.512291f))) - 0.5f) * float3(1368.46143f, 1523.2019f, 1034.50476f)) - 0.5f);
297+
float3 hash(float3 col) {
298+
uint3 v = as_type<uint3>(col);
299+
// See 'Hash Functions for GPU Rendering' (https://jcgt.org/published/0009/03/02/)
300+
v = v * 1664525u + 1013904223u;
301+
v.x += v.y * v.z; v.y += v.z * v.x; v.z += v.x * v.y;
302+
v ^= v >> 16u;
303+
v.x += v.y * v.z; v.y += v.z * v.x; v.z += v.x * v.y;
304+
return float3(v) * float3(1.0f / 4294967295.0f);
285305
}
286306
287307
float3 applyTonemap(float3 col, float4 background, int tonemap, float offset, float gamma, texture2d<float, access::sample> colormap, sampler colormapSampler) {
@@ -315,7 +335,7 @@ UberShader::UberShader(RenderPass* renderPass) {
315335
return float3(0.0f);
316336
}
317337
318-
float4 sample(texture2d<float, access::sample> texture, sampler textureSampler, float2 uv) {
338+
float4 sampleImage(texture2d<float, access::sample> texture, sampler textureSampler, float2 uv) {
319339
float4 color = texture.sample(textureSampler, uv);
320340
if (uv.x < 0.0f || uv.x > 1.0f || uv.y < 0.0f || uv.y > 1.0f) {
321341
return float4(0.0f);
@@ -361,7 +381,7 @@ UberShader::UberShader(RenderPass* renderPass) {
361381
362382
float cropAlpha = vert.imageUv.x < cropMin.x || vert.imageUv.x > cropMax.x || vert.imageUv.y < cropMin.y || vert.imageUv.y > cropMax.y ? 0.3f : 1.0f;
363383
364-
float4 imageVal = sample(image, image_sampler, vert.imageUv);
384+
float4 imageVal = sampleImage(image, image_sampler, vert.imageUv);
365385
imageVal.a *= cropAlpha;
366386
if (!hasReference) {
367387
float4 color = float4(
@@ -380,7 +400,7 @@ UberShader::UberShader(RenderPass* renderPass) {
380400
return color;
381401
}
382402
383-
float4 referenceVal = sample(reference, reference_sampler, vert.referenceUv);
403+
float4 referenceVal = sampleImage(reference, reference_sampler, vert.referenceUv);
384404
referenceVal.a *= cropAlpha;
385405
386406
float3 difference = imageVal.rgb - referenceVal.rgb;

0 commit comments

Comments
 (0)