3DEE - 3D Extrapolated Extension for SFMLYes... some people might have expected this from me, and this was in the planning for quite a while and since Tank preferred that I work on this rather than SFGUI how could I say no?
General IdeaI've been using SFML for quite a while now, and it sort of fulfilled my needs in the beginning. But as I wrote more and more things, I always had to resort to using raw OpenGL to get 3D rendering done because well... SFML doesn't support 3D rendering through its drawable API. It got quite annoying that all my applications had basically the same OpenGL boilerplate code that SFML happily takes care of... for 2D. I thought: there must be a common subset of functionality that all 3D applications rely on that everybody has to code, but nobody truly likes to code. That is basically what this extension is for. It takes all the concepts that make rapid prototyping and coding graphical applications with SFML so simple and fast, and applies them to the 3D domain as well. Moreover, it was designed to be as general as possible to fit as many use cases as possible while still adhering to the SFML architecture... somewhat.
As for the name... no I initially had no idea that it could be pronounced like that. I tend to name my projects after what they are since I am such a creative person. It is just a working title after all. I couldn't name it SFML, I already had a directory named SFML
.
The idea is simple. Take all SFML classes that are bound to the 2D plane and extrapolate them into the next dimension (I know, it sounds awesome if you say it like that). 2D objects are furthermore still compatible with 3D rendering. They will simply have their z coordinate set to 0 appropriately.
Features3D PrimitivesAnalog to RectangleShape and CircleShape, there are the 3D counterparts named Cuboid and SphericalPolyhedron respectively. They are based on Polyhedron which is the analog to Shape. For constructing one's own polyhedra, there is the ConvexPolyhedron class as an analog to ConvexShape (don't ask me why it is named ConvexPolyhedron, I don't understand either
).
3D ModelsYou might be asking: OK great, we have primitives, but what about models? After all they represent the bulk of geometry in a typical 3D application. That is true, and that is why there is a very light interface class called Model which provides a few methods that might be helpful when building your own application specific 3D model classes. Since model loading, storage and representation is a science in itself, one isn't limited to using Model at all costs. Even a simple VertexArray can be used to represent model data if you want more control. Model was one of the classes for which I genuinely had no idea how to design. The requirements differ so much per application so instead of trying to implement a solution for every possible scenario, I figured just make it as light as possible and purely optional to use. I didn't implement model data loading because that would have introduced another dependency (which I don't like), and it ends up in a lot of code that the application would not make use of in the end. Model loading is done by the application specific class. Feedback would be appreciated on what other useful features could be added to Model.
BillboardsAlthough so simple, billboards are so common in 3D applications, as a replacement for complex geometry at lower levels of detail, as the representation of particles and many other things. Billboards are implemented as Sprites which are automatically rotated to always face the camera they were set to track. Nothing more, nothing less.
CamerasWhat 3D application would be complete without Cameras? They are indeed the analog to a View and derive from View just to keep things simple (I could have derived the other way around or made a common parent interface but I wanted to minimize the needed changes). They can be used anywhere a normal View would be able to be used. As inspiration for its API I took the newly added/changed Listener API with its position and directions so combining a Listener and Camera becomes quite trivial and the only natural thing to do
.
LightsThis is the first controversial feature. There is a Light class, and it bases its functionality on the fixed-function lighting of OpenGL with all its limitations. This could also be done using shaders, which I also recommend doing if you can afford it. However, sticking with SFML philosophy I felt that I had to provide an alternative for those unlucky people without programmable graphics hardware. Light can also be used for rapid prototyping and replaced later on with something more... flexible, but short of copying and pasting shader code along with its handling code, this is the fastest you will get lighting up and running which is absolutely necessary in many 3D applications.
ShadowsThis is the second controversial (non-)feature. Yes... it is a non-feature because I didn't implement shadowing. There simply isn't any fixed-function support for shadows and writing a custom shadow implementation
- Is guaranteed to have worse performance than the equivalent shader/modern variant
- Is not guaranteed to be optimal given the scene for which it is to be used, meaning that I would have to write multiple implementations for each scenario which would all be inferior to writing an application specific implementation
- Is still a science in itself. There is no consensus on "how to do it right", just general techniques that still need to be adapted to each application
For those reasons I thought it be better to let the application developer implement their own shadows which suits their needs the best.
Minor Features4x4 TransformsThis was a given, considering we are working in 3D now. This could be considered a major feature, however I don't directly use Transforms all that much and I don't think many others do as well
.
Stencil attachment for RenderTexturesI figured when rendering in 3D, it is going to be necessary to have an optional stencil attachment for RenderTextures, after all, many advanced techniques rely on use of stencil data (this includes shadowing techniques). This also sparks the question of whether the format of RenderTextures should be even more flexible to e.g. prevent the creation of a color buffer in cases where one isn't required.
2D Drawable WindingI altered all 2D drawable classes to specify vertex data with counter-clockwise winding. This was a requirement because I enabled backface culling in RenderTarget by default, get used to it
.
OK, enough with the features, where's the...Yes... the repository can be found at GitHub:
https://github.com/binary1248/SFMLThe branch consists of additions/changes to the SFML master branch in order to make integration as seamless as possible. Because I consider this to be a strict superset of SFML's features, this extension should be able to be dropped in place of the standard SFML implementation and it
should work out of the box. If it doesn't, either it is a bug (not unlikely at all
) or have something to do with the caveats that I am going to list.
The change set should stay more or less compatible with future changes to mainline SFML if not too much is changed. As such it should be easily rebased to the current SFML master when anything happens there.
CaveatsWindingIf you make use of your own geometry specification using VertexArray or a custom ConvexShape/Shape, make sure the face winding matches with what is expected (counter-clockwise). Culling is enabled by default in this implementation and any clockwise faces will not be rendered. Make it into a good habit and one day you will thank me because of the performance boost you might observe
.
Vertex NormalsBy default, vertex normals should be set correctly for all 2D drawables, facing in the positive z direction. When specifying your own vertex data, do not forget to specify them if the default doesn't cut it and you want to light your geometry.
View MatrixContrary to popular belief, you in fact don't move the view around by manipulating the projection matrix. The projection matrix is there for one purpose, and as its name implies that is the projection from eye/view space coordinates into normalized device coordinates. The reason why the architects of OpenGL chose the term model
view matrix is because the modelview matrix combines the Model and the View matrix into a single matrix. With the help of pushing and popping the stack it isn't hard to understand the theoretical concept. This is how a vertex is transformed:
vertex_out = projection * view * model * vertex_in
The model matrix transforms the vertex into world space, the view matrix into eye space and the projection matrix into normalized device space which is fed into the rasterizer. The reason why combining the view matrix into the projection matrix is possible is simple to understand from the equation. However, this brings problems with it, especially when lighting and normals come into play. Vertex normals are transformed just like normal vertex data, however
they are not multiplied with the projection matrix. This means if you have your view matrix combined with the projection matrix as opposed to the modelview matrix the normals will not be transformed properly, and lighting will produce unexpected results.
The proper way to move the view around is to instead "move the world around the view". This is done using the inverse of what would normally be considered the rotation and translation of the camera.
This is less of a problem when rendering in 2D without lighting because... well... there are no normals to worry about. There are other strange side-effects that are the result of this mistake. For more information refer to
this. If you have some obscure code that relies on the vanilla "non-standard" matrix implementation then maybe it's time to consider fixing it up.
Frequently Asked QuestionsQ: Where are the pre-compiled libraries for XYZ compiler?
A: You know me... No pre-compiled libraries here.
Q: I can't see anything I draw!
A: Read documentation? Read caveats? Did everything right? Report bug.
Q: Why are there no copyright notices in the newly added files?
A: I can't just copy them from the standard SFML files can I? Until I figure out what best to do, the source is available under the same license as SFML, zlib.
Q: Do you plan on ....
A: Yes I have plans for a lot of things, and they will be implemented when I have a general idea of how to implement them. Don't be afraid of asking for features, if they are simple enough and are general enough to be
useful to people besides you as well, I might implement them. However I will not take the route of implementing every possible variation of a certain feature to cater to every possible use case
like certain individuals try and fail to do.
Q: I know this isn't a question but I found a bug and I am sure it isn't intended behaviour described in a footnote of the documentation, and it wasn't in your caveat list.
A: Ask here or GitHub tracker.
Q: Where is the documentation?
A: doxygen inside the doc directory, or just generate the doc target in CMake. Same as SFML.
Q: What? No screenshots? What kind of presentation is this?!
A: The only thing to see would be the example I added, and that is not the focus as it is there purely for code demonstration purposes. And besides... building the example and running it yourself isn't really hard is it?
Q: This is too complicated for me. Is there a simpler way?
A: What? This is supposed to make your life simpler, and your development... faster. If you prefer writing 500 lines of OpenGL code to get a rotating lit cube up and running, be my guest.
Q: I don't understand OpenGL! That's the reason I use SFML. Why does this look a lot like OpenGL?
A: Like everything in the universe, there is a reason why OpenGL looks like what it is. Indeed you will find that many 3D APIs that don't get too high level have similar interfaces. Nothing else makes much sense. This is no exception. It helps to understand OpenGL concepts but most of the time it should not be needed when using this (my opinion, very subjective). In the case where a bit more knowledge is required, I have tried to write documentation explaining everything that is required.
Q: ... this engine ...
A: This is not an engine. SFML is not an engine. If you want an engine, you will have to look elsewhere.
Q: I want XYZ to look like ABC and when I click UVW it should become IJK. Please help.
A: Look for code slaves elsewhere.
Q: Will parts of this become part of SFML?
A: That is not for me to decide. If Laurent wants to grab bits and pieces, he is very welcome to. I am fine if all of this gets merged and I end up relinquishing my rights to the code. Anything that increases the number of 3D projects in this subforum... I'm getting quite bored... Teapot Defence anyone?
Q: Man that interface is completely moronic. How did you even come up with such a monstrosity?!
A: Constructive criticism welcome. I know this is a sensitive (and quite complicated) topic. And I guess nobody (not even Laurent) tried anything like this before from what I can tell. One learns from their mistakes, and mistakes have to be made to learn.
Q: Are those the only questions in the FAQ?
A: Nope, more will be added if needed.
Q: Why does this thread look like the
SFNUL one?
A: Because I am a truly creative individual.