I want to convert SVG data to ShapeGeometry, then turn it into particles and display them.
The following code converts multiple SVG data into vertex coordinates.
const getSVGPositions = (svgPath) => {
return new Promise((resolve, reject) => {
const loader = new SVGLoader();
loader.load(
svgPath,
(data) => {
const group = new THREE.Group();
const paths = data.paths;
paths.forEach((path) => {
const material = new THREE.MeshBasicMaterial({
color: path.color,
side: THREE.DoubleSide,
depthWrite: false,
});
const shapes = SVGLoader.createShapes(path);
shapes.forEach((shape) => {
const geometry = new THREE.ShapeGeometry(shape);
const mesh = new THREE.Mesh(geometry, material);
group.add(mesh);
});
});
const particlesPositionsArray = changedParticlePosition(group);
const flattenedPositions = new Float32Array(
particlesPositionsArray.reduce(
(acc, val) => acc.concat(Array.from(val)),
[]
)
);
resolve(flattenedPositions);
},
undefined,
reject
);
});
};
const changedParticlePosition = (group) => {
const numParticles = 10000;
const particlesPositionsArray = group.children.map((mesh) => {
const sampler = new MeshSurfaceSampler(mesh).build();
const particlesPosition = new Float32Array(numParticles * 3);
for (let i = 0; i < numParticles; i++) {
const newPosition = new THREE.Vector3();
const normal = new THREE.Vector3();
sampler.sample(newPosition, normal);
particlesPosition.set(
[newPosition.x, newPosition.y, newPosition.z],
i * 3
);
}
return particlesPosition;
});
return particlesPositionsArray;
};
The following code adds the obtained vertex coordinates to the attributes of BufferGeometry.
Looking at console.log(geometry), we can confirm that the vertex coordinates of position1, position2 … are stored in an array.
const setGeometryAttributes = (stage, positionsArray) => {
const geometry = new THREE.BufferGeometry();
positionsArray.forEach((positions, index) => {
geometry.setAttribute(
`position${index + 1}`,
new THREE.BufferAttribute(positions, 3)
);
});
const material = new THREE.RawShaderMaterial({
vertexShader: vertexShader,
fragmentShader: document.querySelector("#js-fragment-shader").textContent,
transparent: true,
blending: THREE.AdditiveBlending,
});
const mesh = new THREE.Points(geometry, material);
stage.scene.add(mesh);
};
Below is the vertexShader.
export const vertexShader = /* glsl */ `
attribute vec3 position1;
attribute vec3 position2;
uniform mat4 modelViewMatrix;
uniform mat4 projectionMatrix;
uniform float u_time;
void main() {
gl_Position = projectionMatrix * modelViewMatrix * vec4(position1, 1.0);
gl_PointSize = 3.0;
}
`;
It’s the whole code.
class Stage {
constructor() {
this.renderParam = {
clearColor: 0x000000,
width: window.innerWidth,
height: window.innerHeight,
};
this.cameraParam = {
fov: 45,
near: 0.1,
far: 2000,
lookAt: new THREE.Vector3(0, 0, 0),
x: 0,
y: -125,
z: 1800,
};
this.scene = null;
this.camera = null;
this.renderer = null;
this.isInitialized = false;
this.isDev = false;
}
init() {
this._setScene();
this._setRender();
this._setCamera();
window.addEventListener("resize", () => this.onResize());
}
_setScene() {
this.scene = new THREE.Scene();
}
_setRender() {
this.renderer = new THREE.WebGLRenderer({ antialias: true });
this.renderer.setPixelRatio(window.devicePixelRatio);
this.renderer.setClearColor(new THREE.Color(this.renderParam.clearColor));
this.renderer.setSize(this.renderParam.width, this.renderParam.height);
const wrapper = document.querySelector("#fv-webgl");
wrapper.appendChild(this.renderer.domElement);
}
_setCamera() {
if (!this.isInitialized) {
this.camera = new THREE.PerspectiveCamera(
this.cameraParam.fov,
this.renderParam.width / this.renderParam.height,
this.cameraParam.near,
this.cameraParam.far
);
this.camera.position.set(
this.cameraParam.x,
this.cameraParam.y,
this.cameraParam.z
);
this.camera.lookAt(this.cameraParam.lookAt);
this.isInitialized = true;
}
const windowWidth = window.innerWidth;
const windowHeight = window.innerHeight;
this.camera.aspect = windowWidth / windowHeight;
this.camera.updateProjectionMatrix();
this.renderer.setSize(windowWidth, windowHeight);
}
_render() {
this.renderer.render(this.scene, this.camera);
if (this.isDev) this.orbitcontrols.update();
}
onResize() {
this.renderParam.width = window.innerWidth;
this.renderParam.height = window.innerHeight;
this._setCamera();
}
onRaf() {
this._render();
}
}
const getSVGPositions = (svgPath) => {
return new Promise((resolve, reject) => {
const loader = new SVGLoader();
loader.load(
svgPath,
(data) => {
const group = new THREE.Group();
const paths = data.paths;
paths.forEach((path) => {
const material = new THREE.MeshBasicMaterial({
color: path.color,
side: THREE.DoubleSide,
depthWrite: false,
});
const shapes = SVGLoader.createShapes(path);
shapes.forEach((shape) => {
const geometry = new THREE.ShapeGeometry(shape);
const mesh = new THREE.Mesh(geometry, material);
group.add(mesh);
});
});
const particlesPositionsArray = changedParticlePosition(group);
const flattenedPositions = new Float32Array(
particlesPositionsArray.reduce(
(acc, val) => acc.concat(Array.from(val)),
[]
)
);
resolve(flattenedPositions);
},
undefined,
reject
);
});
};
const setGeometryAttributes = (stage, positionsArray) => {
const geometry = new THREE.BufferGeometry();
positionsArray.forEach((positions, index) => {
geometry.setAttribute(
`position${index + 1}`,
new THREE.BufferAttribute(positions, 3)
);
});
const material = new THREE.RawShaderMaterial({
vertexShader: vertexShader,
fragmentShader: document.querySelector("#js-fragment-shader").textContent,
transparent: true,
blending: THREE.AdditiveBlending,
});
const mesh = new THREE.Points(geometry, material);
stage.scene.add(mesh);
};
const changedParticlePosition = (group) => {
const numParticles = 10000;
const particlesPositionsArray = group.children.map((mesh) => {
const sampler = new MeshSurfaceSampler(mesh).build();
const particlesPosition = new Float32Array(numParticles * 3);
for (let i = 0; i < numParticles; i++) {
const newPosition = new THREE.Vector3();
const normal = new THREE.Vector3();
sampler.sample(newPosition, normal);
particlesPosition.set(
[newPosition.x, newPosition.y, newPosition.z],
i * 3
);
}
return particlesPosition;
});
return particlesPositionsArray;
};
class Webgl {
constructor() {
const stage = new Stage();
stage.init();
const svgPaths = ["../images/test.svg", "../images/0.svg"];
Promise.all(svgPaths.map(getSVGPositions))
.then((positionsArray) => {
setGeometryAttributes(stage, positionsArray);
})
.catch(console.error);
window.addEventListener("resize", () => {
stage.onResize();
});
const _raf = () => {
window.requestAnimationFrame(() => {
_raf();
stage.onRaf();
});
};
_raf();
}
}
new Webgl();
I want to display the vertex coordinates of the particles added to BufferGeometry.
yuu is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.