Closed EliasHasle closed 8 years ago
What problems are you running into? Looking at the code, I think it would be as simple as offsetting the center vertices of the CircleBufferGeometry in the +z direction to get the cone.
A THREE.CylinderGeometry
based THREE.ConeGeometry
may be a nice addition actually.
@SuberFu That was how I did it. For some reason, I had difficulty rotating the geometry to match the cylinder. Also, the textures seem to be applied differently. And, at least in one attempt, the cone is not fully rendered. I am aware that it will be open in the bottom, but it's not just that. I will try to reproduce the problem with a simple example soon... Or just solve it, of course. I have that idea of just moving the vertice coordinates in the position array. Don't know if it is right yet...
@mrdoob It would be nice to have a ConeGeometry with only one radius parameter, but wouldn't it be terribly inefficient to implement it as a cone, because it would create a lot of unneeded vertices to begin with? (I haven't really dug into the depths of it, but I notice that there is a call to a function that merges vertices in the constructor of CylinderBufferGeometry..)
@mrdoob It would be nice to have a ConeGeometry with only one radius parameter, but wouldn't it be terribly inefficient to implement it as a cone, because it would create a lot of unneeded vertices to begin with? (I haven't really dug into the depths of it, but I notice that there is a call to a function that merges vertices in the constructor of CylinderBufferGeometry..)
I don't think it would be terribly inefficient 😉
@mrdoob Hehe.I must admit I am thinking in perfect superoptimization all the time. I guess implementing it as a cylinder gives less maintenance work in the future. But for me, being able to have, say, twice as (ridiculously many) objects in memory is very interesting, as I have a very old computer. ;-)
I got it to work with an example that also demonstrates how the texture is applied differently (which makes sense). The good thing with the circleCone is that AFAICS it has nearly half the number of vertices (see console log).
var clock, renderer, scene, camera;
var cylinderCone, circleCone;
init();
function init() {
clock = new THREE.Clock();
document.body.style = "overflow: hidden;";
var container = document.createElement("div");
container.style = "position: absolute; top: 0; left: 0;"
document.body.appendChild(container);
renderer = new THREE.WebGLRenderer( {antialias: true} );
renderer.setClearColor(0xcccccc);
renderer.setPixelRatio(window.devicePixelRatio);
renderer.setSize(window.innerWidth, window.innerHeight);
container.appendChild(renderer.domElement);
camera = new THREE.PerspectiveCamera(55, window.innerWidth/window.innerHeight, 1, 10000);
camera.position.set(0, 800, -1200);
camera.lookAt(new THREE.Vector3(0,0,0));
scene = new THREE.Scene();
scene.add(new THREE.GridHelper(600, 50));
scene.add(new THREE.AmbientLight(0xffffff, 1));
var material = new THREE.MeshBasicMaterial({
map: function() {
var texture = new THREE.DataTexture(
function(){
var data = new Uint8Array(3*4*2);
for (var pos=0; pos<9; pos++) data[pos]=255;
return data;
}(),
4,2,
THREE.RGBFormat,
undefined, undefined,
THREE.RepeatWrapping, THREE.RepeatWrapping
);
texture.repeat.set(10,10);
texture.needsUpdate = true;
return texture;
}()
});
//Common parameters
var radius = 100;
var height = 500;
var rSegments = 24;
cylinderCone = new THREE.Mesh(
function() {
var geom = new THREE.CylinderBufferGeometry(0,radius,height,rSegments,1,true);
geom.translate(0,height/2,0);
return geom;
}(),
material);
cylinderCone.position.x = 3*radius;
circleCone = new THREE.Mesh(
function() {
var geom = new THREE.CircleBufferGeometry(radius, rSegments);
geom.attributes.position.array[2] = height;
geom.rotateX(-Math.PI/2);
return geom;
}(),
material);
circleCone.position.x = -3*radius;
scene.add(cylinderCone, circleCone);
//log some stats:
console.log("cylinderCone has %d vertices",
cylinderCone.geometry.attributes.position.array.length/3);
console.log("circleCone has %d vertices",
circleCone.geometry.attributes.position.array.length/3);
animate();
}
function animate() {
requestAnimationFrame(animate);
//Make sure rotation around x axis is not affected by the geometry rotation:
var t = clock.getElapsedTime();
cylinderCone.rotation.x = Math.sin(t);
circleCone.rotation.x = Math.sin(t);
renderer.render(scene, camera);
}
A THREE.CylinderGeometry based THREE.ConeGeometry may be a nice addition actually.
Would you restrict height segments to 1 in that one? I think that makes sense. Then those who want to manipulate the shape in detail will just use a CylinderGeometry instead.
The good thing with the circleCone is that AFAICS it has nearly half the number of vertices (see console log).
As you can see, this statement is (wrongly?) based upon an assumption that the number of vertices at all times can be computed as one third of the length of the position array. I can think of reasons for that not to be the case. (The merging must have done something, right? Changing edges, faces, mapping etc., maybe leaving some inactive entries in the position array?)
Anyway, it looks like I will have to define a new UV mapping to get consistent results with the cylinderCone. Then it is probably better (the only possibility?) to create a new BufferGeometry. I will look into it, maybe do a PR too, in case you think it might be useful to have a highly optimized, but less flexible, cone geometry (in addition to an unoptimized, flexible one).
I'm interested in submitting a fix for this. I can take a crack at augmenting CylinderBufferGeometry to better handle the radius=0 case, avoiding the extra triangles for the top height segment.
I think the signature of ConeGeometry
would be:
THREE.ConeBufferGeometry = function (
radius = 20,
height = 20,
radialSegments = 8,
heightSegments = 1,
openEnded = false,
thetaStart = 0,
thetaLength = 2Pi )
If you want a simple optimized cone, use heightSegments=1
@EliasHasle isn't the primary issue w/ the circle geometry approach that you will only get a single normal value at the point of the cone? The CylinderGeometry duplicates the vertex at the point per radial segment in order to make sure the normal is properly set at that discontinuous point.
Perhaps your requirements not such that you need that normal to make sense. And yes, the UV mapping for the circle geom approach will look very different from that of the cylinder.
The CylinderGeometry duplicates the vertex at the point per radial segment in order to make sure the normal is properly set at that discontinuous point.
Agreed.
Also, I expect setting UVs may have to be cone-specific to avoid distortion.
In looking at CylinderBufferGeometry, it's unclear whether there is much to be gained by optimizing the geometry more for the cone case. While it results in some zero-area faces, it's hard to say that the compute impact will be that heavy considering the rest of the scene.
Writing the simple ConeBufferGeometry class that just calls CylinderBufferGeometry would be simple, and I'm happy to do that. I'm just finding the logic in CylinderBufferGeom to be pretty clean as it is.
@abelnation That was my thinking, too, when I first read this post.
But if texture-mapping without distortion is important, I guess cone-specific UVs are required.
I think the UV map for a cone would map an isosceles triangle subregion of the texture to the cone surface. But there would be a visible seam.... Probably not worth it.
Yeah, I mean, ideally the cone uv mapping matches the standard cone wrapping implemented by other modeling tools IMO. Right now, I believe the current mapping is to map every part of the texture square to some point on the texture, meaning the top edge of your texture will all get pulled in to the cone's point. I.e. what results if you took the cylinder torso uv mapping, and reduced the radius of one point to zero.
Also, in fiddling around w/ the Cylinder geom a bit, and allowing either radius to go to zero, I may have encounted an NaN bug w/ the resulting WireframeGeometry. I'm looking into it, as it's a good way for me to learn my way around the various Geometry classes.
I'm looking into it, as it's a good way for me to learn my way around the various Geometry classes.
: - )
I notice that there is no separate cone geometry, but that a CylinderGeometry with radius 0 in one end will be reduced to a cone through merging of vertices.
I also notice that a simple (straight wall) cone in fact has the same graph of vertices as the CircleGeometry. I have had some success, but mostly failure, trying to manipulate the CircleBufferGeometry into a usable cone for optimizing a scene with an extreme number of simple cones (procedural generation of a tree).
I am not really (only) asking for help here. Wondering what you think and know about the differences, regarding how textures are applied et cetera, and maybe considering the idea of building a simple cone class on top of the CircleBufferGeometry, if that is wise.
You may all have a tree, by the way. A Three tree. :-)