Scratches - 图1

    1. // Micro Scratched Texture
    2. //
    3. // Author: John Su <cuckons@gmail.com>
    4. // Changes by Michael Abrahams <miabraha@gmail.com>
    5. // Last Modified 1/11/2021 for Redshift 3D + Metadata & Triplaner
    6. // An OSL shader that generates texture to make swirly micro scratch look by
    7. // controlling the anistropy and roughness.
    8. // The original idea is from Hang Li(悬挂鲤) and Ben Paschke. Here I implemented
    9. // it using OSL and exposured some arts friendly parameters.
    10. float AxisMask(point axis, float power)
    11. {
    12. return pow(abs(dot(N, axis)), power);
    13. }
    14. float lineDistance(point p, float direction){
    15. float theta = direction * M_2PI;
    16. float s = 0, c = 1;
    17. sincos(theta, s, c);
    18. vector v = vector(c,s,0);
    19. float distance = length(p - (v * dot(v, p)));
    20. return distance;
    21. }
    22. void generateScratchPlane(point shading_p,
    23. int max_search_cell,
    24. point index,
    25. int seed,
    26. float delta,
    27. float hardScratches,
    28. float roughness_default,
    29. float roughness_min,
    30. float roughness_max,
    31. float anisotropic_min,
    32. float anisotropic_max,
    33. float scratchWidth,
    34. output float roughness, output float anisotropy, output float rotation, output float scratch)
    35. {
    36. for (int x = -max_search_cell; x <= max_search_cell; ++x){
    37. for (int y = -max_search_cell; y <= max_search_cell; ++y){
    38. // Distance from line in neighbor cell
    39. point line_cell_index = index + point(x, y, 0);
    40. point scratch_origin_p = (line_cell_index + (hashnoise(line_cell_index + seed + .8) - 0.5)) * delta;
    41. rotation = hashnoise(line_cell_index + seed + .88);
    42. float dist = lineDistance(scratch_origin_p - shading_p, rotation);
    43. // Randomize width
    44. float width = scratchWidth * hashnoise(line_cell_index + seed + .888) / 2048;
    45. // hard = 0-1 step function; soft = linear gradient
    46. if (hardScratches) {
    47. scratch = 1 - step(width, dist);
    48. }
    49. else {
    50. scratch = 1 - min(dist / width, 1);
    51. }
    52. if (scratch)
    53. {
    54. roughness = select(
    55. roughness_default,
    56. mix(roughness_min, roughness_max, hashnoise(line_cell_index + seed + .8888)),
    57. scratch > 0
    58. );
    59. anisotropy = select(
    60. 0,
    61. mix(anisotropic_min, anisotropic_max, hashnoise(line_cell_index + seed + .88888)),
    62. scratch > 0
    63. );
    64. rotation *= scratch;
    65. return;
    66. }
    67. }
    68. }
    69. }
    70. shader Scratches
    71. [[ string help = "Procedural Scratches",
    72. string label = "Scratches" ]]
    73. (
    74. float density=10
    75. [[string label="Density",
    76. string widget="number",
    77. float min=1,
    78. float max=50]],
    79. float scale=5
    80. [[string label="Scale",
    81. string widget="number",
    82. float min=.01,
    83. float max=100]],
    84. float scratchLength=10
    85. [[string label="Scratch Length",
    86. string widget="number",
    87. float min=0,
    88. float max=10]],
    89. float scratchWidth=1
    90. [[string label="Scratch Width",
    91. string widget="number",
    92. float min=0,
    93. float max=10]],
    94. int hardScratches=1
    95. [[string label="Hard scratches",
    96. string widget="checkBox"]],
    97. float roughness_default = 0.0
    98. [[string label="Default Roughness",
    99. string widget="number",
    100. float min=0,
    101. float max=1]],
    102. float roughness_min=0.1
    103. [[string label="Minimum Roughness",
    104. string widget="number",
    105. float min=0,
    106. float max=1]],
    107. float roughness_max=0.2
    108. [[string label="Maximum Roughness",
    109. string widget="number",
    110. float min=0,
    111. float max=1]],
    112. float anisotropic_min = 0.0
    113. [[string label="Minimum Anisotropy",
    114. string widget="number",
    115. float min=0,
    116. float max=1]],
    117. float anisotropic_max = 0.2
    118. [[string label="Maximum Anisotropy",
    119. string widget="number",
    120. float min=0,
    121. float max=1]],
    122. float blendPower = 1,
    123. int seed=12345
    124. [[string label="Random Seed",
    125. string widget="number",
    126. int min=0,
    127. int max=99999]],
    128. output float roughness = 0 + roughness_default,
    129. output float anisotropy = 0,
    130. output float rotation = 0,
    131. output float scratch = 0
    132. ){
    133. // Divides texture space into a grid
    134. // Each cell contains a scratch that will be offset by a hash noise.
    135. // "density" and "scale" both effectively scale the shader,
    136. // but density preserves scratch length.
    137. float delta = 1/max(density * density * scale, .1);
    138. int max_search_cell = (int)ceil(scratchLength);
    139. //XY
    140. point xy = point(P[0], P[1], 0)*scale;
    141. point xyIndex = point(round(scale * P[0]/delta), round(scale * P[1]/delta), 0.0);
    142. float xyPlaneRoughness = 0;
    143. float xyPlaneAnisotropy = 0;
    144. float xyPlaneRotation = 0;
    145. float xyPlaneScratch = 0;
    146. generateScratchPlane(xy, max_search_cell, xyIndex, seed, delta, hardScratches, roughness_default, roughness_min, roughness_max, anisotropic_min, anisotropic_max, scratchWidth, xyPlaneRoughness, xyPlaneAnisotropy, xyPlaneRotation, xyPlaneScratch);
    147. //XZ
    148. point xz = point(P[0], P[2], 0)*scale;
    149. point xzIndex = point(round(scale * P[0]/delta), round(scale * P[2]/delta), 0.0);
    150. float xzPlaneRoughness = 0;
    151. float xzPlaneAnisotropy = 0;
    152. float xzPlaneRotation = 0;
    153. float xzPlaneScratch = 0;
    154. generateScratchPlane(xz, max_search_cell, xzIndex, seed + 1, delta, hardScratches, roughness_default, roughness_min, roughness_max, anisotropic_min, anisotropic_max, scratchWidth, xzPlaneRoughness, xzPlaneAnisotropy, xzPlaneRotation, xzPlaneScratch);
    155. //YZ
    156. point yz = point(P[1], P[2], 0)*scale;
    157. point yzIndex = point(round(scale * P[1]/delta), round(scale * P[2]/delta), 0.0);
    158. float yzPlaneRoughness = 0;
    159. float yzPlaneAnisotropy = 0;
    160. float yzPlaneRotation = 0;
    161. float yzPlaneScratch = 0;
    162. generateScratchPlane(yz, max_search_cell, yzIndex, seed + 2, delta, hardScratches, roughness_default, roughness_min, roughness_max, anisotropic_min, anisotropic_max, scratchWidth, yzPlaneRoughness, yzPlaneAnisotropy, yzPlaneRotation, yzPlaneScratch);
    163. roughness = mix(xyPlaneRoughness, xzPlaneRoughness, AxisMask(point(0,1,0), blendPower));
    164. anisotropy = mix(xyPlaneAnisotropy, xzPlaneAnisotropy, AxisMask(point(0,1,0), blendPower));
    165. rotation = mix(xyPlaneRotation, xzPlaneRotation, AxisMask(point(0,1,0), blendPower));
    166. scratch = mix(xyPlaneScratch, xzPlaneScratch, AxisMask(point(0,1,0), blendPower));
    167. roughness = mix(roughness, yzPlaneRoughness, AxisMask(point(1,0,0), blendPower));
    168. anisotropy = mix(anisotropy, yzPlaneAnisotropy, AxisMask(point(1,0,0), blendPower));
    169. rotation = mix(rotation, yzPlaneRotation, AxisMask(point(1,0,0), blendPower));
    170. scratch = mix(scratch, yzPlaneScratch, AxisMask(point(1,0,0), blendPower));
    171. }