import * as Three from 'three';
import { BufferAttribute, BufferGeometry, MeshBasicMaterial } from 'three';
import { MeshLine, MeshLineMaterial, MeshLineRaycast } from 'three.meshline';
export function Rectangle(
w: number,
h: number,
r: number,
s: number,
edge: {
r: number;
g: number;
b: number;
a: number;
originA: number;
},
fill: {
r: number;
g: number;
b: number;
a: number;
originA: number;
},
) {
const pi2 = Math.PI * 2;
const n = (s + 1) * 4; // number of segments
let indices = [];
let positions = [];
let uvs = [];
let qu, sgx, sgy, x, y;
for (let j = 1; j < n + 1; j++) indices.push(0, j, j + 1); // 0 is center
indices.push(0, n, 1);
positions.push(w / 2, -h / 2, 0); // rectangle center
uvs.push(0.5, 0.5);
for (let j = 0; j < n; j++) contour(j);
const boxGeometry = new Three.BoxGeometry(w, h);
const mergeGeometry = new Three.BufferGeometry();
const edgeGeometry = new Three.BufferGeometry();
edgeGeometry.setIndex(
new Three.BufferAttribute(new Uint32Array(indices), 1),
);
edgeGeometry.setAttribute(
'position',
new Three.BufferAttribute(new Float32Array(positions), 3),
);
edgeGeometry.setAttribute(
'uv',
new Three.BufferAttribute(new Float32Array(uvs), 2),
);
const rectEdge = new MeshLine();
let material = [
new MeshLineMaterial({
color: new Three.Color(
`rgb(${edge.r},${edge.g},${edge.b})`,
).getHex(),
opacity: edge.a,
transparent: true,
lineWidth: 10,
side: Three.DoubleSide,
}),
new MeshBasicMaterial({
color: new Three.Color(`rgb(${fill.r},${fill.g},${fill.b})`),
opacity: fill.a,
transparent: true,
side: Three.DoubleSide,
}),
];
let box = Array.from(
(boxGeometry.attributes.position as BufferAttribute).array,
);
let boxUv = Array.from(
(boxGeometry.attributes.uv as BufferAttribute).array,
);
let boxIndex = Array.from((boxGeometry.index as BufferAttribute).array);
rectEdge.setGeometry(edgeGeometry);
mergeGeometry.addGroup(0, rectEdge.attributes.position.array.length, 0);
mergeGeometry.addGroup(
rectEdge.attributes.position.array.length,
positions.length,
1,
);
let tmpIndices = [...rectEdge.index.array];
let tmpCounters = [...rectEdge.attributes.counters.array];
let tmpNext = [...rectEdge.attributes.next.array];
let tmpPosition = [...rectEdge.attributes.position.array];
let tmpPrevious = [...rectEdge.attributes.previous.array];
let tmpSide = [...rectEdge.attributes.side.array];
let tmpUv = [...rectEdge.attributes.uv.array];
let tmpWidth = [...rectEdge.attributes.width.array];
tmpPosition.push(...positions);
tmpUv.push(...uvs);
mergeGeometry.setIndex(
new Three.BufferAttribute(new Uint32Array(tmpIndices), 1),
);
mergeGeometry.setAttribute(
'counters',
new Three.BufferAttribute(new Float32Array(tmpCounters), 1),
);
mergeGeometry.setAttribute(
'next',
new Three.BufferAttribute(new Float32Array(tmpNext), 3),
);
mergeGeometry.setAttribute(
'position',
new Three.BufferAttribute(new Float32Array(tmpPosition), 3),
);
mergeGeometry.setAttribute(
'previous',
new Three.BufferAttribute(new Float32Array(tmpPrevious), 3),
);
mergeGeometry.setAttribute(
'side',
new Three.BufferAttribute(new Float32Array(tmpSide), 1),
);
mergeGeometry.setAttribute(
'uv',
new Three.BufferAttribute(new Float32Array(tmpUv), 2),
);
mergeGeometry.setAttribute(
'width',
new Three.BufferAttribute(new Float32Array(tmpWidth), 1),
);
let mesh = new Three.Mesh(mergeGeometry, material);
return mesh;
function contour(j: number) {
qu = Math.trunc((4 * j) / n) + 1; // quadrant qu: 1..4
sgx = qu === 1 || qu === 4 ? 1 : -1; // signum left/right
sgy = qu < 3 ? 1 : -1; // signum top / bottom
if (r > 0) {
x =
sgx * (w / 2 - r) +
r * Math.cos((pi2 * (j - qu + 1)) / (n - 4)); // corner center + circle
y =
sgy * (h / 2 - r) +
r * Math.sin((pi2 * (j - qu + 1)) / (n - 4));
positions.push(x, y, 0);
uvs.push(0.5 + x / w, 0.5 + y / h);
} else {
x = sgx * (w / 2);
y = sgy * (h / 2);
positions.push(x, y, 0);
uvs.push(0.5, 0.5);
}
}
}
I tried to fill the inside of the rectangle with the color I want, but I couldn’t. Can anyone help?