
// Randomly place (and alpha-blend) bitmap on top of something else// RamdomBitmap.osl by Zap Andersson)// Modified: 2019-11-26// Modified: 2021-03-26 by Saul Espinosa for Redshift 3D// Copyright 2019 Autodesk Inc, All rights reserved. This file is licensed under Apache 2.0 license// https://github.com/ADN-DevTech/3dsMax-OSL-Shaders/blob/master/LICENSE.txtcolor TextureFetch(string filename, point lp, output float a){ color rgb = texture(filename, lp[0], 1.0-lp[1], "alpha", a, "wrap", "clamp"); int channels = 3; gettextureinfo(filename, "channels", channels); if (channels <= 3) // If there is no alpha... a = 1.0; // ...use 1.0 return rgb;}shader RandomBitmaps[[ string help = "Randomly place (and alpha blend) a set of<br>bitmaps on top of something else", string version = "2.0.0", string label = "Randomized Bitmaps", string page = "0 : General" ]]( int Layers = 1 [[ int min=1, int max=9, int connectable=0, string page = "0 : General" ]], vector UVW = vector(u,v,0) [[string page = "3 : Other"]], float Scale = 1.0 [[ float min = 0, float max = 2, string label = "Overall Scale", string page = "0 : General" ]], color Input = 0.0 [[ string label = "Background RGB", string page = "0 : General", string help="The input color on top of which everything else is put. Thia allows cascading multiple RandomBitmap on top of each other easily..." ]], float InputAlpha = 1.0 [[ float min = 0, float max = 1.0, string label = "Background Alpha", string page = "0 : General", string help="The input alpha on top of which everything else is put. Thia allows cascading multiple RandomBitmap on top of each other easily..." ]], #define LAYER(x) \ string Filename##x = "" \ [[ string widget="filename", \ string label="File name " #x, \ string help="The name of the bitmap to place randomly", string page = "1 : Textures" ]], LAYER(0) //====LAYER-BEGIN==== LAYER(1) LAYER(2) LAYER(3) LAYER(4) LAYER(5) LAYER(6) LAYER(7) LAYER(8) LAYER(9) //====LAYER-END==== #undef LAYER int NumFiles = 0 [[ string label = "Limit to N Files", string help = "By default, all files are used, but for testing purpouses, " "one can choose to only use a few of them by setting this " "value greater than zero.", int min = 0, int max = 10, string page = "0 : General" ]], int Seed = 39 [[ string help="The random seed", string page = "2 : Randomization", int min = 0, int max = 100 ]], vector Probability = vector(1.0, 0.0, 0.1) [[ string help="Three values: The probability a bitmap will show up, the randomness of the variation in the probability, and the scale of said randomness", float min = 0.0, float max = 1.0, string page = "2 : Randomization" ]], vector PosRandom = vector(0.5,0.5,0.0) [[ string page = "2 : Randomization", string help="Position randomness. For large numbers you may have to turn Overlap up, but impacts performance! Note: the Z value is not used." ]], vector ScaleMin = vector(1.0, 1.0, 0.0) [[ string help="The scale randomness. For large scales you may have to turn Overlap up, but impacts performance! Note: the Z value is not used." , float min = 0.0, float max = 10.0, string page = "2 : Randomization" ]], vector ScaleMax = vector(1.0, 1.0, 0.0) [[ string help="The scale randomness. For large scales you may have to turn Overlap up, but impacts performance! Note: the Z value is not used." , float min = 0.0, float max = 10.0, string page = "2 : Randomization" ]], int UniformScale = 1 [[ string widget="checkBox", string help="If enabled, U and V scales in sync with each other, if off, they scale independently", string label = "Randomize Scale Proportionally", string page = "2 : Randomization" ]], float PixelScale = 0.0 [[ float min = 0, float max = 8192, float sensitivity = 1, string page = "2 : Randomization", string help="Relates pixels to image size.<ul><li>If zero, each image is considered to be a 1.0 x 1.0 square in UV space.<li>If nonzero, maps that many pixels to a the size of 1.0, so that images are the same size w.r.t. to pixels <i>and</i> retains their aspect ratio.<br/><b>NOTE</b>: Sizes ending up larger than 1.0 will require turning up Overlap, which reduces performance!</li></ul>" ]], float RotMin = 0.0 [[ string help="The Rotational randomness." , float min = -180, float max = 0, string page = "2 : Randomization", float sensitivity = 1 ]], float RotMax = 0.0 [[ string help="The Rotational randomness." , float min = 0, float max = 180, string page = "2 : Randomization", float sensitivity = 1 ]], int RotSteps = 1 [[ string help="Number of 'steps' of Rotational randomness. 1 means 'no steps'.<br><br>For example, to rotate something only 0, 90, 180 and 270 degrees, set min rotation to 0, max rotation to 270, and RotSteps to 4." , int min = 1, int max = 10, string page = "2 : Randomization" ]], vector HSVMin = vector(0.0, 1.0, 1.0) [[ string help="Hue/Saturation/Value randomness. Start range of hue shift and saturation/value scaling" , float min = -2.0, float max = 2.0, string page = "2 : Randomization" ]], vector HSVMax = vector(0.0, 1.0, 1.0) [[ string help="Hue/Saturation/Value randomness. End range of hue shift and saturation/value scaling" , float min = -2.0, float max = 2.0, string page = "2 : Randomization" ]], float AlphaMin = 1.0 [[ string help="The Alpha randomness. Minimum multiplier of alpha." , float min = 0.0, float max = 1.0, string page = "2 : Randomization" ]], float AlphaMax = 1.0 [[ string help="The Alpha randomness. Maximum multiplier of alpha." , float min = 0.0, float max = 1.0, string page = "2 : Randomization" ]], float GammaMin = 0.0 [[ string help="The Gamma randomness. Minimum offset of gamma value." , float min = -5.0, float max = 5.0, string page = "2 : Randomization" ]], float GammaMax = 0.0 [[ string help="The Gamma randomness. Maximum offset of gamma value." , float min = -5.0, float max = 5.0, string page = "2 : Randomization" ]], int Clamp = 1 [[ string widget = "checkBox", string page = "3 : Other", string help = "Large color tweaks can yield colors outside of the 0-1 range. It's a good idea to clamp those colors to the 0-1 range..." ]], float ManualGamma = 2.2 [[ string label="Manual Gamma", string page = "3 : Other" ]], int OverLap = 1 [[ string help="For very large scales or position shifts, you may see cut-off textures. This means the shader may need to look further into more neighbouring cells. Increasing this reduces performance A LOT so ONLY do this if absolutely necessary!", int min=0, int max=5, string page = "3 : Other" ]], output color Out = 0.0, output float Alpha = 1.0,){ // Adjust behaviour based on version int oslversion = 0; getattribute("osl:version", oslversion); point UVWs = UVW / Scale; int ix = int(floor(UVWs[0])); int iy = int(floor(UVWs[1])); float fx = UVWs[0] - ix; float fy = UVWs[1] - iy; float gamma = 1.0; gamma = ManualGamma; // Start with the output being the input Out = Input; Alpha = InputAlpha; // The modulo value is number of layers+1 int modValue = Layers+1; // Has the user chosen to limit number of files? if (NumFiles > 0 && NumFiles <= Layers) modValue = NumFiles; for (int xx = -OverLap; xx <= OverLap; xx++) { for(int yy = -OverLap; yy <= OverLap; yy++) { // The point used for all the randomness point rndpoint = point(ix + xx, iy + yy, Seed); // Compensate for old cellnoise behaviour if (oslversion >= 11000) { rndpoint[0] = rndpoint[0] < 0 ? rndpoint[0]-1: rndpoint[0]; rndpoint[1] = rndpoint[1] < 0 ? rndpoint[1]-1: rndpoint[1]; rndpoint[2] = rndpoint[2] < 0 ? rndpoint[2]-1: rndpoint[2]; } // Random pos data point pos = ((noise("cell", rndpoint, 0) - vector(0.5,0.5,0.0)) * vector(PosRandom[0], PosRandom[1], 1.0)); // The actual lookup point point lp = point(fx-xx, fy-yy, 0) - pos; float prob = Probability[0] + noise("perlin", rndpoint * Probability[2]) * Probability[1]; if (pos[2] < prob) { // Scale and rotation randomness point scr = noise("cell", rndpoint, 1); int pic = int((float)noise("cell", rndpoint, 15) * 100) % modValue; // XY scaling tweak float sx = 1.0, sy = 1.0; if (PixelScale > 0.0) { int res[2]; if (pic == 0) gettextureinfo(Filename0, "resolution", res); #define LAYER(x) else if (pic == x) gettextureinfo(Filename##x, "resolution", res); //====LAYER-BEGIN==== LAYER(0) LAYER(1) LAYER(2) LAYER(3) LAYER(4) LAYER(5) LAYER(6) LAYER(7) LAYER(8) LAYER(9) //====LAYER-END==== #undef LAYER sx = res[0] / PixelScale; sy = res[1] / PixelScale; } float scaleX = sx * mix(ScaleMin[0], ScaleMax[0], scr[0]); float scaleY = sy * mix(ScaleMin[1], ScaleMax[1], scr[UniformScale?0:1]); if (RotSteps > 1) { scr[2] = floor(scr[2] * RotSteps) / (RotSteps - 1); } float rot = mix(RotMin, RotMax, scr[2]); lp -= 0.5; lp = rotate(lp, radians(rot), point(0,0,0), vector(0,0,1)); lp /= vector(scaleX, scaleY, 1.0); lp += 0.5; if (lp[0] >= 0.0 && lp[0] < 1.0 && lp[1] >= 0.0 && lp[1] < 1.0) { color rgb; float a = 1.0; if (pic == 0) rgb = TextureFetch(Filename0, lp, a); #define LAYER(x) else if (pic == x) rgb = TextureFetch(Filename##x, lp, a); //====LAYER-BEGIN==== LAYER(0) LAYER(1) LAYER(2) LAYER(3) LAYER(4) LAYER(5) LAYER(6) LAYER(7) LAYER(8) LAYER(9) //====LAYER-END==== #undef LAYER if (a > 0.0) { // Color randomness point clr = noise("cell", rndpoint, 2); // Alpha and Gamma randomness point arr = noise("cell", rndpoint, 3); float gr = mix(GammaMin, GammaMax, arr[1]); if (gamma + gr != 1.0) rgb = pow(rgb, gamma + gr); vector hsvTweak = mix(HSVMin, HSVMax, clr); float ar = mix(AlphaMin, AlphaMax, arr[0]); color hsv = transformc("rgb", "hsv", rgb); hsv[0] += hsvTweak[0]; // Offset the hue hsv[1] *= hsvTweak[1]; // Scale the saturation hsv[2] *= hsvTweak[2]; // Scale the value rgb = transformc("hsv", "rgb", hsv); // Apply alpha randomness rgb *= ar; a *= ar; if (Clamp) rgb = clamp(rgb, 0.0, 1.0); } Alpha = 1.0 - ((1.0-Alpha)*(1.0-a)); Out = Out * (1.0-a) + rgb; } } } } }