   Clouds- 2.5d raytracing problem...  need more eyes!
  There must be something small I'm skipping over.  I understand the whole 2.5 raytracing technique to extract a 3d heightfield from a 2d texture and calculate scattering through it.  If you don't, I don't think it's worth explaining, I'm the one who needs help here I've been struggling with this for a couple days, and I CANNOT figure out this artifact for the life of me.Here's what happens.  So I calculate the Perlin Noise with fBm to make a cloud texture.  I want to shade it.  I go through every pixel and trace a line from pixel (x,y) to sun(x,y) and calculate the scattering along this line.  With that number, I calculate the shading for the particular point.This looks pretty darn good... for the most part.  There's a small artifact and I just can't get rid of the damn thing.  Here's a screenshot to show you what I mean:This is the artifact:The sun is at position (128, 1500, 128).  I set it so high just to make sure that there's nothing shading those edges.  If you are familiar with this technique, you will know that I use the cloud value (0-255) BEFORE exponentiation for a height value, thus I have a height field.  Then I shade it with the raytracing technique I described.  Those edges should not be shaded.. there's something about the whole picture that seems off, as if the lower height values (0-15) don't get shaded, although the sun SHOULD be shining STRAIGHT onto it.  I'm going to post some code to finalize this post, but unless you ask me any specific questions, there nothing else to really be said I don't think...I'm really stuck.  even if we can't figure out the problem, I'd really appreciate some direction as where to go from here   I want a pretty sky!This is my code that generates the texture:    noise myNoise;myNoise.SetOctaves(12);myNoise.SetPersistance(.5f);myNoise.SetParam(dimen,dimen);myNoise.FillLookupTables();clouds = new float[dimen*dimen];for(int i=0; i<dimen; i++) {for(int j=0; j<dimen; j++) {float value = myNoise.FineTuned((j+900)/(dimen/2.0f), (i+765)/(dimen/2.0f));if(value > 1.0f) value = 1.0f;if(value < 0.0f) value = 0.0f;BYTE final = (BYTE)(value*255);clouds[i*dimen + j] = (float)final;}}BYTE * TextureImage = RayTraceTexture();and my RayTraceTexture() routine:    BYTE *image = new BYTE[dimen*dimen*4];for(int i=0; i<dimen; i++) {for(int j=0; j<dimen; j++) {float bi = ComputeBreshenamIntegral(j, i, sunx, suny, NULL);if(bi<1.0f) bi = 1.0f;bi = (1.0f/expf(bi * .05f))*255.0f;//if(bi<0) bi = 0.0f;//if(bi>1) bi = 1.0f;BYTE final = (BYTE)(255-pow(.96, clouds[i*dimen+j])*255);image[(i*4)*dimen + (j*4)] = (BYTE)bi;image[(i*4)*dimen + (j*4)+1] = (BYTE)bi;image[(i*4)*dimen + (j*4)+2] = (BYTE)bi;image[(i*4)*dimen + (j*4)+3] = final;//(BYTE)lerp(100, 255, bi);}}return image;and finally my Breshenam line tracing algorithm.  This basically traces through a line and sees how much it hits "cloud."  this is easily done by tracing through the line and then testing the cloud value with the current height value at the point, if you are "under" a cloud then your height value will be lower.float sky::ComputeBreshenamIntegral(int x, int y, int sunpos_x, int sunpos_y, BYTE * data) {if(clouds == NULL)return 0;int width = sunpos_x - x;int height = sunpos_y - y;int Yerror = 0, selX, selY, upX, upY;float total = 0.0f, vheight;if(width < 0) upX = -1;else upX = 1;if(height < 0) upY = -1;else upY = 1;width = abs(width);height = abs(height);if(width >= height) {selY = y;for(selX=x; selX != sunpos_x+upX; selX+=upX){if(data != NULL) {data[(selY*4)*dimen+(selX*4)] = 255;data[(selY*4)*dimen+(selX*4)+1] = 255;data[(selY*4)*dimen+(selX*4)+2] = 255;data[(selY*4)*dimen+(selX*4)+3] = 255;}vheight = clouds[y*dimen + x] + ((1500-clouds[y*dimen + x])*abs((selX-x)/(float)width));if(vheight <= clouds[selY*dimen + selX]) {total += 1;}Yerror = Yerror + height;if(Yerror >= width) {selY += upY;Yerror = Yerror - width;}}}else {selX = x;for(selY=y; selY != sunpos_y+upY; selY+=upY){if(data != NULL) {data[(selY*4)*dimen+(selX*4)] = 255;data[(selY*4)*dimen+(selX*4)+1] = 255;data[(selY*4)*dimen+(selX*4)+2] = 255;data[(selY*4)*dimen+(selX*4)+3] = 255;}vheight = clouds[y*dimen + x] + ((1500-clouds[y*dimen + x])*abs((selY-y)/(float)height));if(vheight <= clouds[selY*dimen + selX]) {total += 1;}Yerror = Yerror + width;if(Yerror >= height) {selX += upX;Yerror = Yerror - height;}}}return total;}[edited by - okonomiyaki on February 10, 2004 8:15:31 PM]
  Maybe your breshenam is not entering the for loop for the dark bits (if this is happening it would happen for vertical and near-vertical rays like when the sun is directly above). And they don't look completely dark because of the blending with the sky colour.Also might I suggest calculating the distance your ray travels vertically through the cloud instead of incrementing by one at each breshenam step.I do the following (don't remember exactly what it does but it's the part that calculates the vertical distance the ray has travelled through the height voxel (includes the ray slope)...const float deltaHeight = (1 - lowerHeight) / numVox;const float slopeFac = sqrt(1 + 1 / (zSlope * zSlope));...const float cld = invMaxU16 * cloud[(y + perlinOffsetY) *myPerlinTextureWidth + (x + perlinOffsetX)];const float low = cloudCentre - cloudCentre * cld;const float high = cloudCentre + (1 - cloudCentre) * cld;float b = high - (height + deltaHeight);if ( b < 0 ) b = 0;float a = height - low;if ( a < 0 ) a = 0;float len = cld - a - b;if (len < 0) len = 0;multipleScatterLen += len * slopeFac;   ... so basically adds deltaHeight instead of one at each step (the a and b stuff just tests the range [height, height + deltaHeight] against top and bottom of cloud and clips as needed.   [edited by - soiled on February 10, 2004 11:15:43 PM];  hm, that is interesting, but do you think I need that kind of accuracy?  Even just incrementing by 1 looks damn good for most of the texture.. though I know it''s not terribly accurate.  I may try taking it further (since obviously it''s not working perfectly).  Thanks for the suggestion... haven''t checked the breshenam loop yet, but I''m not sure that''s the problem, since the artifact seems to be rather constant throughout the picture.  I''ll check on it though.I''m not too sure what some of your variables mean. what is lowerheight?  and cloudCentre?  I think I can see the gist of the code...  not sure if I could implement it quite yet though myself. ;quote:Original post by okonomiyaki  hm, that is interesting, but do you think I need that kind of accuracy? Even just incrementing by 1 looks damn good for most of the texture.. though I know it''s not terribly accurate.If it looks good then I wouldn''t bother.quote:I''m not too sure what some of your variables mean. what is lowerheight?  and cloudCentre?  I think I can see the gist of the code...  not sure if I could implement it quite yet though myself.All cloud thicknesses (''cld'') are in range [0,1]. Instead of having a flat cloud bottom and lumpy top (cloudCentre=0) you can have a flat top and a bottom lumpy (cloudCentre=1) or somewhere inbetween (where both top and bottom are lumpy). So both the bottom and top (''low'' and ''high'') of the cloud has a height in range [0,1]. I found that having the bottom flat worked best anyway. ''lowerHeight'' is the height of the bottom of the cloud at the start of the ray going to the sun. ;  contact me via aim: samgzmansee this for a shot of my (surprisingly similar) project.Are u going for realtime?  i have found complete raytracing of my texture is very expensive. I was aiming for higher resolutions too such as 1024x1024. I have tried as many optimization tricks as i could.  i did my initial noise offset and clamping via SSE and utilize quite a few lookup tables for exponentiation and whatnot.  Im starting to contemplate using simple bumpmapping for the shading.  It wont look nearly as good, but im starting to think realtime is gonna be too demanding.  What are your thoughts? [edited by - samgzman on February 11, 2004 4:16:35 PM];quote:Original post by samgzman  Im starting to contemplate using simple bumpmapping for the shading.  It wont look nearly as good, but im starting to think realtime is gonna be too demanding.  What are your thoughts?Trace through a low-res version (e.g. fewer octaves, what exactly depends on your implementation, hardware, software, etc.).  Sorry for being obvious. ;quote:Original post by okonomiyaki  There must be something small I''m skipping over.  I understand the whole 2.5 raytracing technique to extract a 3d heightfield from a 2d texture and calculate scattering through it.  If you don''t, I don''t think it''s worth explaining, I''m the one who needs help here I''ve been struggling with this for a couple days, and I CANNOT figure out this artifact for the life of me.Here''s what happens.  So I calculate the Perlin Noise with fBm to make a cloud texture.  I want to shade it.  I go through every pixel and trace a line from pixel (x,y) to sun(x,y) and calculate the scattering along this line.  With that number, I calculate the shading for the particular point.Perhaps rendering the clouds and the shading on different images would help.  I don''t understand why there is so much shading for example to the right, when the sun is that high.  The cloud heights are between 0 and 255?  In your images, is the sun in the upper left quadrant, or closer to the center?For the problem you mention, I don''t like your test for incrementing total.  You might be incrementing it once at the very beginning when you shouldn''t.I know you don''t want to explain 2.5D cloudmapping, but I don''t think your implementation is correct.  It is tracing from the tops of the clouds instead of from the (flat, in your implementation) bottoms.  This will not properly shade the middle (thick) part of clouds, which I think is evident from your screenshot.  (I''m assuming you are rendering the clouds from below, of course!)  E.g., when the sun is directly overhead, the thickest part of the cloud should be heavily shaded; in your implementation it would be bright. ;  Thanks soiled, once I get the big kinks in this system smoothed out, I''ll consider implementing something like that..quote:Are u going for realtime? i have found complete raytracing of my texture is very expensive. Yes, that''s not my problem.  it is expensive but there are so many ways to speed it up (not like it has to be too fast anyway, the sun doesn''t move very quickly).  it wasn''t too hard to make it real time (slow moving clouds).I cannot accept bumpmapping.  I tried it and it looked pretty bad quote:I don''t understand why there is so much shading for example to the right, when the sun is that high. The cloud heights are between 0 and 255? In your images, is the sun in the upper left quadrant, or closer to the center?Exactly!!  I don''t know why either.  I think I''ve narrowed it down to how I trace up the line.  I''m not sure if it''s doing it correctly anymore.  I thought it was..  The sun is at the center :\quote:For the problem you mention, I don''t like your test for incrementing total. You might be incrementing it once at the very beginning when you shouldn''t.Bah.Yeah, I know, I found out that I was!  But still, that didn''t make a huge difference.quote:It is tracing from the tops of the clouds instead of from the (flat, in your implementation) bottoms. This will not properly shade the middle (thick) part of clouds, which I think is evident from your screenshot. (I''m assuming you are rendering the clouds from below, of course!) E.g., when the sun is directly overhead, the thickest part of the cloud should be heavily shaded; in your implementation it would be bright. Great point AP!!  A while ago I pondered how to do this, that is, extract the 3d heightfield.  I thought of doing it that way but I decided against it, it seemed like rays would always pass through the cloud and make it darker all around, but you are right... that is the correct way of doing it.  Do you suggest extracting it so that the bottom is not flat, but simply the top of the cloud reflected?  This would create symmetrical clouds (cut horizontally) if you know what I mean.  And then ray trace with the sun beneath the clound plane.  I will definitely try this, and also investigate my raytracing further (I know breshenam is working, it''s extracting the height of the ray at point(x,y) :/ who knows).Thanks a lot everyone.  I have an idea of where to go from here.  any more thoughts would be appreciated! ;quote:Original post by Soiled  quote:Original post by okonomiyaki   hm, that is interesting, but do you think I need that kind of accuracy? Even just incrementing by 1 looks damn good for most of the texture.. though I know it''s not terribly accurate.If it looks good then I wouldn''t bother.Actually, you were right.  I just found a huge inaccuracy in my algorithm.  Think of this scenario: the sun is at the center of a 256x256 texture, and I''m tracing from the sun to point (128, 129).  With my algorithm, It will trace two pixels, and maybe only pass once through the cloud (total = 1).  When in reality it''s actually passing all the way down through the cloud, and the "total" scattering would be much higher...  So areas near the sun wouldn''t be accurate at all (areas far away wouldn''t be too bad).It seems like we have to measure both passing vertically and horizonally.  If we only measure vertically, what about that cloud that so far away from the sun that the ray basically passes horizontally through it?;  why would going realtime be so hard? if you have a decent optimized routine, you can render a new one over a couple of frames, and just blend between the old and new ones. it should look fair enough, unless you want to simulate a planet with a daylength of ten minutes, but in that case maybe you should just reconsider your design document 