I am trying to draw a color filled rectangle with a thick border

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?

https://hofk.de/main/discourse.threejs/2021/ThickBorder2D/ThickBorder2D.html
from the


UPDATE:
Is there a reason you don’t just use a matching texture to add a thick different colored border to the rectangle?

2 Likes

There was no particular big reason. thanks.