¡Esta es una revisión vieja del documento!
This is the traditional way to draw:
ofFill(); ofSetColor(255,0,0); ofBeginShape(); ofVertex(20,20); ofVertex(40,20); ofVertex(40,40); ofVertex(20,40); ofEndShape(true);
However we have several functions to draw primitives like…
The tradictional way is deprecated because internally, the openFrameworks version is tessellating the shape (converting it into triangles), then storing all the triangles in an ofMesh, and then drawing that ofMesh. It doesn't make much sense to send them to the graphics card every frame.
If you are using openGL 3+ instead of an ofMesh that will be drawn through a VBO using an ofVboMesh, since that's the only possible way of drawing in newer openGL. The paradigm that newer versions of openGL use is something like this: create the shape once, upload it to the graphics card, and then draw it every frame without having to reupload again, this is usually don through some kind of buffer in the graphics card, usually vbo's. In openFrameworks, the ofPolyline and ofPath classes do this in 2D and ofVboMesh for 3D.
ofPolyline, allows us to represent the contour of a shape.
ofPolyline polyline; void ofApp::setup(){ polyline.lineTo(20,20); polyline.lineTo(40,20); polyline.lineTo(40,40); polyline.lineTo(20,40); polyline.close(); } void ofApp::draw(){ polyline.draw(); }
ofPolyline is really a class meant to be used to do operations over polylines, like simplifications, smoothing… Also ofPolyline can only draw outlines, not filled shapes.
ofPath path; void ofApp::setup(){ path.moveTo(20,20); path.lineTo(40,20); path.lineTo(40,40); path.lineTo(20,40); path.close(); } void ofApp::draw(){ path.draw(); }
ofPath draws filled shapes by default, however ofFill and ofNoFill do not effect ofPolyline or ofPath. That's because they also follow the more modern openGL paradigm where most global state values are deprecated. Instead, you can set the color per vertex on every shape or use a shader to specify a color or line thickness.
ofPath allows us to specify if we want to draw it with outline, fill, color, and width per path, so those properties are local to each path instead of specifying them globally:
ofPath path; void ofApp::setup(){ path.moveTo(20,20); path.lineTo(40,20); path.lineTo(40,40); path.lineTo(20,40); path.close(); path.setStrokeColor(ofColor::blue); path.setFillColor(ofColor::red); path.setFilled(true); path.setStrokeWidth(2); } void ofApp::draw(){ path.draw(); }
When we draw a path the first time, ofPath internally calculates it's tessellation and stores it in an ofVboMesh, keeping its vertices in the GPU. If the vertices haven't changed when we draw an ofPath the next time, the vertices don't need to be uploaded again to the graphics card. This makes things really fast. You can actually access that tessellation using:
ofPath path; ofVboMesh tessellation; void ofApp::setup(){ path.moveTo(20,20); path.lineTo(40,20); path.lineTo(40,40); path.lineTo(20,40); path.close(); path.setStrokeColor(ofColor::blue); path.setFillColor(ofColor::red); path.setFilled(true); path.setStrokeWidth(2); tessellation = path.getTessellation(); } void ofApp::draw(){ tessellation.drawWireframe(); }
The tessellation only represents the fill of our shape. If the path has no fill, it'll return an empty mesh. We can also access the outlines of an ofPath as a vector of ofPolylines using path.getOutline()
path.setMode(ofPath::POLYLINES) which will make that path override the creation of primitives and work directly with ofPolylines which can be slightly faster in certain cases, mostly if you are creating a really high number of paths and modifying them frequently.
You can use the next functions…
ofTranslate(20,20); ofRotate(45); ofRect(20,20,20,20);
… enclosed that between ofPush/PopMatrix. But they are also deprecated. Each call to them, or the gl equivalents for that matter, are doing a multiplication of 4×4 matrices. But we can avoid it somehow. Instead of doing all of the multiplications of the matrices every frame, we can use an ofMatrix4x4 for each shape we use, do all of that shape's transformations once (or every time the shape moves), and apply them later when we want to draw that frame:
ofPath path ofMatrix4x4 m; //ofApp.cpp void ofApp::setup(){ path.moveTo(20,20); path.lineTo(40,20); path.lineTo(40,40); path.lineTo(20,40); path.close(); m.rotate(45); m.translate(20,20); } void ofApp::draw(){ ofMultMatrix(m); path.draw(); }
In openFrameworks, there's a utility class called ofNode, that allows you to apply complex transformations like set an object to look to another, set a hierarchy of nodes… When working with 3D it's useful to keep an ofNode along with every mesh that represents it's transformations, so when you draw each mesh, instead of using ofTranslate, rotate, scale you can just apply the transformation of it's node using node.transformGL(). This will multiply the current matrix by the one in the node. When you are done you can use node.restoreTransformGL()to go back to the previous state. Instead of using ofTranslate/Rotate/Scale, it is usually easier to implement an ofNode associated to each mesh or shape that you draw.