Hi, I recently played a game called Momodora: Reverie Under the Moonlight and loved it.
This game has some pretty cool effects (I think it’s made with Game Maker).
One of the effects is nice reflection/mirror effect from water.
How should I approach to make something similar?
I think it could be done with RenderTargets, but I currently don’t use RenderTargets for drawing, just SpriteBatch.Draw(). Is it possible to position RenderTarget in screen, look what is above it and just copy and mirror it? Also I have never used shaders outside Unity, so I don’t know how to use them.
My game uses OpenGL.
If you render the whole screen to a render target before rendering it to the backbuffer you can do this. Steps:
Render the scene without any water to a render target
Render the render target to the backbuffer.
Render the part of the render target that should be reflected on water to the back buffer at the position of the water if there is any. Use spritebatch with a source rectangle and SpriteEffects.FlipVertically here. Optionally you can apply some post processing effects like blurring or slightly changing colors.
You don’t have to render to the back buffer directly in case you want to do some extra processing or something.
Can confirm Jjaggs response from experience… Very smooth
Because I was so happy with my results using this approach, I will share a few additional findings:
For shallow water you can wade or drive through:
Once I had my rendertarget ( containing all the bits I wanted reflected), I then drew the bottom of the lake, so that the player could see the collision surface, and then drew the render target slightly transparent on top of that…
This way, the murky bottom and other things below the surface are visible through the water, while not being reflected…
-And then on top of it all, I added an overlay image of some fore-ground coastal elements to hide the rectangular nature of the render-target, and make it blend into the scene…
Here is a link to my games showcase post on this site… Scroll down a bit for the picture of water, and you can get a visual of what I’m describing.
I tried out drawing to RenderTarget2D and then drawing it at Vector2.zero. I didn’t get to trying out mirror-effect before encountering problems…
I always draw RenderTarget to Vector2.zero so it shows my game correctly. However, I also use floats in my game so when moving in-game the screen drawing looks bad. It’s kinda hard to explain since English isn’t my native language, but main point is I think that need to draw it in float position instead of integers, now the screen is “jumping between two positions”.
By the way, how good are RenderTargets performance wise? It’s feels like drawing same things twice, expect last time there is one big-ass texture instead of bunch of small textures.
PS. monopalle the game looks good, good luck with it
the screen “jumping” between two positions should be more of a case with ints instead of floats… curious. Maybe share your code.
Drawing everything to a rendertarget from the beginning like so:
graphicsDevice.SetRenderTarget(myRenderTarget)
spriteBatch.Begin()
…
//draw your stuff here (will be reflected later)
spriteBatch.End();
//Draw to backbuffer
graphicsDevice.SetRenderTarget(null);
_spriteBatch.Begin();
//Draw the scene
_spriteBatch.Draw(myRenderTarget, … )
//Draw the reflection
_spriteBatch.Draw( myRenderTarget, … get right coordinates … , SpriteEffects.FlipVertically);
//Draw stuff in the foreground (UI, stuff in front of water)
…
_spriteBatch.End();
The reflection here costs barely anything. 2D platformers have no performance problems in general and this should be almost free, it’s just like drawing another big sprite.
You might consider always drawing your game, or each layer of game, on its own render-target under all circumstances.
Then in your final draw lines, you draw those render-targets to screen…
This makes it easy to do post-processing like camera shake, ambient color change, scaling/zoom level… As well as reflections…
For reflections, you would draw the screen like normal, then draw to a new render target the layers you want reflected (ie NO foreground elements, HUD, etc)
and then draw that render target to the screen, and THEN draw foregrounds etc…
Now, when you draw the reflection render target to the screen, you need to specify that you want it drawn only within the bounding box of the water…
And you also need to specify a stencil rect, so it knows which part of the render target to actually draw within that bounding box.
This way, you can have any number of reflective bodies, all drawing from the same screen-sized render target.