Not logged in, Join Here! or Log In Below:  
 
News Articles Search    
 


Submitted by Uthman Apatira, posted on July 17, 2000




Image Description, by Uthman Apatira



This is just some sample output from a procedural texture generator. It took about twenty minutes to get it working... I plan to use it as a heightmap as well as texturer in an upcomming 3D Landscape Heightmap project of mine. I was going to use perline noise, but then I found some implementation ideas on the net for a _MUCH_ easier approach, so I used it instead. I could send a link for a demo of it if people want..


[prev]
Image of the Day Gallery
www.flipcode.com

[next]

 
Message Center / Reader Comments: ( To Participate in the Discussion, Join the Community )
 
Archive Notice: This thread is old and no longer active. It is here for reference purposes. This thread was created on an older version of the flipcode forums, before the site closed in 2005. Please keep that in mind as you view this thread, as many of the topics and opinions may be outdated.
 
Rui Martins

July 17, 2000, 06:31 AM

> I could send a link for a demo of it if people want..

Do you even need to ask ?

The more stuff people share, more is the increase in peoples know-how, and better software will be developed!

Always share what you can (limited to patents and NDA), but do share !
Long live the OpenSource Community !

Are you sure the method you are using isn't a simplified method of Perlin-Noise.
Perlin it self has a simplified version which he explains in a web page of is own.
For Noise to be classified as "Perlin-Noise", it just has to have some specific properties that Perlin defined, it does Not depend on how you implement it.

See ya

 
Uthman

July 17, 2000, 09:54 AM

Trust me, it ain't PN. It's 129% random ;)

 
Uthman

July 17, 2000, 10:01 AM

I learned this offa the TGLTSBFSASP. Basically, I create an array, lets say 32x32. I tile it across a 256x256 buffer. Then I smooth and resample/size it up to 64. Then I tile the 4x64 across another 256x256 buffer. Then I take the 64 and smooth and resample it up to 128. then I tile that across another 256x256 buffer. Then I take the 128 and smooth and resize it up to 256, and I dump that into a 256x256 buffer. I take all of the buffers and combine them. This approach is simple but quite slow though. I just got my perlin noise generator working well, so I'll post that up with a screen shoot here today, and hopefully it their ain't that much traffic, it'll be up soon.

 
fluffy

July 17, 2000, 11:38 AM

Something which works pretty well for procedural random textures is this: fill your buffer with random data, average each pixel with its neighbors to the right, bottom, and down-right (wrapping around as necessary), add some randomness by sprinkling more random values in, then average it again. It generates similar distributions as to what you have, doesn't have the edge effects, and is VERY fast, and can be insanely optimized for non-general cases. For example, if your texturemap is 256x256, 1 channel:


unsigned char texture[256*256];

// Randomize the texture - we'll not assume RAND_MAX == INT_MAX
for (int i = 0; i < 65536; i++)
texture = rand()>>4; // most libcs' rand()s are very unrandom in the lower bits // Average the texture for (int i = 0; i < 65536; i++) texture = (texture + tdat[(i+1)&65535] + texture[(i+256)&65535] + texture[(i+257)&65535])>>2; // Sprinkle in some random noise - rerandomize approx 1/8 of the texels for (int i = 0; i < 8192; i++) texture[(rand()>>2)&65535] = rand(); // Average the texture again for (int i = 0; i < 65536; i++) texture = (texture + tdat[(i+1)&65535] + texture[(i+256)&65535] + texture[(i+257)&65535])>>2;

If your texture is RGBA, then you can do a similar technique, and it can be optimized to be almost as fast as the monochrome case if you're willing to lose a little precision. I'll leave that as an exercise to you, but will hint that it involves liberal use of bitmasks. :)

 
Uthman

July 17, 2000, 12:24 PM

compile this for a fast and easy sub-authentic noise generator. This is one of the 3 ways I know of how to generate noise, not JUST those fluffy cloud images. For more information, look for my lecture at the upcomming XGDC (www.xgames3d.com), titled, Procedural Texture Generation, where I will discuss over 15 types of different Procedural Textures and their implementation. Full sources included.

BTW-forgive me if the following code is unoptimized, as I ported it from VB->C++. I use VB as a prototyping language now, as i find it easier to debug my code in it.


float Cubic_Interpolate(v0, v1, v2, v3, x){
int P = (v3 - v2) - (v0 - v1);
int Q = (v0 - v1) - P;
int R = v2 - v0;
int s = v1;
int xx = x * x;
int a = (P * xx * x) + (Q * xx) + (R * x) + s;
if(a > 255) a = 255;
if(a < 0) a = 0;
return(a);
}


for(int x = 0; x<256; x+=8){
for(int y = 0; y<256; y+=8){
BuFFeR[x+y*lpitch] = (int)(rand() % 255);
}
}



for(x = 0; x<256; x+=8){
for(y = 0; y<248; y+=8){
int w = y - 8;
if(w < 0) w = 256 + w;
for(int z = y + 1; z<y + 7; z++){
BuFFeR[x+z*lpitch] = Cubic_Interpolate(BuFFeR[x+w*lpitch], BuFFeR[x+y*lpitch], BuFFeR[x+ (y + 8) % 257)*lpitch], BuFFeR[x + (y + 16) % 257)*lpitch], (z - y) / 7);
}
}
}



for(y = 0; y<256; y++){
for(x = 0; x<248; x++){
w = x - 8;
if(w < 0) w = 256 + w;
for(z = x + 1; z<x + 7; z++){
BuFFeR[z+y*lpitch) = Cubic_Interpolate(BuFFeR[w+y*lpitch], BuFFeR[x+y*lpitch], BuFFeR[((x + 8) % 257) + y*lpitch], BuFFeR[((x + 16) % 257) +y*lpitch], (z - x) / 7)
}
}
}




 
Uthman

July 17, 2000, 12:42 PM

compile this for my implementation of a REAL perlin noise generator (BTW- a few minutes ago, this too was VB code..):


int Noise2D(int x, int y)
{
int a = ((x * (x + 1 + y) * 3.1415927) ^ 1.3579) * 97;
return((int)a % 255);
}

void AddLayer(float factor, int size, int sScale)
{
int s1 = sScale - 1;

for(int x = 0; x<size - sScale; x+= sScale){
for(int y = 0; y<size - sScale; y+= sScale){
int c = Noise(x, y);
for(int x2 = x; x2<x + s1; x2++){
for(y2 = y; y2<y + s1; y2++){
BuFFeR[x2+y2*lpitch] = (BuFFeR[x2+y2*lpitch] + c) * 0.5;
}
}
}
}
}

void Blur(void)
{
for(int x = 1; x<254; x++){
for(int y = 1; y<254; y++){
BuFFeR[x+y*lpitch] = (BuFFeR[x+1+y*lpitch] + BuFFeR[x+ (y + 1)*lpitch]) * 0.5
}
}
}


void DrawPT(void)
{
AddLayer(0.5, 252, 126);
AddLayer(0.6, 252, 31);
AddLayer(0.4, 252, 16);
AddLayer(0.5, 252, 8);
AddLayer(1, 252, 63);
AddLayer(0.6, 252, 4);
AddLayer(0.7, 252, 2);
Blur;
Blur;
}



 
fluffy

July 17, 2000, 12:57 PM

Uthman, you have a different definition of "fast" than most people. You realize, of course, that a % (on x86) uses a div instruction, right? div is SLOW. :) Those two %s and the one / amount to three divs per texel...

Also, that exponentiation in your Perlin generator can't be all that fast, either. ;) Of course, that can be approximated using a Taylor series... overall, that code DOES make for a nice starting point for generating true Perlin noise efficiently, but as it stands, I just wouldn't call it fast. :)

 
fluffy

July 17, 2000, 12:59 PM

Oh, and maybe you should have just posted it in the original VB instead of doing a lackluster, half-assed conversion to C, given that ^ means 'xor' in C and has no meaning for floats, and you forgot the ()s on your Blur calls. :)

BTW, I don't mean any offense, really. Sorry if I've come off as flaming.

 
Uthman

July 17, 2000, 01:09 PM

when i program in VB, I don't optimize, VB does it automatically when my program is compiled. By "fast" I ment, faster that creating multiple buffers of random arrays, bluring them, AND resampling them. The one that I was talking about that is "fast" itn't the one you were looking at, its the one that uses the diamond/square variant. As you can see, most of the code here is in ^2, so I plan to be using "&" when I finish prototyping.. LBNL, by "^" I mean, to the power to, AKA exp. If you want realtime wait till I finish optimizations, and besides, 99% of the usages of Procedural Textures that _I_ have seen we're all pregenerated at application startup. not that I don't plan at hitting realtime. >:}

 
Uthman

July 17, 2000, 01:22 PM

to tell u the truth, that ngf can be any non linier function, so as long as it has an (x+y)*x, in it, it wont even need any other shit.

 
EGreg

July 17, 2000, 08:12 PM

By the way if you're talking about heightmaps you could just generate procedural heightmaps rather than textures, which might in some ways be more flexible.

Fluffy -- in your code, there is only one problem, and that is, at the right and bottom edges the values will be averaged with the already changed values of the left and top edges, but it's not a big deal. Other than that, it's fast and can even be used in realtime maybe.
But again, i'd just recommend not thinking of these as images then, but as heightmaps. If your heightmap is a table in regular RAM, then you could deform it using your algo, and make it VERY fast using dirty rectangles if you're just updating one part of the landscape.

Anyway, that's one example of procedural heightmaps.
BTW I'd recommend several smoothing passes for that one.

Procedural textures is a big topic, they're used for everything from clouds to water. Ken Perlin's page is really great.

-Greg

"What direction you should go in depends very much on where you want to end up." - a famous cat :)

 
Brandon Moro

July 17, 2000, 10:30 PM

If all of you guys use VB to ease debugging your code, why don't you guys just start using Delphi? It has all the ease, readability and maintainability (and much more) of VB with all the power of C++. I am currently writing an open source 3D Engine using OpenGL in Delphi. Instead of writing in VB and the porting to C++, simplify your life and use a powerful compiled language like Delphi (especially with Delphi for Linux coming soon).

 
fluffy

July 17, 2000, 11:17 PM

EGreg, yeah, I'm aware of the slightly flawed causality with respects to the edge effects. However, that only applies to the bottom edge (the right edge wraps around to the next row) and this is only an approximate effect. As far as "maybe realtime," actually, I use that generator in realtime on a per-frame basis just fine. Even on a lowly P166 it's quite fast. Hell, I first coded it for realtime use (i.e. >60fps) on a 486/100.

Brandon: Uthman doesn't speak for the rest of the development community. Frankly, I think VB is a *horrible* prototyping language for this sort of thing; I just code directly to C++ and be done with it (the prototype code usually ends up as the final code). I agree with your stance on Delphi though; back when I was a DOS programmer, I was a religious Turbo Pascal nut, and between high school and college I got a summer job programming Windows apps in Delphi and was completely in love with the language. It's very nice, and I wish C++'s object model were more like it. (Actually, I often describe Java as being Delphi with C syntax, since Java's object model is VERY much like Delphi's except with everything being implicitly a pointer and not having any low-level control over those pointers, not that Delphi gave you much of that to begin with).

For what it's worth, I'd like to use a Free implementation of Delphi for Linux. I do all my coding in Linux now (I can't STAND Windows programming, never could), but I've gotten so used to the C++ way of doing things that I don't think that I would switch back.

 
Albert Sandberg

July 19, 2000, 06:56 AM

If you're using windows (as I assume you are :-) why don't you use visual c++'s debugger? If that's not enough, it shouldn't be too hard creating a logfile... hell, why not, here you are :


void System::clearLog() {
#ifdef _DEBUG
FILE* fil = fopen("debug.log", "w");
fclose(fil);

log("My cool logfilen");
#endif
}

void System::log(const char *message, ...) {
#ifdef _DEBUG
char str[256];
va_list args;

va_start(args, message);
vsprintf(str, message, args);
va_end(args);

FILE* fil = fopen("debug.log", "a");
fprintf(fil, "%sn", str);
fclose(fil);
#endif
}






As you can see, clearLog just clears the file and log opens the logfile and stores a string... shouldn't be too hard to use for proper debugging, for instance, I use it in construcors and destructors, to see which objects were created.

Though, open a file each log takes some valuable CPU (I have to this each time to allow multiple instances of the System class), I use the #ifdef _DEBUG to make sure it isn't included in the release version.

And if this isn't good enough, you can type text directly to the debugwindow below your code... but that's described somewhere else :)

Visual C++ is good enough for everyone I beleive.

By the way, as you can see, I like the javasyntax ;)

Albert "thec" Sandberg

 
EGreg

July 20, 2000, 02:22 PM

I am of the idea that Visual Basic is great for RAD, while for powerful stuff like game engines C++ should be used. Why go just one way, black or white? You can mix both.

When developing for Windows, I think it's really worthwhile to code your back end systems in C++ first, test them out, then embed them in an ActiveX control or DLL and write a front end using Visual Basic. As you're writing you have your entire engine in front of you. It also makes you focus on making your engine a complete component, which will later help you if you want to license it.

Most games run at full-screen, though, so the "visual" part of visual basic might not be all that important.

While the Visual Basic thing might be only for Windows, the general concept applies everywhere. Code powerful, fast modules in a language, expose some automation (COM does this for you automatically), then use a scripting language or something similar to finish the job at a higher level, and give it that "polished" look. If you think of Visual Basic as a powerful scripting language, a lot is possible. The only downside is that you have to include the 1 Meg runtimes.

-Greg

"What direction you should go in depends very much on where you want to end up." - a famous cat :)

 
This thread contains 15 messages.
 
 
Hosting by Solid Eight Studios, maker of PhotoTangler Collage Maker.