@johnmorrisdotca/wakusei-planets 0.11.0 → 0.11.1
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/CHANGELOG.md +7 -0
- package/README.md +3 -3
- package/dist/bodies/dwarfs.js +1 -0
- package/dist/element.d.ts +2 -2
- package/dist/scene/glsl.d.ts +2 -2
- package/dist/scene/glsl.js +10 -6
- package/dist/textures/triton-1024.webp +0 -0
- package/dist/textures/triton-512.webp +0 -0
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,12 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.11.1 - 2026-11-03
|
|
4
|
+
|
|
5
|
+
The dwarf planets' realistic look is smooth when it is small (MODULES-332).
|
|
6
|
+
|
|
7
|
+
- **No more pixel-sized specks on a small body.** At about 80 px (the portrait builder) Ceres, Orcus, Quaoar, Makemake, Gonggong and Sedna showed square dark specks: the craters and the fine noise were finer than a pixel and were sampled anyway. The shader now knows how big a pixel is: an octave of noise finer than the pixel is replaced by its average, a crater smaller than about two pixels fades out, a crater's rim no longer starts with a step (which a pixel could not draw), and the bump-mapped relief, which is worked out from neighbouring pixels and cannot show a bump a few pixels wide, fades out on a small disc so the colour alone carries the craters. Compared at 64, 128 and 512 px, light and dark: soft craters at every size, the same look as before at 512. All the realistic bodies share the shader, so Mercury, the Moon and the rest are smoother when small too. Test: a realistic dwarf planet at 64, 80 and 128 px has under 0.4 in a thousand speck pixels (the old shader had 17 in a thousand at 64 px).
|
|
8
|
+
- **Ceres looks like Ceres in the realistic look** (it uses Dawn's map as the painted look does, with Occator's bright spots), not a generic cratered ball.
|
|
9
|
+
- **Triton's filled north is soft**: the unseen north of the map (a fill made by `scripts/make-textures.py`) took the dark ground at its edge and smeared it into blobs with a hard line at the seam; it now fades gradually from the real picture's colour to the map's mean, over a long smooth band.
|
|
3
10
|
## 0.11.0 - 2026-11-03
|
|
4
11
|
|
|
5
12
|
The drag rule, checked with the family's own check.
|
package/README.md
CHANGED
|
@@ -13,9 +13,9 @@ A clean line drawing, a shaded realistic drawing, or a painted surface map, with
|
|
|
13
13
|
|
|
14
14
|
<p align="center"><a href="https://johnmorrisdotca.github.io/wakusei-planets/"><strong>Open the demo →</strong></a> · <a href="https://johnmorrisdotca.github.io/wakusei-planets/embed.html">Embed page</a> · <a href="https://johnmorrisdotca.github.io/wakusei-planets/docs/">Docs</a></p>
|
|
15
15
|
|
|
16
|
-
<p align="center"><img alt="Jupiter and Saturn drawn in the realistic look, and Saturn as a line drawing" src="https://raw.githubusercontent.com/johnmorrisdotca/wakusei-planets/v0.11.
|
|
16
|
+
<p align="center"><img alt="Jupiter and Saturn drawn in the realistic look, and Saturn as a line drawing" src="https://raw.githubusercontent.com/johnmorrisdotca/wakusei-planets/v0.11.1/docs/images/hero-desk.png" width="640"></p>
|
|
17
17
|
|
|
18
|
-
<p align="center"><img alt="Every body at one scale, the Earth among them: each small body has a magnified picture joined by a line, and the Sun shows only its edge" src="https://raw.githubusercontent.com/johnmorrisdotca/wakusei-planets/v0.11.
|
|
18
|
+
<p align="center"><img alt="Every body at one scale, the Earth among them: each small body has a magnified picture joined by a line, and the Sun shows only its edge" src="https://raw.githubusercontent.com/johnmorrisdotca/wakusei-planets/v0.11.1/docs/images/lineup-desk.png" width="640"></p>
|
|
19
19
|
|
|
20
20
|
## One minute
|
|
21
21
|
|
|
@@ -273,7 +273,7 @@ A body that turns by itself and a moving sky, in HTML:
|
|
|
273
273
|
|
|
274
274
|
## The portrait builder
|
|
275
275
|
|
|
276
|
-
<p align="center"><img alt="The Sun and the planets in an arc, painted, with their names, in the portrait builder" src="https://raw.githubusercontent.com/johnmorrisdotca/wakusei-planets/v0.11.
|
|
276
|
+
<p align="center"><img alt="The Sun and the planets in an arc, painted, with their names, in the portrait builder" src="https://raw.githubusercontent.com/johnmorrisdotca/wakusei-planets/v0.11.1/docs/images/portrait-family.png" width="640"></p>
|
|
277
277
|
|
|
278
278
|
[The portrait builder](https://johnmorrisdotca.github.io/wakusei-planets/portrait.html) puts any bodies in one picture: drag them, size them, turn them, order them front to back, arrange them in a row, an arc, a grid or at true orbit distance (true or readable sizes, a planet's moons round it in orbit order), light them from one direction, and take the code, a PNG or an SVG. The scene is kept in the address, and every body is drawn in one WebGL scene, so the page holds one WebGL context. [The portrait builder](docs/guides/portrait-builder.md) is its guide.
|
|
279
279
|
|
package/dist/bodies/dwarfs.js
CHANGED
|
@@ -16,6 +16,7 @@ registerLook({
|
|
|
16
16
|
relief: 0.7,
|
|
17
17
|
ambient: 0.02,
|
|
18
18
|
painted: { map: "ceres", widths: [512, 1024, 2048], far: 2048 },
|
|
19
|
+
mapped: true,
|
|
19
20
|
});
|
|
20
21
|
registerLook({ id: "orcus", surface: rock({ dark: "#6f7074", light: "#a9a9ab", craters: 0.5, contrast: 0.5, seed: 63, patches: 2.2 }), relief: 0.5, ambient: 0.02 });
|
|
21
22
|
registerLook({
|
package/dist/element.d.ts
CHANGED
|
@@ -25,7 +25,7 @@ export type WakuseiState = "line" | "loading" | "still" | "live" | "lost" | "una
|
|
|
25
25
|
* console.log(TEXTURE_BASE);
|
|
26
26
|
* ```
|
|
27
27
|
*/
|
|
28
|
-
export declare const TEXTURE_BASE = "https://cdn.jsdelivr.net/npm/@johnmorrisdotca/wakusei-planets@0.11.
|
|
28
|
+
export declare const TEXTURE_BASE = "https://cdn.jsdelivr.net/npm/@johnmorrisdotca/wakusei-planets@0.11.1/dist/textures/";
|
|
29
29
|
/**
|
|
30
30
|
* Where the sharpest surface pictures are: the files of this exact version in the repository, on jsDelivr's GitHub address. The npm package holds only the two smaller widths, so a page that
|
|
31
31
|
* never zooms in never fetches them. Set `texture-far-base` on an element to serve them yourself.
|
|
@@ -37,7 +37,7 @@ export declare const TEXTURE_BASE = "https://cdn.jsdelivr.net/npm/@johnmorrisdot
|
|
|
37
37
|
* console.log(TEXTURE_FAR_BASE);
|
|
38
38
|
* ```
|
|
39
39
|
*/
|
|
40
|
-
export declare const TEXTURE_FAR_BASE = "https://cdn.jsdelivr.net/gh/johnmorrisdotca/wakusei-planets@v0.11.
|
|
40
|
+
export declare const TEXTURE_FAR_BASE = "https://cdn.jsdelivr.net/gh/johnmorrisdotca/wakusei-planets@v0.11.1/textures/";
|
|
41
41
|
/**
|
|
42
42
|
* The `<wakusei-body>` custom element: a body of the solar system, drawn in a look.
|
|
43
43
|
*
|
package/dist/scene/glsl.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
export declare const VERTEX = "\nvarying vec3 vObj;\nvarying vec3 vN;\nvarying vec3 vW;\nvoid main() {\n vObj = vec3(position.z, position.x, position.y);\n vN = normalize(normalMatrix * normal);\n vec4 w = modelMatrix * vec4(position, 1.0);\n vW = w.xyz;\n gl_Position = projectionMatrix * viewMatrix * w;\n}";
|
|
2
2
|
/** Noise, craters and the band palette, for the surface code of a body to call. */
|
|
3
|
-
export declare const PRELUDE = "\nfloat hash13(vec3 p) { p = fract(p * 0.1031); p += dot(p, p.zyx + 31.32); return fract((p.x + p.y) * p.z); }\nvec3 hash33(vec3 p) { p = fract(p * vec3(0.1031, 0.1030, 0.0973)); p += dot(p, p.yxz + 33.33); return fract((p.xxy + p.yxx) * p.zyx); }\nfloat vnoise(vec3 p) {\n vec3 i = floor(p); vec3 f = fract(p); f = f * f * (3.0 - 2.0 * f);\n return mix(mix(mix(hash13(i), hash13(i + vec3(1,0,0)), f.x), mix(hash13(i + vec3(0,1,0)), hash13(i + vec3(1,1,0)), f.x), f.y),\n mix(mix(hash13(i + vec3(0,0,1)), hash13(i + vec3(1,0,1)), f.x), mix(hash13(i + vec3(0,1,1)), hash13(i + vec3(1,1,1)), f.x), f.y), f.z);\n}\nfloat fbm(vec3 p) { float a = 0.5; float s = 0.0; for (int i = 0; i < 5; i++) { s += a * vnoise(p); p = p * 2.03 + vec3(1.7, 9.2, 3.1); a *= 0.5; } return s; }\n// Craters: a bowl and a raised rim in each cell that has one. Returns a height, negative in a bowl.\nfloat craters(vec3 p, float freq, float amp, float seed) {\n vec3 q = p * freq + seed; vec3 ip = floor(q); float h = 0.0;\n for (int x = -1; x <= 1; x++) for (int y = -1; y <= 1; y++) for (int z = -1; z <= 1; z++) {\n vec3 c = ip + vec3(float(x), float(y), float(z));\n float on = step(0.52, hash13(c + 3.7));\n vec3 ctr = c + hash33(c);\n float rad = mix(0.12, 0.36, hash13(c + 17.3));\n float d = length(q - ctr) / rad;\n float bowl = d < 1.0 ? (d * d - 1.0) : 0.0;\n float rim = d >= 1.0 ? exp(-pow((d - 1.0) * 5.0, 2.0)) * 0.3 : 0.0;\n h += on * amp * rad * (bowl + rim);\n }\n return h;\n}\nfloat lon(vec3 p) { return atan(p.y, p.x); }\nfloat lat(vec3 p) { return asin(clamp(p.z, -1.0, 1.0)); }\nfloat wrapPi(float a) { return a - 6.2831853 * floor((a + 3.1415927) / 6.2831853); }\nvec3 dirOf(float lonDeg, float latDeg) { float lo = radians(lonDeg); float la = radians(latDeg); return vec3(cos(la) * cos(lo), cos(la) * sin(lo), sin(la)); }\n// One big round bowl with a rim, by longitude, latitude and angular radius in degrees. Negative inside.\nfloat bowl(vec3 p, float lonDeg, float latDeg, float radDeg, float depth) {\n float d = acos(clamp(dot(p, dirOf(lonDeg, latDeg)), -1.0, 1.0)) / radians(radDeg);\n return d < 1.0 ? depth * (d * d - 1.0) : depth * exp(-pow((d - 1.0) * 5.0, 2.0)) * 0.3;\n}\n// A soft oval on the body, 1 inside and 0 outside, by longitude and latitude in degrees.\nfloat oval(vec3 p, float lon0, float lat0, float rx, float ry, float soft) {\n float dx = wrapPi(lon(p) - radians(lon0)) * cos(radians(lat0)) / radians(rx);\n float dy = (lat(p) - radians(lat0)) / radians(ry);\n return 1.0 - smoothstep(1.0 - soft, 1.0, sqrt(dx * dx + dy * dy));\n}";
|
|
3
|
+
export declare const PRELUDE = "\nfloat hash13(vec3 p) { p = fract(p * 0.1031); p += dot(p, p.zyx + 31.32); return fract((p.x + p.y) * p.z); }\nvec3 hash33(vec3 p) { p = fract(p * vec3(0.1031, 0.1030, 0.0973)); p += dot(p, p.yxz + 33.33); return fract((p.xxy + p.yxx) * p.zyx); }\nfloat vnoise(vec3 p) {\n vec3 i = floor(p); vec3 f = fract(p); f = f * f * (3.0 - 2.0 * f);\n return mix(mix(mix(hash13(i), hash13(i + vec3(1,0,0)), f.x), mix(hash13(i + vec3(0,1,0)), hash13(i + vec3(1,1,0)), f.x), f.y),\n mix(mix(hash13(i + vec3(0,0,1)), hash13(i + vec3(1,0,1)), f.x), mix(hash13(i + vec3(0,1,1)), hash13(i + vec3(1,1,1)), f.x), f.y), f.z);\n}\n// Noise that knows how big a pixel is: an octave finer than the pixel can show is replaced by its average (0.5) instead of being sampled, so a small body is smooth and not a spray of pixel-sized specks.\nfloat fbm(vec3 p) { float fw = length(fwidth(p)); float a = 0.5; float s = 0.0; for (int i = 0; i < 5; i++) { s += a * mix(0.5, vnoise(p), 1.0 - smoothstep(0.3, 0.7, fw)); p = p * 2.03 + vec3(1.7, 9.2, 3.1); fw *= 2.03; a *= 0.5; } return s; }\n// Craters: a bowl and a raised rim in each cell that has one. Returns a height, negative in a bowl. A crater smaller than about two pixels fades out (it would only be noise).\nfloat craters(vec3 p, float freq, float amp, float seed) {\n vec3 q = p * freq + seed; vec3 ip = floor(q); float h = 0.0;\n float fw = length(fwidth(q));\n for (int x = -1; x <= 1; x++) for (int y = -1; y <= 1; y++) for (int z = -1; z <= 1; z++) {\n vec3 c = ip + vec3(float(x), float(y), float(z));\n float on = step(0.52, hash13(c + 3.7));\n vec3 ctr = c + hash33(c);\n float rad = mix(0.12, 0.36, hash13(c + 17.3));\n float d = length(q - ctr) / rad;\n float bowl = d < 1.0 ? (d * d - 1.0) : 0.0;\n float rim = d >= 1.0 ? exp(-pow((d - 1.0) * 5.0, 2.0)) * 0.3 * smoothstep(1.0, 1.08, d) : 0.0;\n h += on * amp * rad * (bowl + rim) * (1.0 - smoothstep(0.35, 0.9, fw / rad));\n }\n return h;\n}\nfloat lon(vec3 p) { return atan(p.y, p.x); }\nfloat lat(vec3 p) { return asin(clamp(p.z, -1.0, 1.0)); }\nfloat wrapPi(float a) { return a - 6.2831853 * floor((a + 3.1415927) / 6.2831853); }\nvec3 dirOf(float lonDeg, float latDeg) { float lo = radians(lonDeg); float la = radians(latDeg); return vec3(cos(la) * cos(lo), cos(la) * sin(lo), sin(la)); }\n// One big round bowl with a rim, by longitude, latitude and angular radius in degrees. Negative inside.\nfloat bowl(vec3 p, float lonDeg, float latDeg, float radDeg, float depth) {\n float d = acos(clamp(dot(p, dirOf(lonDeg, latDeg)), -1.0, 1.0)) / radians(radDeg);\n return d < 1.0 ? depth * (d * d - 1.0) : depth * exp(-pow((d - 1.0) * 5.0, 2.0)) * 0.3 * smoothstep(1.0, 1.08, d);\n}\n// A soft oval on the body, 1 inside and 0 outside, by longitude and latitude in degrees.\nfloat oval(vec3 p, float lon0, float lat0, float rx, float ry, float soft) {\n float dx = wrapPi(lon(p) - radians(lon0)) * cos(radians(lat0)) / radians(rx);\n float dy = (lat(p) - radians(lat0)) / radians(ry);\n return 1.0 - smoothstep(1.0 - soft, 1.0, sqrt(dx * dx + dy * dy));\n}";
|
|
4
4
|
/** The fragment shader of a body: the surface code goes between the prelude and `main`. */
|
|
5
5
|
export declare function bodyFragment(surface: string, painted: boolean, world?: boolean): string;
|
|
6
6
|
/** A painted body's surface code: the map by longitude and latitude, with the seam at 180 degrees left alone. */
|
|
@@ -19,4 +19,4 @@ export declare const RING_FRAGMENT_WORLD: string;
|
|
|
19
19
|
export declare const GLOW_VERTEX = "\nvarying vec2 vP;\nvoid main() { vP = position.xy; gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0); }";
|
|
20
20
|
export declare const GLOW_FRAGMENT = "\nprecision highp float;\nvarying vec2 vP;\nuniform vec3 uColour;\nvoid main() {\n float r = length(vP);\n if (r < 0.98) discard;\n float a = exp(-(r - 1.0) * 2.4) * 0.62;\n float streak = 0.82 + 0.18 * sin(atan(vP.y, vP.x) * 9.0 + r * 3.0);\n a *= streak * smoothstep(3.0, 1.6, r);\n gl_FragColor = vec4(uColour * a, a);\n}";
|
|
21
21
|
/** A cheap lit ball for a moon seen small beside its planet. */
|
|
22
|
-
export declare const BALL_FRAGMENT = "\nprecision highp float;\nuniform vec3 uLight;\nuniform vec3 uColour;\nvarying vec3 vObj;\nvarying vec3 vN;\nvarying vec3 vW;\n\nfloat hash13(vec3 p) { p = fract(p * 0.1031); p += dot(p, p.zyx + 31.32); return fract((p.x + p.y) * p.z); }\nvec3 hash33(vec3 p) { p = fract(p * vec3(0.1031, 0.1030, 0.0973)); p += dot(p, p.yxz + 33.33); return fract((p.xxy + p.yxx) * p.zyx); }\nfloat vnoise(vec3 p) {\n vec3 i = floor(p); vec3 f = fract(p); f = f * f * (3.0 - 2.0 * f);\n return mix(mix(mix(hash13(i), hash13(i + vec3(1,0,0)), f.x), mix(hash13(i + vec3(0,1,0)), hash13(i + vec3(1,1,0)), f.x), f.y),\n mix(mix(hash13(i + vec3(0,0,1)), hash13(i + vec3(1,0,1)), f.x), mix(hash13(i + vec3(0,1,1)), hash13(i + vec3(1,1,1)), f.x), f.y), f.z);\n}\nfloat fbm(vec3 p) { float a = 0.5; float s = 0.0; for (int i = 0; i < 5; i++) { s += a * vnoise(p); p = p * 2.03 + vec3(1.7, 9.2, 3.1); a *= 0.5; } return s; }\n// Craters: a bowl and a raised rim in each cell that has one. Returns a height, negative in a bowl.\nfloat craters(vec3 p, float freq, float amp, float seed) {\n vec3 q = p * freq + seed; vec3 ip = floor(q); float h = 0.0;\n for (int x = -1; x <= 1; x++) for (int y = -1; y <= 1; y++) for (int z = -1; z <= 1; z++) {\n vec3 c = ip + vec3(float(x), float(y), float(z));\n float on = step(0.52, hash13(c + 3.7));\n vec3 ctr = c + hash33(c);\n float rad = mix(0.12, 0.36, hash13(c + 17.3));\n float d = length(q - ctr) / rad;\n float bowl = d < 1.0 ? (d * d - 1.0) : 0.0;\n float rim = d >= 1.0 ? exp(-pow((d - 1.0) * 5.0, 2.0)) * 0.3 : 0.0;\n h += on * amp * rad * (bowl + rim);\n }\n return h;\n}\nfloat lon(vec3 p) { return atan(p.y, p.x); }\nfloat lat(vec3 p) { return asin(clamp(p.z, -1.0, 1.0)); }\nfloat wrapPi(float a) { return a - 6.2831853 * floor((a + 3.1415927) / 6.2831853); }\nvec3 dirOf(float lonDeg, float latDeg) { float lo = radians(lonDeg); float la = radians(latDeg); return vec3(cos(la) * cos(lo), cos(la) * sin(lo), sin(la)); }\n// One big round bowl with a rim, by longitude, latitude and angular radius in degrees. Negative inside.\nfloat bowl(vec3 p, float lonDeg, float latDeg, float radDeg, float depth) {\n float d = acos(clamp(dot(p, dirOf(lonDeg, latDeg)), -1.0, 1.0)) / radians(radDeg);\n return d < 1.0 ? depth * (d * d - 1.0) : depth * exp(-pow((d - 1.0) * 5.0, 2.0)) * 0.3;\n}\n// A soft oval on the body, 1 inside and 0 outside, by longitude and latitude in degrees.\nfloat oval(vec3 p, float lon0, float lat0, float rx, float ry, float soft) {\n float dx = wrapPi(lon(p) - radians(lon0)) * cos(radians(lat0)) / radians(rx);\n float dy = (lat(p) - radians(lat0)) / radians(ry);\n return 1.0 - smoothstep(1.0 - soft, 1.0, sqrt(dx * dx + dy * dy));\n}\nvoid main() {\n vec3 n = normalize(vN);\n float shade = 0.82 + 0.3 * (fbm(normalize(vObj) * 4.0) - 0.5);\n float diff = max(dot(n, uLight), 0.0);\n vec3 c = pow(uColour * shade, vec3(2.2)) * (0.04 + 1.1 * diff);\n gl_FragColor = vec4(pow(c, vec3(1.0 / 2.2)), 1.0);\n}";
|
|
22
|
+
export declare const BALL_FRAGMENT = "\nprecision highp float;\nuniform vec3 uLight;\nuniform vec3 uColour;\nvarying vec3 vObj;\nvarying vec3 vN;\nvarying vec3 vW;\n\nfloat hash13(vec3 p) { p = fract(p * 0.1031); p += dot(p, p.zyx + 31.32); return fract((p.x + p.y) * p.z); }\nvec3 hash33(vec3 p) { p = fract(p * vec3(0.1031, 0.1030, 0.0973)); p += dot(p, p.yxz + 33.33); return fract((p.xxy + p.yxx) * p.zyx); }\nfloat vnoise(vec3 p) {\n vec3 i = floor(p); vec3 f = fract(p); f = f * f * (3.0 - 2.0 * f);\n return mix(mix(mix(hash13(i), hash13(i + vec3(1,0,0)), f.x), mix(hash13(i + vec3(0,1,0)), hash13(i + vec3(1,1,0)), f.x), f.y),\n mix(mix(hash13(i + vec3(0,0,1)), hash13(i + vec3(1,0,1)), f.x), mix(hash13(i + vec3(0,1,1)), hash13(i + vec3(1,1,1)), f.x), f.y), f.z);\n}\n// Noise that knows how big a pixel is: an octave finer than the pixel can show is replaced by its average (0.5) instead of being sampled, so a small body is smooth and not a spray of pixel-sized specks.\nfloat fbm(vec3 p) { float fw = length(fwidth(p)); float a = 0.5; float s = 0.0; for (int i = 0; i < 5; i++) { s += a * mix(0.5, vnoise(p), 1.0 - smoothstep(0.3, 0.7, fw)); p = p * 2.03 + vec3(1.7, 9.2, 3.1); fw *= 2.03; a *= 0.5; } return s; }\n// Craters: a bowl and a raised rim in each cell that has one. Returns a height, negative in a bowl. A crater smaller than about two pixels fades out (it would only be noise).\nfloat craters(vec3 p, float freq, float amp, float seed) {\n vec3 q = p * freq + seed; vec3 ip = floor(q); float h = 0.0;\n float fw = length(fwidth(q));\n for (int x = -1; x <= 1; x++) for (int y = -1; y <= 1; y++) for (int z = -1; z <= 1; z++) {\n vec3 c = ip + vec3(float(x), float(y), float(z));\n float on = step(0.52, hash13(c + 3.7));\n vec3 ctr = c + hash33(c);\n float rad = mix(0.12, 0.36, hash13(c + 17.3));\n float d = length(q - ctr) / rad;\n float bowl = d < 1.0 ? (d * d - 1.0) : 0.0;\n float rim = d >= 1.0 ? exp(-pow((d - 1.0) * 5.0, 2.0)) * 0.3 * smoothstep(1.0, 1.08, d) : 0.0;\n h += on * amp * rad * (bowl + rim) * (1.0 - smoothstep(0.35, 0.9, fw / rad));\n }\n return h;\n}\nfloat lon(vec3 p) { return atan(p.y, p.x); }\nfloat lat(vec3 p) { return asin(clamp(p.z, -1.0, 1.0)); }\nfloat wrapPi(float a) { return a - 6.2831853 * floor((a + 3.1415927) / 6.2831853); }\nvec3 dirOf(float lonDeg, float latDeg) { float lo = radians(lonDeg); float la = radians(latDeg); return vec3(cos(la) * cos(lo), cos(la) * sin(lo), sin(la)); }\n// One big round bowl with a rim, by longitude, latitude and angular radius in degrees. Negative inside.\nfloat bowl(vec3 p, float lonDeg, float latDeg, float radDeg, float depth) {\n float d = acos(clamp(dot(p, dirOf(lonDeg, latDeg)), -1.0, 1.0)) / radians(radDeg);\n return d < 1.0 ? depth * (d * d - 1.0) : depth * exp(-pow((d - 1.0) * 5.0, 2.0)) * 0.3 * smoothstep(1.0, 1.08, d);\n}\n// A soft oval on the body, 1 inside and 0 outside, by longitude and latitude in degrees.\nfloat oval(vec3 p, float lon0, float lat0, float rx, float ry, float soft) {\n float dx = wrapPi(lon(p) - radians(lon0)) * cos(radians(lat0)) / radians(rx);\n float dy = (lat(p) - radians(lat0)) / radians(ry);\n return 1.0 - smoothstep(1.0 - soft, 1.0, sqrt(dx * dx + dy * dy));\n}\nvoid main() {\n vec3 n = normalize(vN);\n float shade = 0.82 + 0.3 * (fbm(normalize(vObj) * 4.0) - 0.5);\n float diff = max(dot(n, uLight), 0.0);\n vec3 c = pow(uColour * shade, vec3(2.2)) * (0.04 + 1.1 * diff);\n gl_FragColor = vec4(pow(c, vec3(1.0 / 2.2)), 1.0);\n}";
|
package/dist/scene/glsl.js
CHANGED
|
@@ -19,10 +19,12 @@ float vnoise(vec3 p) {
|
|
|
19
19
|
return mix(mix(mix(hash13(i), hash13(i + vec3(1,0,0)), f.x), mix(hash13(i + vec3(0,1,0)), hash13(i + vec3(1,1,0)), f.x), f.y),
|
|
20
20
|
mix(mix(hash13(i + vec3(0,0,1)), hash13(i + vec3(1,0,1)), f.x), mix(hash13(i + vec3(0,1,1)), hash13(i + vec3(1,1,1)), f.x), f.y), f.z);
|
|
21
21
|
}
|
|
22
|
-
|
|
23
|
-
|
|
22
|
+
// Noise that knows how big a pixel is: an octave finer than the pixel can show is replaced by its average (0.5) instead of being sampled, so a small body is smooth and not a spray of pixel-sized specks.
|
|
23
|
+
float fbm(vec3 p) { float fw = length(fwidth(p)); float a = 0.5; float s = 0.0; for (int i = 0; i < 5; i++) { s += a * mix(0.5, vnoise(p), 1.0 - smoothstep(0.3, 0.7, fw)); p = p * 2.03 + vec3(1.7, 9.2, 3.1); fw *= 2.03; a *= 0.5; } return s; }
|
|
24
|
+
// Craters: a bowl and a raised rim in each cell that has one. Returns a height, negative in a bowl. A crater smaller than about two pixels fades out (it would only be noise).
|
|
24
25
|
float craters(vec3 p, float freq, float amp, float seed) {
|
|
25
26
|
vec3 q = p * freq + seed; vec3 ip = floor(q); float h = 0.0;
|
|
27
|
+
float fw = length(fwidth(q));
|
|
26
28
|
for (int x = -1; x <= 1; x++) for (int y = -1; y <= 1; y++) for (int z = -1; z <= 1; z++) {
|
|
27
29
|
vec3 c = ip + vec3(float(x), float(y), float(z));
|
|
28
30
|
float on = step(0.52, hash13(c + 3.7));
|
|
@@ -30,8 +32,8 @@ float craters(vec3 p, float freq, float amp, float seed) {
|
|
|
30
32
|
float rad = mix(0.12, 0.36, hash13(c + 17.3));
|
|
31
33
|
float d = length(q - ctr) / rad;
|
|
32
34
|
float bowl = d < 1.0 ? (d * d - 1.0) : 0.0;
|
|
33
|
-
float rim = d >= 1.0 ? exp(-pow((d - 1.0) * 5.0, 2.0)) * 0.3 : 0.0;
|
|
34
|
-
h += on * amp * rad * (bowl + rim);
|
|
35
|
+
float rim = d >= 1.0 ? exp(-pow((d - 1.0) * 5.0, 2.0)) * 0.3 * smoothstep(1.0, 1.08, d) : 0.0;
|
|
36
|
+
h += on * amp * rad * (bowl + rim) * (1.0 - smoothstep(0.35, 0.9, fw / rad));
|
|
35
37
|
}
|
|
36
38
|
return h;
|
|
37
39
|
}
|
|
@@ -42,7 +44,7 @@ vec3 dirOf(float lonDeg, float latDeg) { float lo = radians(lonDeg); float la =
|
|
|
42
44
|
// One big round bowl with a rim, by longitude, latitude and angular radius in degrees. Negative inside.
|
|
43
45
|
float bowl(vec3 p, float lonDeg, float latDeg, float radDeg, float depth) {
|
|
44
46
|
float d = acos(clamp(dot(p, dirOf(lonDeg, latDeg)), -1.0, 1.0)) / radians(radDeg);
|
|
45
|
-
return d < 1.0 ? depth * (d * d - 1.0) : depth * exp(-pow((d - 1.0) * 5.0, 2.0)) * 0.3;
|
|
47
|
+
return d < 1.0 ? depth * (d * d - 1.0) : depth * exp(-pow((d - 1.0) * 5.0, 2.0)) * 0.3 * smoothstep(1.0, 1.08, d);
|
|
46
48
|
}
|
|
47
49
|
// A soft oval on the body, 1 inside and 0 outside, by longitude and latitude in degrees.
|
|
48
50
|
float oval(vec3 p, float lon0, float lat0, float rx, float ry, float soft) {
|
|
@@ -90,7 +92,9 @@ void main() {
|
|
|
90
92
|
float hx = dFdx(s.a); float hy = dFdy(s.a);
|
|
91
93
|
vec3 grad = cross(dpy, n) * hx + cross(n, dpx) * hy;
|
|
92
94
|
float det = dot(dpx, cross(dpy, n));
|
|
93
|
-
|
|
95
|
+
// relief is worked out from differences between neighbouring pixels, which cannot show a bump only a few pixels wide: on a small disc it fades out and the colour alone carries the craters
|
|
96
|
+
float reliefLod = 1.0 - smoothstep(0.008, 0.024, length(fwidth(p)));
|
|
97
|
+
vec3 nb = normalize(abs(det) * n - sign(det) * uRelief * reliefLod * grad * 22.0);
|
|
94
98
|
float d = dot(nb, uLight);
|
|
95
99
|
float diff = clamp((d + uWrap) / (1.0 + uWrap), 0.0, 1.0) * smoothstep(-0.02 - uWrap * 0.6, 0.1 + uWrap * 0.8, dg);
|
|
96
100
|
if (uRingOn > 0.5) {
|
|
Binary file
|
|
Binary file
|
package/dist/version.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export declare const VERSION = "0.11.
|
|
1
|
+
export declare const VERSION = "0.11.1";
|
package/dist/version.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export const VERSION = "0.11.
|
|
1
|
+
export const VERSION = "0.11.1";
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@johnmorrisdotca/wakusei-planets",
|
|
3
|
-
"version": "0.11.
|
|
3
|
+
"version": "0.11.1",
|
|
4
4
|
"description": "Wakusei Planets 惑星 — The Sun, planets and moons for the web: each as a clean line drawing, a shaded realistic drawing or a painted surface map, with real sizes, axial tilt and rotation as data, and positions of the moons for any date and time. SVG for the lines, three.js (optional) for the rest.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"planets",
|