SFML community forums

General => SFML projects => Topic started by: binary1248 on April 02, 2014, 04:24:46 am

Title: 3DEE
Post by: binary1248 on April 02, 2014, 04:24:46 am
3DEE - 3D Extrapolated Extension for SFML

Yes... 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? ;D

General Idea
I'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.

Features
3D Primitives
Analog 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 Models
You 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.

Billboards
Although 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.

Cameras
What 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 :).

Lights
This 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.

Shadows
This 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
For those reasons I thought it be better to let the application developer implement their own shadows which suits their needs the best.

Minor Features
4x4 Transforms
This 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 RenderTextures
I 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 Winding
I 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 ;D.

OK, enough with the features, where's the...
Yes... the repository can be found at GitHub: https://github.com/binary1248/SFML

The 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.

Caveats
Winding
If 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 Normals
By 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 Matrix
Contrary 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 modelview 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 (http://sjbaker.org/steve/omniv/projection_abuse.html). 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 Questions
Q: 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 (http://en.sfml-dev.org/forums/index.php?topic=13723.0) one?
A: Because I am a truly creative individual.
Title: Re: 3DEE
Post by: ChronicRat on April 02, 2014, 07:03:53 am
Cool, i'll take a look when my current game will be done.
Title: Re: 3DEE
Post by: therocode on April 02, 2014, 08:39:40 am
Oh, wow, this sounds quite awesome! Good job.

I have always found the lack of 3D and the complications that arise when using SFML with own rendering code what makes SFML to many a "kindergarten" library where it is awesome to learn and get familiar with things, but is left behind for alternatives that are easier to integrate and gets less in your way when you want to make more advanced things. Perhaps this extension could hold people a bit longer. :)

Would definitely try it out, but right now I have no fitting project. Will keep it in mind for future reference.
Title: Re: 3DEE
Post by: eXpl0it3r on April 02, 2014, 08:51:58 am
Oh look it's finally here! :D

I like it, can we merge it into SFML, Laurent? :P
Title: Re: 3DEE
Post by: Nexus on April 02, 2014, 11:52:05 am
Really nice! There are meanwhile quite a few 3D extensions, but a lot of them are either "engines" with rather specific use cases, abandoned or a huge mess (from "certain individuals" ;)). It looks like yours is the first serious attempt to stay with the SFML philosophy and extend it with as few changes as possible. Especially the "drop-in" semantics sound very promising, you should definitely keep that.

By the way, the project description is quite funny to read :D
Title: Re: 3DEE
Post by: lolz123 on April 02, 2014, 04:41:07 pm
Looks really nice! A clean interface, as always  :)

That said, I do see a few problems with this. I am a "Use OpenGL directly" type of guy, mostly because I try to stay on top of the latest and greatest OpenGL features, so it is quite possible that these criticisms do not apply since it is not what the library is trying to achieve. So, please take this with a grain of salt.

The idea of providing an interface as opposed to an engine is cool, but it is really hard to do for something with a scope like OpenGL has. OpenGL's API is probably as simple as it can get FOR C (DirectX has objects, making it a much nicer to use library  ;) )

I do not see how one can maintain the design philosophy of SFML for 3D. SFML's graphics API is great for 2D, but the same design doesn't really translate into 3D IMO. Its going to be really hard to do something like deferred shading in your current setup, since it modifies the entire pipeline to be "Not SFML-style". In deferred shading, all rendered things must have a uniform interface for materials, for instance. Also, you cannot simply add features to a deferred shading pipeline without changing the entire pipleline.

Also, I am sure you are aware of this, but pretty much everything you wrote in OpenGL is highly deprecated.

These criticisms may be wrong, they may be stupid, I need more coffee  :)
Title: Re: 3DEE
Post by: binary1248 on April 02, 2014, 05:17:15 pm
I am also more of an OpenGL guy, and I know how deferred shading basically requires you to take control of the whole pipeline yourself. But if you consider that rewriting any of the SFML examples in modern OpenGL would require writing the same functionality directly in OpenGL code, then there really is no point in trying to abstract further. With every layer of abstraction, you lose expressiveness, unless it is a super-thin layer which would be nothing but redundant.

The idea is to provide simple access to the most used functionality hidden behind abstraction, until the developer decides that they need more control. SFML does this, and without 3DEE, the realm of 3D rendering was also "beyond" SFML and something you had to do by hand. 3DEE just pushes this barrier a bit further, but for the purposes of complex things like deferred shading the barrier would have to be pushed so far, that it wouldn't make much sense to abstract any more. As such, you are probably right. You are unfortunately not (yet?) the target audience of 3DEE ;).

Bear in mind that I had to stick to deprecated features to "fit into SFML" better. If SFML had used modern OpenGL I would have too, I didn't want to change the requirements or even add new dependencies. I was merely exposing more of the lower level features using the same resources. I could have rewritten SFML to make more use of modern OpenGL but I figured that shouldn't be undertaken at the same time as this, as it is a completely separate concern. After all I am not really the one maintaining mainline SFML ;).

I do not see how one can maintain the design philosophy of SFML for 3D. SFML's graphics API is great for 2D, but the same design doesn't really translate into 3D IMO.
The reason I see for this, is that OpenGL was designed with 3D rendering in mind from the start, and as such 2D rendering was "squeezed into" the 3D rendering API. What this meant is that things that should be conceptually simple are artificially bloated due to the generalization. SFML is hiding the unneeded parts of this generalization again and maps directly from 2D concepts to the subset of OpenGL that is concerned with 2D rendering.

Its going to be really hard to do something like deferred shading in your current setup, since it modifies the entire pipeline to be "Not SFML-style". In deferred shading, all rendered things must have a uniform interface for materials, for instance. Also, you cannot simply add features to a deferred shading pipeline without changing the entire pipleline.
I can already picture how the pipeline itself would be abstracted in order to provide an easier to use interface. What OpenGL still does not do well, if you ask me, is provide a uniform intuitive API to its pipeline. I think every OpenGL programmer knows what I am talking about when I say that knowledge of the OpenGL programming API alone is not enough to get things done. You actually have to understand how the pipeline works "behind the scenes" in order to make use of it in a meaningful way. And that leads to having to understand the fundamentals of 3D computer graphics itself which is where most people stop and start running away ;D. Maybe it was for this reason that Laurent didn't want to enter the realm of this "black magic"? :D

Maybe one day, SFML will support 2D and 3D rendering without use of any deprecated features and easy access to a modular pipeline API. I still have no idea what that will look like, but one can keep hoping :D.
Title: 3DEE
Post by: The Terminator on April 02, 2014, 10:44:26 pm
I've been waiting for something like this for a long time. Definitely will be using this in my later games, it looks amazing!
Title: Re: 3DEE
Post by: Lolilolight on April 02, 2014, 11:50:38 pm
This is exacly what I'm trying to do for my next games. :)

Title: Re: 3DEE
Post by: binary1248 on April 04, 2014, 06:45:41 am
Update
VertexBuffer and VertexContainer
I figured this was a good time to implement an abstraction of an OpenGL VBO that could be used as a drop-in replacement for a VertexArray. All it does is delay data upload until the buffer is bound and the data has changed because more often than not, when you bind a buffer you want to do something with the data on the GPU. This has the nice side effect that for geometry that hardly changes, there is no cheaper way to draw. I can already imagine how much performance improvement people using huge VertexArrays will benefit from when using a VertexBuffer instead (this is one of those few times when my work actually benefits the tilemap community ::)) if they are truly bottlenecked by bus transfers.

For the really special use cases, one can even access the memory block directly and use a VertexBuffer to transfer arbitrary (non-Vertex) data to GPU memory. Buffer objects are probably the most common way of transferring any kind of data between host and GPU memory.

In the case where you want compatibility with older (ancient) hardware, you can use VertexContainer as a drop-in replacement instead. It will automatically select the optimal storage implementation based on the system it is running on. I also went ahead and replaced all instances of VertexArray or normal Vertex arrays in the drawable classes with VertexContainer, so they will hopefully profit from the reduced data transfers as well.

I would be interested to hear about any performance improvements (or possibly even declines) when dropping in 3DEE in place of vanilla SFML. My aim is to make something that everybody can benefit from.

1DEE and 3DEE Textures (I couldn't resist ;D)
Maybe not many beginners might know, but counter to intuition, OpenGL supports 1D and 3D textures in addition to 2D textures which SFML already exposes through its API. They won't be too useful when sticking to fixed-function 2D rendering, however they might be useful to those that make heavy use of raw OpenGL and shaders.

To demonstrate how a 1D texture might be used (this is still a very synthetic example), I altered the Storm + Blink Effect in the Shader example a bit to add a bit more... "chaotic energy" to it :D.

Shader Language Version Query
It is important to know what is supported when writing your own shaders, and until now, the user would have to manually query OpenGL themselves to find out what is supported. I added a small method to the Shader class that returns that information in a simple string that can be processed to find out what is supported. Getting the information should be a one-liner in the future.


The changes have all been pushed to GitHub.

These are a few of the features on the roadmap to de-deprecation of the SFML drawable implementation I had in mind. In the future I hope to see SFML run using modern OpenGL behind the scenes on hardware that supports it. It should still be completely hidden from beginners though, they have enough to worry about :). OpenGL users (like myself) should also benefit from having less to worry about because the really low-level details and C API restrictions would be sufficiently hidden behind higher level C++ constructs.
Title: Re: 3DEE
Post by: BaneTrapper on April 06, 2014, 02:49:49 pm
Hello, it seams quite a good addition to sfml this would bring so i want to check it out:

I got few issues,
I cannot build the documentation with cmake. Id like to see documentation.

I Downloaded from provided link
Quote
OK, enough with the features, where's the...
Yes... the repository can be found at GitHub: https://github.com/binary1248/SFML

I see there is a documentation
Quote
Q: Where is the documentation?
A: doxygen inside the doc directory, or just generate the doc target in CMake. Same as SFML.
But when i build it with cmake i get following error
Code: [Select]
The C compiler identification is MSVC 17.0.50727.1
The CXX compiler identification is MSVC 17.0.50727.1
Check for working C compiler using: Visual Studio 11
Check for working C compiler using: Visual Studio 11 -- works
Detecting C compiler ABI info
Detecting C compiler ABI info - done
Check for working CXX compiler using: Visual Studio 11
Check for working CXX compiler using: Visual Studio 11 -- works
Detecting CXX compiler ABI info
Detecting CXX compiler ABI info - done
CMake Error at C:/Program Files/CMake 2.8/share/cmake-2.8/Modules/FindPackageHandleStandardArgs.cmake:108 (message):
  Could NOT find Doxygen (missing: DOXYGEN_EXECUTABLE)
Call Stack (most recent call first):
  C:/Program Files/CMake 2.8/share/cmake-2.8/Modules/FindPackageHandleStandardArgs.cmake:315 (_FPHSA_FAILURE_MESSAGE)
  C:/Program Files/CMake 2.8/share/cmake-2.8/Modules/FindDoxygen.cmake:85 (FIND_PACKAGE_HANDLE_STANDARD_ARGS)
  CMakeLists.txt:16 (find_package)


CMake Warning (dev) in CMakeLists.txt:
  No cmake_minimum_required command is present.  A line of code such as

    cmake_minimum_required(VERSION 2.8)

  should be added at the top of the file.  The version specified may be lower
  if you wish to support older CMake versions for this project.  For more
  information run "cmake --help-policy CMP0000".
This warning is for project developers.  Use -Wno-dev to suppress it.

Configuring incomplete, errors occurred!

EDIT:: I fixed the unresolved link compiler error.
Downloaded fresh copy repeated process to build, no compiler error now.
Title: Re: 3DEE
Post by: Laurent on April 06, 2014, 03:40:24 pm
Quote
Could NOT find Doxygen
I think it's clear: you have to install doxygen to build the documentation.
Title: Re: 3DEE
Post by: BaneTrapper on April 06, 2014, 03:42:07 pm
Quote
Could NOT find Doxygen
I think it's clear: you have to install doxygen to build the documentation.
Ooh i had no idea what it is, thank you.
Title: Re: 3DEE
Post by: Laurent on April 06, 2014, 03:45:44 pm
Yeah, since he says "same as SFML", I guess he means "read the SFML tutorial for more detailed information" ;)

Quote from: SFML tutorial
SFML_BUILD_DOC

This boolean option controls whether you generate the SFML documentation or not. Note that the doxygen tool must be installed and accessible, otherwise enabling this option will produce an error.
Title: Re: 3DEE
Post by: BaneTrapper on April 06, 2014, 04:08:25 pm
Yeah, since he says "same as SFML", I guess he means "read the SFML tutorial for more detailed information" ;)

Quote from: SFML tutorial
SFML_BUILD_DOC

This boolean option controls whether you generate the SFML documentation or not. Note that the doxygen tool must be installed and accessible, otherwise enabling this option will produce an error.
It was a lot to take in at moment read, thank you on help!
Title: Re: 3DEE
Post by: Deathbeam on April 06, 2014, 07:35:21 pm
1DEE and 3DEE Textures (I couldn't resist ;D)
Maybe not many beginners might know, but counter to intuition, OpenGL supports 1D and 3D textures in addition to 2D textures which SFML already exposes through its API. They won't be too useful when sticking to fixed-function 2D rendering, however they might be useful to those that make heavy use of raw OpenGL and shaders.

To demonstrate how a 1D texture might be used (this is still a very synthetic example), I altered the Storm + Blink Effect in the Shader example a bit to add a bit more... "chaotic energy" to it :D.

1D textures? For what they can be used, becouse from name it seems that they have only 1 dimension, and rendering 1 dimension is not possible. Hmm never heard about 1D textures, what is it and for what it is exactly? Becouse I am not skilled in C++ I can´t check your example to understand it :D But your 3D extension is epic, I agree that this should be atleast official extension for SFML.
Title: Re: 3DEE
Post by: Lolilolight on April 06, 2014, 07:48:41 pm
the direction in your class camera, it's the lookat vector ???
Title: AW: Re: 3DEE
Post by: eXpl0it3r on April 06, 2014, 07:50:23 pm
1D textures? For what they can be used, becouse from name it seems that they have only 1 dimension, and rendering 1 dimension is not possible. Hmm never heard about 1D textures, what is it and for what it is exactly? Becouse I am not skilled in C++ I can´t check your example to understand it :D
I bet Google could've explained it to you in an understandable way... ::)

1D textures have a dimension of x*1px. I'm not enough familiar with OpenGL or graphics in general to explain why they exist but I'm sure wikipedia can. ;)
Title: Re: 3DEE
Post by: Laurent on April 06, 2014, 08:33:43 pm
1D textures can be used for color lookup in pixel shaders (it's basically an efficient way to pass an array, and to get interpolation between values for free). Example: toon shading.
Title: Re: 3DEE
Post by: binary1248 on April 07, 2014, 11:41:17 pm
Major Update
Non-legacy rendering implementation for drawables
As already stated previously, I aimed to (re-)implement SFML's drawable implementation using only the modern, non-legacy OpenGL API. I think I've succeeded at that short of any undiscovered bugs I didn't find during testing. SFML will query OpenGL for the required functionality (shader support obviously, along with a minimum space requirement regarding uniform storage for storing light arrays and a minimum GLSL version of 1.30).

The idea is that the fixed-function pipeline is replicated in a Shader object that the RenderTarget will default to for rendering if the user doesn't specify otherwise. This means that certain attributes need to be sent per drawable to the vertex shader and currently they are hardcoded (position, color, texture coordinate, normal), so if you write your own shaders be sure to make use of them to interact with SFML. To ease the transition from the previous Shader API, I followed the naming scheme of the deprecated/removed built-in OpenGL attributes, e.g. gl_Vertex becomes sf_Vertex, gl_Normal becomes sf_Normal, gl_MultiTexCoord[0] becomes sf_MultiTexCoord0. All of the matrices are also provided as uniforms (model, view, projection, texture, normal). Lighting data is provided in a uniform array of structs as-is straight from Light and is used to compute per-pixel lighting. Maybe some time in the future, there will be a mechanism to choose from per-pixel and per-vertex lighting if the former isn't required.

A full list of uniforms and vertex attributes can be found in the Shader documentation. For anybody who is interested, the hard-coded shader source is inside RenderTarget.cpp.

As the previous posts, this is meant to be drop-in compatible with vanilla SFML. If something breaks that wasn't explicitly mentioned either here or in the documentation, report it as a possible bug. This was something I hacked together in a few days and although I tried to stay as clean as possible, the possibility of bugs slipping in is still there ;).

In the case that this completely and utterly breaks all of your code and would cost you an enormous amount of time rewriting all of your shaders and what not, there is the SFML_LEGACY_GL option/define in CMake that forces SFML to keep using the legacy pipeline. Be aware that if you use this you might not get to make use of any future additions ;).

Minor change to Light
I decided that it made little sense to provide a separate color for each component of a light as opposed to a single color and multiple intensities. There aren't many use cases where you would want ambient, diffuse and specular colors of the same light to be different. In the cases where it is required for some reason, one can simply create multiple lights instead. Currently, the specular component doesn't contribute anything. In the future, objects should be able to be assigned materials that provide surface information so that the proper lighting calculations among other effects can be performed.

The changes have all been pushed to GitHub.

With the initial de-deprecation done, this lays a nice foundation to implement other features that are widely used and that SFML still lacks to cater to more experienced 3D programmers. If anybody has ideas/concrete features that they and others might find useful, I'd like to know about them. I can only brainstorm out of my own perspective when it comes to this.
Title: Re: 3DEE
Post by: Grimshaw on April 08, 2014, 12:51:19 am
Hey binary! Good job on this library! Looking awesome :)

I wonder if there are computers around with no shader support.. I keep seeing people trying out for shader support, but I guess its 99.9% of the times a yes :) Any further information on this topic? =)
Title: Re: 3DEE
Post by: binary1248 on April 08, 2014, 02:14:23 am
Shaders have been around for a long time (maybe even when 3dfx was still around) but the current incarnation of shaders only came to life when Nvidia/ATI noticed that developers needed more flexibility when transforming vertices and performing shading. GL_NV_vertex_program was probably the first extension that provided the developer a way to send a whole program (still written in assembly 8)) down to the vertex shader to execute on vertices. That specification was written against the OpenGL 1.2.1 specification, so you can guess how old it is. After that more and more programmability got exposed to the developer and eventually Direct3D's HLSL and OpenGL's GLSL showed up and that is what we are still using today.

The joke is, even now, probably around 14 years later, some "graphics processor manufacturers", yes... graphics processor, not graphics processing unit because they aren't units, still fail to implement the specification that it allegedly follows. If you are lucky, querying the GL capabilities yields that some certain feature isn't supported. Tough luck in that case, but at least you're not in for an adventure. If you are not so lucky, GL tells you that some certain extension is supported, but in reality, either it isn't at all, or that implementation is so buggy that you voluntarily stay away from it.

I listed 3 requirements for non-legacy rendering to be activated.

As you can see, testing for support by asking GL nicely is certainly a crazy thing to do since more often than not certain things are more random than one might like. This is probably also the reason why AAA developers tend to look up in hard-coded hardware tables what the capabilities of the underlying hardware allow them to do rather than asking nicely. This also lets them add the "Select best settings for my hardware" feature to their settings screens. If they really probed each and every capability, it would take them more than a few milliseconds to do, and it wouldn't even result in a functioning setup sometimes.

This is also one of the problems that OpenGL opponents (i.e. Direct3D fanboys) love to point out. DirectX has an emulation layer that tries to smooth out the feature landscape of the hardware that it abstracts. It can't make up for every single feature that might be missing, but the more mundane ones that OpenGL would still require a capability lookup for are transparently added via other means so the developer can assume it is present given some other preconditions. I can still remember long ago how Quake Engine based games tended to have more settings than DirectX based games and some of them even crashed and failed to start up without configuration file editing if you accidentally checked a box you weren't supposed to :).
Title: Re: 3DEE
Post by: binary1248 on April 13, 2014, 07:25:46 pm
Major Update
Vertex Array Objects
In an attempt to reduce the OpenGL API call overhead, I implemented a way for RenderTargets to batch attribute bindings into vertex array objects when they are supported and the requirements are set. Due to the way SFML goes about with its contexts, I couldn't make it into its own class because VAOs need to be bound to a context due to their inability to be shared between contexts. This means that the RenderTarget has to manage creation and destruction of VAOs on its own using a dynamic aging system, which was also a bit annoying to implement. Right now, each RenderTarget (and their context) has the ability to track up to 10000 VAOs meaning you can draw 10000 distinct drawables per frame before they will be continuously created and destroyed which will likely kill performance. Hopefully 10000 distinct drawables is enough ::). This is a limitation of SFML's context architecture and might change in the future.

Geometry Shaders
Added support to load in geometry shaders. Geometry shaders are optional so Shader objects can still be used without them. In order to keep the API clean, I chose to support only the core specification of geometry shaders as it doesn't add any new GL functions because all the needed information is encapsulated in the shader source.

Uniform Buffer Objects
Buffer objects (sf::VertexBuffer) can now be used as storage for uniform data in shaders. sf::VertexBuffer already had the option of storing generic (non-vertex) data previously and if you bind it to a uniform block in a shader, you can upload truly huge chunks of data in a single call just by modifying the contents of the buffer and rebinding it. Access to the data is as simple as accessing any other array type in the shader.

Light Optimizations
I moved the light component colour computations out of the shader and into the Light class so it only has to be computed once and can be used for every fragment without taxing the shader needlessly. The attenuation values are also packed into a vec4 now so that the shader compiler has an easier time vectorizing the attenuation computations that are performed inside the shader, and the number of glUniform calls using the non-buffer method is reduced.

General Optimizations
There are also many other optimizations that I implemented that reduce the amount of redundant operations that are performed as well as the number of OpenGL calls per frame. The vanilla shader API wasn't designed for frequent (multiple times per frame) setting of parameters and as one can see below, the call count exploded with the initial implementation.

For comparison, here are the function call lists running the 3d example per frame using CodeXL:
Legacy rendering using minimally modified SFML:
(http://i.imgur.com/Ou3oBOS.png)

Initial non-legacy rendering:
(http://i.imgur.com/xa2GOH5.png)

Optimized non-legacy rendering:
(http://i.imgur.com/tQZ9onN.png)

It might look like the legacy rendering is still advantageous over the optimized non-legacy rendering, however keep in mind that glDrawArrays using client-side arrays was transferring huge amounts of data every frame along with having to reset the attribute source in every draw call which might lead to pipeline stalls on the GPU in some cases. In addition to that, the implicit data transfers that take place as part of the fixed-function behaviour would also have an effect but not show up on the list. The performance difference might not be noticeable in this scenario, however, the larger the amount of geometry gets and the more data the GPU has to process each frame, the more the new implementation will gain over the others.

I think the ARB was right when they said that the non-legacy API is designed to be much cleaner :D. This can easily be seen by the reduction of the number of function types that are called from legacy to non-legacy.

The changes have all been pushed to GitHub.

Title: Re: 3DEE
Post by: BaneTrapper on April 14, 2014, 12:32:08 am
Is it possible to use your "Light" engine for 2d world?
Title: Re: 3DEE
Post by: binary1248 on April 14, 2014, 04:26:55 pm
Light is not an engine... it is a class that instructs the rendering pipeline to apply lighting effects to whatever is drawn.

Because shadows aren't cast from lights, it makes little sense to use it for lighting a 2D world. You could easily achieve the same effect by blending a light map on top of your rendered world while saving a lot of GPU resources.
Title: Re: 3DEE
Post by: BaneTrapper on April 15, 2014, 01:14:39 am
I aren't really known with the light "class" you have, because i had issues setting up the camera or the objects something was off and i couldn't get stuff on screen.
If i draw everything on 0 and set camera position to 0 i would get image but any attempt to move the camera made screen just black.
Is there a example code? i didn't find any except the sfml one, but that is not using your "camera" which is afaik needed for light.

What i want from light is just to have point and emit light from it for X radius, but be blockable/obstructed by objects/terrain.
Title: Re: 3DEE
Post by: binary1248 on April 15, 2014, 02:05:38 am
I aren't really known with the light "class" you have, because i had issues setting up the camera or the objects something was off and i couldn't get stuff on screen.
If i draw everything on 0 and set camera position to 0 i would get image but any attempt to move the camera made screen just black.
If you put your camera right in the object you are trying to look at, depending on how big the object is, you will move it out of the view even with small movements of the camera. Not only that, if they both have exactly the same location, and you are literally "inside" the object, you won't see anything because backfaces are culled. If you want to look at a box in real life you also don't put the camera inside of it...

If you post the code you wrote, maybe it might be easier for me to tell what you did wrong...

Is there a example code? i didn't find any except the sfml one, but that is not using your "camera" which is afaik needed for light.
There is a "3d" example in the examples directory, and it uses a camera... along with a few 3D objects and some 2D objects.

What i want from light is just to have point and emit light from it for X radius, but be blockable/obstructed by objects/terrain.
Because shadows aren't cast from lights
Lights do not cast shadows... Things behind other things will be lit up as if nothing was in front of it blocking the light. If you want shadows, you will have to implement it yourself. Don't use the Light class and take the detour into the 3D realm if you just want shadows for your 2D application, that is not what it is meant for. Light is only used to shade 3D objects to give them a sense of depth which you would not perceive without it. It makes little to no sense using it in a truly 2D application (consisting only of 2D geometry).
Title: Re: 3DEE
Post by: cooldog99 on April 21, 2014, 07:54:18 am
This. is. amazing. EXACTLY what i've been looking for!

I tried to create something like this for myself awhile back... and kinda lost interest since I'm still new-ish to openGL.

I really love how simplistic it is to get a 3d application up and running with a small file.

Thank you so much for this :D

I AM having one issue though, I can't seem to get anything textured (besides billboard). Does the .setTexture function not work for most of the classes yet? I'm really tired and am probably screwing it up.

When I add something like this to the example... it doesn't seem to work.
Code: [Select]
cube.setTexture(&billboardTexture);

Even when I use your example code for loading .obj files and .setTexture the model class (from example) It gets the texture coordinates right, but doesn't seem to use them?

Like I said, I probably screwed something up... still new-ish to openGL.

Thanks again.