Skip to content

Commit cc5415a

Browse files
Nathaniel NifongSkia Commit-Bot
authored andcommitted
Modify 3D example with light and bump shader.
Depends on what I assume the final version of https://skia-review.googlesource.com/c/skia/+/272646 will be Change-Id: I53485c5f47e0fef120c8a1bd6d0620fddfb3cde9 Bug: skia:9866 Reviewed-on: https://skia-review.googlesource.com/c/skia/+/272529 Commit-Queue: Kevin Lubick <[email protected]> Reviewed-by: Kevin Lubick <[email protected]>
1 parent 57bc977 commit cc5415a

File tree

5 files changed

+145
-39
lines changed

5 files changed

+145
-39
lines changed
151 KB
Loading
176 KB
Loading

modules/canvaskit/canvaskit/extra.html

Lines changed: 114 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,6 @@ <h2> 3D perspective transformations </h2>
7676
RTShaderAPI1(CanvasKit);
7777

7878
SkpExample(CanvasKit, skpData);
79-
Camera3D(CanvasKit);
8079
});
8180

8281
fetch('https://storage.googleapis.com/skia-cdn/misc/lego_loader.json').then((resp) => {
@@ -140,6 +139,9 @@ <h2> 3D perspective transformations </h2>
140139

141140
const loadDog = fetch('https://storage.googleapis.com/skia-cdn/misc/dog.jpg').then((response) => response.arrayBuffer());
142141
const loadMandrill = fetch('https://storage.googleapis.com/skia-cdn/misc/mandrill_256.png').then((response) => response.arrayBuffer());
142+
const loadBrickTex = fetch('./brickwork-texture.jpg').then((response) => response.arrayBuffer());
143+
const loadBrickBump = fetch('./brickwork_normal-map.jpg').then((response) => response.arrayBuffer());
144+
Promise.all([ckLoaded, loadBrickTex, loadBrickBump]).then((results) => {Camera3D(...results)});
143145

144146
function SkottieExample(CanvasKit, id, jsonStr, bounds, assets) {
145147
if (!CanvasKit || !jsonStr) {
@@ -544,7 +546,10 @@ <h2> 3D perspective transformations </h2>
544546
surface.drawOnce(drawFrame);
545547
}
546548

547-
function Camera3D(canvas) {
549+
function Camera3D(canvas, textureImgData, normalImgData) {
550+
if (!canvas) {
551+
552+
}
548553
const surface = CanvasKit.MakeCanvasSurface('camera3d');
549554
if (!surface) {
550555
console.error('Could not make surface');
@@ -554,12 +559,12 @@ <h2> 3D perspective transformations </h2>
554559
const sizeX = document.getElementById('camera3d').width;
555560
const sizeY = document.getElementById('camera3d').height;
556561

557-
var clickToWorld = CanvasKit.SkM44.identity();
558-
var worldToClick = CanvasKit.SkM44.identity();
562+
let clickToWorld = CanvasKit.SkM44.identity();
563+
let worldToClick = CanvasKit.SkM44.identity();
559564
// rotation of the cube shown in the demo
560-
var rotation = CanvasKit.SkM44.identity();
565+
let rotation = CanvasKit.SkM44.identity();
561566
// temporary during a click and drag
562-
var clickRotation = CanvasKit.SkM44.identity();
567+
let clickRotation = CanvasKit.SkM44.identity();
563568

564569
// A virtual sphere used for tumbling the object on screen.
565570
const vSphereCenter = [sizeX/2, sizeY/2];
@@ -578,23 +583,82 @@ <h2> 3D perspective transformations </h2>
578583
const camCOA = [0, 0, 0];
579584
const camUp = [0, 1, 0];
580585

581-
var mouseDown = false;
582-
var clickDown = [0, 0]; // location of click down
583-
var lastMouse = [0, 0]; // last mouse location
586+
let mouseDown = false;
587+
let clickDown = [0, 0]; // location of click down
588+
let lastMouse = [0, 0]; // last mouse location
584589

585590
// keep spinning after mouse up. Also start spinning on load
586-
var axis = [0.4, 1, 1];
587-
var totalSpin = 0;
588-
var spinRate = 0.1;
589-
var lastRadians = 0;
590-
var spinning = setInterval(keepSpinning, 30);
591+
let axis = [0.4, 1, 1];
592+
let totalSpin = 0;
593+
let spinRate = 0.1;
594+
let lastRadians = 0;
595+
let spinning = setInterval(keepSpinning, 30);
591596

592597
const textPaint = new CanvasKit.SkPaint();
593598
textPaint.setColor(CanvasKit.BLACK);
594599
textPaint.setAntiAlias(true);
595600
const roboto = CanvasKit.SkFontMgr.RefDefault().MakeTypefaceFromData(robotoData);
596601
const textFont = new CanvasKit.SkFont(roboto, 30);
597602

603+
const imgscale = CanvasKit.SkMatrix.scaled(2, 2);
604+
const textureShader = CanvasKit.MakeImageFromEncoded(textureImgData).makeShader(
605+
CanvasKit.TileMode.Clamp, CanvasKit.TileMode.Clamp, imgscale);
606+
const normalShader = CanvasKit.MakeImageFromEncoded(normalImgData).makeShader(
607+
CanvasKit.TileMode.Clamp, CanvasKit.TileMode.Clamp, imgscale);
608+
const children = [textureShader, normalShader];
609+
610+
const prog = `
611+
in fragmentProcessor color_map;
612+
in fragmentProcessor normal_map;
613+
614+
uniform float4x4 localToWorld;
615+
uniform float4x4 localToWorldAdjInv;
616+
uniform float3 lightPos;
617+
618+
float3 convert_normal_sample(half4 c) {
619+
float3 n = 2 * c.rgb - 1;
620+
n.y = -n.y;
621+
return n;
622+
}
623+
624+
void main(float2 p, inout half4 color) {
625+
float3 norm = convert_normal_sample(sample(normal_map, p));
626+
float3 plane_norm = normalize(localToWorld * float4(norm, 0)).xyz;
627+
628+
float3 plane_pos = (localToWorld * float4(p, 0, 1)).xyz;
629+
float3 light_dir = normalize(lightPos - plane_pos);
630+
631+
float ambient = 0.2;
632+
float dp = dot(plane_norm, light_dir);
633+
float scale = min(ambient + max(dp, 0), 1);
634+
635+
color = sample(color_map, p) * half4(float4(scale, scale, scale, 1));
636+
}
637+
`;
638+
const fact = CanvasKit.SkRuntimeEffect.Make(prog);
639+
640+
// properties of light
641+
let lightLocation = [...vSphereCenter];
642+
let lightDistance = vSphereRadius;
643+
let lightIconRadius = 12;
644+
let draggingLight = false;
645+
646+
function computeLightWorldPos() {
647+
return CanvasKit.SkVector.add(CanvasKit.SkVector.mulScalar([...vSphereCenter, 0], 0.5),
648+
CanvasKit.SkVector.mulScalar(vSphereUnitV3(lightLocation), lightDistance));
649+
}
650+
651+
let lightWorldPos = computeLightWorldPos();
652+
653+
function drawLight(canvas) {
654+
const paint = new CanvasKit.SkPaint();
655+
paint.setAntiAlias(true);
656+
paint.setColor(CanvasKit.WHITE);
657+
canvas.drawCircle(...lightLocation, lightIconRadius + 2, paint);
658+
paint.setColor(CanvasKit.BLACK);
659+
canvas.drawCircle(...lightLocation, lightIconRadius, paint);
660+
}
661+
598662
// Takes an x and y rotation in radians and a scale and returns a 4x4 matrix used to draw a
599663
// face of the cube in that orientation.
600664
function faceM44(rx, ry, scale) {
@@ -668,11 +732,15 @@ <h2> 3D perspective transformations </h2>
668732
canvas.experimental_concat44(CanvasKit.SkM44.multiply(trans, m, mustInvert(trans)));
669733
const znormal = front(canvas.experimental_getLocalToDevice());
670734
if (znormal < 0) {
671-
return;// skip faces facing backwards
735+
return; // skip faces facing backwards
672736
}
737+
const ltw = canvas.experimental_getLocalToWorld();
738+
// shader expects the 4x4 matrices in column major order.
739+
const uniforms = [...CanvasKit.SkM44.transpose(ltw), ...mustInvert(ltw), ...lightWorldPos];
673740
const paint = new CanvasKit.SkPaint();
674-
paint.setColor(color);
675-
// TODO replace color with a bump shader
741+
paint.setAntiAlias(true);
742+
const shader = fact.makeShaderWithChildren(uniforms, true /*=opaque*/, children);
743+
paint.setShader(shader);
676744
canvas.drawRRect(rr, paint);
677745
canvas.drawText(znormal.toFixed(2), faceScale*0.25, faceScale*0.4, textPaint, textFont);
678746
}
@@ -705,6 +773,8 @@ <h2> 3D perspective transformations </h2>
705773
vSphereCenter[0], vSphereCenter[1] + vSphereRadius, paint);
706774
canvas.drawLine(vSphereCenter[0] - vSphereRadius, vSphereCenter[1],
707775
vSphereCenter[0] + vSphereRadius, vSphereCenter[1], paint);
776+
777+
drawLight(canvas);
708778
}
709779

710780
// convert a 2D point in the circle displayed on screen to a 3D unit vector.
@@ -763,22 +833,40 @@ <h2> 3D perspective transformations </h2>
763833

764834
function interact(e) {
765835
const type = e.type;
836+
let eventPos = [e.offsetX, e.offsetY];
766837
if (type === 'lostpointercapture' || type === 'pointerup' || type == 'pointerleave') {
767-
mouseDown = false;
768-
if (spinRate > 0.02) {
769-
stopSpinning();
770-
spinning = setInterval(keepSpinning, 30);
838+
if (draggingLight) {
839+
draggingLight = false;
840+
} else if (mouseDown) {
841+
mouseDown = false;
842+
if (spinRate > 0.02) {
843+
stopSpinning();
844+
spinning = setInterval(keepSpinning, 30);
845+
}
846+
} else {
847+
return;
771848
}
772849
return;
773850
} else if (type === 'pointermove') {
774-
if (!mouseDown) { return; }
775-
lastMouse = [e.offsetX, e.offsetY];
776-
clickRotation = computeVSphereRotation(clickDown, lastMouse);
851+
if (draggingLight) {
852+
lightLocation = eventPos;
853+
lightWorldPos = computeLightWorldPos();
854+
} else if (mouseDown) {
855+
lastMouse = eventPos;
856+
clickRotation = computeVSphereRotation(clickDown, lastMouse);
857+
} else {
858+
return;
859+
}
777860
} else if (type === 'pointerdown') {
861+
// Are we repositioning the light?
862+
if (CanvasKit.SkVector.dist(eventPos, lightLocation) < lightIconRadius) {
863+
draggingLight = true;
864+
return;
865+
}
778866
stopSpinning();
779867
mouseDown = true;
780-
clickDown = [e.offsetX, e.offsetY];
781-
lastMouse = clickDown;
868+
clickDown = eventPos;
869+
lastMouse = eventPos;
782870
}
783871
surface.requestAnimationFrame(drawFrame);
784872
};

modules/canvaskit/externs.js

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -293,6 +293,7 @@ var CanvasKit = {
293293
lookat: function() {},
294294
perspective: function() {},
295295
rc: function() {},
296+
transpose: function() {},
296297
},
297298

298299
SkMatrix: {
@@ -335,7 +336,7 @@ var CanvasKit = {
335336
setStrokeWidth: function() {},
336337
setStyle: function() {},
337338

338-
// private API
339+
// Private API
339340
delete: function() {},
340341
},
341342

@@ -493,6 +494,7 @@ var CanvasKit = {
493494
mulScalar: function() {},
494495
length: function() {},
495496
lengthSquared: function() {},
497+
dist: function() {},
496498
},
497499

498500
SkVertices: {

modules/canvaskit/interface.js

Lines changed: 28 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -214,6 +214,9 @@ CanvasKit.onRuntimeInitialized = function() {
214214
CanvasKit.SkVector.sub = function(a, b) {
215215
return a.map(function(v, i) { return v-b[i]; });
216216
}
217+
CanvasKit.SkVector.dist = function(a, b) {
218+
return CanvasKit.SkVector.length(CanvasKit.SkVector.sub(a, b));
219+
}
217220
CanvasKit.SkVector.normalize = function(v) {
218221
return CanvasKit.SkVector.mulScalar(v, 1/CanvasKit.SkVector.length(v));
219222
}
@@ -408,6 +411,14 @@ CanvasKit.onRuntimeInitialized = function() {
408411
return tmp;
409412
}
410413

414+
CanvasKit.SkM44.transpose = function(m) {
415+
return [
416+
m[0], m[4], m[8], m[12],
417+
m[1], m[5], m[9], m[13],
418+
m[2], m[6], m[10], m[14],
419+
m[3], m[7], m[11], m[15],
420+
];
421+
}
411422

412423
// An SkColorMatrix is a 4x4 color matrix that transforms the 4 color channels
413424
// with a 1x4 matrix that post-translates those 4 channels.
@@ -421,28 +432,33 @@ CanvasKit.onRuntimeInitialized = function() {
421432
// Much of this was hand-transcribed from SkColorMatrix.cpp, because it's easier to
422433
// deal with a Float32Array of length 20 than to try to expose the SkColorMatrix object.
423434

435+
var rScale = 0;
436+
var gScale = 6;
437+
var bScale = 12;
438+
var aScale = 18;
439+
424440
var rPostTrans = 4;
425441
var gPostTrans = 9;
426442
var bPostTrans = 14;
427443
var aPostTrans = 19;
428444

429445
CanvasKit.SkColorMatrix = {};
430446
CanvasKit.SkColorMatrix.identity = function() {
431-
return Float32Array.of([
432-
1, 0, 0, 0, 0,
433-
0, 1, 0, 0, 0,
434-
0, 0, 1, 0, 0,
435-
0, 0, 0, 1, 0,
436-
]);
447+
var m = new Float32Array(20);
448+
m[rScale] = 1;
449+
m[gScale] = 1;
450+
m[bScale] = 1;
451+
m[aScale] = 1;
452+
return m;
437453
}
438454

439455
CanvasKit.SkColorMatrix.scaled = function(rs, gs, bs, as) {
440-
return Float32Array.of([
441-
rs, 0, 0, 0, 0,
442-
0, gs, 0, 0, 0,
443-
0, 0, bs, 0, 0,
444-
0, 0, 0, as, 0,
445-
]);
456+
var m = new Float32Array(20);
457+
m[rScale] = rs;
458+
m[gScale] = gs;
459+
m[bScale] = bs;
460+
m[aScale] = as;
461+
return m;
446462
}
447463

448464
var rotateIndices = [

0 commit comments

Comments
 (0)