I have an arbitrary tubeGeometry made from a curved path.
How can I add End Caps to it.
Don’t want hollow tube.
It’s not possible to apply end caps, you can only close a tube like demonstrated in this example:
https://threejs.org/examples/webgl_geometry_extrude_splines
Check/uncheck the “closed” checkbox to see the different.
Do you mean something like that? (example 0.4 * Math.sin( Math.PI * 2 * v ))
You can do things like that with my addon THREEf. Addon. Produces almost infinite many time-varying geometries with functions
hofk (Klaus Hoffmeister) · GitHub
examples https://hofk.de/main/threejs/sandboxthreef/examplesTHREEf%20r90.html
https://hofk.de/main/threejs/sandboxthreef/formLibrary.html
e.g.
//0011 curved cylinder @author hofk
withBottom: true,
moveX: function ( u, v, t ) { return Math.exp( -200 * v * v * v * v ) }
How to find the correct mathematical formula
How to get Starting and Ending Cap Vertices (Blue) to make a shape (like Red) out of them and use the shape as End Caps?
Not so difficult, actually.
You know amount of radial segments, you know amount of tubular segments, so you can get information about vertices of start and end segments:
https://jsfiddle.net/prisoner849/6jp3snvq/
Another thing you’ll need are points for start and end of the curve.
Something like:
var curve = _your_curve_;
var pointStart = curve.getPoint(0);
var pointEnd = curve.getPoint(1);
https://jsfiddle.net/prisoner849/25mLpg3r/
The last thing is to set .index
for geometries so you’ll have faces:
https://jsfiddle.net/prisoner849/yueLpdb2/
Or you can set index without setting that mid point, using just points of the tube’s ends Creativity is up to you
Your code makes new meshes for end caps. how to make end caps part of the tube?
The code creates geometries. I use meshes just to visualize the result.
Use THREE.BufferGeometryUtils.mergeBufferGeometries()
to make caps part of the tube.
is it possible and would you know how to close the gap between theta start and theta length if it is not a complete cylinder by any chance?
heres a visual reference to what i mean…
where the orange outlines would make up “solid” faces?
@Lawrence3DPK
Somehow your question is similar to these topic and post: Group And Animate Meshes - #8 by prisoner849
Agreed it is, i used the image of the cylinder for simplicity sake, i actually intend to try and use the same principle for a sphere with less phi length, like so…
which i guess has the same principle but i can only imagine a lot more difficult to work out, do you know if someone has achived this before?
I have done something like this in my Addon. Produces almost infinite many time-varying geometries with functions - #24 by hofk.
However, the code is not easy to keep track of.
yeah, was just looking into the link you sent, thanks for the link man, gonna give it a shot but honestly it doesn’t look easy aha.
The thing itself is not so complicated, the problem is the embedding in the complex addon.
I myself have problems when I want to extract a piece from one of my addons for a simple thing.
Look for wedges.
To build such a sphere, you need one sphere and two half-circles.
Example: https://jsfiddle.net/prisoner849/cLqrghdm/
Picture:
Code:
let r = 2.5;
let wS = 16;
let hS = 8;
let phiStart = Math.PI;
let phiLength = Math.PI * 1.35;
let gSphere = new THREE.SphereGeometry(r, wS, hS, phiStart, phiLength);
let gCircle1 = new THREE.CircleGeometry(r, hS, Math.PI * 1.5, Math.PI);
gCircle1.rotateY(Math.PI + phiStart);
let gCircle2 = new THREE.CircleGeometry(r, hS, Math.PI * 0.5, Math.PI);
gCircle2.rotateY(phiStart + phiLength);
let g = BufferGeometryUtils.mergeBufferGeometries([gSphere, gCircle1, gCircle2]);
let m = new THREE.MeshPhongMaterial({color: 0x007fff, flatShading: true});
let o = new THREE.Mesh(g, m);
scene.add(o);
@prisoner849 Ahh man!! no way!! that’s really cool of you! i was going off of your example from yesterday and going the ultra long route by creating BufferGeometry from points, i got 2 faces together last night and it was proving to be a very long task…
let sg = new THREE.BufferGeometry().setFromPoints(
[
new THREE.Vector3(0, cH, 0),
new THREE.Vector3(-1+cH*0.8125,1-cH*0.015625, 0),//.applyAxisAngle(new THREE.Vector3(0, 1, 0), perc1 * Math.PI /180),
new THREE.Vector3(0, 0, 0),
new THREE.Vector3(-1+cH*0.8125,1-cH*0.015625, 0),//.applyAxisAngle(new THREE.Vector3(0, 1, 0), perc1 * Math.PI /180),
new THREE.Vector3(-1+cH*0.609375,1-cH*0.078125, 0),//.applyAxisAngle(new THREE.Vector3(0, 1, 0), perc1 * Math.PI /180),
new THREE.Vector3(0, 0, 0)
// new THREE.Vector3(0, cH * 0.3125, 0.1875),
// new THREE.Vector3(0, cH * 0.25, 0.25),
// new THREE.Vector3(0, cH * 0.1875, 0.3125),
// new THREE.Vector3(0, cH * 0.125, 0.375),
// new THREE.Vector3(0, cH * 0.0625, 0.4375),
// new THREE.Vector3(0, cH * 0, ch * 0.5),
// new THREE.Vector3(0, cH * -0.0625, 0.4375),
// new THREE.Vector3(0, cH * -0.125, 0.375),
// new THREE.Vector3(0, cH * -0.1875, 0.3125),
// new THREE.Vector3(0, cH * -0.25, 0.25),
// new THREE.Vector3(0, cH * -0.3125, 0.1875),
// new THREE.Vector3(0, cH * -0.375, 0.125),
// new THREE.Vector3(0, cH * -0.4375, 0.0625),
//new THREE.Vector3(0, cH * -0.5, 0)
]
);
sg.addGroup(0, 3, 0);
sg.setIndex([0, 1, 2, 3, 4, 5]);
sg.setAttribute("uv", new THREE.Float32BufferAttribute([
0, 1, 0, 0, 1, 0
], 2));
sg.computeVertexNormals();
as you can see i barely got to creating points for the third face and ran into quite a complexity of number calculations…
the approach you’ve provided should be a little simpler aha!! i will give it a go and let you know!!
Thanks so much man!!
@prisoner849 Worked a charm!! you’re work is amazing so i really appreciate your help with such a simple mundane task!!
@Lawrence3DPK you’re welcome
Hi everyone,
I know this is an old question but I am struggling with this for a while now and need some advice or suggestion to get unstuck. I am using r160 and I am a beginner at three.js.
I implemented end caps for a tube geometry using a solution posted by @prisoner849 in a jsfiddle back in September '19, and it’s working nicely. Now, I want to merge the end caps into the tube geometry using BufferGeometryUtils.mergeGeometries()
, but I’m encountering an error:
BufferGeometryUtils.js:160 THREE.BufferGeometryUtils: .mergeGeometries() failed with geometry at index 1. Make sure all geometries have the same number of attributes.
mergeGeometries @ BufferGeometryUtils.js:160
addObject @ example.html:119
(anonymous) @ example.html:150
three.module.js:11634 Uncaught TypeError: Cannot read properties of null (reading 'morphAttributes')
at Mesh.updateMorphTargets (three.module.js:11634:36)
at new Mesh (three.module.js:11603:8)
at addObject (example.html:125:30)
at example.html:150:5
It seems there’s an issue with the number of attributes, and I am currently clueless about it. I have attached my current code below:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Three.js Example</title>
<style>
body { margin: 0; }
</style>
<script async src="https://unpkg.com/es-module-shims@1.6.3/dist/es-module-shims.js"></script>
<script type="importmap">
{
"imports": {
"three": "https://unpkg.com/three@v0.160.0/build/three.module.js",
"three/addons/": "https://unpkg.com/three@v0.160.0/examples/jsm/"
}
}
</script>
</head>
<body>
<script type="module">
import * as THREE from 'three';
import { OrbitControls } from 'three/addons/controls/OrbitControls.js';
import { TransformControls } from 'three/addons/controls/TransformControls.js';
import * as BufferGeometryUtils from 'three/addons/utils/BufferGeometryUtils.js';
const scene = new THREE.Scene();
const camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
const renderer = new THREE.WebGLRenderer();
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);
const controls = new OrbitControls(camera, renderer.domElement);
function addObject(position) {
var curve = new THREE.CatmullRomCurve3([
new THREE.Vector3(0.4, 0.4, 0),
new THREE.Vector3(0, 0.4, 0),
new THREE.Vector3(0, 0, 0)
]);
var geom = new THREE.TubeGeometry(curve, 10, 0.1, 10, false);
var mat = new THREE.MeshLambertMaterial({ color: Math.random() * 0xffffff });
const object = new THREE.Mesh(geom, mat);
var pos = geom.attributes.position;
var startPoints = [];
startPoints.push(curve.getPoint(0));
for (let i = 0; i <= geom.parameters.radialSegments; i++) {
startPoints.push(new THREE.Vector3().fromBufferAttribute(pos, i));
}
var pointsStartGeom = new THREE.BufferGeometry().setFromPoints(startPoints);
var psgPos = pointsStartGeom.attributes.position;
var indexStart = [];
for (let i = 1; i < psgPos.count - 1; i++) {
indexStart.push(0, i, i + 1);
}
pointsStartGeom.setIndex(indexStart);
var shapeStart = new THREE.Mesh(pointsStartGeom, mat);
var endPoints = [];
endPoints.push(curve.getPoint(1));
for (let i = (geom.parameters.radialSegments + 1) * geom.parameters.tubularSegments; i < pos.count; i++) {
endPoints.push(new THREE.Vector3().fromBufferAttribute(pos, i));
}
var pointsEndGeom = new THREE.BufferGeometry().setFromPoints(endPoints);
var pegPos = pointsEndGeom.attributes.position;
var indexEnd = [];
for (let i = 1; i < pegPos.count - 1; i++) {
indexEnd.push(0, i + 1, i);
}
pointsEndGeom.setIndex(indexEnd);
var shapeEnd = new THREE.Mesh(pointsEndGeom, mat);
object.position.y = 0.0;
if (position) {
object.position.copy(position);
} else {
object.position.x = Math.random() * 10 - 5;
object.position.z = Math.random() * 10 - 5;
}
shapeStart.position.copy(object.position);
shapeEnd.position.copy(object.position);
const mergedGeometry = BufferGeometryUtils.mergeGeometries([object.geometry, shapeStart.geometry, shapeEnd.geometry]);
const tubeMaterial = new THREE.MeshLambertMaterial({ color: Math.random() * 0xffffff });
const tubeMesh = new THREE.Mesh(mergedGeometry, tubeMaterial);
tubeMesh.castShadow = true;
tubeMesh.receiveShadow = true;
scene.add(tubeMesh);
return tubeMesh;
}
const light = new THREE.PointLight(0xFFFFFF, 1, 100);
light.position.set(0, 5, 5);
scene.add(light);
camera.position.z = 5;
function animate() {
requestAnimationFrame(animate);
controls.update();
renderer.render(scene, camera);
}
addObject(new THREE.Vector3(0, 0, 0));
animate();
</script>
</body>
</html>
Thank you in advance for any help or guidance!