AVSim/simulation-package
Simulation runtime: the third-party half of the AVSim data generation package This repository holds the third-party runtime of the Simulation data generation package, version 3: the pieces the pipeline needs that were not written by the authors. It contains no code and no data of the authors. It is not usable on its own: the private half of the package, AVSim/simulation, downloads this repository into the same directory at a pinned revision with its fetch_runtime.sh script and… See the full description on the dataset page: https://huggingface.co/datasets/AVSim/simulation-package.
03.7k
1/******************************************************************************
2 * Copyright 1986, 2019 NVIDIA ARC GmbH. All rights reserved. *
3 ******************************************************************************
4
5Permission is hereby granted by NVIDIA Corporation ("NVIDIA"), free of charge,
6to any person obtaining a copy of the sample definition code that uses our
7Material Definition Language (the "MDL Materials"), to reproduce and distribute
8the MDL Materials, including without limitation the rights to use, copy, merge,
9publish, distribute, and sell modified and unmodified copies of the MDL
10Materials, and to permit persons to whom the MDL Materials is furnished to do
11so, in all cases solely for use with NVIDIA’s Material Definition Language,
12subject to the following further conditions:
13
141. The above copyright notices, this list of conditions, and the disclaimer
15that follows shall be retained in all copies of one or more of the MDL
16Materials, including in any software with which the MDL Materials are bundled,
17redistributed, and/or sold, and included either as stand-alone text files,
18human-readable headers or in the appropriate machine-readable metadata fields
19within text or binary files as long as those fields can be easily viewed by the
20user, as applicable.
212. The name of NVIDIA shall not be used to promote, endorse or advertise any
22Modified Version without specific prior written permission, except a) to comply
23 with the notice requirements otherwise contained herein; or b) to acknowledge
24the contribution(s) of NVIDIA.
25
26THE MDL MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
27OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF MERCHANTABILITY,
28FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF COPYRIGHT, PATENT,
29TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL NVIDIA CORPORATION BE LIABLE FOR
30ANY CLAIM, DAMAGES OR OTHER LIABILITY, INCLUDING ANY GENERAL, SPECIAL,
31INDIRECT, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, WHETHER IN AN ACTION OF
32CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF THE USE OR INABILITY TO USE
33THE MDL MATERIALS OR FROM OTHER DEALINGS IN THE MDL MATERIALS.
34*/
35
36//* 1.0.1 - using absolute import paths when importing standard modules
37
38mdl 1.3;
39
40import ::df::*;
41import ::state::*;
42import ::math::*;
43import ::tex::*;
44import ::anno::*;
45
46
47export float3x3 matrix_inverse(float3x3 matrix)
48[[
49 anno::description("Inverse the 3x3 matrix"),
50 anno::noinline()
51]]
52{
53 float determinant = (matrix[0][0] * matrix[1][1] * matrix[2][2] + matrix[1][0] * matrix[2][1] * matrix[0][2] + matrix[2][0] * matrix[0][1] * matrix[1][2]) - (matrix[0][2] * matrix[1][1] * matrix[2][0] + matrix[1][2] * matrix[2][1] * matrix[0][0] + matrix[2][2] * matrix[0][1] * matrix[1][0]);
54 float rdet = 1.0f / determinant;
55
56 float3x3 result;
57
58 result[0][0] = rdet * (matrix[1][1] * matrix[2][2] - matrix[1][2] * matrix[2][1]);
59 result[0][1] = -rdet * (matrix[0][1] * matrix[2][2] - matrix[0][2] * matrix[2][1]);
60 result[0][2] = rdet * (matrix[0][1] * matrix[1][2] - matrix[0][2] * matrix[1][1]);
61
62 result[1][0] = -rdet * (matrix[1][0] * matrix[2][2] - matrix[1][2] * matrix[2][0]);
63 result[1][1] = rdet * (matrix[0][0] * matrix[2][2] - matrix[0][2] * matrix[2][0]);
64 result[1][2] = -rdet * (matrix[0][0] * matrix[1][2] - matrix[0][2] * matrix[1][0]);
65
66 result[2][0] = rdet * (matrix[1][0] * matrix[2][1] - matrix[1][1] * matrix[2][0]);
67 result[2][1] = -rdet * (matrix[0][0] * matrix[2][1] - matrix[0][1] * matrix[2][0]);
68 result[2][2] = rdet * (matrix[0][0] * matrix[1][1] - matrix[0][1] * matrix[1][0]);
69
70 return result;
71}
72
73export float3 transform_vector_from_tangent_to_world(float3 vector)
74[[
75 anno::description("Transform vector from tangent space to world space"),
76 anno::noinline()
77]]
78{
79 float3x3 tangent_to_world = float3x3(state::texture_tangent_u(0), state::texture_tangent_v(0), state::normal());
80 return tangent_to_world * vector;
81}
82
83export float3 transform_vector_from_world_to_tangent(float3 vector)
84[[
85 anno::description("Transform vector from world space to tangent space"),
86 anno::noinline()
87]]
88{
89 float3x3 tangent_to_world = float3x3(state::texture_tangent_u(0), state::texture_tangent_v(0), state::normal());
90
91 // inverse tangent to world matrix
92 float3x3 world_to_tangent = matrix_inverse(tangent_to_world);
93
94 return world_to_tangent * vector;
95}
96
97export float4 unpack_normal_map(
98 float4 texture_sample = float4(0.0, 0.0, 1.0, 1.0)
99 )
100[[
101 anno::description("Unpack a normal stored in a normal map"),
102 anno::noinline()
103]]
104{
105 float2 normal_xy = float2(texture_sample.x, texture_sample.y);
106
107 normal_xy = normal_xy * float2(2.0,2.0) - float2(1.0,1.0);
108 float normal_z = math::sqrt( math::saturate( 1.0 - math::dot( normal_xy, normal_xy ) ) );
109 return float4( normal_xy.x, normal_xy.y, normal_z, 1.0 );
110}
111
112// for get color value from normal.
113export float4 pack_normal_map(
114 float4 texture_sample = float4(0.0, 0.0, 1.0, 1.0)
115 )
116[[
117 anno::description("Pack to color from a normal")
118]]
119{
120 float2 return_xy = float2(texture_sample.x, texture_sample.y);
121
122 return_xy = (return_xy + float2(1.0,1.0)) / float2(2.0,2.0);
123
124 return float4( return_xy.x, return_xy.y, 0.0, 1.0 );
125}
126
127export float4 greyscale_texture_lookup(
128 float4 texture_sample = float4(0.0, 0.0, 0.0, 1.0)
129 )
130[[
131 anno::description("Sampling a greyscale texture"),
132 anno::noinline()
133]]
134{
135 return float4(texture_sample.x, texture_sample.x, texture_sample.x, texture_sample.x);
136}
137
138export float3 pixel_normal_world_space()
139[[
140 anno::description("Pixel normal in world space"),
141 anno::noinline()
142]]
143{
144 return state::transform_normal(state::coordinate_internal,state::coordinate_world,state::normal());
145}
146
147export float3 vertex_normal_world_space()
148[[
149 anno::description("Vertex normal in world space"),
150 anno::noinline()
151]]
152{
153 return state::transform_normal(state::coordinate_internal,state::coordinate_world,state::normal());
154}
155
156export float3 landscape_normal_world_space()
157[[
158 anno::description("Landscape normal in world space")
159]]
160{
161 float3 normalFromNormalmap = math::floor((::vertex_normal_world_space() * 0.5 + 0.5) * 255.0) / 255.0 * 2.0 - 1.0;
162
163 float2 normalXY = float2(normalFromNormalmap.x, normalFromNormalmap.y);
164 return float3(normalXY.x, normalXY.y, math::sqrt(math::saturate(1.0 - math::dot(normalXY, normalXY))));
165}
166
167// Different implementation specific between mdl and hlsl for smoothstep
168export float smoothstep(float a, float b, float l)
169{
170 if (a < b)
171 {
172 return math::smoothstep(a, b, l);
173 }
174 else if (a > b)
175 {
176 return 1.0 - math::smoothstep(b, a, l);
177 }
178 else
179 {
180 return l <= a ? 0.0 : 1.0;
181 }
182}
183
184export float2 smoothstep(float2 a, float2 b, float2 l)
185{
186 return float2(smoothstep(a.x, b.x, l.x), smoothstep(a.y, b.y, l.y));
187}
188
189export float3 smoothstep(float3 a, float3 b, float3 l)
190{
191 return float3(smoothstep(a.x, b.x, l.x), smoothstep(a.y, b.y, l.y), smoothstep(a.z, b.z, l.z));
192}
193
194export float4 smoothstep(float4 a, float4 b, float4 l)
195{
196 return float4(smoothstep(a.x, b.x, l.x), smoothstep(a.y, b.y, l.y), smoothstep(a.z, b.z, l.z), smoothstep(a.w, b.w, l.w));
197}
198
199export float2 smoothstep(float2 a, float2 b, float l)
200{
201 return float2(smoothstep(a.x, b.x, l), smoothstep(a.y, b.y, l));
202}
203
204export float3 smoothstep(float3 a, float3 b, float l)
205{
206 return float3(smoothstep(a.x, b.x, l), smoothstep(a.y, b.y, l), smoothstep(a.z, b.z, l));
207}
208
209export float4 smoothstep(float4 a, float4 b, float l)
210{
211 return float4(smoothstep(a.x, b.x, l), smoothstep(a.y, b.y, l), smoothstep(a.z, b.z, l), smoothstep(a.w, b.w, l));
212}
213
214//------------------ Random from UE4 -----------------------
215float length2(float3 v)
216{
217 return math::dot(v, v);
218}
219
220float3 GetPerlinNoiseGradientTextureAt(uniform texture_2d PerlinNoiseGradientTexture, float3 v)
221{
222 const float2 ZShear = float2(17.0f, 89.0f);
223
224 float2 OffsetA = v.z * ZShear;
225 float2 TexA = (float2(v.x, v.y) + OffsetA + 0.5f) / 128.0f;
226 float4 PerlinNoise = tex::lookup_float4(PerlinNoiseGradientTexture,float2(TexA.x,1.0-TexA.y),tex::wrap_repeat,tex::wrap_repeat);
227 return float3(PerlinNoise.x, PerlinNoise.y, PerlinNoise.z) * 2.0 - 1.0;
228}
229
230float3 SkewSimplex(float3 In)
231{
232 return In + math::dot(In, float3(1.0 / 3.0f) );
233}
234float3 UnSkewSimplex(float3 In)
235{
236 return In - math::dot(In, float3(1.0 / 6.0f) );
237}
238
239// 3D random number generator inspired by PCGs (permuted congruential generator)
240// Using a **simple** Feistel cipher in place of the usual xor shift permutation step
241// @param v = 3D integer coordinate
242// @return three elements w/ 16 random bits each (0-0xffff).
243// ~8 ALU operations for result.x (7 mad, 1 >>)
244// ~10 ALU operations for result.xy (8 mad, 2 >>)
245// ~12 ALU operations for result.xyz (9 mad, 3 >>)
246
247//TODO: uint3
248int3 Rand3DPCG16(int3 p)
249{
250 // taking a signed int then reinterpreting as unsigned gives good behavior for negatives
251 //TODO: uint3
252 int3 v = int3(p);
253
254 // Linear congruential step. These LCG constants are from Numerical Recipies
255 // For additional #'s, PCG would do multiple LCG steps and scramble each on output
256 // So v here is the RNG state
257 v = v * 1664525 + 1013904223;
258
259 // PCG uses xorshift for the final shuffle, but it is expensive (and cheap
260 // versions of xorshift have visible artifacts). Instead, use simple MAD Feistel steps
261 //
262 // Feistel ciphers divide the state into separate parts (usually by bits)
263 // then apply a series of permutation steps one part at a time. The permutations
264 // use a reversible operation (usually ^) to part being updated with the result of
265 // a permutation function on the other parts and the key.
266 //
267 // In this case, I'm using v.x, v.y and v.z as the parts, using + instead of ^ for
268 // the combination function, and just multiplying the other two parts (no key) for
269 // the permutation function.
270 //
271 // That gives a simple mad per round.
272 v.x += v.y*v.z;
273 v.y += v.z*v.x;
274 v.z += v.x*v.y;
275 v.x += v.y*v.z;
276 v.y += v.z*v.x;
277 v.z += v.x*v.y;
278
279 // only top 16 bits are well shuffled
280 return v >> 16;
281}
282
283// Wraps noise for tiling texture creation
284// @param v = unwrapped texture parameter
285// @param bTiling = true to tile, false to not tile
286// @param RepeatSize = number of units before repeating
287// @return either original or wrapped coord
288float3 NoiseTileWrap(float3 v, bool bTiling, float RepeatSize)
289{
290 return bTiling ? (math::frac(v / RepeatSize) * RepeatSize) : v;
291}
292
293// Evaluate polynomial to get smooth transitions for Perlin noise
294// only needed by Perlin functions in this file
295// scalar(per component): 2 add, 5 mul
296float4 PerlinRamp(float4 t)
297{
298 return t * t * t * (t * (t * 6 - 15) + 10);
299}
300
301// Blum-Blum-Shub-inspired pseudo random number generator
302// http://www.umbc.edu/~olano/papers/mNoise.pdf
303// real BBS uses ((s*s) mod M) with bignums and M as the product of two huge Blum primes
304// instead, we use a single prime M just small enough not to overflow
305// note that the above paper used 61, which fits in a half, but is unusably bad
306// @param Integer valued floating point seed
307// @return random number in range [0,1)
308// ~8 ALU operations (5 *, 3 frac)
309float RandBBSfloat(float seed)
310{
311 float BBS_PRIME24 = 4093.0;
312 float s = math::frac(seed / BBS_PRIME24);
313 s = math::frac(s * s * BBS_PRIME24);
314 s = math::frac(s * s * BBS_PRIME24);
315 return s;
316}
317
318// Modified noise gradient term
319// @param seed - random seed for integer lattice position
320// @param offset - [-1,1] offset of evaluation point from lattice point
321// @return gradient direction (xyz) and contribution (w) from this lattice point
322float4 MGradient(int seed, float3 offset)
323{
324 //TODO uint
325 int rand = Rand3DPCG16(int3(seed,0,0)).x;
326 int3 MGradientMask = int3(0x8000, 0x4000, 0x2000);
327 float3 MGradientScale = float3(1.0 / 0x4000, 1.0 / 0x2000, 1.0 / 0x1000);
328 float3 direction = float3(int3(rand, rand, rand) & MGradientMask) * MGradientScale - 1;
329 return float4(direction.x, direction.y, direction.z, math::dot(direction, offset));
330}
331
332// compute Perlin and related noise corner seed values
333// @param v = 3D noise argument, use float3(x,y,0) for 2D or float3(x,0,0) for 1D
334// @param bTiling = true to return seed values for a repeating noise pattern
335// @param RepeatSize = integer units before tiling in each dimension
336// @param seed000-seed111 = hash function seeds for the eight corners
337// @return fractional part of v
338struct SeedValue
339{
340 float3 fv = float3(0);
341 float seed000 = 0;
342 float seed001 = 0;
343 float seed010 = 0;
344 float seed011 = 0;
345 float seed100 = 0;
346 float seed101 = 0;
347 float seed110 = 0;
348 float seed111 = 0;
349};
350
351SeedValue NoiseSeeds(float3 v, bool bTiling, float RepeatSize)
352{
353 SeedValue seeds;
354 seeds.fv = math::frac(v);
355 float3 iv = math::floor(v);
356
357 const float3 primes = float3(19, 47, 101);
358
359 if (bTiling)
360 { // can't algebraically combine with primes
361 seeds.seed000 = math::dot(primes, NoiseTileWrap(iv, true, RepeatSize));
362 seeds.seed100 = math::dot(primes, NoiseTileWrap(iv + float3(1, 0, 0), true, RepeatSize));
363 seeds.seed010 = math::dot(primes, NoiseTileWrap(iv + float3(0, 1, 0), true, RepeatSize));
364 seeds.seed110 = math::dot(primes, NoiseTileWrap(iv + float3(1, 1, 0), true, RepeatSize));
365 seeds.seed001 = math::dot(primes, NoiseTileWrap(iv + float3(0, 0, 1), true, RepeatSize));
366 seeds.seed101 = math::dot(primes, NoiseTileWrap(iv + float3(1, 0, 1), true, RepeatSize));
367 seeds.seed011 = math::dot(primes, NoiseTileWrap(iv + float3(0, 1, 1), true, RepeatSize));
368 seeds.seed111 = math::dot(primes, NoiseTileWrap(iv + float3(1, 1, 1), true, RepeatSize));
369 }
370 else
371 { // get to combine offsets with multiplication by primes in this case
372 seeds.seed000 = math::dot(iv, primes);
373 seeds.seed100 = seeds.seed000 + primes.x;
374 seeds.seed010 = seeds.seed000 + primes.y;
375 seeds.seed110 = seeds.seed100 + primes.y;
376 seeds.seed001 = seeds.seed000 + primes.z;
377 seeds.seed101 = seeds.seed100 + primes.z;
378 seeds.seed011 = seeds.seed010 + primes.z;
379 seeds.seed111 = seeds.seed110 + primes.z;
380 }
381
382 return seeds;
383}
384
385struct SimplexWeights
386{
387 float4 Result = float4(0);
388 float3 PosA = float3(0);
389 float3 PosB = float3(0);
390 float3 PosC = float3(0);
391 float3 PosD = float3(0);
392};
393
394// Computed weights and sample positions for simplex interpolation
395// @return float4(a,b,c, d) Barycentric coordinate defined as Filtered = Tex(PosA) * a + Tex(PosB) * b + Tex(PosC) * c + Tex(PosD) * d
396SimplexWeights ComputeSimplexWeights3D(float3 OrthogonalPos)
397{
398 SimplexWeights weights;
399 float3 OrthogonalPosFloor = math::floor(OrthogonalPos);
400
401 weights.PosA = OrthogonalPosFloor;
402 weights.PosB = weights.PosA + float3(1, 1, 1);
403
404 OrthogonalPos -= OrthogonalPosFloor;
405
406 float Largest = math::max(OrthogonalPos.x, math::max(OrthogonalPos.y, OrthogonalPos.z));
407 float Smallest = math::min(OrthogonalPos.x, math::min(OrthogonalPos.y, OrthogonalPos.z));
408
409 weights.PosC = weights.PosA + float3(Largest == OrthogonalPos.x, Largest == OrthogonalPos.y, Largest == OrthogonalPos.z);
410 weights.PosD = weights.PosA + float3(Smallest != OrthogonalPos.x, Smallest != OrthogonalPos.y, Smallest != OrthogonalPos.z);
411
412 float RG = OrthogonalPos.x - OrthogonalPos.y;
413 float RB = OrthogonalPos.x - OrthogonalPos.z;
414 float GB = OrthogonalPos.y - OrthogonalPos.z;
415
416 weights.Result.z =
417 math::min(math::max(0, RG), math::max(0, RB)) // X
418 + math::min(math::max(0, -RG), math::max(0, GB)) // Y
419 + math::min(math::max(0, -RB), math::max(0, -GB)); // Z
420
421 weights.Result.w =
422 math::min(math::max(0, -RG), math::max(0, -RB)) // X
423 + math::min(math::max(0, RG), math::max(0, -GB)) // Y
424 + math::min(math::max(0, RB), math::max(0, GB)); // Z
425
426 weights.Result.y = Smallest;
427 weights.Result.x = 1.0f - weights.Result.y - weights.Result.z - weights.Result.w;
428
429 return weights;
430}
431
432// filtered 3D gradient simple noise (few texture lookups, high quality)
433// @param v >0
434// @return random number in the range -1 .. 1
435float SimplexNoise3D_TEX(uniform texture_2d PerlinNoiseGradientTexture, float3 EvalPos)
436{
437 float3 OrthogonalPos = SkewSimplex(EvalPos);
438
439 SimplexWeights Weights = ComputeSimplexWeights3D(OrthogonalPos);
440
441 // can be optimized to 1 or 2 texture lookups (4 or 8 channel encoded in 32 bit)
442 float3 A = GetPerlinNoiseGradientTextureAt(PerlinNoiseGradientTexture, Weights.PosA);
443 float3 B = GetPerlinNoiseGradientTextureAt(PerlinNoiseGradientTexture, Weights.PosB);
444 float3 C = GetPerlinNoiseGradientTextureAt(PerlinNoiseGradientTexture, Weights.PosC);
445 float3 D = GetPerlinNoiseGradientTextureAt(PerlinNoiseGradientTexture, Weights.PosD);
446
447 Weights.PosA = UnSkewSimplex(Weights.PosA);
448 Weights.PosB = UnSkewSimplex(Weights.PosB);
449 Weights.PosC = UnSkewSimplex(Weights.PosC);
450 Weights.PosD = UnSkewSimplex(Weights.PosD);
451
452 float DistanceWeight;
453
454 DistanceWeight = math::saturate(0.6f - length2(EvalPos - Weights.PosA)); DistanceWeight *= DistanceWeight; DistanceWeight *= DistanceWeight;
455 float a = math::dot(A, EvalPos - Weights.PosA) * DistanceWeight;
456 DistanceWeight = math::saturate(0.6f - length2(EvalPos - Weights.PosB)); DistanceWeight *= DistanceWeight; DistanceWeight *= DistanceWeight;
457 float b = math::dot(B, EvalPos - Weights.PosB) * DistanceWeight;
458 DistanceWeight = math::saturate(0.6f - length2(EvalPos - Weights.PosC)); DistanceWeight *= DistanceWeight; DistanceWeight *= DistanceWeight;
459 float c = math::dot(C, EvalPos - Weights.PosC) * DistanceWeight;
460 DistanceWeight = math::saturate(0.6f - length2(EvalPos - Weights.PosD)); DistanceWeight *= DistanceWeight; DistanceWeight *= DistanceWeight;
461 float d = math::dot(D, EvalPos - Weights.PosD) * DistanceWeight;
462
463 return 32 * (a + b + c + d);
464}
465
466// filtered 3D noise, can be optimized
467// @param v = 3D noise argument, use float3(x,y,0) for 2D or float3(x,0,0) for 1D
468// @param bTiling = repeat noise pattern
469// @param RepeatSize = integer units before tiling in each dimension
470// @return random number in the range -1 .. 1
471float GradientNoise3D_TEX(uniform texture_2d PerlinNoiseGradientTexture, float3 v, bool bTiling, float RepeatSize)
472{
473 bTiling = true;
474 float3 fv = math::frac(v);
475 float3 iv0 = NoiseTileWrap(math::floor(v), bTiling, RepeatSize);
476 float3 iv1 = NoiseTileWrap(iv0 + 1, bTiling, RepeatSize);
477
478 const int2 ZShear = int2(17, 89);
479
480 float2 OffsetA = iv0.z * ZShear;
481 float2 OffsetB = OffsetA + ZShear; // non-tiling, use relative offset
482 if (bTiling) // tiling, have to compute from wrapped coordinates
483 {
484 OffsetB = iv1.z * ZShear;
485 }
486
487 // Texture size scale factor
488 float ts = 1 / 128.0f;
489
490 // texture coordinates for iv0.xy, as offset for both z slices
491 float2 TexA0 = (float2(iv0.x, iv0.y) + OffsetA + 0.5f) * ts;
492 float2 TexB0 = (float2(iv0.x, iv0.y) + OffsetB + 0.5f) * ts;
493
494 // texture coordinates for iv1.xy, as offset for both z slices
495 float2 TexA1 = TexA0 + ts; // for non-tiling, can compute relative to existing coordinates
496 float2 TexB1 = TexB0 + ts;
497 if (bTiling) // for tiling, need to compute from wrapped coordinates
498 {
499 TexA1 = (float2(iv1.x, iv1.y) + OffsetA + 0.5f) * ts;
500 TexB1 = (float2(iv1.x, iv1.y) + OffsetB + 0.5f) * ts;
501 }
502
503
504 // can be optimized to 1 or 2 texture lookups (4 or 8 channel encoded in 8, 16 or 32 bit)
505 float4 PerlinNoise = tex::lookup_float4(PerlinNoiseGradientTexture,float2(TexA0.x,1.0-TexA0.y),tex::wrap_repeat,tex::wrap_repeat);
506 float3 PerlinNoiseColor = float3(PerlinNoise.x, PerlinNoise.y, PerlinNoise.z);
507 float3 A = PerlinNoiseColor * 2 - 1;
508 PerlinNoise = tex::lookup_float4(PerlinNoiseGradientTexture,float2(TexA1.x,1.0-TexA0.y),tex::wrap_repeat,tex::wrap_repeat);
509 PerlinNoiseColor = float3(PerlinNoise.x, PerlinNoise.y, PerlinNoise.z);
510 float3 B = PerlinNoiseColor * 2 - 1;
511 PerlinNoise = tex::lookup_float4(PerlinNoiseGradientTexture,float2(TexA0.x,1.0-TexA1.y),tex::wrap_repeat,tex::wrap_repeat);
512 PerlinNoiseColor = float3(PerlinNoise.x, PerlinNoise.y, PerlinNoise.z);
513 float3 C = PerlinNoiseColor * 2 - 1;
514 PerlinNoise = tex::lookup_float4(PerlinNoiseGradientTexture,float2(TexA1.x,1.0-TexA1.y),tex::wrap_repeat,tex::wrap_repeat);
515 PerlinNoiseColor = float3(PerlinNoise.x, PerlinNoise.y, PerlinNoise.z);
516 float3 D = PerlinNoiseColor * 2 - 1;
517 PerlinNoise = tex::lookup_float4(PerlinNoiseGradientTexture,float2(TexB0.x,1.0-TexB0.y),tex::wrap_repeat,tex::wrap_repeat);
518 PerlinNoiseColor = float3(PerlinNoise.x, PerlinNoise.y, PerlinNoise.z);
519 float3 E = PerlinNoiseColor * 2 - 1;
520 PerlinNoise = tex::lookup_float4(PerlinNoiseGradientTexture,float2(TexB1.x,1.0-TexB0.y),tex::wrap_repeat,tex::wrap_repeat);
521 PerlinNoiseColor = float3(PerlinNoise.x, PerlinNoise.y, PerlinNoise.z);
522 float3 F = PerlinNoiseColor * 2 - 1;
523 PerlinNoise = tex::lookup_float4(PerlinNoiseGradientTexture,float2(TexB0.x,1.0-TexB1.y),tex::wrap_repeat,tex::wrap_repeat);
524 PerlinNoiseColor = float3(PerlinNoise.x, PerlinNoise.y, PerlinNoise.z);
525 float3 G = PerlinNoiseColor * 2 - 1;
526 PerlinNoise = tex::lookup_float4(PerlinNoiseGradientTexture,float2(TexB1.x,1.0-TexB1.y),tex::wrap_repeat,tex::wrap_repeat);
527 PerlinNoiseColor = float3(PerlinNoise.x, PerlinNoise.y, PerlinNoise.z);
528 float3 H = PerlinNoiseColor * 2 - 1;
529
530 float a = math::dot(A, fv - float3(0, 0, 0));
531 float b = math::dot(B, fv - float3(1, 0, 0));
532 float c = math::dot(C, fv - float3(0, 1, 0));
533 float d = math::dot(D, fv - float3(1, 1, 0));
534 float e = math::dot(E, fv - float3(0, 0, 1));
535 float f = math::dot(F, fv - float3(1, 0, 1));
536 float g = math::dot(G, fv - float3(0, 1, 1));
537 float h = math::dot(H, fv - float3(1, 1, 1));
538
539 float4 Weights = PerlinRamp(math::frac(float4(fv.x, fv.y, fv.z, 0)));
540
541 float i = math::lerp(math::lerp(a, b, Weights.x), math::lerp(c, d, Weights.x), Weights.y);
542 float j = math::lerp(math::lerp(e, f, Weights.x), math::lerp(g, h, Weights.x), Weights.y);
543
544 return math::lerp(i, j, Weights.z);
545}
546
547// @return random number in the range -1 .. 1
548// scalar: 6 frac, 31 mul/mad, 15 add,
549float FastGradientPerlinNoise3D_TEX(uniform texture_3d PerlinNoise3DTexture, float3 xyz)
550{
551 // needs to be the same value when creating the PerlinNoise3D texture
552 float Extent = 16;
553
554 // last texel replicated and needed for filtering
555 // scalar: 3 frac, 6 mul
556 xyz = math::frac(xyz / (Extent - 1)) * (Extent - 1);
557
558 // scalar: 3 frac
559 float3 uvw = math::frac(xyz);
560 // = floor(xyz);
561 // scalar: 3 add
562 float3 p0 = xyz - uvw;
563// float3 f = math::pow(uvw, 2) * 3.0f - math::pow(uvw, 3) * 2.0f; // original perlin hermite (ok when used without bump mapping)
564 // scalar: 2*3 add 5*3 mul
565 float4 pr = PerlinRamp(float4(uvw.x, uvw.y, uvw.z, 0));
566 float3 f = float3(pr.x, pr.y, pr.z); // new, better with continues second derivative for bump mapping
567 // scalar: 3 add
568 float3 p = p0 + f;
569 // scalar: 3 mad
570 // TODO: need reverse???
571 float4 NoiseSample = tex::lookup_float4(PerlinNoise3DTexture, p / Extent + 0.5f / Extent); // +0.5f to get rid of bilinear offset
572
573 // reconstruct from 8bit (using mad with 2 constants and dot4 was same instruction count)
574 // scalar: 4 mad, 3 mul, 3 add
575 float3 n = float3(NoiseSample.x, NoiseSample.y, NoiseSample.z) * 255.0f / 127.0f - 1.0f;
576 float d = NoiseSample.w * 255.f - 127;
577 return math::dot(xyz, n) - d;
578}
579
580// Perlin-style "Modified Noise"
581// http://www.umbc.edu/~olano/papers/index.html#mNoise
582// @param v = 3D noise argument, use float3(x,y,0) for 2D or float3(x,0,0) for 1D
583// @param bTiling = repeat noise pattern
584// @param RepeatSize = integer units before tiling in each dimension
585// @return random number in the range -1 .. 1
586float GradientNoise3D_ALU(float3 v, bool bTiling, float RepeatSize)
587{
588 SeedValue seeds = NoiseSeeds(v, bTiling, RepeatSize);
589
590 float rand000 = MGradient(int(seeds.seed000), seeds.fv - float3(0, 0, 0)).w;
591 float rand100 = MGradient(int(seeds.seed100), seeds.fv - float3(1, 0, 0)).w;
592 float rand010 = MGradient(int(seeds.seed010), seeds.fv - float3(0, 1, 0)).w;
593 float rand110 = MGradient(int(seeds.seed110), seeds.fv - float3(1, 1, 0)).w;
594 float rand001 = MGradient(int(seeds.seed001), seeds.fv - float3(0, 0, 1)).w;
595 float rand101 = MGradient(int(seeds.seed101), seeds.fv - float3(1, 0, 1)).w;
596 float rand011 = MGradient(int(seeds.seed011), seeds.fv - float3(0, 1, 1)).w;
597 float rand111 = MGradient(int(seeds.seed111), seeds.fv - float3(1, 1, 1)).w;
598
599 float4 Weights = PerlinRamp(float4(seeds.fv.x, seeds.fv.y, seeds.fv.z, 0));
600
601 float i = math::lerp(math::lerp(rand000, rand100, Weights.x), math::lerp(rand010, rand110, Weights.x), Weights.y);
602 float j = math::lerp(math::lerp(rand001, rand101, Weights.x), math::lerp(rand011, rand111, Weights.x), Weights.y);
603 return math::lerp(i, j, Weights.z);
604}
605
606// 3D value noise - used to be incorrectly called Perlin noise
607// @param v = 3D noise argument, use float3(x,y,0) for 2D or float3(x,0,0) for 1D
608// @param bTiling = repeat noise pattern
609// @param RepeatSize = integer units before tiling in each dimension
610// @return random number in the range -1 .. 1
611float ValueNoise3D_ALU(float3 v, bool bTiling, float RepeatSize)
612{
613 SeedValue seeds = NoiseSeeds(v, bTiling, RepeatSize);
614
615 float rand000 = RandBBSfloat(seeds.seed000) * 2 - 1;
616 float rand100 = RandBBSfloat(seeds.seed100) * 2 - 1;
617 float rand010 = RandBBSfloat(seeds.seed010) * 2 - 1;
618 float rand110 = RandBBSfloat(seeds.seed110) * 2 - 1;
619 float rand001 = RandBBSfloat(seeds.seed001) * 2 - 1;
620 float rand101 = RandBBSfloat(seeds.seed101) * 2 - 1;
621 float rand011 = RandBBSfloat(seeds.seed011) * 2 - 1;
622 float rand111 = RandBBSfloat(seeds.seed111) * 2 - 1;
623
624 float4 Weights = PerlinRamp(float4(seeds.fv.x, seeds.fv.y, seeds.fv.z, 0));
625
626 float i = math::lerp(math::lerp(rand000, rand100, Weights.x), math::lerp(rand010, rand110, Weights.x), Weights.y);
627 float j = math::lerp(math::lerp(rand001, rand101, Weights.x), math::lerp(rand011, rand111, Weights.x), Weights.y);
628 return math::lerp(i, j, Weights.z);
629}
630
631// 3D jitter offset within a voronoi noise cell
632// @param pos - integer lattice corner
633// @return random offsets vector
634float3 VoronoiCornerSample(float3 pos, int Quality)
635{
636 // random values in [-0.5, 0.5]
637 float3 noise = float3(Rand3DPCG16(int3(pos))) / 0xffff - 0.5;
638
639 // quality level 1 or 2: searches a 2x2x2 neighborhood with points distributed on a sphere
640 // scale factor to guarantee jittered points will be found within a 2x2x2 search
641 if (Quality <= 2)
642 {
643 return math::normalize(noise) * 0.2588;
644 }
645
646 // quality level 3: searches a 3x3x3 neighborhood with points distributed on a sphere
647 // scale factor to guarantee jittered points will be found within a 3x3x3 search
648 if (Quality == 3)
649 {
650 return math::normalize(noise) * 0.3090;
651 }
652
653 // quality level 4: jitter to anywhere in the cell, needs 4x4x4 search
654 return noise;
655}
656
657// compare previous best with a new candidate
658// not producing point locations makes it easier for compiler to eliminate calculations when they're not needed
659// @param minval = location and distance of best candidate seed point before the new one
660// @param candidate = candidate seed point
661// @param offset = 3D offset to new candidate seed point
662// @param bDistanceOnly = if true, only set maxval.w with distance, otherwise maxval.w is distance and maxval.xyz is position
663// @return position (if bDistanceOnly is false) and distance to closest seed point so far
664float4 VoronoiCompare(float4 minval, float3 candidate, float3 offset, bool bDistanceOnly)
665{
666 if (bDistanceOnly)
667 {
668 return float4(0, 0, 0, math::min(minval.w, math::dot(offset, offset)));
669 }
670 else
671 {
672 float newdist = math::dot(offset, offset);
673 return newdist > minval.w ? minval : float4(candidate.x, candidate.y, candidate.z, newdist);
674 }
675}
676
677// 220 instruction Worley noise
678float4 VoronoiNoise3D_ALU(float3 v, int Quality, bool bTiling, float RepeatSize, bool bDistanceOnly)
679{
680 float3 fv = math::frac(v), fv2 = math::frac(v + 0.5);
681 float3 iv = math::floor(v), iv2 = math::floor(v + 0.5);
682
683 // with initial minimum distance = infinity (or at least bigger than 4), first min is optimized away
684 float4 mindist = float4(0,0,0,100);
685 float3 p, offset;
686
687 // quality level 3: do a 3x3x3 search
688 if (Quality == 3)
689 {
690 int offset_x;
691 int offset_y;
692 int offset_z;
693 for (offset_x = -1; offset_x <= 1; ++offset_x)
694 {
695 for (offset_y = -1; offset_y <= 1; ++offset_y)
696 {
697 for (offset_z = -1; offset_z <= 1; ++offset_z)
698 {
699 offset = float3(offset_x, offset_y, offset_z);
700 p = offset + VoronoiCornerSample(NoiseTileWrap(iv2 + offset, bTiling, RepeatSize), Quality);
701 mindist = VoronoiCompare(mindist, iv2 + p, fv2 - p, bDistanceOnly);
702 }
703 }
704 }
705 }
706
707 // everybody else searches a base 2x2x2 neighborhood
708 else
709 {
710 int offset_x;
711 int offset_y;
712 int offset_z;
713 for (offset_x = 0; offset_x <= 1; ++offset_x)
714 {
715 for (offset_y = 0; offset_y <= 1; ++offset_y)
716 {
717 for (offset_z = 0; offset_z <= 1; ++offset_z)
718 {
719 offset = float3(offset_x, offset_y, offset_z);
720 p = offset + VoronoiCornerSample(NoiseTileWrap(iv + offset, bTiling, RepeatSize), Quality);
721 mindist = VoronoiCompare(mindist, iv + p, fv - p, bDistanceOnly);
722
723 // quality level 2, do extra set of points, offset by half a cell
724 if (Quality == 2)
725 {
726 // 467 is just an offset to a different area in the random number field to avoid similar neighbor artifacts
727 p = offset + VoronoiCornerSample(NoiseTileWrap(iv2 + offset, bTiling, RepeatSize) + 467, Quality);
728 mindist = VoronoiCompare(mindist, iv2 + p, fv2 - p, bDistanceOnly);
729 }
730 }
731 }
732 }
733 }
734
735 // quality level 4: add extra sets of four cells in each direction
736 if (Quality >= 4)
737 {
738 int offset_x;
739 int offset_y;
740 int offset_z;
741 for (offset_x = -1; offset_x <= 2; offset_x += 3)
742 {
743 for (offset_y = 0; offset_y <= 1; ++offset_y)
744 {
745 for (offset_z = 0; offset_z <= 1; ++offset_z)
746 {
747 offset = float3(offset_x, offset_y, offset_z);
748 // along x axis
749 p = offset + VoronoiCornerSample(NoiseTileWrap(iv + offset, bTiling, RepeatSize), Quality);
750 mindist = VoronoiCompare(mindist, iv + p, fv - p, bDistanceOnly);
751
752 // along y axis
753 p = float3(offset.y, offset.z, offset.x) + VoronoiCornerSample(NoiseTileWrap(iv + float3(offset.y, offset.z, offset.x), bTiling, RepeatSize), Quality);
754 mindist = VoronoiCompare(mindist, iv + p, fv - p, bDistanceOnly);
755
756 // along z axis
757 p = float3(offset.z, offset.x, offset.y) + VoronoiCornerSample(NoiseTileWrap(iv + float3(offset.z, offset.x, offset.y), bTiling, RepeatSize), Quality);
758 mindist = VoronoiCompare(mindist, iv + p, fv - p, bDistanceOnly);
759 }
760 }
761 }
762 }
763
764 // transform squared distance to real distance
765 return float4(mindist.x, mindist.y, mindist.z, math::sqrt(mindist.w));
766}
767
768// Coordinates for corners of a Simplex tetrahedron
769// Based on McEwan et al., Efficient computation of noise in GLSL, JGT 2011
770// @param v = 3D noise argument
771// @return 4 corner locations
772float4x3 SimplexCorners(float3 v)
773{
774 // find base corner by skewing to tetrahedral space and back
775 float3 tet = math::floor(v + v.x/3 + v.y/3 + v.z/3);
776 float3 base = tet - tet.x/6 - tet.y/6 - tet.z/6;
777 float3 f = v - base;
778
779 // Find offsets to other corners (McEwan did this in tetrahedral space,
780 // but since skew is along x=y=z axis, this works in Euclidean space too.)
781 float3 g = math::step(float3(f.y,f.z,f.x), float3(f.x,f.y,f.z)), h = 1 - float3(g.z, g.x, g.y);
782 float3 a1 = math::min(g, h) - 1.0 / 6.0, a2 = math::max(g, h) - 1.0 / 3.0;
783
784 // four corners
785 return float4x3(base, base + a1, base + a2, base + 0.5);
786}
787
788// Improved smoothing function for simplex noise
789// @param f = fractional distance to four tetrahedral corners
790// @return weight for each corner
791float4 SimplexSmooth(float4x3 f)
792{
793 const float scale = 1024. / 375.; // scale factor to make noise -1..1
794 float4 d = float4(math::dot(f[0], f[0]), math::dot(f[1], f[1]), math::dot(f[2], f[2]), math::dot(f[3], f[3]));
795 float4 s = math::saturate(2 * d);
796 return (1 * scale + s*(-3 * scale + s*(3 * scale - s*scale)));
797}
798
799// Derivative of simplex noise smoothing function
800// @param f = fractional distanc eto four tetrahedral corners
801// @return derivative of smoothing function for each corner by x, y and z
802float3x4 SimplexDSmooth(float4x3 f)
803{
804 const float scale = 1024. / 375.; // scale factor to make noise -1..1
805 float4 d = float4(math::dot(f[0], f[0]), math::dot(f[1], f[1]), math::dot(f[2], f[2]), math::dot(f[3], f[3]));
806 float4 s = math::saturate(2 * d);
807 s = -12 * scale + s*(24 * scale - s * 12 * scale);
808
809 return float3x4(
810 s * float4(f[0][0], f[1][0], f[2][0], f[3][0]),
811 s * float4(f[0][1], f[1][1], f[2][1], f[3][1]),
812 s * float4(f[0][2], f[1][2], f[2][2], f[3][2]));
813}
814
815// Simplex noise and its Jacobian derivative
816// @param v = 3D noise argument
817// @param bTiling = whether to repeat noise pattern
818// @param RepeatSize = integer units before tiling in each dimension, must be a multiple of 3
819// @return float3x3 Jacobian in J[*].xyz, vector noise in J[*].w
820// J[0].w, J[1].w, J[2].w is a Perlin-style simplex noise with vector output, e.g. (Nx, Ny, Nz)
821// J[i].x is X derivative of the i'th component of the noise so J[2].x is dNz/dx
822// You can use this to compute the noise, gradient, curl, or divergence:
823// float3x4 J = JacobianSimplex_ALU(...);
824// float3 VNoise = float3(J[0].w, J[1].w, J[2].w); // 3D noise
825// float3 Grad = J[0].xyz; // gradient of J[0].w
826// float3 Curl = float3(J[1][2]-J[2][1], J[2][0]-J[0][2], J[0][1]-J[1][2]);
827// float Div = J[0][0]+J[1][1]+J[2][2];
828// All of these are confirmed to compile out all unneeded terms.
829// So Grad of X doesn't compute Y or Z components, and VNoise doesn't do any of the derivative computation.
830float3x4 JacobianSimplex_ALU(float3 v, bool bTiling, float RepeatSize)
831{
832 int3 MGradientMask = int3(0x8000, 0x4000, 0x2000);
833 float3 MGradientScale = float3(1. / 0x4000, 1. / 0x2000, 1. / 0x1000);
834
835 // corners of tetrahedron
836 float4x3 T = SimplexCorners(v);
837 // TODO: uint3
838 int3 rand = int3(0);
839 float4x3 gvec0 = float4x3(1.0);
840 float4x3 gvec1 = float4x3(1.0);
841 float4x3 gvec2 = float4x3(1.0);
842 float4x3 fv = float4x3(1.0);
843 float3x4 grad = float3x4(1.0);
844
845 // processing of tetrahedral vertices, unrolled
846 // to compute gradient at each corner
847 fv[0] = v - T[0];
848 rand = Rand3DPCG16(int3(math::floor(NoiseTileWrap(6 * T[0] + 0.5, bTiling, RepeatSize))));
849 gvec0[0] = float3(int3(rand.x,rand.x,rand.x) & MGradientMask) * MGradientScale - 1;
850 gvec1[0] = float3(int3(rand.y,rand.y,rand.y) & MGradientMask) * MGradientScale - 1;
851 gvec2[0] = float3(int3(rand.z,rand.z,rand.z) & MGradientMask) * MGradientScale - 1;
852 grad[0][0] = math::dot(gvec0[0], fv[0]);
853 grad[1][0] = math::dot(gvec1[0], fv[0]);
854 grad[2][0] = math::dot(gvec2[0], fv[0]);
855
856 fv[1] = v - T[1];
857 rand = Rand3DPCG16(int3(math::floor(NoiseTileWrap(6 * T[1] + 0.5, bTiling, RepeatSize))));
858 gvec0[1] = float3(int3(rand.x,rand.x,rand.x) & MGradientMask) * MGradientScale - 1;
859 gvec1[1] = float3(int3(rand.y,rand.y,rand.y) & MGradientMask) * MGradientScale - 1;
860 gvec1[1] = float3(int3(rand.z,rand.z,rand.z) & MGradientMask) * MGradientScale - 1;
861 grad[0][1] = math::dot(gvec0[1], fv[1]);
862 grad[1][1] = math::dot(gvec1[1], fv[1]);
863 grad[2][1] = math::dot(gvec2[1], fv[1]);
864
865 fv[2] = v - T[2];
866 rand = Rand3DPCG16(int3(math::floor(NoiseTileWrap(6 * T[2] + 0.5, bTiling, RepeatSize))));
867 gvec0[2] = float3(int3(rand.x,rand.x,rand.x) & MGradientMask) * MGradientScale - 1;
868 gvec1[2] = float3(int3(rand.y,rand.y,rand.y) & MGradientMask) * MGradientScale - 1;
869 gvec2[2] = float3(int3(rand.z,rand.z,rand.z) & MGradientMask) * MGradientScale - 1;
870 grad[0][2] = math::dot(gvec0[2], fv[2]);
871 grad[1][2] = math::dot(gvec1[2], fv[2]);
872 grad[2][2] = math::dot(gvec2[2], fv[2]);
873
874 fv[3] = v - T[3];
875 rand = Rand3DPCG16(int3(math::floor(NoiseTileWrap(6 * T[3] + 0.5, bTiling, RepeatSize))));
876 gvec0[3] = float3(int3(rand.x,rand.x,rand.x) & MGradientMask) * MGradientScale - 1;
877 gvec1[3] = float3(int3(rand.y,rand.y,rand.y) & MGradientMask) * MGradientScale - 1;
878 gvec2[3] = float3(int3(rand.z,rand.z,rand.z) & MGradientMask) * MGradientScale - 1;
879 grad[0][3] = math::dot(gvec0[3], fv[3]);
880 grad[1][3] = math::dot(gvec1[3], fv[3]);
881 grad[2][3] = math::dot(gvec2[3], fv[3]);
882
883 // blend gradients
884 float4 sv = SimplexSmooth(fv);
885 float3x4 ds = SimplexDSmooth(fv);
886
887 float3x4 jacobian = float3x4(1.0);
888 float3 vec0 = gvec0*sv + grad[0]*ds; // NOTE: mdl is column major, convert from UE4 (row major)
889 jacobian[0] = float4(vec0.x, vec0.y, vec0.z, math::dot(sv, grad[0]));
890 float3 vec1 = gvec1*sv + grad[1]*ds;
891 jacobian[1] = float4(vec1.x, vec1.y, vec1.z, math::dot(sv, grad[1]));
892 float3 vec2 = gvec2*sv + grad[2]*ds;
893 jacobian[2] = float4(vec2.x, vec2.y, vec2.z, math::dot(sv, grad[2]));
894
895 return jacobian;
896}
897
898// While RepeatSize is a float here, the expectation is that it would be largely integer values coming in from the UI. The downstream logic assumes
899// floats for all called functions (NoiseTileWrap) and this prevents any float-to-int conversion errors from automatic type conversion.
900float Noise3D_Multiplexer(uniform texture_2d PerlinNoiseGradientTexture, uniform texture_3d PerlinNoise3DTexture, int Function, float3 Position, int Quality, bool bTiling, float RepeatSize)
901{
902 // verified, HLSL compiled out the switch if Function is a constant
903 switch(Function)
904 {
905 case 0:
906 return SimplexNoise3D_TEX(PerlinNoiseGradientTexture, Position);
907 case 1:
908 return GradientNoise3D_TEX(PerlinNoiseGradientTexture, Position, bTiling, RepeatSize);
909 case 2:
910 return FastGradientPerlinNoise3D_TEX(PerlinNoise3DTexture, Position);
911 case 3:
912 return GradientNoise3D_ALU(Position, bTiling, RepeatSize);
913 case 4:
914 return ValueNoise3D_ALU(Position, bTiling, RepeatSize);
915 case 5:
916 return VoronoiNoise3D_ALU(Position, Quality, bTiling, RepeatSize, true).w * 2.0 - 1.0;
917 }
918 return 0;
919}
920//----------------------------------------------------------
921
922export float noise(uniform texture_2d PerlinNoiseGradientTexture, uniform texture_3d PerlinNoise3DTexture, float3 Position, float Scale, float Quality, float Function, float Turbulence, float Levels, float OutputMin, float OutputMax, float LevelScale, float FilterWidth, float Tiling, float RepeatSize)
923[[
924 anno::description("Noise"),
925 anno::noinline()
926]]
927{
928 Position *= Scale;
929 FilterWidth *= Scale;
930
931 float Out = 0.0f;
932 float OutScale = 1.0f;
933 float InvLevelScale = 1.0f / LevelScale;
934
935 int iFunction(Function);
936 int iQuality(Quality);
937 int iLevels(Levels);
938 bool bTurbulence(Turbulence);
939 bool bTiling(Tiling);
940
941 for(int i = 0; i < iLevels; ++i)
942 {
943 // fade out noise level that are too high frequent (not done through dynamic branching as it usually requires gradient instructions)
944 OutScale *= math::saturate(1.0 - FilterWidth);
945
946 if(bTurbulence)
947 {
948 Out += math::abs(Noise3D_Multiplexer(PerlinNoiseGradientTexture, PerlinNoise3DTexture, iFunction, Position, iQuality, bTiling, RepeatSize)) * OutScale;
949 }
950 else
951 {
952 Out += Noise3D_Multiplexer(PerlinNoiseGradientTexture, PerlinNoise3DTexture, iFunction, Position, iQuality, bTiling, RepeatSize) * OutScale;
953 }
954
955 Position *= LevelScale;
956 RepeatSize *= LevelScale;
957 OutScale *= InvLevelScale;
958 FilterWidth *= LevelScale;
959 }
960
961 if(!bTurbulence)
962 {
963 // bring -1..1 to 0..1 range
964 Out = Out * 0.5f + 0.5f;
965 }
966
967 // Out is in 0..1 range
968 return math::lerp(OutputMin, OutputMax, Out);
969}
970
971// Material node for noise functions returning a vector value
972// @param LevelScale usually 2 but higher values allow efficient use of few levels
973// @return in user defined range (OutputMin..OutputMax)
974export float4 vector4_noise(float3 Position, float Quality, float Function, float Tiling, float TileSize)
975[[
976 anno::description("Vector Noise"),
977 anno::noinline()
978]]
979{
980 float4 result = float4(0,0,0,1);
981 float3 ret = float3(0);
982 int iQuality = int(Quality);
983 int iFunction = int(Function);
984 bool bTiling = Tiling > 0.0;
985
986 float3x4 Jacobian = JacobianSimplex_ALU(Position, bTiling, TileSize); // compiled out if not used
987
988 // verified, HLSL compiled out the switch if Function is a constant
989 switch (iFunction)
990 {
991 case 0: // Cellnoise
992 ret = float3(Rand3DPCG16(int3(math::floor(NoiseTileWrap(Position, bTiling, TileSize))))) / 0xffff;
993 result = float4(ret.x, ret.y, ret.z, 1);
994 break;
995 case 1: // Color noise
996 ret = float3(Jacobian[0].w, Jacobian[1].w, Jacobian[2].w);
997 result = float4(ret.x, ret.y, ret.z, 1);
998 break;
999 case 2: // Gradient
1000 result = Jacobian[0];
1001 break;
1002 case 3: // Curl
1003 ret = float3(Jacobian[2][1] - Jacobian[1][2], Jacobian[0][2] - Jacobian[2][0], Jacobian[1][0] - Jacobian[0][1]);
1004 result = float4(ret.x, ret.y, ret.z, 1);
1005 break;
1006 case 4: // Voronoi
1007 result = VoronoiNoise3D_ALU(Position, iQuality, bTiling, TileSize, false);
1008 break;
1009 }
1010 return result;
1011}
1012
1013export float3 vector3_noise(float3 Position, float Quality, float Function, float Tiling, float TileSize)
1014[[
1015 anno::description("Vector Noise float3 version"),
1016 anno::noinline()
1017]]
1018{
1019 float4 noise = vector4_noise(Position, Quality, Function, Tiling, TileSize);
1020 return float3(noise.x, noise.y, noise.z);
1021}
1022
1023
1024// workaround for ue4 fresnel (without supporting for camera vector) : replacing it with 0.0, means facing to the view
1025export float fresnel(float exponent [[anno::unused()]], float base_reflect_fraction [[anno::unused()]], float3 normal [[anno::unused()]])
1026[[
1027 anno::description("Fresnel"),
1028 anno::noinline()
1029]]
1030{
1031 return 0.0;
1032}
1033
1034export float fresnel_function(float3 normal_vector [[anno::unused()]], float3 camera_vector [[anno::unused()]],
1035 bool invert_fresnel [[anno::unused()]], float power [[anno::unused()]],
1036 bool use_cheap_contrast [[anno::unused()]], float cheap_contrast_dark [[anno::unused()]], float cheap_contrast_bright [[anno::unused()]],
1037 bool clamp_fresnel_dot_product [[anno::unused()]])
1038[[
1039 anno::description("Fresnel Function"),
1040 anno::noinline()
1041]]
1042{
1043 return 0.0;
1044}
1045
1046export float3 camera_vector()
1047[[
1048 anno::description("Camera Vector"),
1049 anno::noinline()
1050]]
1051{
1052 // assume camera postion is 0,0,0
1053 return math::normalize(float3(0) - state::transform_point(state::coordinate_internal,state::coordinate_world,state::position()));
1054}
1055
1056export float pixel_depth()
1057[[
1058 anno::description("Pixel Depth"),
1059 anno::noinline()
1060]]
1061{
1062 return 256.0f;
1063}
1064
1065export float scene_depth()
1066[[
1067 anno::description("Scene Depth")
1068]]
1069{
1070 return 65500.0f;
1071}
1072
1073export float3 scene_color()
1074[[
1075 anno::description("Scene Color")
1076]]
1077{
1078 return float3(1.0f);
1079}
1080
1081export float4 vertex_color()
1082[[
1083 anno::description("Vertex Color"),
1084 anno::noinline()
1085]]
1086{
1087 return float4(1.0f);
1088}
1089
1090export float4 vertex_color_from_coordinate(int VertexColorCoordinateIndex)
1091[[
1092 anno::description("Vertex Color for float2 PrimVar"),
1093 anno::noinline()
1094]]
1095{
1096 // Kit only supports 4 uv sets, 2 uvs are available to vertex color. if vertex color index is invalid, output the constant WHITE color intead
1097 return (VertexColorCoordinateIndex > 2) ? float4(1.0f) : float4(state::texture_coordinate(VertexColorCoordinateIndex).x, state::texture_coordinate(VertexColorCoordinateIndex).y, state::texture_coordinate(VertexColorCoordinateIndex+1).x, state::texture_coordinate(VertexColorCoordinateIndex+1).y);
1098}
1099
1100export float3 camera_position()
1101[[
1102 anno::description("Camera Position"),
1103 anno::noinline()
1104]]
1105{
1106 return float3(1000.0f, 0, 0);
1107}
1108
1109export float3 rotate_about_axis(float4 NormalizedRotationAxisAndAngle, float3 PositionOnAxis, float3 Position)
1110[[
1111 anno::description("Rotates Position about the given axis by the given angle")
1112]]
1113{
1114 // Project Position onto the rotation axis and find the closest point on the axis to Position
1115 float3 NormalizedRotationAxis = float3(NormalizedRotationAxisAndAngle.x,NormalizedRotationAxisAndAngle.y,NormalizedRotationAxisAndAngle.z);
1116 float3 ClosestPointOnAxis = PositionOnAxis + NormalizedRotationAxis * math::dot(NormalizedRotationAxis, Position - PositionOnAxis);
1117 // Construct orthogonal axes in the plane of the rotation
1118 float3 UAxis = Position - ClosestPointOnAxis;
1119 float3 VAxis = math::cross(NormalizedRotationAxis, UAxis);
1120 float[2] SinCosAngle = math::sincos(NormalizedRotationAxisAndAngle.w);
1121 // Rotate using the orthogonal axes
1122 float3 R = UAxis * SinCosAngle[1] + VAxis * SinCosAngle[0];
1123 // Reconstruct the rotated world space position
1124 float3 RotatedPosition = ClosestPointOnAxis + R;
1125 // Convert from position to a position offset
1126 return RotatedPosition - Position;
1127}
1128
1129export float2 rotate_scale_offset_texcoords(float2 InTexCoords, float4 InRotationScale, float2 InOffset)
1130[[
1131 anno::description("Returns a float2 texture coordinate after 2x2 transform and offset applied")
1132]]
1133{
1134 return float2(math::dot(InTexCoords, float2(InRotationScale.x, InRotationScale.y)), math::dot(InTexCoords, float2(InRotationScale.z, InRotationScale.w))) + InOffset;
1135}
1136
1137export float3 reflection_custom_world_normal(float3 WorldNormal, bool bNormalizeInputNormal)
1138[[
1139 anno::description("Reflection vector about the specified world space normal")
1140]]
1141{
1142 if (bNormalizeInputNormal)
1143 {
1144 WorldNormal = math::normalize(WorldNormal);
1145 }
1146
1147 return -camera_vector() + WorldNormal * math::dot(WorldNormal, camera_vector()) * 2.0;
1148}
1149
1150export float3 reflection_vector()
1151[[
1152 anno::description("Reflection Vector"),
1153 anno::noinline()
1154]]
1155{
1156 float3 normal = state::transform_normal(state::coordinate_internal,state::coordinate_world,state::normal());
1157 return reflection_custom_world_normal(normal, false);
1158}
1159
1160export float dither_temporalAA(float AlphaThreshold = 0.5f, float Random = 1.0f [[anno::unused()]])
1161[[
1162 anno::description("Dither TemporalAA"),
1163 anno::noinline()
1164]]
1165{
1166 return AlphaThreshold;
1167}
1168
1169 