I made a line mesh with elliptical shape, representing the orbit wiht eccentricity e, and semi-major axis a. The mesh is a child of a group called orbitGroup that contains other objects.
Also, I added a gui to change this parameters. Every time gui changes it calls the next function:
function ElementsUpdate(){
scene.remove(orbitGroup);
orbitGroup.remove(Orbit);
Orbit = undefined;
Orbit = new THREE.Line( GetGeometryOrbit(GetOrbitLine(a,e,100)), materialOrbit);
orbitGroup.add(Orbit);
scene.add(orbitGroup);
}
The mesh (Orbit) is being created successfully. However the it does not update. I'm aware that setGeometry method is not working anymore. Any solution? I am replacing the mesh because replacing only the geometry seems to be more complicated.
Thanks beforehand for the help.
The project is in this link
You should be able to replace the vertex (position) buffer and call it a day.
function ElementsUpdate(){
let points = GetOrbitLine(a,e,100).getPoints(); // THREE.Curve.getPoints
Orbit.geometry.setFromPoints( points ); // replaces the position buffer
}
Curve.getPoints gives you an array of the points on your elipse.
BufferBgeometry.setFromPoints replaces the position buffer, derived from your array of points.
Because it replaces the buffer (and the BufferAttribute) You should not need to mark anything as needing re-sent to the GPU.
Related
I'm new to PixiJS and I'm trying something simple like a painting application.
I'm having difficulty trying to capture a collection of shapes as a single grouping. I'm not interested in working code for this as I'd like to figure that out on my own; I'm simply interested in knowing whether I'm on the right track or if I need to explore some other PixiJS concepts to get what I need.
I have one canvas in which I can drag shapes such as rectangles, ellipse, and lines. These "strokes" are being stored as individual Graphics objects, for instance:
var shape = new PIXI.Graphics();
shape.position.set(...);
...
shape.lineStyle(...)
.beginFill(...)
.drawRect(...)
.endFill();
...
stage.addChild(shape);
...
renderer.render(stage);
I'm also holding onto these shapes in an array:
shapes.push(shape);
Now that I have these displayed as well as have the order of the strokes available, I'd like to be able to capture them somehow. Imagine maybe taking the drawing and saving it, or perhaps using it as a thumbnail in a gallery, or simply just storing it on the back-end in a database, preferably keeping all the raw strokes so that they can be scaled up or down as desired.
For now, I'm simply trying to take this collection of strokes and display them again by holding them, clearing the graphics from my canvas, and then plopping down what I have held.
Looking at this example, I've been able to get a texture that I can reliably reproduce wherever I click with the mouse:
http://jsfiddle.net/gzh14bcn/
This means I've been able to take the first part that creates the texture object, and I tweaked the second part to create and display the sprites when I click the mouse.
When I try to replace this example code with my own code to create the texture itself, I can't get that part to work.
So this example snippet works fine when I try to create a sprite from it:
var texture = new PIXI.RenderTexture(renderer, 16, 16);
var graphics = new PIXI.Graphics();
graphics.beginFill(0x44FFFF);
graphics.drawCircle(8, 8, 8);
graphics.endFill();
texture.render(graphics);
FYI to create sprites:
var sprite = new PIXI.Sprite(texture);
sprite.position.set(xPos, yPos);
stage.addChild(sprite);
Since I have my shapes in the shapes array or on the stage, what is the preferred way I proceed to capture this as a single grouping from which I can create one or more sprites?
So basicaly you've got how to make some PIXI.Graphics shape
var pixiRect = new PIXI.Graphics();
pixiRect.lineStyle(..);
pixiRect.beginFill(..);
pixiRect.drawRect(..);
pixiRect.endFill(..);
(You can draw as many rects/circles/shapes as you want into one PIXI.Graphics)
But to convert it to texture you must tell renderer to create it
var texture = renderer.generateTexture(pixiRect);
Then you can easily create PIXI.Sprite from this texture
var spr = new PIXI.Sprite(texture);
And the last thing is to add it to your stage or array, but you can also make some empty PIXI.Container and then addChild to that and you've got your array
option - add sprite (created from graphics) to stage
stage.addChild(spr);
option - push it to your array
shapes.push(spr);
option - if you have var shapes = new PIXI.Container(); you can make a container for your sprites
shapes.addChild(spr);
Working example : https://jsfiddle.net/co7Lrbq1/3/
EDIT:
to position your canvas above you have to addChild it later, it means first addChild has zIndex = 0 and every addChild adds a layer on top of last
I figured it out. My stage is a container:
var stage = new PIXI.Container();
var canvas = new PIXI.Graphics();
canvas.lineStyle(4, 0xffffff, 1);
canvas.beginFill(0xffffff);
canvas.drawRect(canvasStartX, canvasStartY, 500, 600);
canvas.endFill();
stage.addChild(canvas);
I changed this to the following:
var canvas = new PIXI.Container();
var canvasRect = new PIXI.Graphics();
canvasRect.lineStyle(4, 0xffffff, 1);
canvasRect.beginFill(0xffffff);
canvasRect.drawRect(canvasStartX, canvasStartY, 500, 600);
canvasRect.endFill();
canvas.addChild(canvasRect);
stage.addChild(canvas);
Then, I replaced stage with canvas where appropriate and canvas with canvasRect where appropriate.
Finally, I got my texture with:
var texture = canvas.generateTexture(renderer);
At the moment, this grabbed the entire width/height of the stage, but I think I just need to tweak a bit on how I create my canvas above and I should be fine.
I'm trying to clone and then scale a mesh, but scaling does not seem to be working immediately on the cloned object, for programming purposes using CSG ThreeBSP. I think I should call a function after the scaling to force the matrix or other internal variables to recalculate immediately and not to wait for the full update loop on render side.
My code looks something like this:
var someMesh2 = someMesh1.clone();
someMesh2.scale.set(2,2,2);
someProgrammingOperation(someMesh2);
//It turns out that internally, someMesh2 still has the same properties (matrix?) as someMesh1 :(
What am I missing? Suggestions are also welcomed :)
object.matrix is updated for you by the renderer whenever you call renderer.render().
If you need to update the object matrix manually, call
object.updateMatrix();
and it will update the matrix from the current values of object.position, object.quaternion, and object.scale.
(Note that object.rotation and object.quaternion remain synchronized. When you update one, the other updates automatically.)
three.js r.84
In the end, my problem was that the CSG ThreeBSP object needed to work based on the Geometry of the object, not in the Mesh itself. I applied the scaling on the Geometry and it worked as expected.
There is a caveat though, that one should be careful as with the meshes and geometries instances, therefore is needed to do some cloning in order to keep the original objects as they were, as in the following example:
var clonedMesh = original.mesh.clone()
var clonedGeometry = clonedMesh.geometry.clone()
clonedMesh.geometry = clonedGeometry
clonedMesh.geometry.scale(2,2,2)
var someBsp = new ThreeBSP( clonedMesh )
var newMesh = someBspBsp.toMesh()
someScene.add newMesh
I have several meshes, with about 5000 vertices each. these are the original vertices and call "verticesA" the problem is that it is delayed to run the following line:
shapeFigure[x] = new THREE.Shape (geometry [x] .vertices); // Very slow.
then transformed "shape [x]" in a mesh.
shape[x] = new THREE.ShapeGeometry( shapeFigure[x][x] );
mesh[x] = new THREE.Mesh (shape[x], new THREE.MeshLambertMaterial ({color: "# FF0000"}));
this is obvious because they are many mesh with many vertices. I have a button in my alplicación which generates an algorithm. This algorithm ONLY generates new vertices (I'll call verticesB, these vertices have the same length as the "verticesA"). I want to update the "verticesA" with "verticesB".
how I can update the "verticesA" that figure is in the form of "verticesB".
I do not want to use again "new THREE.Shape ..." because it is delayed (because I have many mesh with many vertices). I want to directly update verticesA TO verticesB, (it is faster)
I'm doing something like this:
//mesh-> is the original (verticesA)
http://imgur.com/ympHorb (verticesA)
//geometry[x]-> is a array with the new vertices (verticesB)
//geometry[x] and mesh[x] is the same length of vertices
for (var a in mesh[x].geometry.vertices) {
mesh[x].geometry.vertices[a].x=geometry[x][a].x;
mesh[x].geometry.vertices[a].y=geometry[x][a].y;
}
In my function render(), i have:
for (var t in mesh){
mesh[t].geometry.verticesNeedUpdate=true;
mesh[t].geometry.dynamic = true;
}
this is a map, but after running the above code and is updated but is distorted.the problem is that is not properly updated geometry.
http://imgur.com/qCWoMWe
the map should be this way:
http://imgur.com/MYXzaEd (this is verticesB)
how I can update the geometry correctly?
Adding new vertices to a three.js mesh goes by mesh.geometry.vertices.push(new THREE.Vector3(x, y, z)), but how do I remove them?
"geometry" is an array, so I thought, I could remove vertices with:
mesh.geometry.vertices.splice(vertexIndex, 1)
mesh.geometry.verticesNeedUpdate = true;
But when I do that, that whole thing breaks with three.js internal error messages that say: "Uncaught TypeError: Cannot read property 'x' of undefined" inside three.min.js.
I searched their wiki, their github issues. And can't find an answer to this. The mesh is a simple BoxGeometry, so not even a custom one.
In threejs each face is made of 3 vertices. Here is an example to make it clearer. Here is how you create a geometry in r71 :
geometry=new THREE.Geometry();
geometry.vertices.push(// few vertices with random coordinates
new THREE.Vector3(12,15,5),//index:0 -- the numbers are (x,y,z) coordinates
new THREE.Vector3(10,15,5),//index:1
new THREE.Vector3(12,10,2),//index:2
new THREE.Vector3(10,10,2)//index:3
);
geometry.faces.push(
new THREE.Face3(0,1,2),//those numbers are indices of vertices in the previous array
new THREE.Face3(0,3,2)
);
geometry.computeFaceNormals();// we won't care about this here
(I did not care about the values so i do not know which shape it can give)
What you can see is that two arrays are built : vertices and faces. Now what happens at each frame is that each face is 'drawed' with the position of its vertices.
You ask what is wrong by deleting a vertex in the geometry.vertices array : let's imagine the second vertex above is deleted. The array now looks like this :
geometry.vertices=[
THREE.Vector3(12,15,5),//index:0
THREE.Vector3(12,10,2),//new index:1
THREE.Vector3(10,10,2)//new index:2
];
There is no more vertex at index 3. So when the GPU will draw the next frame, if a face points to it (here the second face) it will try to access its coordinates (first x before y and z). That is why the console returns that it cannot read x of undefined.
Here was a long explanation of the error. You can see the vertex deletion also shifted the array so faces do not have the correct shape, and their normals do not correspond anymore. The worst is that the buffer will have to change and that is simply not allowed, as stated there for example :
Dynamically Adding Vertices to a Line in Three.js
Adding geometry to a three.js mesh after render
The solution is to use tricks, as quoted : modify your vertex coordinates, hide faces... this depends on what you want to do.
If your scene has not much vertices you can also remove the previous mesh and create a new one with a new geometry, without one vertex and with a corrected face array.
Is it possible to merge vertices only at render time? I'm doing a series of morphs which requires the vertex list to stay the same, however I want to merge the vertices to get a smooth reflection on a cube camera. Any one aware of a command similar to unmerge vertices?
Have you tried doing it? It should work.
You'll need to call
geometry.verticesNeedUpdate()
geometry.elementsNeedUpdate()
to tell three.js that the vertices and faces, respectively, have changed. There are other update functions you may need to call too (for instance if normals have changed). More details here: https://github.com/mrdoob/three.js/wiki/Updates
Note the comment on that page that the total number of vertices can't change. This may require you to do the merge on a temp geometry and then copy the vertices to your rendered geometry.
Alright, this is not in the documentation section, but you need to use the explode modifier as demonstrated in this example: http://threejs.org/examples/#webgl_geometry_tessellation
var explodeModifier = new THREE.ExplodeModifier();
explodeModifier.modify( geometry );
geometry.computeFaceNormals();
geometry.computeVertexNormals();
//This will undo the geometry.mergeVertices();