@ikijs/engine 0.3.0 → 0.3.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +4 -2
- package/dist/index.js +28 -11
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +28 -11
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -86,8 +86,10 @@ delta, so a backgrounded tab or a long hitch cannot snap the rig.
|
|
|
86
86
|
|
|
87
87
|
## Rendering notes
|
|
88
88
|
|
|
89
|
-
- The whole pipeline is **premultiplied alpha** —
|
|
90
|
-
|
|
89
|
+
- The whole pipeline is **premultiplied alpha** — textures are uploaded
|
|
90
|
+
premultiplied (so LINEAR filtering never blends a transparent texel's rgb
|
|
91
|
+
into an edge), the shader keeps them so, and the canvas is created with
|
|
92
|
+
`premultipliedAlpha: true`.
|
|
91
93
|
- Clipping masks use the stencil buffer. If the context grants no stencil, the
|
|
92
94
|
affected parts render unclipped and `load()` logs it.
|
|
93
95
|
- Textures are decoded from `data:` URIs only; external URLs are skipped with a
|
package/dist/index.js
CHANGED
|
@@ -399,10 +399,10 @@ var IkiPlayer = class {
|
|
|
399
399
|
this.canvas = canvas;
|
|
400
400
|
const gl = canvas.getContext("webgl2", {
|
|
401
401
|
alpha: true,
|
|
402
|
-
// The whole pipeline is premultiplied-alpha:
|
|
403
|
-
//
|
|
404
|
-
// ONE_MINUS_SRC_ALPHA, and the page compositor reads the
|
|
405
|
-
// as premultiplied. Straight-alpha (`premultipliedAlpha: false`) cannot
|
|
402
|
+
// The whole pipeline is premultiplied-alpha: textures are uploaded
|
|
403
|
+
// premultiplied, the fragment shader keeps them so, the blend function
|
|
404
|
+
// is ONE / ONE_MINUS_SRC_ALPHA, and the page compositor reads the
|
|
405
|
+
// framebuffer as premultiplied. Straight-alpha (`premultipliedAlpha: false`) cannot
|
|
406
406
|
// be made consistent with SRC_ALPHA-style blending: semi-transparent
|
|
407
407
|
// pixels over a transparent background come out premultiplied anyway
|
|
408
408
|
// and composite too dark.
|
|
@@ -538,7 +538,7 @@ var IkiPlayer = class {
|
|
|
538
538
|
return null;
|
|
539
539
|
}
|
|
540
540
|
gl.bindTexture(gl.TEXTURE_2D, texture);
|
|
541
|
-
gl.pixelStorei(gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL,
|
|
541
|
+
gl.pixelStorei(gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, true);
|
|
542
542
|
gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, false);
|
|
543
543
|
drainGlErrors(gl);
|
|
544
544
|
gl.texImage2D(
|
|
@@ -949,14 +949,17 @@ uniform float u_alphaCutoff;
|
|
|
949
949
|
in vec2 v_uv;
|
|
950
950
|
out vec4 outColor;
|
|
951
951
|
void main() {
|
|
952
|
+
// Texels are premultiplied (see the upload); the untextured fill is opaque
|
|
953
|
+
// white, premultiplied or not.
|
|
952
954
|
vec4 base = u_useTexture ? texture(u_tex, v_uv) : vec4(1.0);
|
|
953
955
|
vec4 tinted = base * u_color;
|
|
954
956
|
// 0 for normal draws (no-op); raised during the stencil mask-write pass so
|
|
955
957
|
// only opaque mask coverage marks the stencil (the transparent fringe is cut).
|
|
956
958
|
if (tinted.a < u_alphaCutoff) discard;
|
|
957
|
-
//
|
|
958
|
-
//
|
|
959
|
-
|
|
959
|
+
// The blend function and the canvas compositing contract (premultipliedAlpha:
|
|
960
|
+
// true) both expect rgb already scaled by alpha. base.rgb is; the tint's own
|
|
961
|
+
// alpha still has to scale it (base.a is already folded into base.rgb).
|
|
962
|
+
outColor = vec4(tinted.rgb * u_color.a, tinted.a);
|
|
960
963
|
}`;
|
|
961
964
|
async function decodeTexture(source) {
|
|
962
965
|
if (!source.startsWith("data:")) {
|
|
@@ -969,7 +972,7 @@ async function decodeTexture(source) {
|
|
|
969
972
|
const blob = await (await fetch(source)).blob();
|
|
970
973
|
return createImageBitmap(blob, {
|
|
971
974
|
imageOrientation: "none",
|
|
972
|
-
premultiplyAlpha: "
|
|
975
|
+
premultiplyAlpha: "premultiply"
|
|
973
976
|
});
|
|
974
977
|
}
|
|
975
978
|
function createUnitQuad(gl) {
|
|
@@ -1073,7 +1076,10 @@ var FixedStepClock = class {
|
|
|
1073
1076
|
// src/idle-motion.ts
|
|
1074
1077
|
var BLINK_INTERVAL_MIN_MS = 1500;
|
|
1075
1078
|
var BLINK_INTERVAL_MAX_MS = 6e3;
|
|
1076
|
-
var
|
|
1079
|
+
var BLINK_CLOSE_MS = 60;
|
|
1080
|
+
var BLINK_HOLD_MS = 20;
|
|
1081
|
+
var BLINK_OPEN_MS = 100;
|
|
1082
|
+
var BLINK_DURATION_MS = BLINK_CLOSE_MS + BLINK_HOLD_MS + BLINK_OPEN_MS;
|
|
1077
1083
|
var BREATH_PERIOD_MS = 3500;
|
|
1078
1084
|
var GAZE_RADIUS = 0.3;
|
|
1079
1085
|
var GAZE_RETARGET_MIN_MS = 1200;
|
|
@@ -1091,7 +1097,18 @@ function lerp(a, b, t) {
|
|
|
1091
1097
|
return a + (b - a) * t;
|
|
1092
1098
|
}
|
|
1093
1099
|
function blinkEnvelope(phase) {
|
|
1094
|
-
|
|
1100
|
+
const ms = phase * BLINK_DURATION_MS;
|
|
1101
|
+
if (ms <= 0) return 1;
|
|
1102
|
+
if (ms < BLINK_CLOSE_MS) {
|
|
1103
|
+
const t = ms / BLINK_CLOSE_MS;
|
|
1104
|
+
return 1 - t * t * (3 - 2 * t);
|
|
1105
|
+
}
|
|
1106
|
+
if (ms <= BLINK_CLOSE_MS + BLINK_HOLD_MS) return 0;
|
|
1107
|
+
if (ms < BLINK_DURATION_MS) {
|
|
1108
|
+
const t = (ms - BLINK_CLOSE_MS - BLINK_HOLD_MS) / BLINK_OPEN_MS;
|
|
1109
|
+
return 1 - (1 - t) * (1 - t);
|
|
1110
|
+
}
|
|
1111
|
+
return 1;
|
|
1095
1112
|
}
|
|
1096
1113
|
function randomInDisk(rng, radius) {
|
|
1097
1114
|
const r = Math.sqrt(rng()) * radius;
|