Alternative to glColorMask(), glDrawBuffer()could be used however that requires some additional tracking of the frame-buffer's attachments, which could affect future changes to the rendering system. glGet() with GL_DRAW_BUFFER would need to be used to track the current frame-buffer's state so it can be restored after the invisible lids are rendered.
Expected Result
Benefits
Boats won't look like they are filled with water.
Does not add complexity with stencil buffers (the traditional way to solve this problem).
Only adds 1 extra step to the existing rendering path.
All of the draw-backs below only apply to boats, it will not effect any other object rendered in the game.
Draw-backs
Waterfalls will suddenly stop at the lid of the boat. This may look strange, but it is more common to have a boat on flat water surface.
Any object drawn after the water is drawn will also suddenly stop at the lid of the boat. This may look strange - but most of the time boats are in water, rather than inside other blocks.
More quads are drawn to the depth buffer.
Why does this work?
The water will not draw on-top of pixels that are "above" the surface, otherwise objects built above water will appear covered by water. This is because the water tests against the OpenGL depth-buffer (See Wikipedia for more information), an image that is drawn to behind-the-scenes to describe how far away pixels are from the player's point of view.
By rendering an invisible lid to the depth buffer, we increase the height of the pixels around this area of the boat so when the water performs the depth test it believes that the pixels around the inside area of the boat are "above" the surface and ends up skipping those pixels.
Even when the boat is fully under-water, the depth test will see that the lid is below the surface and no strange visual errors will occur.
This image here shows how the invisible lid (shown in pink) is "above" the water's surface (shown in blue).
That sounds really interesting. Would this affect frame rate though?
Draw-backs I mentioned it adds 1 extra quad (2 triangles) for each boat that is visible. However, only the depth buffer is rendered to (so 1 value written, rather than the usual 4/5 that boats render to with RGBA+depth).
This results in 2 extra triangles per boat rendering to 1 buffer. It will have a negligible effect on the frame-rate.
As a comparison*, drawing a single particle has more of an affect on FPS than this proposed solution. It will take 3 or 4 boats with this method to have a similar FPS impact to a single particle - even at that the single particle is more expensive as they usually involve an intensive blend operation and an alpha test, my solution here involves no blending and no alpha testing (only depth read/write used).
* To my fellow graphics programmers; yes I know this isn't how performance scales, I am just giving a very rough comparison to other areas where quads are rendered!
A number of people are contacting Mojang about the boat solution I have proposed here; as a result there is a very good chance that Mojang will at least have a look at this suggestion.
I'll post back here if Mojang say anything.
In the meantime, some additional support from the forums here wouldn't go amiss. If people are confused about any part of what I am suggesting in this thread then do ask and I'll clarify.
This really irritates me. It looks like my boat is sinking and it just looks dumb. And finally, a solution that isn't just "please fix the water in boats, it's annoying" but an actual practical explanation that shows HOW to fix it. Awesome effort dude, I really really hope Mojang use your idea to fix it. See you next snapshot hopefully.
I don't understand much of this, but you obviously know what you are talking about. Since this is sort of a bug fix, I would suggest tweeting Mojang about it and asking people to do the same in the OP.
I've sent a Tweet to Dinnerbone, unfortunately I don't have any strong contact links with Mojang so anything I say is lost amongst all the other messages they receive.
I don't think encouraging people to send messages is the best idea. A lot of users have already started notifying Mojang employees about this solution I've proposed, so I don't feel I need to encourage the practise anyway as people are already doing it.
Admittedly, I don't have much experience with contributing fixes via public facing means. Most studios I work with have a dedicated contact channels which most of the time end up with direct means of contact via Skype or similar. Mojang are rather elusive so the best I can do is post the suggestion to the community and let the community get it noticed.
The problem with that is the majority of the community, like yourself, have little understanding of the technicalities which is why I think it's important to explain. If you don't understand a specific part then please point it out and I can try to elaborate. As an example, I can probably better explain the technique with a side-on 2-dimensional diagram - which is actually how most depth-buffer tricks are described in technical documents.
I don't like it when my boat appears to be sinking. Great solution. Since it's fairly common sense I have to wonder why Mojang hadn't thought of it.
They have higher priorities, their bug tracker has this issue down as fairly low.
The solution is not immediately obvious either. Standard GL practice for this would involve stencil buffer portals to mask out the geometry, however that comes with a lot of complexity so it would have needed a lot of thought for a small bug fix.
Using the depth buffer instead is much simpler but is not as intuitive, it's not the first solution people jump to when considering this sort of problem.
Also, it could be that this solution has been thought of and tried by Mojang but the "uniqueness" of Minecraft's rendering path made it impractical to use.
Update: Looks like this hasn't been solved in the latest snapshot.
I Tweeted Searge this time, I honestly thought they'd have seen the technique I described after Reddit kept requesting they looked at it, but alas. Here's the Tweet: https://twitter.com/Xilefian/status/662292896545140736 please favourite/retweet/forward back at Mojang.
A lot of people wanted this to get noticed, sorry for everyone who tried the first time round.
To reiterate; I have tested this idea out independently in an external OpenGL application I've written myself, it does work and is not speculation.
EDIT: And thanks to the 1000+ people who attempted to notify various Mojang employees! I haven't got a list of names, but I got numbers and it's amazing that only 1 of you got noticed!
So this has been implemented for the latest snapshot, however the current implementation suffers from z-fighting.
Z-fighting happens when depth-buffer inaccuracies causes some fragments (pixels) to pass the depth test, despite being sort-of in the same location. It happens mostly when two planes are in the same orientation and location.
Assuming that the boat depth-masks are rendered before the water is rendered, depth fighting will only occur when the depth-mask of the boat is the same height as the water. This is why in my pictures I had the "lid" at the top of the boat, to avoid the depth-fighting with having it too low-down.
With some GPUs, this bug may be fixed, but for it to be totally fixed Mojang need to raise that depth-mask (the "lid" of the boat) so it is above the water's surface.
Update: Grum confirmed that Mojang has already planned to use this exact method for 1.9 and has completed the implementation - https://twitter.com/_grum/status/662556485663215616
[1.9 Confirmed]
Issue this resolves; https://bugs.mojang.com/browse/MC-47636
This is not speculation, this is proven rendering logic and uses real features that are available in OpenGL.
Image album describing technique
Alternative to glColorMask(), glDrawBuffer()could be used however that requires some additional tracking of the frame-buffer's attachments, which could affect future changes to the rendering system. glGet() with GL_DRAW_BUFFER would need to be used to track the current frame-buffer's state so it can be restored after the invisible lids are rendered.
Expected Result
Benefits
Draw-backs
Why does this work?
The water will not draw on-top of pixels that are "above" the surface, otherwise objects built above water will appear covered by water. This is because the water tests against the OpenGL depth-buffer (See Wikipedia for more information), an image that is drawn to behind-the-scenes to describe how far away pixels are from the player's point of view.
By rendering an invisible lid to the depth buffer, we increase the height of the pixels around this area of the boat so when the water performs the depth test it believes that the pixels around the inside area of the boat are "above" the surface and ends up skipping those pixels.
Even when the boat is fully under-water, the depth test will see that the lid is below the surface and no strange visual errors will occur.
This image here shows how the invisible lid (shown in pink) is "above" the water's surface (shown in blue).
This is a very simple solution to this problem that avoids damaging the existing rendering path as much as possible. I have Tweeted this technique to Dinnerbone.
Draw-backs I mentioned it adds 1 extra quad (2 triangles) for each boat that is visible. However, only the depth buffer is rendered to (so 1 value written, rather than the usual 4/5 that boats render to with RGBA+depth).
This results in 2 extra triangles per boat rendering to 1 buffer. It will have a negligible effect on the frame-rate.
As a comparison*, drawing a single particle has more of an affect on FPS than this proposed solution. It will take 3 or 4 boats with this method to have a similar FPS impact to a single particle - even at that the single particle is more expensive as they usually involve an intensive blend operation and an alpha test, my solution here involves no blending and no alpha testing (only depth read/write used).
* To my fellow graphics programmers; yes I know this isn't how performance scales, I am just giving a very rough comparison to other areas where quads are rendered!
A number of people are contacting Mojang about the boat solution I have proposed here; as a result there is a very good chance that Mojang will at least have a look at this suggestion.
I'll post back here if Mojang say anything.
In the meantime, some additional support from the forums here wouldn't go amiss. If people are confused about any part of what I am suggesting in this thread then do ask and I'll clarify.
This really irritates me. It looks like my boat is sinking and it just looks dumb. And finally, a solution that isn't just "please fix the water in boats, it's annoying" but an actual practical explanation that shows HOW to fix it. Awesome effort dude, I really really hope Mojang use your idea to fix it. See you next snapshot hopefully.
Support
This is very well explained and a great idea.
Support
I've sent a Tweet to Dinnerbone, unfortunately I don't have any strong contact links with Mojang so anything I say is lost amongst all the other messages they receive.
I don't think encouraging people to send messages is the best idea. A lot of users have already started notifying Mojang employees about this solution I've proposed, so I don't feel I need to encourage the practise anyway as people are already doing it.
Admittedly, I don't have much experience with contributing fixes via public facing means. Most studios I work with have a dedicated contact channels which most of the time end up with direct means of contact via Skype or similar. Mojang are rather elusive so the best I can do is post the suggestion to the community and let the community get it noticed.
The problem with that is the majority of the community, like yourself, have little understanding of the technicalities which is why I think it's important to explain. If you don't understand a specific part then please point it out and I can try to elaborate. As an example, I can probably better explain the technique with a side-on 2-dimensional diagram - which is actually how most depth-buffer tricks are described in technical documents.
I already posted this on the subreddit. People have been informing various Mojang employees of it's existence over there.
There is a very high chance it will get noticed as a result.
Very detailed. Support.
THE KITTY HAST BEEN RESURRECTED, AND LIVES ONCE MORE!
I don't like it when my boat appears to be sinking. Great solution. Since it's fairly common sense I have to wonder why Mojang hadn't thought of it.
If you are planning to make a suggestion, please read this.
If you want to know more, you can read this.
For those who complain about post-Beta generation, you might want to see this.
Support.
I love it when people make techy posts like this.
"Are you falling asleep in the middle of my fascinating explanation?" - Qibli
"I can't even dignify that with a snort." - Winter
"This is important and fascinating!" - Starflight
"You're nonagashabibble." - Squid
They have higher priorities, their bug tracker has this issue down as fairly low.
The solution is not immediately obvious either. Standard GL practice for this would involve stencil buffer portals to mask out the geometry, however that comes with a lot of complexity so it would have needed a lot of thought for a small bug fix.
Using the depth buffer instead is much simpler but is not as intuitive, it's not the first solution people jump to when considering this sort of problem.
Also, it could be that this solution has been thought of and tried by Mojang but the "uniqueness" of Minecraft's rendering path made it impractical to use.
Update: Looks like this hasn't been solved in the latest snapshot.
I Tweeted Searge this time, I honestly thought they'd have seen the technique I described after Reddit kept requesting they looked at it, but alas. Here's the Tweet: https://twitter.com/Xilefian/status/662292896545140736 please favourite/retweet/forward back at Mojang.
A lot of people wanted this to get noticed, sorry for everyone who tried the first time round.
To reiterate; I have tested this idea out independently in an external OpenGL application I've written myself, it does work and is not speculation.
Grum noticed and has confirmed that Mojang have planned to implement this exact method (and have already done so!)
https://twitter.com/_grum/status/662556485663215616
EDIT: And thanks to the 1000+ people who attempted to notify various Mojang employees! I haven't got a list of names, but I got numbers and it's amazing that only 1 of you got noticed!
So this has been implemented for the latest snapshot, however the current implementation suffers from z-fighting.
Z-fighting happens when depth-buffer inaccuracies causes some fragments (pixels) to pass the depth test, despite being sort-of in the same location. It happens mostly when two planes are in the same orientation and location.
Assuming that the boat depth-masks are rendered before the water is rendered, depth fighting will only occur when the depth-mask of the boat is the same height as the water. This is why in my pictures I had the "lid" at the top of the boat, to avoid the depth-fighting with having it too low-down.
With some GPUs, this bug may be fixed, but for it to be totally fixed Mojang need to raise that depth-mask (the "lid" of the boat) so it is above the water's surface.
thanks for all the effort