Skip to content
This repository was archived by the owner on Feb 25, 2025. It is now read-only.

Commit f0b7edf

Browse files
reed-at-googleSkia Commit-Bot
authored and
Skia Commit-Bot
committed
hack up bump-map
Change-Id: Ib1e92359f0decd60bdcb628a5b11be1c597b4f82 Reviewed-on: https://skia-review.googlesource.com/c/skia/+/265219 Reviewed-by: Mike Reed <[email protected]> Commit-Queue: Mike Reed <[email protected]>
1 parent 5344cc3 commit f0b7edf

File tree

1 file changed

+190
-4
lines changed

1 file changed

+190
-4
lines changed

samplecode/Sample3D.cpp

Lines changed: 190 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -358,10 +358,6 @@ class SamplePointLight3D : public Sample3DView {
358358

359359
bool onChar(SkUnichar uni) override {
360360
switch (uni) {
361-
case 'X': fLight.fPos.x += 10; return true;
362-
case 'x': fLight.fPos.x -= 10; return true;
363-
case 'Y': fLight.fPos.y += 10; return true;
364-
case 'y': fLight.fPos.y -= 10; return true;
365361
case 'Z': fLight.fPos.z += 10; return true;
366362
case 'z': fLight.fPos.z -= 10; return true;
367363
}
@@ -439,3 +435,193 @@ class SamplePointLight3D : public Sample3DView {
439435
}
440436
};
441437
DEF_SAMPLE( return new SamplePointLight3D(); )
438+
439+
#include "include/core/SkColorPriv.h"
440+
#include "include/core/SkSurface.h"
441+
442+
static sk_sp<SkImage> make_bump(sk_sp<SkImage> src) {
443+
src = src->makeRasterImage();
444+
445+
SkPixmap s;
446+
SkAssertResult(src->peekPixels(&s));
447+
448+
SkImageInfo info = SkImageInfo::Make(src->width(), src->height(),
449+
kR8G8_unorm_SkColorType, kOpaque_SkAlphaType);
450+
451+
size_t rb = info.minRowBytes();
452+
auto data = SkData::MakeUninitialized(rb * info.height());
453+
SkPixmap d = { info, data->writable_data(), rb };
454+
455+
const int W = src->width();
456+
const int H = src->height();
457+
458+
for (int y = 0; y < H; ++y) {
459+
int y1 = y == H-1 ? 0 : y + 1;
460+
for (int x = 0; x < W; ++x) {
461+
int x1 = x == W-1 ? 0 : x + 1;
462+
463+
auto lum = [](SkPMColor c) {
464+
return SkGetPackedR32(c);
465+
return (SkGetPackedR32(c) * 2 + SkGetPackedG32(c) * 5 + SkGetPackedB32(c)) >> 3;
466+
};
467+
468+
int s00 = lum(*s.addr32(x, y)),
469+
s01 = lum(*s.addr32(x1, y)),
470+
s10 = lum(*s.addr32(x, y1));
471+
472+
auto delta_lum_to_byte = [](int d) {
473+
SkASSERT(d >= -255 && d <= 255);
474+
d >>= 1;
475+
if (d < 0) {
476+
d += 255;
477+
}
478+
SkASSERT(d >= 0 && d <= 255);
479+
return d;
480+
};
481+
482+
int dx = delta_lum_to_byte(s01 - s00);
483+
int dy = delta_lum_to_byte(s10 - s00);
484+
*d.writable_addr16(x, y) = (dx << 8) | dy;
485+
}
486+
}
487+
return SkImage::MakeRasterData(info, data, rb);
488+
}
489+
490+
class SampleBump3D : public Sample3DView {
491+
SkRRect fRR;
492+
LightPos fLight = {{200, 200, 800, 1}, 8};
493+
494+
sk_sp<SkShader> fBmpShader, fImgShader;
495+
sk_sp<SkRuntimeEffect> fEffect;
496+
497+
SkM44 fWorldToClick,
498+
fClickToWorld;
499+
500+
SkString name() override { return SkString("bump3d"); }
501+
502+
void onOnceBeforeDraw() override {
503+
fRR = SkRRect::MakeRectXY({20, 20, 380, 380}, 50, 50);
504+
auto img = GetResourceAsImage("images/brickwork-texture.jpg");
505+
fImgShader = img->makeShader(SkMatrix::MakeScale(2, 2));
506+
fBmpShader = make_bump(img)->makeShader(SkMatrix::MakeScale(2, 2));
507+
508+
const char code[] = R"(
509+
in fragmentProcessor color_map;
510+
in fragmentProcessor bump_map;
511+
512+
uniform float4x4 localToWorld;
513+
uniform float3 lightPos;
514+
515+
float convert_bump_to_delta(float bump) {
516+
if (bump > 0.5) {
517+
bump -= 1;
518+
}
519+
return bump * 6;
520+
}
521+
522+
void main(float x, float y, inout half4 color) {
523+
half4 bmp = sample(bump_map);
524+
525+
float3 plane_pos = (localToWorld * float4(x, y, 0, 1)).xyz;
526+
527+
float3 plane_norm = (localToWorld * float4(
528+
convert_bump_to_delta(bmp.r),
529+
convert_bump_to_delta(bmp.g),
530+
1, 0)).xyz;
531+
plane_norm = normalize(plane_norm);
532+
533+
float3 light_dir = normalize(lightPos - plane_pos);
534+
float ambient = 0.4;
535+
float dp = dot(plane_norm, light_dir);
536+
float scale = min(ambient + max(dp, 0), 2);
537+
538+
color = sample(color_map) * half4(float4(scale, scale, scale, 1));
539+
}
540+
)";
541+
auto [effect, error] = SkRuntimeEffect::Make(SkString(code));
542+
if (!effect) {
543+
SkDebugf("runtime error %s\n", error.c_str());
544+
}
545+
fEffect = effect;
546+
}
547+
548+
bool onChar(SkUnichar uni) override {
549+
switch (uni) {
550+
case 'Z': fLight.fPos.z += 10; return true;
551+
case 'z': fLight.fPos.z -= 10; return true;
552+
}
553+
return this->Sample3DView::onChar(uni);
554+
}
555+
556+
void drawContent(SkCanvas* canvas, const SkMatrix44& m, SkColor color) {
557+
SkMatrix44 trans;
558+
trans.setTranslate(200, 200, 0); // center of the rotation
559+
560+
canvas->experimental_concat44(trans * fRot * m * inv(trans));
561+
562+
// wonder if the runtimeeffect can do this reject? (in a setup function)
563+
if (!front(canvas->experimental_getLocalToDevice())) {
564+
return;
565+
}
566+
567+
struct Uniforms {
568+
SkM44 fLocalToWorld;
569+
SkV3 fLightPos;
570+
} uni;
571+
uni.fLocalToWorld = canvas->experimental_getLocalToWorld();
572+
uni.fLightPos = {fLight.fPos.x, fLight.fPos.y, fLight.fPos.z};
573+
sk_sp<SkData> data = SkData::MakeWithCopy(&uni, sizeof(uni));
574+
sk_sp<SkShader> children[] = { fImgShader, fBmpShader };
575+
576+
SkPaint paint;
577+
paint.setColor(color);
578+
paint.setShader(fEffect->makeShader(data, children, 2, nullptr, true));
579+
580+
canvas->drawRRect(fRR, paint);
581+
}
582+
583+
void setClickToWorld(SkCanvas* canvas, const SkM44& clickM) {
584+
auto l2d = canvas->experimental_getLocalToDevice();
585+
fWorldToClick = inv(clickM) * l2d;
586+
fClickToWorld = inv(fWorldToClick);
587+
}
588+
589+
void onDrawContent(SkCanvas* canvas) override {
590+
if (canvas->getGrContext() == nullptr) {
591+
return;
592+
}
593+
SkM44 clickM = canvas->experimental_getLocalToDevice();
594+
595+
canvas->save();
596+
canvas->translate(400, 300);
597+
598+
this->saveCamera(canvas, {0, 0, 400, 400}, 200);
599+
600+
this->setClickToWorld(canvas, clickM);
601+
602+
for (auto f : faces) {
603+
SkAutoCanvasRestore acr(canvas, true);
604+
this->drawContent(canvas, f.asM44(200), f.fColor);
605+
}
606+
607+
fLight.draw(canvas);
608+
canvas->restore();
609+
canvas->restore();
610+
}
611+
612+
Click* onFindClickHandler(SkScalar x, SkScalar y, skui::ModifierKey modi) override {
613+
auto L = fWorldToClick * fLight.fPos;
614+
SkPoint c = project(fClickToWorld, {x, y, L.z/L.w, 1});
615+
if (fLight.hitTest(c.fX, c.fY)) {
616+
return new Click();
617+
}
618+
return nullptr;
619+
}
620+
bool onClick(Click* click) override {
621+
auto L = fWorldToClick * fLight.fPos;
622+
SkPoint c = project(fClickToWorld, {click->fCurr.fX, click->fCurr.fY, L.z/L.w, 1});
623+
fLight.update(c.fX, c.fY);
624+
return true;
625+
}
626+
};
627+
DEF_SAMPLE( return new SampleBump3D(); )

0 commit comments

Comments
 (0)