three-material 0.2.0
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/dist/brushed.d.ts +9 -0
- package/dist/brushed.js +60 -0
- package/dist/brushed.js.map +1 -0
- package/dist/flakes.d.ts +8 -0
- package/dist/flakes.js +36 -0
- package/dist/flakes.js.map +1 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.js +4 -0
- package/dist/index.js.map +1 -0
- package/dist/scratches.d.ts +8 -0
- package/dist/scratches.js +37 -0
- package/dist/scratches.js.map +1 -0
- package/dist/shared.d.ts +4 -0
- package/dist/shared.js +23 -0
- package/dist/shared.js.map +1 -0
- package/dist/types.d.ts +24 -0
- package/dist/types.js +2 -0
- package/dist/types.js.map +1 -0
- package/package.json +40 -0
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type * as THREE from 'three';
|
|
2
|
+
import type { BrushedMaterialOptions } from './types.js';
|
|
3
|
+
export type { BrushedMaterialOptions } from './types.js';
|
|
4
|
+
export declare class BrushedMetalTexture {
|
|
5
|
+
readonly normalCanvas: HTMLCanvasElement;
|
|
6
|
+
readonly roughnessCanvas: HTMLCanvasElement;
|
|
7
|
+
constructor(width?: number, height?: number, options?: Pick<BrushedMaterialOptions, 'density' | 'length' | 'variation'>);
|
|
8
|
+
}
|
|
9
|
+
export declare function brushedMaterial(options?: BrushedMaterialOptions): THREE.MeshPhysicalMaterial;
|
package/dist/brushed.js
ADDED
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import { physicalMaterial, textureFrom } from './shared.js';
|
|
2
|
+
function hash(row, column) {
|
|
3
|
+
let value = Math.imul(row + 1, 0x45d9f3b) ^ Math.imul(column + 17, 0x27d4eb2d);
|
|
4
|
+
value = Math.imul(value ^ (value >>> 16), 0x45d9f3b);
|
|
5
|
+
value ^= value >>> 16;
|
|
6
|
+
return (value >>> 0) / 4294967295;
|
|
7
|
+
}
|
|
8
|
+
export class BrushedMetalTexture {
|
|
9
|
+
constructor(width = 1024, height = 1024, options = {}) {
|
|
10
|
+
this.normalCanvas = document.createElement('canvas');
|
|
11
|
+
this.roughnessCanvas = document.createElement('canvas');
|
|
12
|
+
this.normalCanvas.width = this.roughnessCanvas.width = width;
|
|
13
|
+
this.normalCanvas.height = this.roughnessCanvas.height = height;
|
|
14
|
+
const normalContext = this.normalCanvas.getContext('2d');
|
|
15
|
+
const roughnessContext = this.roughnessCanvas.getContext('2d');
|
|
16
|
+
if (!normalContext || !roughnessContext)
|
|
17
|
+
throw new Error('Unable to create brushed-metal texture canvases.');
|
|
18
|
+
const normalImage = normalContext.createImageData(width, height);
|
|
19
|
+
const roughnessImage = roughnessContext.createImageData(width, height);
|
|
20
|
+
const density = (options.density ?? 72) / 100;
|
|
21
|
+
const length = (options.length ?? 84) / 100;
|
|
22
|
+
const variation = (options.variation ?? 32) / 100;
|
|
23
|
+
const slopes = new Float32Array(height);
|
|
24
|
+
for (let y = 0; y < height; y += 1) {
|
|
25
|
+
const previous = hash((y - 1 + height) % height, 91) * 2 - 1;
|
|
26
|
+
const current = hash(y, 91) * 2 - 1;
|
|
27
|
+
const next = hash((y + 1) % height, 91) * 2 - 1;
|
|
28
|
+
slopes[y] = current * (0.65 + density * 0.25) + (previous + current * 2 + next) * 0.25 * (0.35 - density * 0.2) + (hash(y, 413) > 0.975 ? (hash(y, 719) * 2 - 1) * 0.75 : 0);
|
|
29
|
+
}
|
|
30
|
+
const segmentCount = Math.max(2, Math.round(18 - length * 15));
|
|
31
|
+
const segmentWidth = width / segmentCount;
|
|
32
|
+
const amplitude = 7 + density * 15;
|
|
33
|
+
for (let y = 0; y < height; y += 1)
|
|
34
|
+
for (let x = 0; x < width; x += 1) {
|
|
35
|
+
const position = x / segmentWidth;
|
|
36
|
+
const segment = Math.floor(position);
|
|
37
|
+
const t = position - segment;
|
|
38
|
+
const blend = t * t * (3 - 2 * t);
|
|
39
|
+
const first = hash(y, segment % segmentCount);
|
|
40
|
+
const longitudinal = first + (hash(y, (segment + 1) % segmentCount) - first) * blend;
|
|
41
|
+
const slope = slopes[y] * (1 - variation * 0.32 + longitudinal * variation * 0.55);
|
|
42
|
+
const index = (y * width + x) * 4;
|
|
43
|
+
normalImage.data.set([127, Math.max(0, Math.min(255, 127 + slope * amplitude)), 254, 255], index);
|
|
44
|
+
const roughness = Math.max(0, Math.min(255, 225 + slope * (3 + variation * 7) + (longitudinal - 0.5) * variation * 12));
|
|
45
|
+
roughnessImage.data.set([roughness, roughness, roughness, 255], index);
|
|
46
|
+
}
|
|
47
|
+
normalContext.putImageData(normalImage, 0, 0);
|
|
48
|
+
roughnessContext.putImageData(roughnessImage, 0, 0);
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
export function brushedMaterial(options = {}) {
|
|
52
|
+
const texture = new BrushedMetalTexture(1024, 1024, options);
|
|
53
|
+
const material = physicalMaterial(options);
|
|
54
|
+
material.normalMap = textureFrom(texture.normalCanvas, options, options.direction);
|
|
55
|
+
material.roughnessMap = textureFrom(texture.roughnessCanvas, options, options.direction);
|
|
56
|
+
material.anisotropy = options.anisotropy ?? 0.8;
|
|
57
|
+
material.anisotropyRotation = material.normalMap.rotation;
|
|
58
|
+
return material;
|
|
59
|
+
}
|
|
60
|
+
//# sourceMappingURL=brushed.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"brushed.js","sourceRoot":"","sources":["../src/brushed.ts"],"names":[],"mappings":"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"}
|
package/dist/flakes.d.ts
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type * as THREE from 'three';
|
|
2
|
+
import type { FlakesMaterialOptions } from './types.js';
|
|
3
|
+
export type { FlakesMaterialOptions } from './types.js';
|
|
4
|
+
export declare class FlakesTexture {
|
|
5
|
+
readonly canvas: HTMLCanvasElement;
|
|
6
|
+
constructor(width?: number, height?: number, density?: number, size?: number);
|
|
7
|
+
}
|
|
8
|
+
export declare function flakesMaterial(options?: FlakesMaterialOptions): THREE.MeshPhysicalMaterial;
|
package/dist/flakes.js
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { physicalMaterial, textureFrom } from './shared.js';
|
|
2
|
+
export class FlakesTexture {
|
|
3
|
+
constructor(width = 512, height = 512, density = 40, size = 6) {
|
|
4
|
+
const canvas = document.createElement('canvas');
|
|
5
|
+
canvas.width = width;
|
|
6
|
+
canvas.height = height;
|
|
7
|
+
const context = canvas.getContext('2d');
|
|
8
|
+
if (!context)
|
|
9
|
+
throw new Error('Unable to create a 2D canvas context.');
|
|
10
|
+
context.fillStyle = 'rgb(127, 127, 255)';
|
|
11
|
+
context.fillRect(0, 0, width, height);
|
|
12
|
+
for (let i = 0; i < density * 100; i += 1) {
|
|
13
|
+
const x = Math.random() * width;
|
|
14
|
+
const y = Math.random() * height;
|
|
15
|
+
const radius = Math.random() * (size / 2) + size / 2;
|
|
16
|
+
let nx = Math.random() * 2 - 1;
|
|
17
|
+
let ny = Math.random() * 2 - 1;
|
|
18
|
+
let nz = 1.5;
|
|
19
|
+
const vectorLength = Math.sqrt(nx * nx + ny * ny + nz * nz);
|
|
20
|
+
nx /= vectorLength;
|
|
21
|
+
ny /= vectorLength;
|
|
22
|
+
nz /= vectorLength;
|
|
23
|
+
context.fillStyle = `rgb(${nx * 127 + 127}, ${ny * 127 + 127}, ${nz * 255})`;
|
|
24
|
+
context.beginPath();
|
|
25
|
+
context.arc(x, y, radius, 0, Math.PI * 2);
|
|
26
|
+
context.fill();
|
|
27
|
+
}
|
|
28
|
+
this.canvas = canvas;
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
export function flakesMaterial(options = {}) {
|
|
32
|
+
const material = physicalMaterial(options);
|
|
33
|
+
material.normalMap = textureFrom(new FlakesTexture(512, 512, options.density, options.size).canvas, options);
|
|
34
|
+
return material;
|
|
35
|
+
}
|
|
36
|
+
//# sourceMappingURL=flakes.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"flakes.js","sourceRoot":"","sources":["../src/flakes.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,gBAAgB,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAK5D,MAAM,OAAO,aAAa;IAGxB,YAAY,KAAK,GAAG,GAAG,EAAE,MAAM,GAAG,GAAG,EAAE,OAAO,GAAG,EAAE,EAAE,IAAI,GAAG,CAAC;QAC3D,MAAM,MAAM,GAAG,QAAQ,CAAC,aAAa,CAAC,QAAQ,CAAC,CAAC;QAChD,MAAM,CAAC,KAAK,GAAG,KAAK,CAAC;QACrB,MAAM,CAAC,MAAM,GAAG,MAAM,CAAC;QACvB,MAAM,OAAO,GAAG,MAAM,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC;QACxC,IAAI,CAAC,OAAO;YAAE,MAAM,IAAI,KAAK,CAAC,uCAAuC,CAAC,CAAC;QACvE,OAAO,CAAC,SAAS,GAAG,oBAAoB,CAAC;QACzC,OAAO,CAAC,QAAQ,CAAC,CAAC,EAAE,CAAC,EAAE,KAAK,EAAE,MAAM,CAAC,CAAC;QACtC,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,OAAO,GAAG,GAAG,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC;YAC1C,MAAM,CAAC,GAAG,IAAI,CAAC,MAAM,EAAE,GAAG,KAAK,CAAC;YAChC,MAAM,CAAC,GAAG,IAAI,CAAC,MAAM,EAAE,GAAG,MAAM,CAAC;YACjC,MAAM,MAAM,GAAG,IAAI,CAAC,MAAM,EAAE,GAAG,CAAC,IAAI,GAAG,CAAC,CAAC,GAAG,IAAI,GAAG,CAAC,CAAC;YACrD,IAAI,EAAE,GAAG,IAAI,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,CAAC,CAAC;YAC/B,IAAI,EAAE,GAAG,IAAI,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,CAAC,CAAC;YAC/B,IAAI,EAAE,GAAG,GAAG,CAAC;YACb,MAAM,YAAY,GAAG,IAAI,CAAC,IAAI,CAAC,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,CAAC,CAAC;YAC5D,EAAE,IAAI,YAAY,CAAC;YAAC,EAAE,IAAI,YAAY,CAAC;YAAC,EAAE,IAAI,YAAY,CAAC;YAC3D,OAAO,CAAC,SAAS,GAAG,OAAO,EAAE,GAAG,GAAG,GAAG,GAAG,KAAK,EAAE,GAAG,GAAG,GAAG,GAAG,KAAK,EAAE,GAAG,GAAG,GAAG,CAAC;YAC7E,OAAO,CAAC,SAAS,EAAE,CAAC;YAAC,OAAO,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,IAAI,CAAC,EAAE,GAAG,CAAC,CAAC,CAAC;YAAC,OAAO,CAAC,IAAI,EAAE,CAAC;QACjF,CAAC;QACD,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;IACvB,CAAC;CACF;AAED,MAAM,UAAU,cAAc,CAAC,UAAiC,EAAE;IAChE,MAAM,QAAQ,GAAG,gBAAgB,CAAC,OAAO,CAAC,CAAC;IAC3C,QAAQ,CAAC,SAAS,GAAG,WAAW,CAAC,IAAI,aAAa,CAAC,GAAG,EAAE,GAAG,EAAE,OAAO,CAAC,OAAO,EAAE,OAAO,CAAC,IAAI,CAAC,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAC7G,OAAO,QAAQ,CAAC;AAClB,CAAC"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
export { flakesMaterial, FlakesTexture } from './flakes.js';
|
|
2
|
+
export { scratchesMaterial, ScratchesTexture } from './scratches.js';
|
|
3
|
+
export { brushedMaterial, BrushedMetalTexture } from './brushed.js';
|
|
4
|
+
export type { MaterialFinishOptions, FlakesMaterialOptions, ScratchesMaterialOptions, BrushedMaterialOptions } from './types.js';
|
package/dist/index.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAC5D,OAAO,EAAE,iBAAiB,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAC;AACrE,OAAO,EAAE,eAAe,EAAE,mBAAmB,EAAE,MAAM,cAAc,CAAC"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type * as THREE from 'three';
|
|
2
|
+
import type { ScratchesMaterialOptions } from './types.js';
|
|
3
|
+
export type { ScratchesMaterialOptions } from './types.js';
|
|
4
|
+
export declare class ScratchesTexture {
|
|
5
|
+
readonly canvas: HTMLCanvasElement;
|
|
6
|
+
constructor(width?: number, height?: number, options?: Pick<ScratchesMaterialOptions, 'density' | 'length'>);
|
|
7
|
+
}
|
|
8
|
+
export declare function scratchesMaterial(options?: ScratchesMaterialOptions): THREE.MeshPhysicalMaterial;
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { physicalMaterial, textureFrom } from './shared.js';
|
|
2
|
+
export class ScratchesTexture {
|
|
3
|
+
constructor(width = 512, height = 512, options = {}) {
|
|
4
|
+
const canvas = document.createElement('canvas');
|
|
5
|
+
canvas.width = width;
|
|
6
|
+
canvas.height = height;
|
|
7
|
+
const context = canvas.getContext('2d');
|
|
8
|
+
if (!context)
|
|
9
|
+
throw new Error('Unable to create a 2D canvas context.');
|
|
10
|
+
const density = options.density ?? 46;
|
|
11
|
+
const scratchLength = options.length ?? 72;
|
|
12
|
+
context.fillStyle = 'rgb(127, 127, 255)';
|
|
13
|
+
context.fillRect(0, 0, width, height);
|
|
14
|
+
context.lineCap = 'round';
|
|
15
|
+
for (let i = 0; i < density * 10; i += 1) {
|
|
16
|
+
const x = Math.random() * width;
|
|
17
|
+
const y = Math.random() * height;
|
|
18
|
+
const angle = Math.random() * Math.PI * 2;
|
|
19
|
+
const length = scratchLength * (0.25 + Math.random() * 0.75);
|
|
20
|
+
const nx = Math.cos(angle + Math.PI / 2);
|
|
21
|
+
const ny = Math.sin(angle + Math.PI / 2);
|
|
22
|
+
context.strokeStyle = `rgb(${127 + nx * 72}, ${127 + ny * 72}, 245)`;
|
|
23
|
+
context.lineWidth = 0.5 + Math.random() * 1.7;
|
|
24
|
+
context.beginPath();
|
|
25
|
+
context.moveTo(x, y);
|
|
26
|
+
context.lineTo(x + Math.cos(angle) * length, y + Math.sin(angle) * length);
|
|
27
|
+
context.stroke();
|
|
28
|
+
}
|
|
29
|
+
this.canvas = canvas;
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
export function scratchesMaterial(options = {}) {
|
|
33
|
+
const material = physicalMaterial(options);
|
|
34
|
+
material.normalMap = textureFrom(new ScratchesTexture(512, 512, options).canvas, options);
|
|
35
|
+
return material;
|
|
36
|
+
}
|
|
37
|
+
//# sourceMappingURL=scratches.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"scratches.js","sourceRoot":"","sources":["../src/scratches.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,gBAAgB,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAK5D,MAAM,OAAO,gBAAgB;IAG3B,YAAY,KAAK,GAAG,GAAG,EAAE,MAAM,GAAG,GAAG,EAAE,UAAgE,EAAE;QACvG,MAAM,MAAM,GAAG,QAAQ,CAAC,aAAa,CAAC,QAAQ,CAAC,CAAC;QAChD,MAAM,CAAC,KAAK,GAAG,KAAK,CAAC;QAAC,MAAM,CAAC,MAAM,GAAG,MAAM,CAAC;QAC7C,MAAM,OAAO,GAAG,MAAM,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC;QACxC,IAAI,CAAC,OAAO;YAAE,MAAM,IAAI,KAAK,CAAC,uCAAuC,CAAC,CAAC;QACvE,MAAM,OAAO,GAAG,OAAO,CAAC,OAAO,IAAI,EAAE,CAAC;QACtC,MAAM,aAAa,GAAG,OAAO,CAAC,MAAM,IAAI,EAAE,CAAC;QAC3C,OAAO,CAAC,SAAS,GAAG,oBAAoB,CAAC;QAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,EAAE,CAAC,EAAE,KAAK,EAAE,MAAM,CAAC,CAAC;QAAC,OAAO,CAAC,OAAO,GAAG,OAAO,CAAC;QAC3G,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,OAAO,GAAG,EAAE,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC;YACzC,MAAM,CAAC,GAAG,IAAI,CAAC,MAAM,EAAE,GAAG,KAAK,CAAC;YAAC,MAAM,CAAC,GAAG,IAAI,CAAC,MAAM,EAAE,GAAG,MAAM,CAAC;YAAC,MAAM,KAAK,GAAG,IAAI,CAAC,MAAM,EAAE,GAAG,IAAI,CAAC,EAAE,GAAG,CAAC,CAAC;YAC7G,MAAM,MAAM,GAAG,aAAa,GAAG,CAAC,IAAI,GAAG,IAAI,CAAC,MAAM,EAAE,GAAG,IAAI,CAAC,CAAC;YAC7D,MAAM,EAAE,GAAG,IAAI,CAAC,GAAG,CAAC,KAAK,GAAG,IAAI,CAAC,EAAE,GAAG,CAAC,CAAC,CAAC;YAAC,MAAM,EAAE,GAAG,IAAI,CAAC,GAAG,CAAC,KAAK,GAAG,IAAI,CAAC,EAAE,GAAG,CAAC,CAAC,CAAC;YACnF,OAAO,CAAC,WAAW,GAAG,OAAO,GAAG,GAAG,EAAE,GAAG,EAAE,KAAK,GAAG,GAAG,EAAE,GAAG,EAAE,QAAQ,CAAC;YACrE,OAAO,CAAC,SAAS,GAAG,GAAG,GAAG,IAAI,CAAC,MAAM,EAAE,GAAG,GAAG,CAAC;YAC9C,OAAO,CAAC,SAAS,EAAE,CAAC;YAAC,OAAO,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;YAAC,OAAO,CAAC,MAAM,CAAC,CAAC,GAAG,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,MAAM,EAAE,CAAC,GAAG,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,MAAM,CAAC,CAAC;YAAC,OAAO,CAAC,MAAM,EAAE,CAAC;QAC1I,CAAC;QACD,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;IACvB,CAAC;CACF;AAED,MAAM,UAAU,iBAAiB,CAAC,UAAoC,EAAE;IACtE,MAAM,QAAQ,GAAG,gBAAgB,CAAC,OAAO,CAAC,CAAC;IAC3C,QAAQ,CAAC,SAAS,GAAG,WAAW,CAAC,IAAI,gBAAgB,CAAC,GAAG,EAAE,GAAG,EAAE,OAAO,CAAC,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAC1F,OAAO,QAAQ,CAAC;AAClB,CAAC"}
|
package/dist/shared.d.ts
ADDED
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import * as THREE from 'three';
|
|
2
|
+
import type { MaterialFinishOptions } from './types.js';
|
|
3
|
+
export declare function physicalMaterial(options: MaterialFinishOptions): THREE.MeshPhysicalMaterial;
|
|
4
|
+
export declare function textureFrom(canvas: HTMLCanvasElement, options: MaterialFinishOptions, direction?: number): THREE.CanvasTexture;
|
package/dist/shared.js
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import * as THREE from 'three';
|
|
2
|
+
export function physicalMaterial(options) {
|
|
3
|
+
return new THREE.MeshPhysicalMaterial({
|
|
4
|
+
color: options.color ?? '#8418ca',
|
|
5
|
+
metalness: options.metalness ?? 0.9,
|
|
6
|
+
roughness: options.roughness ?? 0.5,
|
|
7
|
+
clearcoat: options.clearcoat ?? 1,
|
|
8
|
+
clearcoatRoughness: options.clearcoatRoughness ?? 0.1,
|
|
9
|
+
normalScale: new THREE.Vector2(options.strength ?? 0.15, options.strength ?? 0.15),
|
|
10
|
+
});
|
|
11
|
+
}
|
|
12
|
+
export function textureFrom(canvas, options, direction = 0) {
|
|
13
|
+
const texture = new THREE.CanvasTexture(canvas);
|
|
14
|
+
texture.colorSpace = THREE.NoColorSpace;
|
|
15
|
+
texture.wrapS = THREE.RepeatWrapping;
|
|
16
|
+
texture.wrapT = THREE.RepeatWrapping;
|
|
17
|
+
const scale = options.scale ?? 8;
|
|
18
|
+
texture.repeat.set(scale, scale * 0.6);
|
|
19
|
+
texture.center.set(0.5, 0.5);
|
|
20
|
+
texture.rotation = THREE.MathUtils.degToRad(direction);
|
|
21
|
+
return texture;
|
|
22
|
+
}
|
|
23
|
+
//# sourceMappingURL=shared.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"shared.js","sourceRoot":"","sources":["../src/shared.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAG/B,MAAM,UAAU,gBAAgB,CAAC,OAA8B;IAC7D,OAAO,IAAI,KAAK,CAAC,oBAAoB,CAAC;QACpC,KAAK,EAAE,OAAO,CAAC,KAAK,IAAI,SAAS;QACjC,SAAS,EAAE,OAAO,CAAC,SAAS,IAAI,GAAG;QACnC,SAAS,EAAE,OAAO,CAAC,SAAS,IAAI,GAAG;QACnC,SAAS,EAAE,OAAO,CAAC,SAAS,IAAI,CAAC;QACjC,kBAAkB,EAAE,OAAO,CAAC,kBAAkB,IAAI,GAAG;QACrD,WAAW,EAAE,IAAI,KAAK,CAAC,OAAO,CAAC,OAAO,CAAC,QAAQ,IAAI,IAAI,EAAE,OAAO,CAAC,QAAQ,IAAI,IAAI,CAAC;KACnF,CAAC,CAAC;AACL,CAAC;AAED,MAAM,UAAU,WAAW,CAAC,MAAyB,EAAE,OAA8B,EAAE,SAAS,GAAG,CAAC;IAClG,MAAM,OAAO,GAAG,IAAI,KAAK,CAAC,aAAa,CAAC,MAAM,CAAC,CAAC;IAChD,OAAO,CAAC,UAAU,GAAG,KAAK,CAAC,YAAY,CAAC;IACxC,OAAO,CAAC,KAAK,GAAG,KAAK,CAAC,cAAc,CAAC;IACrC,OAAO,CAAC,KAAK,GAAG,KAAK,CAAC,cAAc,CAAC;IACrC,MAAM,KAAK,GAAG,OAAO,CAAC,KAAK,IAAI,CAAC,CAAC;IACjC,OAAO,CAAC,MAAM,CAAC,GAAG,CAAC,KAAK,EAAE,KAAK,GAAG,GAAG,CAAC,CAAC;IACvC,OAAO,CAAC,MAAM,CAAC,GAAG,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC;IAC7B,OAAO,CAAC,QAAQ,GAAG,KAAK,CAAC,SAAS,CAAC,QAAQ,CAAC,SAAS,CAAC,CAAC;IACvD,OAAO,OAAO,CAAC;AACjB,CAAC"}
|
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
export interface MaterialFinishOptions {
|
|
2
|
+
color?: string | number;
|
|
3
|
+
metalness?: number;
|
|
4
|
+
roughness?: number;
|
|
5
|
+
clearcoat?: number;
|
|
6
|
+
clearcoatRoughness?: number;
|
|
7
|
+
strength?: number;
|
|
8
|
+
scale?: number;
|
|
9
|
+
}
|
|
10
|
+
export interface FlakesMaterialOptions extends MaterialFinishOptions {
|
|
11
|
+
density?: number;
|
|
12
|
+
size?: number;
|
|
13
|
+
}
|
|
14
|
+
export interface ScratchesMaterialOptions extends MaterialFinishOptions {
|
|
15
|
+
density?: number;
|
|
16
|
+
length?: number;
|
|
17
|
+
}
|
|
18
|
+
export interface BrushedMaterialOptions extends MaterialFinishOptions {
|
|
19
|
+
density?: number;
|
|
20
|
+
length?: number;
|
|
21
|
+
variation?: number;
|
|
22
|
+
direction?: number;
|
|
23
|
+
anisotropy?: number;
|
|
24
|
+
}
|
package/dist/types.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":""}
|
package/package.json
ADDED
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "three-material",
|
|
3
|
+
"version": "0.2.0",
|
|
4
|
+
"description": "Runtime-generated physical materials for Three.js",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"sideEffects": false,
|
|
7
|
+
"files": [
|
|
8
|
+
"dist"
|
|
9
|
+
],
|
|
10
|
+
"exports": {
|
|
11
|
+
".": {
|
|
12
|
+
"types": "./dist/index.d.ts",
|
|
13
|
+
"import": "./dist/index.js"
|
|
14
|
+
},
|
|
15
|
+
"./flakes": {
|
|
16
|
+
"types": "./dist/flakes.d.ts",
|
|
17
|
+
"import": "./dist/flakes.js"
|
|
18
|
+
},
|
|
19
|
+
"./scratches": {
|
|
20
|
+
"types": "./dist/scratches.d.ts",
|
|
21
|
+
"import": "./dist/scratches.js"
|
|
22
|
+
},
|
|
23
|
+
"./brushed": {
|
|
24
|
+
"types": "./dist/brushed.d.ts",
|
|
25
|
+
"import": "./dist/brushed.js"
|
|
26
|
+
}
|
|
27
|
+
},
|
|
28
|
+
"peerDependencies": {
|
|
29
|
+
"three": ">=0.161.0"
|
|
30
|
+
},
|
|
31
|
+
"devDependencies": {
|
|
32
|
+
"@types/three": "^0.161.2",
|
|
33
|
+
"three": "^0.161.0",
|
|
34
|
+
"typescript": "^5.4.2"
|
|
35
|
+
},
|
|
36
|
+
"scripts": {
|
|
37
|
+
"build": "tsc -p tsconfig.json",
|
|
38
|
+
"check": "tsc -p tsconfig.json --noEmit"
|
|
39
|
+
}
|
|
40
|
+
}
|