Friday, November 13, 2015

Render Target Madness

So, I made that glass effect. I think it turned out pretty nice, with the important feature being that it doesn't just use alpha blending to modify whatever is behind the glass, it actually warps what is seen to give a reasonable approximation of refraction. However, all my objects are drawn straight to the back buffer representing the screen. My glass objects then need to both draw themselves to the back buffer at the same time they read from it to figure out what warped pixel to use, and that causes a problem. The back buffer can't be bound for both reading and writing at the same time. Stupid parallelism.

To get around this most objects draw to two buffers, the back buffer and a second buffer that can then be safely read by the glass objects. This has some downsides and might want to be reworked eventually, but for now its how I handle it. It  does mean that my pixel shaders for everything have to explicitly output to two different buffers. The weirdness comes into play in that its perfectly possible for my pixel shader to completely ignore one of the two buffers and just dump to the 0-indexed one. In fact, this has happened a few times when I start reusing an old shader I had written earlier. I had arbitrarily chosen the texture that the glass draws from to be bound to this slot, and the back buffer to be the 1-indexed slot, which means that any objects drawn with this shader don't show up on screen. Uuuuunnnless you look through any glass object. Then bam, they show up all warped.


I drew a giant blue triangle, because why debug with anything more complex that literally necessary.
This would actually be a pretty neat feature, allowing the player to peer into other dimensions or something. If I actually intended it.
This is actually an issue I've run into a few times now, as a week or so passes and I forget that some of the shaders kicking around my git client are outdated. This is the sort of issue I stare at confusedly for a minute and immediately remember past-me's efforts. This time however the issue was much more insidious, and tied into another bug I've been dealing with. The above picture is nicely framed to show off the view of the triangle. What I actually saw when trying to debug the problem was this:



You may notice that it is not a triangle. It's actually a little curve thing wind-sail looking thing. Also if you look closely there's a couple blue strips continuing on around the thing. Also whole chunks of the glass funnel are just missing and see through! What is going on!

Turns out this can be blamed on the depth buffer. What was happening is that the blue triangle was being "drawn" during my first render pass, but just to the glass's reference texture. The fact that it didn't show up in the back buffer didn't stop it from marking its depth in the depth buffer though, so when the second render pass went through and drew all the glass the parts of the funnel that were "occluded" by the invisible triangle weren't drawn at all. Except for the tiiiny bit of funnel that happened to be sticking through it and thus passed the z-test. So the blue shape is actually a plane intersecting a cone, technically making it a section of a parabola. Or maybe a hyperbola, depending on if the funnel is slightly tilted.

Also, the blue stripes. Parts of the funnel not behind the triangle, but close enough to refract from the position it wrote to on the glass reference texture. Yes, this means the glass is refracting something in front of it not behind it. I'll get to it later. Probably. Really should make a bug list somewhere or something for all this technical debt I'm racking up.

In any case, this is what things look like after I've fixed the shader.



Big 'ol blue triangle. Just sitting there. All I wanted to do was draw a simple triangle to test a new model loader, but instead I get to debug shaders and deal with render target issues.

But, the good news, now I know why I can see through the tops of my bottles even though I totally sealed the mesh! Hint: it's exactly what I just talked about!


Wednesday, November 4, 2015

Uuuuuugh.

The way I have the fluid in the bottle set up, the whole fluid is always drawn. However, anything above the fill line has a 0 alpha value so it doesn't actually draw anything. Turns out I forgot that it will write to the depth buffer anyways, meaning that the invisible fluid was preventing the inside of the bottle from being drawn. This means I'm probably going to have to do some sort of fancy stuff with either the depth buffer or more render targets in order to make this work. Guh.

Funnels and Math

The first thing that I noticed after adding the ability for bottles to pour into each other was that it was a major pain to actually make that happen. Since they're bottles, their openings are rather small, and since I currently only move them in discrete amounts its hard to place them exactly where I want them. This means that trying to fill one with another consists primarily of tipping one over and waggling it in the direction of another, hoping their tops happen to line up. This is annoying for testing, and pretty early on reveals a major user annoyance point that really should be cleared up.

My solution, as alluded to by the title, was to add a funnel.
Still liking the glass shader, but perhaps the lighting could be positioned a bit better to show it off here.
Using the power of Duck Typing I was able to simply make the funnel another Lua object that happened to have the same fill and drain methods as the bottle, except draining was a no-op and filling passed the buck onto whatever bottles were below the funnel. Then all I had to do was cram this new object into the same list as the bottles and bam, the funnel can fill bottles below it.



Since I really don't want to go to the hassle of recording video at the moment, you'll just have to trust my word that the bottle on the bottom was empty at some point, and the bottle on the top filled it up. Why would I lie about that, I mean come on.

The problem is that the funnel is just sort of sitting there in space. It gets added to the scene at the start and doesn't interact with anything in any way outside of being used for filling bottles. This means the user can't grab or position it, and could actually look straight through it and move bottles on the other side.



The fact that the funnel is translucent is both good, because it makes it easier to demonstrate how the bottle is being moved around behind it, and bad because it makes it more apparent that the bottle is being moved around behind it. Also, this shows how multiple layers of glass can override each other and it really doesn't look as good. On the one hand if I'm actively trying to add more and more glass things I should make this kind of case look nicer. On the other hand that will involve yet more render target wizardry and I don't quite feel like that at the moment.

In any case, making the funnel interactive was my first priority. The first problem being that the funnel had to scripting to move it around. For this I was able to simply copy over all the grabbing and moving code from the bottles. That was an easy fix, but once again demonstrates how I really should get object oriented features into my Lua code before things become overwhelmingly terrible and maintainable. The second problem was that I had no way to actually tell if the user was looking at the funnel. 

For detecting if the viewer is looking at something, I detect the intersection between a ray coming out of the camera and geometric shapes that are tied to the actors and move with them. When there used to be buttons they had circles attached. The bottles are simplified to just the sphere bulb. I also had stuff to detect triangles and rectangles, because I needed super simple test cases. The common thread among all of those shapes is that it is super easy to detect their collision with a ray. The funnel however can't nicely be broken up into those shapes though, so I had to come up with a new shape.

Pretty apparently, the best shape would be a Frustum (of a cone). (For anyone who doesn't know, that's basically a circular cone but with the tip chopped off parallel to the base). A frustum can be used to represent the actual funnel part. If I want a simple bounding area I can use the whole frustum, if I want to put other things inside a super large funnel I can leave the end-cap circles off and just detect collision with the edges. A frustum whose base and top are the same was secretly a cylinder all along, and a frustum whose top has no radius is just a cone. Its a pretty versatile shape that will allow me to kill a handful of birds with one stone. The only problem is that ray-cone collision involves a good deal of math.

Math!

I was able to find some advice online about how to do ray-cone collision, but most of it was either just source code that I didn't want to copy, references to books I didn't own, or had what seemed to be typos and was a pain to try to parse into something usable for my case.

So I decided to solve the problem myself, 'cause I had to justify my math minor somehow. (Related note, if anyone has any bright ideas as to how I can apply topology to my work let me know, it'll make me feel better). This led to a couple pages of scribbling, and a few equations that would let me find my collisions.

That's not entirely true. First it led me to a set of equations that didn't find the correct collisions but I didn't realize that for about 3 hours. However, eventually I figured it out and now I can add frustums to the list of stuff I can detect in space. Which is neato, and it was actually rather fun to get my hands dirty with pretty dense but basic equations.

Sadly, the next thing on my plate is figuring out why you can see through bottles from the inside. I added a second set of triangles, blender tells me their normals point inwards, but noooooooooo, their winding makes them visible from the outside for some reason. Debugging that involves less thinking and writing and more swearing and glowering, so it'll be a bit more work.