Closed PBrockmann closed 5 years ago
The Plain[Buffer]Geometry
classes was renamed when going to 1.x, in order to more closely align with the three.js API: https://pythreejs.readthedocs.io/en/stable/installing.html#upgrading-to-1-x
An example with a face-colored geometry would help me a lot. As the cube in https://stemkoski.github.io/Three.js/Vertex-Colors.html
Here is what I have done using three.js, now I would like to do the same using pythreejs !
function meshCreate(grid, values) { // quad is made from 2 triangles
var geometry = new THREE.Geometry;
var id = 0;
for (var i=0; i<grid.length; i++) {
cell = grid[i];
for (var j=0; j<cell.length; j++) {
geometry.vertices.push(new THREE.Vector3(cell[j][0], cell[j][1], cell[j][2])
}
// counter-clockwise
face = new THREE.Face3(id, id+2, id+1);
r = Math.floor(Math.random());
g = Math.floor(Math.random());
b = Math.floor(Math.random());
face.color.setRGB(r, g,b);
geometry.faces.push(face);
face = new THREE.Face3(id, id+3, id+2);
face.color.setRGB(r, g,b);
geometry.faces.push(face);
id = id + 4;
}
return new THREE.Mesh( geometry, new THREE.MeshBasicMaterial( { vertexColors: THREE.FaceColors, wireframe: false}) );
Or if you still want to use the old Geometry
type, the previous paragraph to that example can be helpful (I would say the BufferGeometry code is cleaner though).
Thanks @vidartf for your help on this issue. In fact I would like to handle faces of a geometry with colored flat faces as this example in three.js.
I would like to do the same in a python notebook.
<!DOCTYPE html>
<html>
<head>
<script src="http://cdnjs.cloudflare.com/ajax/libs/jquery/3.1.1/jquery.min.js"></script>
<script src="three.js/build/three.js"></script>
<script src="three.js/controls/OrbitControls.js"></script>
<script>
$( document ).ready(function() {
//#################################################
width = 500;
height = 500;
$('#div1').width(width);
$('#div1').height(height);
scene = new THREE.Scene();
scene.background = new THREE.Color( 0xeeeeee );
var VIEW_ANGLE = 45, ASPECT = width / height, NEAR = 0.1, FAR = 20000;
camera = new THREE.PerspectiveCamera( VIEW_ANGLE, ASPECT, NEAR, FAR);
camera.position.set(2,2,2);
camera.lookAt(scene.position);
scene.add(camera);
renderer = new THREE.WebGLRenderer({antialias: true});
renderer.setSize(width, height);
$('#div1').append(renderer.domElement);
controls = new THREE.OrbitControls(camera, renderer.domElement);
vertices = [
[0, 0, 0],
[0, 0, 1],
[0, 1, 0],
[0, 1, 1],
[1, 0, 0],
[1, 0, 1],
[1, 1, 0],
[1, 1, 1]
];
faces = [
[0, 1, 3],
[0, 3, 2],
[0, 2, 4],
[2, 6, 4],
[0, 4, 1],
[1, 4, 5],
[2, 3, 6],
[3, 7, 6],
[1, 5, 3],
[3, 5, 7],
[4, 6, 5],
[5, 6, 7]
];
geometry = new THREE.Geometry();
for (var i=0; i<vertices.length; i++) {
vector3 = new THREE.Vector3(vertices[i][0]-0.5, vertices[i][1]-0.5, vertices[i][2]-0.5)
geometry.vertices.push(vector3);
}
for (var i=0; i<faces.length; i++) {
face = new THREE.Face3(faces[i][0], faces[i][1], faces[i][2]);
face.color.setRGB(Math.random(), Math.random(), Math.random());
geometry.faces.push(face);
}
mesh = new THREE.Mesh(
geometry,
new THREE.MeshBasicMaterial( { vertexColors: THREE.FaceColors, wireframe: false})
);
scene.add(mesh);
//==============================================================================================
function animate() {
requestAnimationFrame(animate);
renderer.render(scene, camera);
controls.update();
}
animate();
//#################################################
});
</script>
</head>
<body>
<div id='div1'></div>
</body>
</html>
This line is obscur. And I haven't been able to generate a facesColored list as an argument to Mesh. I would like to understand how to use a facescolors variable.
# Map the vertex colors into the 'color' slot of the faces
faces = [f + [None, [vertexcolors[i] for i in f], None] for f in faces]
vertices = [
[0, 0, 0],
[0, 0, 1],
[0, 1, 0],
[0, 1, 1],
[1, 0, 0],
[1, 0, 1],
[1, 1, 0],
[1, 1, 1]
]
faces = [
[0, 1, 3],
[0, 3, 2],
[0, 2, 4],
[2, 6, 4],
[0, 4, 1],
[1, 4, 5],
[2, 3, 6],
[3, 7, 6],
[1, 5, 3],
[3, 5, 7],
[4, 6, 5],
[5, 6, 7]
]
vertexcolors = ['#000000', '#0000ff', '#00ff00', '#ff0000',
'#00ffff', '#ff00ff', '#ffff00', '#ffffff']
facescolors = ['#000000', '#0000ff', '#00ff00', '#ff0000',
'#00ffff', '#ff00ff', '#ffff00', '#ffffff',
'#00ffff', '#ff00ff', '#ffff00', '#ffffff']
# Map the vertex colors into the 'color' slot of the faces
faces = [f + [None, [vertexcolors[i] for i in f], None] for f in faces]
# Create the geometry:
cubeGeometry = Geometry(
vertices=vertices,
faces=faces
)
# Create a mesh. Note that the material need to be told to use the vertex colors.
mesh = Mesh(
geometry=cubeGeometry,
material=MeshBasicMaterial(vertexColors='FaceColors'),
position=[-0.5, -0.5, -0.5], # Center the cube
)
scene = Scene(children=[mesh], background="#cccccc")
c = PerspectiveCamera(position=[3, 3, 3])
rendererCube = Renderer(camera=c,
scene=scene,
controls=[OrbitControls(controlling=c)])
display(rendererCube)
Got it.
The faces list should be as
[0, 1, 3, None, '#a4fcdd', None]
So replace in the previous pythreejs python code:
faces = [f + [None, [vertexcolors[i] for i in f], None] for f in faces]
by
faces = [faces[i] + [None, rand_color.generate()[0], None] for i in range(0,len(faces))]
So code becomes:
vertices = [
[0, 0, 0],
[0, 0, 1],
[0, 1, 0],
[0, 1, 1],
[1, 0, 0],
[1, 0, 1],
[1, 1, 0],
[1, 1, 1]
]
faces = [
[0, 1, 3],
[0, 3, 2],
[0, 2, 4],
[2, 6, 4],
[0, 4, 1],
[1, 4, 5],
[2, 3, 6],
[3, 7, 6],
[1, 5, 3],
[3, 5, 7],
[4, 6, 5],
[5, 6, 7]
]
faces = [faces[i] + [None, rand_color.generate()[0], None] for i in range(0,len(faces))]
# Create the geometry:
cubeGeometry = Geometry(
vertices=vertices,
faces=faces
)
# Create a mesh. Note that the material need to be told to use the vertex colors.
mesh = Mesh(
geometry=cubeGeometry,
material=MeshBasicMaterial(vertexColors='FaceColors'),
position=[-0.5, -0.5, -0.5], # Center the cube
)
scene = Scene(children=[mesh], background="#cccccc")
c = PerspectiveCamera(position=[3, 3, 3])
rendererCube = Renderer(camera=c,
scene=scene,
controls=[OrbitControls(controlling=c)])
display(rendererCube)
Is there a way to optimize this simple example by using BufferGeometry rather than Geometry ? In fact, my real project is to display and update more than 360x180 quads (made from 2 triangles).
As with this mesh (2 deg x 2 deg)
Test https://gist.github.com/PBrockmann/ddd0d5ad4205f153e1287be3a9a68078#file-pythreejs_07-ipynb
BTW, a 1deg x 1deg mesh is not displayed (https://github.com/jupyter-widgets/pythreejs/issues/219)
Using a BufferGeometry should normally be much more performant, both in sync and in rendering. It might be slightly more complex to understand how to set up the arrays correctly though. Hopefully, there is a relevant JS example out there.
Could you point me this exemple, one with a FacesColor mode ?
Ok, I have figured out how to instantiate a BufferGeometry by transforming a classic Geometry with the from_geometry() method and then checking needed attributes.
geometry = Geometry(vertices=vertices, faces=faces)
bufferGeometry = BufferGeometry()
a = bufferGeometry.from_geometry(geometry)
a.attributes
Cube with FacesColor and a BufferGeometry
vertices = [
[0., 0., 0.],
[0., 0., 1.],
[0., 1., 0.],
[0., 1., 1.],
[1., 0., 0.],
[1., 0., 1.],
[1., 1., 0.],
[1., 1., 1.]
]
faces = [
[0, 1, 3],
[0, 3, 2],
[0, 2, 4],
[2, 6, 4],
[0, 4, 1],
[1, 4, 5],
[2, 3, 6],
[3, 7, 6],
[1, 5, 3],
[3, 5, 7],
[4, 6, 5],
[5, 6, 7]
]
p = []; c = []
for f in faces:
color = [random.uniform(0, 1), random.uniform(0, 1), random.uniform(0, 1)]
for v in f:
p.append(vertices[v])
c.append(color)
# Create the buffer geometry:
geometry = BufferGeometry(attributes=dict(
position=BufferAttribute(p),
color=BufferAttribute(c)
))
# Create a mesh. Note that the material need to be told to use the vertex colors.
mesh = Mesh(
geometry=geometry,
material=MeshBasicMaterial(vertexColors='FaceColors'),
position=[-0.5, -0.5, -0.5], # Center the cube
)
scene = Scene(children=[mesh], background="#cccccc")
c = PerspectiveCamera(position=[3, 3, 3])
rendererCube = Renderer(camera=c,
scene=scene,
controls=[OrbitControls(controlling=c)])
display(rendererCube)
Comparison between the 2 codes are available from https://gist.github.com/PBrockmann/ddd0d5ad4205f153e1287be3a9a68078
I suppose the BufferGeometry procures a better display. Note that I have to set 6 times each color values to display face colored quads. Quad primitives is there crudelly missing.
I still have the limitations of the number of vertex. 1deg x 1deg does not display anything.
Also would need to know how to update colors ?
WIth a Geometry(vertices=vertices,faces=changeFaces())
you can modify faces and the update of the object is done.
Now with a
BufferGeometry(attributes=dict(
position = BufferAttribute(p),
color = changeColors()
))
No changes are done.
So I am wondering how to update a BufferGeometry ?
Thanks to @vidartf for the solution
geometry.attributes['color'] = new_cList
should be
geometry.attributes['color'].array = new_cList
Correct notebook is available from https://gist.github.com/PBrockmann/f155a779382e2b8dec7543f3466e0798
I think this issue can be closed.
I cannot instantiate a PlainGeometry with last 2.0.2 release.
should work. I get
NameError: name 'PlainGeometry' is not defined