1
2
Fixed.
Very cool!
awesome!
Nice. Hm, how did you handle when the end-points don't match up? Also why did you put four triangles into the lower-bottom hole? Wouldn't one be enough?
I pulled up the code for calculation of the intermediate fade points as well as the rendering into C4FoWLight (and a new class C4FoWDrawStrategy). So the C4FoWLightSection simply return their list of calculated fan and fade points, C4FoWLight then concatenates this list of all the four directions and runs the intermediate fade point calculation algorithm on the concatenated list. This algorithm iterates through the list as if it were a ring (because it is).
I don't know exactly what you mean, but I removed a few "do I really need to render this or that triangle" checks in the process of the refactor. It just bloated up the code and effect on render performance is questionable.
>Also why did you put four triangles into the lower-bottom hole
I don't know exactly what you mean, but I removed a few "do I really need to render this or that triangle" checks in the process of the refactor. It just bloated up the code and effect on render performance is questionable.
Ah, smart. But I don't remember the code being too bloated - it was just checking whether the triangles were zero, right? You could generalise that, I think.
>it was just checking whether the triangles were zero, right?
Yes, so that is probably not what you meant.
Fixed.
Fixed
... this was actually completely my fault (spot
DoRelights
going missing!). Sorry for the confusion.
fixed
You have introduced a fade out bias towards top-left normals. After thinking about it - this probably "fixes" the problem because extreme top-left normals are normally not illuminated very heavily. But that's really not the right way to do this.
Maybe try to do another fade out blit that's actually subtractive? Have you checked at what value we actually get stuck? If it's just RGB(1,256/3,256/3) or something, we just need to subtract RGB(-1,0,0) once in a while. You can check that by putting something like "
Maybe try to do another fade out blit that's actually subtractive? Have you checked at what value we actually get stuck? If it's just RGB(1,256/3,256/3) or something, we just need to subtract RGB(-1,0,0) once in a while. You can check that by putting something like "
gl_FragColor = rgba(light.rgb,1.0);
" at the end of the landscape shader - that allows you to see directly what the light texture contains.
Probably I haven't quite understood C4FoWRegion then. I thought these values are for the color of the blending. I have to admit I did very little in OpenGL, so I might get the one or the other thing wrong. I understood it this way:
Line 121:
Clear to color rgb(0,0,0)
Line 154:
Actually draw the illumination texture
Line 171:
Draw rgb(0,0,0) with alpha of 1.0f/16.0f+iAdd*1.0f/256.0f above it (making previously illuminated areas black again)
Line 121:
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT);
Clear to color rgb(0,0,0)
Line 154:
glBlendFunc(GL_ONE, GL_ZERO);
...
glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
Actually draw the illumination texture
Line 171:
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glColor4f(0.0f,0.0f, 0.0f, 1.0f/16.0f+iAdd*1.0f/256.0f );
Draw rgb(0,0,0) with alpha of 1.0f/16.0f+iAdd*1.0f/256.0f above it (making previously illuminated areas black again)
Well, yes, they are. But colours in the lights texture mean very specific things. The red channel is the strength of illumination, the green channel is the x component of the light direction, while the blue channel has the y component (the z component is assumed fixed at 1). As I am explaining somewhere else in a comment, the "zero point" of the signed arithmetic is at 1.0/3, which means that "zero" for our lights is actually rgb(0,1.0f/3,1.0f/3). Hence blending rgb(0,0,0) on top of it means pulling normals towards top-left.
Edit: See this screenshot. Green means the light comes from the left, blue that it comes from the top.
Edit: See this screenshot. Green means the light comes from the left, blue that it comes from the top.
Ah, I see. Yeah I haven't gotten around to read (, understand and document) the core stuff yet - the stuff in C4FoWLightSection::Render / Update. If I had, I would have probably understood that the channels are used differently there.
So the problem is not in the shader again.
already has some alpha at those locations (but no light direction, thats why it looks so flat).
texture2D(lightTex, gl_TexCoord[1].st)
already has some alpha at those locations (but no light direction, thats why it looks so flat).
Having found the problem and seeing that I probably will not find a good solution for now, let me describe what is the problem. I want my work on the lights branch be very transparent, that is why most of the stuff I have done so far was simply documenting the code:
All the light from the lights (=the result of all the complicated calculations) on the screen are rendered as a texture into a framebuffer each frame. The channels have a certain meaning: R=strength of light, G=x-light-direction, B=y-light-direction. After that, to have a fadeout effect of areas that were once lighted and now not anymore, an area is blended over this texture with R=0, GB=neutral light direction and A=1/16. This makes the lighted areas (quickly) fade out as the strength of light is multiplied by (1-1/16) each frame.
However, even though OpenGL seemingly works with floats, actually behind it there is an integer that ranges from 0..255 for every color channel. The blending is rounded. so when R <= 8, R*15/16 always gets rounded to 8 again. A solution is to subtract every few frames an absolute value of R, but I tested that and it kinda doesn't look good. Maybe with a little bit of fiddling around with values, but still it is a hacky solution.
According to Peter, this best solution would be to simply use a shader to do the blending at that position. We need a new_r = min(r-1,r*15/16) or something similar. That is simply not doable with
All the light from the lights (=the result of all the complicated calculations) on the screen are rendered as a texture into a framebuffer each frame. The channels have a certain meaning: R=strength of light, G=x-light-direction, B=y-light-direction. After that, to have a fadeout effect of areas that were once lighted and now not anymore, an area is blended over this texture with R=0, GB=neutral light direction and A=1/16. This makes the lighted areas (quickly) fade out as the strength of light is multiplied by (1-1/16) each frame.
However, even though OpenGL seemingly works with floats, actually behind it there is an integer that ranges from 0..255 for every color channel. The blending is rounded. so when R <= 8, R*15/16 always gets rounded to 8 again. A solution is to subtract every few frames an absolute value of R, but I tested that and it kinda doesn't look good. Maybe with a little bit of fiddling around with values, but still it is a hacky solution.
According to Peter, this best solution would be to simply use a shader to do the blending at that position. We need a new_r = min(r-1,r*15/16) or something similar. That is simply not doable with
glBlendFunc
and glBlendEquation
. With shaders it is, but I have to admit that this solution is simply out of my competence right now.
> With shaders it is, but I have to admit that this solution is simply out of my competence right now.
Is it? As far as I know, blending is not part of the programmable pipeline. It might be possible if you are rendering into a texture.
At that point we are rendering into a texture, into the lightText that is used later in the landscape shader. Was I unclear about that?
Btw, it might be an idea to switch around the order here. Right now we copy the old state, then fade it out 15/16, then draw our stuff over it with 1/16 intensity. Instead, we could first clear the texture, then draw over it with full intensity, and finally do an alpha blit of the old state with 15/16 weight. This might actually have a chance of resolving the stair artefacts in water. Not quite sure why I haven't done this from the start - possibly just because I wanted to use
glBlitFramebuffer
(which can't do blending).
Yes I tried that. I don't know why, but the result was extremely dark. I don't know, perhaps I did something wrong.
>, then fade it out 15/16
where?
Can I interest you in fixing this bug?
Which one? I already implemented the drawing flip-around. Not quite sure how to implement darkness ending up at zero - hm, given that we actually can't make productive use of these last few percents it might actually make sense to just have the shader ignore it?
Even though he declared it as an intermediate solution Peter's fix is absolutely fine. (brightness lower than X is treated as 100% dark)
So the problem is not in the shader.
is already wrong. The area in the screenshot and similar areas in tests have their normals slightly shifted to the upperleft.
Where are the normals of landscapeTex constructed?
texture2D(landscapeTex[0], texCoo).yz
is already wrong. The area in the screenshot and similar areas in tests have their normals slightly shifted to the upperleft.
Where are the normals of landscapeTex constructed?
Fixed
Attachment: raysinviewport.jpg (69k)
Can't reproduce anymore.
fixed
Could be better now. Possibly. We'll probably have to put some more thought into what we want to do with off-screen areas. One solution here might be to increase the area we are computing light for...
Yeah, much better. It does not seem to be an issue anymore, not even when large previously off-screen areas come into view. I would consider it fixed.
Sometimes single triangles in the fan are not rendered. This is in the range of my competence and likely my fault. Will investigate.
fixed.
Attachment: lightdir.png (199k)
Attachment: lightdir2.png (187k)
This can only happen if the last (or first) triangle in the triangle fan is not drawn. I might have fixed this in my last commit.
Attachment: lightoutofviewport.png - (don't mind the sky) (496k)
Pow!
fixed
Btw, what I told you yesterday was wrong - the purpose of that loop is simply to access the pre-transformed ray coordinates. We need those because the transformations might reduce the fan's "base" to 0 (fanL == fanR), at which point find_cross would fail.
So, this is how it looks now. Left: before I reintroduced the code, right: after.
Well, looks better. However your change to
I feel this *really* should be solved by making sure that the line points can never get too close to each other in the first place. My version solved this by looking up the original beam. I think in your case this could be done simply by retaining a pointer to the original beam in your "triangle", then use the left and right end points for finding the cross point.
An alternate solution could be to take the distance of the inner fade point (left for ascending, right for descending, as usual) and construct a point on the mx/my-line that has the same distance to the light. That might even be more stable. After all, my "all over the place" argument still applies here somewhat - even if we have a minimum of 1px distance between the line points, this can still make the line jump around quite a bit.
find_cross
looks seriously awkward - even if you can make it to not divide by zero, that doesn't mean it makes sense. A point and a line don't cross, period. I mean, given that we are dealing with floating point numbers here we might well get something like 0.0001 at some point, and all of sudden points will be all over the place.I feel this *really* should be solved by making sure that the line points can never get too close to each other in the first place. My version solved this by looking up the original beam. I think in your case this could be done simply by retaining a pointer to the original beam in your "triangle", then use the left and right end points for finding the cross point.
An alternate solution could be to take the distance of the inner fade point (left for ascending, right for descending, as usual) and construct a point on the mx/my-line that has the same distance to the light. That might even be more stable. After all, my "all over the place" argument still applies here somewhat - even if we have a minimum of 1px distance between the line points, this can still make the line jump around quite a bit.
> I think in your case this could be done simply by retaining a pointer to the original beam in your "triangle"
Won't work for 45° angles. pBeam->isRight does not work in that coordinate system.
I made sure that the lines are not zero by removing all triangles of the fan where fanR == fanL (zero size).... for now. But I noticed that by that, I effectively made another part of your code defunct - C4FoWLightSection.cpp line 588 - 620 - cause it adds new triangles of zero size. But I didn't really understand what it does... other than,... well, roughly the same as what the intermediate fade triangles should do. That is why I wanted to talk with you yesterday evening.
But I think there is another solution that is actually simpler: light source S to midpoint M is a line segment. Make that line segment advance to a length of the total reach of light (reach + fadeout). The end point I is the point we look for:
dist = total reach of light / (M-S)
I = S + dist * (M-S)
> Won't work for 45° angles. pBeam->isRight does not work in that coordinate system.
Hm? That's why I said to save the pointer in the triangle. The loop is for jumping over beams that have been eliminated in the meantime, it's a bit hack-ish. You would get that for free. You would have to re-transform the beam coordinates though.
> I made sure that the lines are not zero by removing all triangles of the fan where fanR == fanL (zero size)
What? That's wrong. That breaks descend collisions, check the sketches - it's the situation where light shines through a hole but the light is large enough that it doesn't reach the bottom of the hole at 100% intensity. Keep in mind that even if the "beam" itself has been reduced to zero width, this still has an effect on the final triangle fan, as it fills the "holes" between the beams.
If it's not needed, could we then remove the extra cases from
find_cross
, or put assertions into them? Sorry, I really don't think it's a good idea to have the function attempt to be "smart" in undefined cases. Things like "just return any point" sound like a recipe for hard-to-reproduce bugs.> Make that line segment advance to a length of the total reach of light (reach + fadeout).
What's the "total reach of light" here? I think that's pretty much what I proposed, with "total reach" being the distance of the lower fan point. Also I would propose
fadeout/2
.
total reach of light is light reach plus fadeout of the light.
10. some beams do not extend towards max range on first frame. They "wander" outwards in a total duration of perhaps 1-10 frames until they hit solid material. This produces ugly effects that are only covered up by the (too) smooth fading of the whole lighting texture. Here is a screenshot of where the beam did not reach solid material yet. The error must lie in the raytracing algorithm.
This seems to occur always at 45° angles. So it seems of each section the last (or first?) beam has a problem.
1
2
Powered by mwForum 2.29.7 © 1999-2015 Markus Wichitill