Remove Improved Perlin Noise

Is not used by a major client and can be implemented using runtime
effects for users who want this noise.

Bug: skia:10536
Change-Id: Iaa06e6e1406b808c7f8dc0f76621fecf2becabf5
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/352057
Reviewed-by: Brian Osman <brianosman@google.com>
Reviewed-by: Kevin Lubick <kjlubick@google.com>
Commit-Queue: Brian Salomon <bsalomon@google.com>
This commit is contained in:
Brian Salomon 2021-01-08 18:11:33 -05:00 committed by Skia Commit-Bot
parent 70fa84a9bf
commit 4878b3e33c
14 changed files with 16 additions and 707 deletions

View File

@ -6,6 +6,9 @@ This file includes a list of high level updates for each milestone release.
Milestone 89
------------
* Removed SkPerlinNoiseShader::MakeImprovedNoise.
https://review.skia.org/352057
* Removed deperated version of MakeFromYUVATextures. Use the version
that takes GrYUVABackendTextures instead.
https://review.skia.org/345174

View File

@ -25,7 +25,6 @@ namespace {
enum class Type {
kFractalNoise,
kTurbulence,
kImproved,
};
class PerlinNoiseGM : public skiagm::GM {
@ -35,7 +34,7 @@ class PerlinNoiseGM : public skiagm::GM {
SkString onShortName() override { return SkString("perlinnoise"); }
SkISize onISize() override { return {200, 600}; }
SkISize onISize() override { return {200, 500}; }
void drawRect(SkCanvas* canvas, int x, int y, const SkPaint& paint, const SkISize& size) {
canvas->save();
@ -47,7 +46,7 @@ class PerlinNoiseGM : public skiagm::GM {
}
void test(SkCanvas* canvas, int x, int y, Type type,
float baseFrequencyX, float baseFrequencyY, int numOctaves, float seedOrZ,
float baseFrequencyX, float baseFrequencyY, int numOctaves, float seed,
bool stitchTiles) {
SkISize tileSize = SkISize::Make(fSize.width() / 2, fSize.height() / 2);
sk_sp<SkShader> shader;
@ -56,23 +55,16 @@ class PerlinNoiseGM : public skiagm::GM {
shader = SkPerlinNoiseShader::MakeFractalNoise(baseFrequencyX,
baseFrequencyY,
numOctaves,
seedOrZ,
seed,
stitchTiles ? &tileSize : nullptr);
break;
case Type::kTurbulence:
shader = SkPerlinNoiseShader::MakeTurbulence(baseFrequencyX,
baseFrequencyY,
numOctaves,
seedOrZ,
seed,
stitchTiles ? &tileSize : nullptr);
break;
case Type::kImproved:
SkASSERT(!stitchTiles);
shader = SkPerlinNoiseShader::MakeImprovedNoise(baseFrequencyX,
baseFrequencyY,
numOctaves,
seedOrZ);
break;
}
SkPaint paint;
paint.setShader(std::move(shader));
@ -111,16 +103,11 @@ class PerlinNoiseGM : public skiagm::GM {
test(canvas, 100, 300, Type::kFractalNoise,
0.1f, 0.1f, 3, 4, false);
test(canvas, 0, 400, Type::kImproved,
0.0125f, 0.0125f, 4, 0, false);
test(canvas, 100, 400, Type::kImproved,
0.125f, 0.0075f, 2, 0, false);
canvas->scale(0.75f, 1.0f);
test(canvas, 0, 500, Type::kFractalNoise,
test(canvas, 0, 400, Type::kFractalNoise,
0.1f, 0.1f, 2, 0, false);
test(canvas, 100, 500, Type::kFractalNoise,
test(canvas, 100, 400, Type::kFractalNoise,
0.1f, 0.05f, 1, 0, true);
}

View File

@ -7,7 +7,6 @@
_samplecode = get_path_info("../samplecode", "abspath")
samples_sources = [
"$_samplecode/PerlinPatch.cpp",
"$_samplecode/Sample.cpp",
"$_samplecode/Sample.h",
"$_samplecode/Sample2PtRadial.cpp",

View File

@ -44,12 +44,6 @@ public:
static sk_sp<SkShader> MakeTurbulence(SkScalar baseFrequencyX, SkScalar baseFrequencyY,
int numOctaves, SkScalar seed,
const SkISize* tileSize = nullptr);
/**
* Creates an Improved Perlin Noise shader. The z value is roughly equivalent to the seed of the
* other two types, but minor variations to z will only slightly change the noise.
*/
static sk_sp<SkShader> MakeImprovedNoise(SkScalar baseFrequencyX, SkScalar baseFrequencyY,
int numOctaves, SkScalar z);
static void RegisterFlattenables();

View File

@ -9,6 +9,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### Added
- Constants for the shadow flags. Of note, some of these values can be used on previous releases.
### Breaking
- `MakeImprovedNoise` is removed.
### Fixed
- Improper error returned when a WebGL context could not be used.

View File

@ -782,7 +782,6 @@ function shaderTests(CK: CanvasKit) {
);
const s12 = CK.Shader.MakeFractalNoise(0.1, 0.05, 2, 0, 80, 80); // $ExpectType Shader
const s13 = CK.Shader.MakeTurbulence(0.1, 0.05, 2, 0, 80, 80); // $ExpectType Shader
const s14 = CK.Shader.MakeImprovedNoise(0.1, 0.05, 2, 0); // $ExpectType Shader
}
function shapedTextTests(CK: CanvasKit, textFont?: Font) {

View File

@ -3135,16 +3135,6 @@ export interface ShaderFactory {
MakeFractalNoise(baseFreqX: number, baseFreqY: number, octaves: number, seed: number,
tileW: number, tileH: number): Shader;
/**
* Returns a shader with Improved Perlin Noise.
* See SkPerlinNoiseShader.h for more details
* @param baseFreqX - base frequency in the X direction; range [0.0, 1.0]
* @param baseFreqY - base frequency in the Y direction; range [0.0, 1.0]
* @param octaves
* @param z - like seed, but minor variations to z will only slightly change the noise.
*/
MakeImprovedNoise(baseFreqX: number, baseFreqY: number, octaves: number, z: number): Shader;
/**
* Returns a shader is a linear interpolation combines the given shaders with a BlendMode.
* @param t - range of [0.0, 1.0], indicating how far we should be between one and two.

View File

@ -1555,7 +1555,6 @@ EMSCRIPTEN_BINDINGS(Skia) {
return SkPerlinNoiseShader::MakeFractalNoise(baseFreqX, baseFreqY,
numOctaves, seed, &tileSize);
}))
.class_function("MakeImprovedNoise", &SkPerlinNoiseShader::MakeImprovedNoise)
// Here and in other gradient functions, cPtr is a pointer to an array of data
// representing colors. whether this is an array of SkColor or SkColor4f is indicated
// by the colorType argument. Only RGBA_8888 and RGBA_F32 are accepted.

View File

@ -625,7 +625,6 @@ var CanvasKit = {
MakeBlend: function() {},
MakeColor: function() {},
MakeFractalNoise: function() {},
MakeImprovedNoise: function() {},
MakeLerp: function() {},
MakeLinearGradient: function() {},
MakeRadialGradient: function() {},

View File

@ -978,16 +978,6 @@ describe('Core canvas behavior', () => {
shader.delete();
});
gm('improved_noise_shader', (canvas) => {
const shader = CanvasKit.Shader.MakeImprovedNoise(0.1, 0.05, 2, 10);
const paint = new CanvasKit.Paint();
paint.setColor(CanvasKit.BLACK);
paint.setShader(shader);
canvas.drawPaint(paint);
paint.delete();
shader.delete();
});
describe('ColorSpace Support', () => {
it('Can create an SRGB 8888 surface', () => {
const colorSpace = CanvasKit.ColorSpace.SRGB;

View File

@ -1,209 +0,0 @@
/*
* Copyright 2015 Google Inc.
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#include "include/core/SkCanvas.h"
#include "include/effects/SkGradientShader.h"
#include "include/effects/SkPerlinNoiseShader.h"
#include "samplecode/Sample.h"
#include "src/utils/SkPatchUtils.h"
#include "tools/skui/ModifierKey.h"
static void draw_control_points(SkCanvas* canvas, const SkPoint cubics[12]) {
//draw control points
SkPaint paint;
SkPoint bottom[SkPatchUtils::kNumPtsCubic];
SkPatchUtils::GetBottomCubic(cubics, bottom);
SkPoint top[SkPatchUtils::kNumPtsCubic];
SkPatchUtils::GetTopCubic(cubics, top);
SkPoint left[SkPatchUtils::kNumPtsCubic];
SkPatchUtils::GetLeftCubic(cubics, left);
SkPoint right[SkPatchUtils::kNumPtsCubic];
SkPatchUtils::GetRightCubic(cubics, right);
paint.setColor(SK_ColorBLACK);
paint.setStrokeWidth(0.5f);
SkPoint corners[4] = { bottom[0], bottom[3], top[0], top[3] };
canvas->drawPoints(SkCanvas::kLines_PointMode, 4, bottom, paint);
canvas->drawPoints(SkCanvas::kLines_PointMode, 2, bottom + 1, paint);
canvas->drawPoints(SkCanvas::kLines_PointMode, 4, top, paint);
canvas->drawPoints(SkCanvas::kLines_PointMode, 4, left, paint);
canvas->drawPoints(SkCanvas::kLines_PointMode, 4, right, paint);
canvas->drawPoints(SkCanvas::kLines_PointMode, 2, top + 1, paint);
canvas->drawPoints(SkCanvas::kLines_PointMode, 2, left + 1, paint);
canvas->drawPoints(SkCanvas::kLines_PointMode, 2, right + 1, paint);
paint.setStrokeWidth(2);
paint.setColor(SK_ColorRED);
canvas->drawPoints(SkCanvas::kPoints_PointMode, 4, corners, paint);
paint.setColor(SK_ColorBLUE);
canvas->drawPoints(SkCanvas::kPoints_PointMode, 2, bottom + 1, paint);
paint.setColor(SK_ColorCYAN);
canvas->drawPoints(SkCanvas::kPoints_PointMode, 2, top + 1, paint);
paint.setColor(SK_ColorYELLOW);
canvas->drawPoints(SkCanvas::kPoints_PointMode, 2, left + 1, paint);
paint.setColor(SK_ColorGREEN);
canvas->drawPoints(SkCanvas::kPoints_PointMode, 2, right + 1, paint);
}
// These are actually half the total width and hieghts
const SkScalar TexWidth = 100.0f;
const SkScalar TexHeight = 100.0f;
class PerlinPatchView : public Sample {
sk_sp<SkShader> fShader0;
sk_sp<SkShader> fShader1;
sk_sp<SkShader> fShaderCompose;
SkScalar fXFreq;
SkScalar fYFreq;
SkScalar fSeed;
SkPoint fPts[SkPatchUtils::kNumCtrlPts];
SkScalar fTexX;
SkScalar fTexY;
SkScalar fTexScale;
SkMatrix fInvMatrix;
bool fShowGrid = false;
public:
PerlinPatchView() : fXFreq(0.025f), fYFreq(0.025f), fSeed(0.0f),
fTexX(100.0), fTexY(50.0), fTexScale(1.0f) {
const SkScalar s = 2;
// The order of the colors and points is clockwise starting at upper-left corner.
//top points
fPts[0].set(100 * s, 100 * s);
fPts[1].set(150 * s, 50 * s);
fPts[2].set(250 * s, 150 * s);
fPts[3].set(300 * s, 100 * s);
//right points
fPts[4].set(275 * s, 150 * s);
fPts[5].set(350 * s, 250 * s);
//bottom points
fPts[6].set(300 * s, 300 * s);
fPts[7].set(250 * s, 250 * s);
//left points
fPts[8].set(150 * s, 350 * s);
fPts[9].set(100 * s, 300 * s);
fPts[10].set(50 * s, 250 * s);
fPts[11].set(150 * s, 150 * s);
const SkColor colors[SkPatchUtils::kNumCorners] = {
0xFF5555FF, 0xFF8888FF, 0xFFCCCCFF
};
const SkPoint points[2] = { SkPoint::Make(0.0f, 0.0f),
SkPoint::Make(100.0f, 100.0f) };
fShader0 = SkGradientShader::MakeLinear(points,
colors,
nullptr,
3,
SkTileMode::kMirror,
0,
nullptr);
}
protected:
SkString name() override { return SkString("PerlinPatch"); }
bool onChar(SkUnichar uni) override {
switch (uni) {
case 'g': fShowGrid = !fShowGrid; return true;
default: break;
}
return false;
}
bool onAnimate(double nanos) override {
fSeed += 0.005f;
return true;
}
void onDrawContent(SkCanvas* canvas) override {
if (!canvas->getLocalToDeviceAs3x3().invert(&fInvMatrix)) {
return;
}
SkPaint paint;
SkScalar texWidth = fTexScale * TexWidth;
SkScalar texHeight = fTexScale * TexHeight;
const SkPoint texCoords[SkPatchUtils::kNumCorners] = {
{ fTexX - texWidth, fTexY - texHeight},
{ fTexX + texWidth, fTexY - texHeight},
{ fTexX + texWidth, fTexY + texHeight},
{ fTexX - texWidth, fTexY + texHeight}}
;
SkScalar scaleFreq = 2.0;
fShader1 = SkPerlinNoiseShader::MakeImprovedNoise(fXFreq/scaleFreq, fYFreq/scaleFreq, 4,
fSeed);
fShaderCompose = SkShaders::Blend(SkBlendMode::kSrcOver, fShader0, fShader1);
paint.setShader(fShaderCompose);
const SkPoint* tex = texCoords;
if (fShowGrid) {
tex = nullptr;
}
canvas->drawPatch(fPts, nullptr, tex, SkBlendMode::kSrc, paint);
draw_control_points(canvas, fPts);
}
class PtClick : public Click {
public:
int fIndex;
PtClick(int index) : fIndex(index) {}
};
static bool hittest(const SkPoint& pt, SkScalar x, SkScalar y) {
return SkPoint::Length(pt.fX - x, pt.fY - y) < SkIntToScalar(5);
}
Sample::Click* onFindClickHandler(SkScalar x, SkScalar y, skui::ModifierKey modi) override {
modi &= ~skui::ModifierKey::kFirstPress; // ignore this
if (skui::ModifierKey::kShift == modi) {
return new PtClick(-1);
}
if (skui::ModifierKey::kControl == modi) {
return new PtClick(-2);
}
SkPoint clickPoint = {x, y};
fInvMatrix.mapPoints(&clickPoint, 1);
for (size_t i = 0; i < SK_ARRAY_COUNT(fPts); i++) {
if (hittest(fPts[i], clickPoint.fX, clickPoint.fY)) {
return new PtClick((int)i);
}
}
return nullptr;
}
bool onClick(Click* click) override {
PtClick* ptClick = (PtClick*)click;
if (ptClick->fIndex >= 0) {
fPts[ptClick->fIndex].set(click->fCurr.fX , click->fCurr.fY );
} else if (-1 == ptClick->fIndex) {
SkScalar xDiff = click->fPrev.fX - click->fCurr.fX;
SkScalar yDiff = click->fPrev.fY - click->fCurr.fY;
fTexX += xDiff * fTexScale;
fTexY += yDiff * fTexScale;
} else if (-2 == ptClick->fIndex) {
SkScalar yDiff = click->fCurr.fY - click->fPrev.fY;
fTexScale += yDiff / 10.0f;
fTexScale = std::max(0.1f, std::min(20.f, fTexScale));
}
return true;
}
private:
using INHERITED = Sample;
};
DEF_SAMPLE( return new PerlinPatchView(); )

View File

@ -147,7 +147,7 @@ SkTArray<GrXPFactoryTestFactory*, true>* GrXPFactoryTestFactory::GetFactories()
* we verify the count is as expected. If a new factory is added, then these numbers must be
* manually adjusted.
*/
static constexpr int kFPFactoryCount = 37;
static constexpr int kFPFactoryCount = 36;
static constexpr int kGPFactoryCount = 14;
static constexpr int kXPFactoryCount = 4;

View File

@ -36,37 +36,6 @@ static const int kBlockMask = kBlockSize - 1;
static const int kPerlinNoise = 4096;
static const int kRandMaximum = SK_MaxS32; // 2**31 - 1
static uint8_t improved_noise_permutations[] = {
151, 160, 137, 91, 90, 15, 131, 13, 201, 95, 96, 53, 194, 233, 7, 225, 140, 36, 103,
30, 69, 142, 8, 99, 37, 240, 21, 10, 23, 190, 6, 148, 247, 120, 234, 75, 0, 26,
197, 62, 94, 252, 219, 203, 117, 35, 11, 32, 57, 177, 33, 88, 237, 149, 56, 87, 174,
20, 125, 136, 171, 168, 68, 175, 74, 165, 71, 134, 139, 48, 27, 166, 77, 146, 158, 231,
83, 111, 229, 122, 60, 211, 133, 230, 220, 105, 92, 41, 55, 46, 245, 40, 244, 102, 143,
54, 65, 25, 63, 161, 1, 216, 80, 73, 209, 76, 132, 187, 208, 89, 18, 169, 200, 196,
135, 130, 116, 188, 159, 86, 164, 100, 109, 198, 173, 186, 3, 64, 52, 217, 226, 250, 124,
123, 5, 202, 38, 147, 118, 126, 255, 82, 85, 212, 207, 206, 59, 227, 47, 16, 58, 17,
182, 189, 28, 42, 223, 183, 170, 213, 119, 248, 152, 2, 44, 154, 163, 70, 221, 153, 101,
155, 167, 43, 172, 9, 129, 22, 39, 253, 19, 98, 108, 110, 79, 113, 224, 232, 178, 185,
112, 104, 218, 246, 97, 228, 251, 34, 242, 193, 238, 210, 144, 12, 191, 179, 162, 241, 81,
51, 145, 235, 249, 14, 239, 107, 49, 192, 214, 31, 181, 199, 106, 157, 184, 84, 204, 176,
115, 121, 50, 45, 127, 4, 150, 254, 138, 236, 205, 93, 222, 114, 67, 29, 24, 72, 243,
141, 128, 195, 78, 66, 215, 61, 156, 180,
151, 160, 137, 91, 90, 15, 131, 13, 201, 95, 96, 53, 194, 233, 7, 225, 140, 36, 103,
30, 69, 142, 8, 99, 37, 240, 21, 10, 23, 190, 6, 148, 247, 120, 234, 75, 0, 26,
197, 62, 94, 252, 219, 203, 117, 35, 11, 32, 57, 177, 33, 88, 237, 149, 56, 87, 174,
20, 125, 136, 171, 168, 68, 175, 74, 165, 71, 134, 139, 48, 27, 166, 77, 146, 158, 231,
83, 111, 229, 122, 60, 211, 133, 230, 220, 105, 92, 41, 55, 46, 245, 40, 244, 102, 143,
54, 65, 25, 63, 161, 1, 216, 80, 73, 209, 76, 132, 187, 208, 89, 18, 169, 200, 196,
135, 130, 116, 188, 159, 86, 164, 100, 109, 198, 173, 186, 3, 64, 52, 217, 226, 250, 124,
123, 5, 202, 38, 147, 118, 126, 255, 82, 85, 212, 207, 206, 59, 227, 47, 16, 58, 17,
182, 189, 28, 42, 223, 183, 170, 213, 119, 248, 152, 2, 44, 154, 163, 70, 221, 153, 101,
155, 167, 43, 172, 9, 129, 22, 39, 253, 19, 98, 108, 110, 79, 113, 224, 232, 178, 185,
112, 104, 218, 246, 97, 228, 251, 34, 242, 193, 238, 210, 144, 12, 191, 179, 162, 241, 81,
51, 145, 235, 249, 14, 239, 107, 49, 192, 214, 31, 181, 199, 106, 157, 184, 84, 204, 176,
115, 121, 50, 45, 127, 4, 150, 254, 138, 236, 205, 93, 222, 114, 67, 29, 24, 72, 243,
141, 128, 195, 78, 66, 215, 61, 156, 180
};
class SkPerlinNoiseShaderImpl : public SkShaderBase {
public:
struct StitchData {
@ -125,31 +94,6 @@ public:
info = SkImageInfo::Make(kBlockSize, 4, kRGBA_8888_SkColorType, kPremul_SkAlphaType);
fNoiseBitmap.installPixels(info, fNoise[0][0], info.minRowBytes());
fNoiseBitmap.setImmutable();
info = SkImageInfo::MakeA8(256, 1);
fImprovedPermutationsBitmap.installPixels(info, improved_noise_permutations,
info.minRowBytes());
fImprovedPermutationsBitmap.setImmutable();
static uint8_t gradients[] = { 2, 2, 1, 0,
0, 2, 1, 0,
2, 0, 1, 0,
0, 0, 1, 0,
2, 1, 2, 0,
0, 1, 2, 0,
2, 1, 0, 0,
0, 1, 0, 0,
1, 2, 2, 0,
1, 0, 2, 0,
1, 2, 0, 0,
1, 0, 0, 0,
2, 2, 1, 0,
1, 0, 2, 0,
0, 2, 1, 0,
1, 0, 0, 0 };
info = SkImageInfo::Make(16, 1, kBGRA_8888_SkColorType, kPremul_SkAlphaType);
fGradientBitmap.installPixels(info, gradients, info.minRowBytes());
fGradientBitmap.setImmutable();
#endif
}
@ -160,9 +104,7 @@ public:
, fBaseFrequency(that.fBaseFrequency)
, fStitchDataInit(that.fStitchDataInit)
, fPermutationsBitmap(that.fPermutationsBitmap)
, fNoiseBitmap(that.fNoiseBitmap)
, fImprovedPermutationsBitmap(that.fImprovedPermutationsBitmap)
, fGradientBitmap(that.fGradientBitmap) {
, fNoiseBitmap(that.fNoiseBitmap) {
memcpy(fLatticeSelector, that.fLatticeSelector, sizeof(fLatticeSelector));
memcpy(fNoise, that.fNoise, sizeof(fNoise));
memcpy(fGradient, that.fGradient, sizeof(fGradient));
@ -182,8 +124,6 @@ public:
#if SK_SUPPORT_GPU
SkBitmap fPermutationsBitmap;
SkBitmap fNoiseBitmap;
SkBitmap fImprovedPermutationsBitmap;
SkBitmap fGradientBitmap;
#endif
inline int random() {
@ -313,12 +253,6 @@ public:
const SkBitmap& getPermutationsBitmap() const { return fPermutationsBitmap; }
const SkBitmap& getNoiseBitmap() const { return fNoiseBitmap; }
const SkBitmap& getImprovedPermutationsBitmap() const {
return fImprovedPermutationsBitmap;
}
const SkBitmap& getGradientBitmap() const { return fGradientBitmap; }
#endif
};
@ -330,16 +264,11 @@ public:
* kFractalNoise_Type : noise * 0.5 + 0.5
* kTurbulence_Type : abs(noise)
* Very little differences between the 2 types, although you can tell the difference visually.
* "Improved" is based on the Improved Perlin Noise algorithm described at
* http://mrl.nyu.edu/~perlin/noise/. It is quite distinct from the other two, and the noise is
* a 2D slice of a 3D noise texture. Minor changes to the Z coordinate will result in minor
* changes to the noise, making it suitable for animated noise.
*/
enum Type {
kFractalNoise_Type,
kTurbulence_Type,
kImprovedNoise_Type,
kLast_Type = kImprovedNoise_Type
kLast_Type = kTurbulence_Type
};
static const int kMaxOctaves = 255; // numOctaves must be <= 0 and <= kMaxOctaves
@ -359,7 +288,6 @@ public:
SkScalar calculateTurbulenceValueForPoint(
int channel,
StitchData& stitchData, const SkPoint& point) const;
SkScalar calculateImprovedNoiseValueForPoint(int channel, const SkPoint& point) const;
SkScalar noise2D(int channel,
const StitchData& stitchData, const SkPoint& noiseVector) const;
@ -452,8 +380,6 @@ sk_sp<SkFlattenable> SkPerlinNoiseShaderImpl::CreateProc(SkReadBuffer& buffer) {
return SkPerlinNoiseShader::MakeFractalNoise(freqX, freqY, octaves, seed, &tileSize);
case kTurbulence_Type:
return SkPerlinNoiseShader::MakeTurbulence(freqX, freqY, octaves, seed, &tileSize);
case kImprovedNoise_Type:
return SkPerlinNoiseShader::MakeImprovedNoise(freqX, freqY, octaves, seed);
default:
// Really shouldn't get here b.c. of earlier check on type
buffer.validate(false);
@ -572,71 +498,10 @@ SkScalar SkPerlinNoiseShaderImpl::PerlinNoiseShaderContext::calculateTurbulenceV
return SkTPin(turbulenceFunctionResult, 0.0f, SK_Scalar1);
}
////////////////////////////////////////////////////////////////////////////////////////////////////
// Improved Perlin Noise based on Java implementation found at http://mrl.nyu.edu/~perlin/noise/
static SkScalar fade(SkScalar t) {
return t * t * t * (t * (t * 6 - 15) + 10);
}
static SkScalar lerp(SkScalar t, SkScalar a, SkScalar b) {
return a + t * (b - a);
}
static SkScalar grad(int hash, SkScalar x, SkScalar y, SkScalar z) {
int h = hash & 15;
SkScalar u = h < 8 ? x : y;
SkScalar v = h < 4 ? y : h == 12 || h == 14 ? x : z;
return ((h & 1) == 0 ? u : -u) + ((h & 2) == 0 ? v : -v);
}
SkScalar SkPerlinNoiseShaderImpl::PerlinNoiseShaderContext::calculateImprovedNoiseValueForPoint(
int channel, const SkPoint& point) const {
const SkPerlinNoiseShaderImpl& perlinNoiseShader = static_cast<const SkPerlinNoiseShaderImpl&>(fShader);
SkScalar x = point.fX * perlinNoiseShader.fBaseFrequencyX;
SkScalar y = point.fY * perlinNoiseShader.fBaseFrequencyY;
// z offset between different channels, chosen arbitrarily
static const SkScalar CHANNEL_DELTA = 1000.0f;
SkScalar z = channel * CHANNEL_DELTA + perlinNoiseShader.fSeed;
SkScalar result = 0;
SkScalar ratio = SK_Scalar1;
for (int i = 0; i < perlinNoiseShader.fNumOctaves; i++) {
int X = SkScalarFloorToInt(x) & 255;
int Y = SkScalarFloorToInt(y) & 255;
int Z = SkScalarFloorToInt(z) & 255;
SkScalar px = x - SkScalarFloorToScalar(x);
SkScalar py = y - SkScalarFloorToScalar(y);
SkScalar pz = z - SkScalarFloorToScalar(z);
SkScalar u = fade(px);
SkScalar v = fade(py);
SkScalar w = fade(pz);
uint8_t* permutations = improved_noise_permutations;
int A = permutations[X] + Y;
int AA = permutations[A] + Z;
int AB = permutations[A + 1] + Z;
int B = permutations[X + 1] + Y;
int BA = permutations[B] + Z;
int BB = permutations[B + 1] + Z;
result += lerp(w, lerp(v, lerp(u, grad(permutations[AA ], px , py , pz ),
grad(permutations[BA ], px - 1, py , pz )),
lerp(u, grad(permutations[AB ], px , py - 1, pz ),
grad(permutations[BB ], px - 1, py - 1, pz ))),
lerp(v, lerp(u, grad(permutations[AA + 1], px , py , pz - 1),
grad(permutations[BA + 1], px - 1, py , pz - 1)),
lerp(u, grad(permutations[AB + 1], px , py - 1, pz - 1),
grad(permutations[BB + 1], px - 1, py - 1, pz - 1)))) /
ratio;
x *= 2;
y *= 2;
ratio *= 2;
}
result = SkTPin((result + 1.0f) / 2.0f, 0.0f, 1.0f);
return result;
}
////////////////////////////////////////////////////////////////////////////////////////////////////
SkPMColor SkPerlinNoiseShaderImpl::PerlinNoiseShaderContext::shade(
const SkPoint& point, StitchData& stitchData) const {
const SkPerlinNoiseShaderImpl& perlinNoiseShader = static_cast<const SkPerlinNoiseShaderImpl&>(fShader);
SkPoint newPoint;
fMatrix.mapPoints(&newPoint, &point, 1);
newPoint.fX = SkScalarRoundToScalar(newPoint.fX);
@ -645,12 +510,7 @@ SkPMColor SkPerlinNoiseShaderImpl::PerlinNoiseShaderContext::shade(
U8CPU rgba[4];
for (int channel = 3; channel >= 0; --channel) {
SkScalar value;
if (perlinNoiseShader.fType == kImprovedNoise_Type) {
value = calculateImprovedNoiseValueForPoint(channel, newPoint);
}
else {
value = calculateTurbulenceValueForPoint(channel, stitchData, newPoint);
}
value = calculateTurbulenceValueForPoint(channel, stitchData, newPoint);
rgba[channel] = SkScalarFloorToInt(255 * value);
}
return SkPreMultiplyARGB(rgba[3], rgba[0], rgba[1], rgba[2]);
@ -1070,275 +930,6 @@ void GrGLPerlinNoise::onSetData(const GrGLSLProgramDataManager& pdman,
/////////////////////////////////////////////////////////////////////
class GrGLImprovedPerlinNoise : public GrGLSLFragmentProcessor {
public:
void emitCode(EmitArgs&) override;
static inline void GenKey(const GrProcessor&, const GrShaderCaps&, GrProcessorKeyBuilder*);
protected:
void onSetData(const GrGLSLProgramDataManager&, const GrFragmentProcessor&) override;
private:
GrGLSLProgramDataManager::UniformHandle fZUni;
GrGLSLProgramDataManager::UniformHandle fBaseFrequencyUni;
using INHERITED = GrGLSLFragmentProcessor;
};
/////////////////////////////////////////////////////////////////////
class GrImprovedPerlinNoiseEffect : public GrFragmentProcessor {
public:
static std::unique_ptr<GrFragmentProcessor> Make(
int octaves,
SkScalar z,
std::unique_ptr<SkPerlinNoiseShaderImpl::PaintingData> paintingData,
GrSurfaceProxyView permutationsView,
GrSurfaceProxyView gradientView,
const SkMatrix& matrix,
const GrCaps& caps) {
static constexpr GrSamplerState kRepeatXSampler = {GrSamplerState::WrapMode::kRepeat,
GrSamplerState::WrapMode::kClamp,
GrSamplerState::Filter::kNearest};
auto permutationsFP =
GrTextureEffect::Make(std::move(permutationsView), kPremul_SkAlphaType,
SkMatrix::I(), kRepeatXSampler, caps);
auto gradientFP = GrTextureEffect::Make(std::move(gradientView), kPremul_SkAlphaType,
SkMatrix::I(), kRepeatXSampler, caps);
return GrMatrixEffect::Make(matrix, std::unique_ptr<GrFragmentProcessor>(
new GrImprovedPerlinNoiseEffect(octaves, z, std::move(paintingData),
std::move(permutationsFP),
std::move(gradientFP))));
}
const char* name() const override { return "ImprovedPerlinNoise"; }
std::unique_ptr<GrFragmentProcessor> clone() const override {
return std::unique_ptr<GrFragmentProcessor>(new GrImprovedPerlinNoiseEffect(*this));
}
const SkVector& baseFrequency() const { return fPaintingData->fBaseFrequency; }
SkScalar z() const { return fZ; }
int octaves() const { return fOctaves; }
private:
GrGLSLFragmentProcessor* onCreateGLSLInstance() const override {
return new GrGLImprovedPerlinNoise;
}
void onGetGLSLProcessorKey(const GrShaderCaps& caps, GrProcessorKeyBuilder* b) const override {
GrGLImprovedPerlinNoise::GenKey(*this, caps, b);
}
bool onIsEqual(const GrFragmentProcessor& sBase) const override {
const GrImprovedPerlinNoiseEffect& that = sBase.cast<GrImprovedPerlinNoiseEffect>();
return this->z() == that.z() &&
this->octaves() == that.octaves() &&
this->baseFrequency() == that.baseFrequency();
}
GrImprovedPerlinNoiseEffect(int octaves,
SkScalar z,
std::unique_ptr<SkPerlinNoiseShaderImpl::PaintingData> paintingData,
std::unique_ptr<GrFragmentProcessor> permutationsFP,
std::unique_ptr<GrFragmentProcessor> gradientFP)
: INHERITED(kGrImprovedPerlinNoiseEffect_ClassID, kNone_OptimizationFlags)
, fOctaves(octaves)
, fZ(z)
, fPaintingData(std::move(paintingData)) {
this->registerChild(std::move(permutationsFP), SkSL::SampleUsage::Explicit());
this->registerChild(std::move(gradientFP), SkSL::SampleUsage::Explicit());
this->setUsesSampleCoordsDirectly();
}
GrImprovedPerlinNoiseEffect(const GrImprovedPerlinNoiseEffect& that)
: INHERITED(kGrImprovedPerlinNoiseEffect_ClassID, kNone_OptimizationFlags)
, fOctaves(that.fOctaves)
, fZ(that.fZ)
, fPaintingData(std::make_unique<SkPerlinNoiseShaderImpl::PaintingData>(
*that.fPaintingData)) {
this->cloneAndRegisterAllChildProcessors(that);
this->setUsesSampleCoordsDirectly();
}
GR_DECLARE_FRAGMENT_PROCESSOR_TEST
int fOctaves;
SkScalar fZ;
std::unique_ptr<SkPerlinNoiseShaderImpl::PaintingData> fPaintingData;
using INHERITED = GrFragmentProcessor;
};
/////////////////////////////////////////////////////////////////////
GR_DEFINE_FRAGMENT_PROCESSOR_TEST(GrImprovedPerlinNoiseEffect);
#if GR_TEST_UTILS
std::unique_ptr<GrFragmentProcessor> GrImprovedPerlinNoiseEffect::TestCreate(
GrProcessorTestData* d) {
SkScalar baseFrequencyX = d->fRandom->nextRangeScalar(0.01f,
0.99f);
SkScalar baseFrequencyY = d->fRandom->nextRangeScalar(0.01f,
0.99f);
int numOctaves = d->fRandom->nextRangeU(2, 10);
SkScalar z = SkIntToScalar(d->fRandom->nextU());
sk_sp<SkShader> shader(SkPerlinNoiseShader::MakeImprovedNoise(baseFrequencyX,
baseFrequencyY,
numOctaves,
z));
GrTest::TestAsFPArgs asFPArgs(d);
return as_SB(shader)->asFragmentProcessor(asFPArgs.args());
}
#endif
void GrGLImprovedPerlinNoise::emitCode(EmitArgs& args) {
const GrImprovedPerlinNoiseEffect& pne = args.fFp.cast<GrImprovedPerlinNoiseEffect>();
GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder;
GrGLSLUniformHandler* uniformHandler = args.fUniformHandler;
fBaseFrequencyUni = uniformHandler->addUniform(&pne, kFragment_GrShaderFlag, kHalf2_GrSLType,
"baseFrequency");
const char* baseFrequencyUni = uniformHandler->getUniformCStr(fBaseFrequencyUni);
fZUni = uniformHandler->addUniform(&pne, kFragment_GrShaderFlag, kHalf_GrSLType, "z");
const char* zUni = uniformHandler->getUniformCStr(fZUni);
// fade function
const GrShaderVar fadeArgs[] = {
GrShaderVar("t", kHalf3_GrSLType)
};
SkString fadeFuncName = fragBuilder->getMangledFunctionName("fade");
fragBuilder->emitFunction(kHalf3_GrSLType, fadeFuncName.c_str(),
{fadeArgs, SK_ARRAY_COUNT(fadeArgs)},
"return t * t * t * (t * (t * 6.0 - 15.0) + 10.0);");
// perm function
const GrShaderVar permArgs[] = {
{"x", kHalf_GrSLType}
};
SkString samplePerm = this->invokeChild(0, "half4(1)", args, "float2(x, 0.5)");
SkString permFuncName = fragBuilder->getMangledFunctionName("perm");
SkString permCode = SkStringPrintf("return %s.a * 255;", samplePerm.c_str());
fragBuilder->emitFunction(kHalf_GrSLType, permFuncName.c_str(),
{permArgs, SK_ARRAY_COUNT(permArgs)}, permCode.c_str());
// grad function
const GrShaderVar gradArgs[] = {
{"x", kHalf_GrSLType},
{"p", kHalf3_GrSLType}
};
SkString sampleGrad = this->invokeChild(1, "half4(1)", args, "float2(x, 0.5)");
SkString gradFuncName = fragBuilder->getMangledFunctionName("grad");
SkString gradCode = SkStringPrintf("return half(dot(%s.rgb * 255.0 - float3(1.0), p));",
sampleGrad.c_str());
fragBuilder->emitFunction(kHalf_GrSLType, gradFuncName.c_str(),
{gradArgs, SK_ARRAY_COUNT(gradArgs)}, gradCode.c_str());
// lerp function
const GrShaderVar lerpArgs[] = {
{"a", kHalf_GrSLType},
{"b", kHalf_GrSLType},
{"w", kHalf_GrSLType}
};
SkString lerpFuncName = fragBuilder->getMangledFunctionName("lerp");
fragBuilder->emitFunction(kHalf_GrSLType, lerpFuncName.c_str(),
{lerpArgs, SK_ARRAY_COUNT(lerpArgs)}, "return a + w * (b - a);");
// noise function
const GrShaderVar noiseArgs[] = {
{"p", kHalf3_GrSLType},
};
SkString noiseFuncName = fragBuilder->getMangledFunctionName("noise");
SkString noiseCode;
noiseCode.append("half3 P = mod(floor(p), 256.0);");
noiseCode.append("p -= floor(p);");
noiseCode.appendf("half3 f = %s(p);", fadeFuncName.c_str());
noiseCode.appendf("half A = %s(P.x) + P.y;", permFuncName.c_str());
noiseCode.appendf("half AA = %s(A) + P.z;", permFuncName.c_str());
noiseCode.appendf("half AB = %s(A + 1.0) + P.z;", permFuncName.c_str());
noiseCode.appendf("half B = %s(P.x + 1.0) + P.y;", permFuncName.c_str());
noiseCode.appendf("half BA = %s(B) + P.z;", permFuncName.c_str());
noiseCode.appendf("half BB = %s(B + 1.0) + P.z;", permFuncName.c_str());
noiseCode.appendf("half result = %s(", lerpFuncName.c_str());
noiseCode.appendf("%s(%s(%s(%s(AA), p),", lerpFuncName.c_str(), lerpFuncName.c_str(),
gradFuncName.c_str(), permFuncName.c_str());
noiseCode.appendf("%s(%s(BA), p + half3(-1.0, 0.0, 0.0)), f.x),", gradFuncName.c_str(),
permFuncName.c_str());
noiseCode.appendf("%s(%s(%s(AB), p + half3(0.0, -1.0, 0.0)),", lerpFuncName.c_str(),
gradFuncName.c_str(), permFuncName.c_str());
noiseCode.appendf("%s(%s(BB), p + half3(-1.0, -1.0, 0.0)), f.x), f.y),",
gradFuncName.c_str(), permFuncName.c_str());
noiseCode.appendf("%s(%s(%s(%s(AA + 1.0), p + half3(0.0, 0.0, -1.0)),",
lerpFuncName.c_str(), lerpFuncName.c_str(), gradFuncName.c_str(),
permFuncName.c_str());
noiseCode.appendf("%s(%s(BA + 1.0), p + half3(-1.0, 0.0, -1.0)), f.x),",
gradFuncName.c_str(), permFuncName.c_str());
noiseCode.appendf("%s(%s(%s(AB + 1.0), p + half3(0.0, -1.0, -1.0)),",
lerpFuncName.c_str(), gradFuncName.c_str(), permFuncName.c_str());
noiseCode.appendf("%s(%s(BB + 1.0), p + half3(-1.0, -1.0, -1.0)), f.x), f.y), f.z);",
gradFuncName.c_str(), permFuncName.c_str());
noiseCode.append("return result;");
fragBuilder->emitFunction(kHalf_GrSLType, noiseFuncName.c_str(),
{noiseArgs, SK_ARRAY_COUNT(noiseArgs)}, noiseCode.c_str());
// noiseOctaves function
const GrShaderVar noiseOctavesArgs[] = {
{"p", kHalf3_GrSLType}
};
SkString noiseOctavesFuncName = fragBuilder->getMangledFunctionName("noiseOctaves");
SkString noiseOctavesCode;
noiseOctavesCode.append("half result = 0.0;");
noiseOctavesCode.append("half ratio = 1.0;");
noiseOctavesCode.appendf("for (half i = 0.0; i < %d; i++) {", pne.octaves());
noiseOctavesCode.appendf("result += %s(p) / ratio;", noiseFuncName.c_str());
noiseOctavesCode.append("p *= 2.0;");
noiseOctavesCode.append("ratio *= 2.0;");
noiseOctavesCode.append("}");
noiseOctavesCode.append("return (result + 1.0) / 2.0;");
fragBuilder->emitFunction(kHalf_GrSLType, noiseOctavesFuncName.c_str(),
{noiseOctavesArgs, SK_ARRAY_COUNT(noiseOctavesArgs)},
noiseOctavesCode.c_str());
fragBuilder->codeAppendf("half2 coords = half2(%s * %s);", args.fSampleCoord, baseFrequencyUni);
fragBuilder->codeAppendf("half r = %s(half3(coords, %s));", noiseOctavesFuncName.c_str(),
zUni);
fragBuilder->codeAppendf("half g = %s(half3(coords, %s + 0000.0));",
noiseOctavesFuncName.c_str(), zUni);
fragBuilder->codeAppendf("half b = %s(half3(coords, %s + 0000.0));",
noiseOctavesFuncName.c_str(), zUni);
fragBuilder->codeAppendf("half a = %s(half3(coords, %s + 0000.0));",
noiseOctavesFuncName.c_str(), zUni);
// Clamp values
fragBuilder->codeAppendf("half4 color = saturate(half4(r, g, b, a));");
// Pre-multiply the result
fragBuilder->codeAppendf("return half4(color.rgb * color.aaa, color.a);");
}
void GrGLImprovedPerlinNoise::GenKey(const GrProcessor& processor, const GrShaderCaps&,
GrProcessorKeyBuilder* b) {
const GrImprovedPerlinNoiseEffect& pne = processor.cast<GrImprovedPerlinNoiseEffect>();
b->add32(pne.octaves());
}
void GrGLImprovedPerlinNoise::onSetData(const GrGLSLProgramDataManager& pdman,
const GrFragmentProcessor& processor) {
INHERITED::onSetData(pdman, processor);
const GrImprovedPerlinNoiseEffect& noise = processor.cast<GrImprovedPerlinNoiseEffect>();
const SkVector& baseFrequency = noise.baseFrequency();
pdman.set2f(fBaseFrequencyUni, baseFrequency.fX, baseFrequency.fY);
pdman.set1f(fZUni, noise.z());
}
/////////////////////////////////////////////////////////////////////
std::unique_ptr<GrFragmentProcessor> SkPerlinNoiseShaderImpl::asFragmentProcessor(
const GrFPArgs& args) const {
SkASSERT(args.fContext);
@ -1361,28 +952,6 @@ std::unique_ptr<GrFragmentProcessor> SkPerlinNoiseShaderImpl::asFragmentProcesso
m.setTranslateY(-localMatrix->getTranslateY() + SK_Scalar1);
auto context = args.fContext;
if (fType == kImprovedNoise_Type) {
// Need to assert that the textures we'll create are power of 2 so a copy isn't needed.
// We also know that we will not be using mipmaps. If things things weren't true we should
// go through GrBitmapTextureMaker to handle needed copies.
const SkBitmap& permutationsBitmap = paintingData->getImprovedPermutationsBitmap();
SkASSERT(SkIsPow2(permutationsBitmap.width()) && SkIsPow2(permutationsBitmap.height()));
auto permutationsView = GrMakeCachedBitmapProxyView(context, permutationsBitmap);
const SkBitmap& gradientBitmap = paintingData->getGradientBitmap();
SkASSERT(SkIsPow2(gradientBitmap.width()) && SkIsPow2(gradientBitmap.height()));
auto gradientView = GrMakeCachedBitmapProxyView(context, gradientBitmap);
if (!permutationsView || !gradientView) {
return nullptr;
}
return GrImprovedPerlinNoiseEffect::Make(fNumOctaves,
fSeed,
std::move(paintingData),
std::move(permutationsView),
std::move(gradientView),
m,
*context->priv().caps());
}
if (0 == fNumOctaves) {
if (kFractalNoise_Type == fType) {
@ -1468,17 +1037,6 @@ sk_sp<SkShader> SkPerlinNoiseShader::MakeTurbulence(SkScalar baseFrequencyX,
tileSize));
}
sk_sp<SkShader> SkPerlinNoiseShader::MakeImprovedNoise(SkScalar baseFrequencyX,
SkScalar baseFrequencyY,
int numOctaves, SkScalar z) {
if (!valid_input(baseFrequencyX, baseFrequencyY, numOctaves, nullptr, z)) {
return nullptr;
}
return sk_sp<SkShader>(new SkPerlinNoiseShaderImpl(SkPerlinNoiseShaderImpl::kImprovedNoise_Type,
baseFrequencyX, baseFrequencyY, numOctaves, z,
nullptr));
}
void SkPerlinNoiseShader::RegisterFlattenables() {
SK_REGISTER_FLATTENABLE(SkPerlinNoiseShaderImpl);
}

View File

@ -70,9 +70,6 @@ void SkSLSlide::load(SkScalar winWidth, SkScalar winHeight) {
shader = GetResourceAsImage("images/mandrill_256.png")->makeShader(SkSamplingOptions());
fShaders.push_back(std::make_pair("Mandrill", shader));
shader = SkPerlinNoiseShader::MakeImprovedNoise(0.025f, 0.025f, 3, 0.0f);
fShaders.push_back(std::make_pair("Perlin Noise", shader));
fResolution = { winWidth, winHeight, 1.0f };
}