Team Ai
Datasetpublic

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.

sourceHugging Faceotherupdated 29d agoView on Hugging Face
0likes3.7kdownloads
OmniUe4Function.mdl1169 linesDownload Raw Back to materials
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 
AVSim/simulation-package · Team Ai