4
\$\begingroup\$

So, in GPU Gems 3 there is a cool warped terrain that I seek to replicate. Currently, I'm generating the terrain fine, but I want to add that warp effect.

// Do this before using 'ws' to sample the nine octaves!  
float3 warp = noiseVol2.Sample( TrilinearRepeat, ws*0.004 ).xyz;  
ws += warp * 8;

Im wondering how to replicate the above code in C#. What does the above code do? What type of variable is noiseVol2.Sample(x,y).xyz?

I want to warp my own terrain, currently I have a system that creates octaves of perlin noise with certain frequencies and amplitudes.

It looks something like this:

var perlin0 = new Perlin3(0,baseFreq  * 4.03f, 0.25f);
var perlin1 = new Perlin3(1, baseFreq * 1.96f, 0.50f);
var perlin2 = new Perlin3(2, baseFreq * 1.01f, 1.00f);
var perlin3 = new Perlin3(3, baseFreq * 0.49f, 2.00f);
var perlin4 = new Perlin3(4, baseFreq * 0.24f, 4.00f);

return new Density(ws => {

        // start with plane
        float density = plane.Evaluate(ws);

        // add perlin noise to get density values at each ws co-ord.
        //3 octaves currently (3 perlin noise +=)
        density += perlin0.Evaluate(ws);
        density += perlin1.Evaluate(ws);
        density += perlin2.Evaluate(ws);
        density += perlin3.Evaluate(ws);
        density += perlin4.Evaluate(ws);
        return density;
    });

I've tried replicating it like so:

var q = new Vector3(perlin0.Evaluate(new Vector3(0,0,0)), perlin0.Evaluate(new Vector3(5.2f, 1.3f, 1.3f)));
var q1 = new Vector3(perlin1.Evaluate(new Vector3(0, 0, 0)), perlin1.Evaluate(new Vector3(5.2f, 1.3f, 1.3f)));
var q2 = new Vector3(perlin2.Evaluate(new Vector3(0, 0, 0)), perlin2.Evaluate(new Vector3(5.2f, 1.3f, 1.3f)));
density += perlin0.Evaluate(p + 4.0f*q);
density += perlin1.Evaluate(p + 4.0f * q1);
density += perlin2.Evaluate(p + 4.0f * q2);

I've read the article that Íñigo Quílez created, and implemented it like above. Am I doing something wrong? It looks the same without that, just using

density += perlin0.Evaluate(p);
density += perlin1.Evaluate(p);
density += perlin2.Evaluate(p);

I want to know what I'm doing wrong, what I misunderstood and how to implement it correctly.

This is all based off this lumpn's proceedural-generation on github (I would link it, but I can't)

Thanks.

I would also want to know if there are any examples (I learn best from codebases) with this implementation using shaders. (Maybe it will run faster because it uses the GPU instead of the CPU?)

This is still unanswered on how to do it on the CPU (and I'm still confused on how to do it on the GPU, do you have to do some vertex stuff? how do you pass in a noise texture through the shader?)

\$\endgroup\$
5
  • \$\begingroup\$ Have you read Íñigo Quilez's article on domain warping? He gives a good overview of the technique. You seem to have the basic idea down, but where the original code is generating a 3-dimensional warp vector, you're generating just one float and adding it to all three axes, which means you're only warping the domain along a single diagonal line. \$\endgroup\$
    – DMGregory
    Jul 7, 2016 at 0:07
  • \$\begingroup\$ I've just read the article that you referenced, and I tried implementing it by doing this: pastebin.com/jLZ24rvW and it doesn't seem to be working. I don't understand why he uses those numbers when calling fbm() and if there is any difference between my perlin noise that i'm using right now (libnoise perlin) and his fbm() method. I tried my best implementing it in 3d. Do i have to add an extra parameter for z? can i just keep that at 0? Heres what it looks like without/with: gyazo.com/d8c7073f9912fa85d68f34236c1d4027 and gyazo.com/3835b263e207d3c999ebc33cd9a60b41 \$\endgroup\$
    – salarc
    Jul 10, 2016 at 3:18
  • \$\begingroup\$ "fbm" refers to a sum of multiple "octaves" of Perlin noise, sampled with increasing frequency and decreasing amplitude in a fractal-like way. In the article, he adds some random constant offsets to the lookup, different in each octave, so he's not sampling from the same part of the domain all the time — as though the octaves of noise were coming from different generators. It looks like what you're missing is that q should depend on p. If it doesn't, then you're just applying a constant shift to every part of your noise equally, instead of warping it in directions that change as you wander. \$\endgroup\$
    – DMGregory
    Jul 10, 2016 at 13:45
  • \$\begingroup\$ How would I pass p to have any effect on the terrain? If I i add p to the random samples, wouldn't that just shift the sample area? What process actually warps the terrain? \$\endgroup\$
    – salarc
    Jul 13, 2016 at 1:14
  • \$\begingroup\$ You'd replace q = (perlin(constantA), perlin(constantB)) (which is constant) with q = (perlin(p + constantA), perlin(p + constantB)) (which varies pseudo-randomly as p changes). This means your subsequent lookups biased by q are shifted by a pseudo-random vector that varies over the space of p, creating the domain warp effect. This is all in Íñigo Quilez's post, so I'd recommend reading it more carefully or moving to Game Development Chat to discuss further if you have more questions. Comments don't really suit back-and-forth discussion. \$\endgroup\$
    – DMGregory
    Jul 13, 2016 at 1:24

1 Answer 1

-1
\$\begingroup\$

Most of the stuff in GPU Gems is shader stuff. The code you are trying to replicate in C# is ShaderLab, which Unity also uses for shaders.

In other words, the lines of code would be the same and would be part of a custom shader that you would apply.

\$\endgroup\$
10
  • \$\begingroup\$ Would I have to do warping terrain with a shader? can I not just use the CPU (as i understand) to warp the terrain? If not, I would love to see some full code project implementing this in unity. I only have the partial sources from that article, and i didn't really understand it \$\endgroup\$
    – salarc
    Jul 3, 2016 at 5:45
  • 1
    \$\begingroup\$ Yes, you can use the CPU, however you cannot just convert HLSL code to C#, that is just not possible. You need to look at CPU based implementations, or be clever and write one yourself. \$\endgroup\$
    – jgallant
    Jul 3, 2016 at 12:02
  • \$\begingroup\$ @salarc as Jon said, you certainly CAN implement it on the CPU, but I'm not sure it's the best plan. This sort of thing is e exactly what GPUs are intended for, and even on mobile platforms, most phones have a GPU to handle these sorts of things. ShaderLab code is a whole new language and is a big weakness for me as well, but the results are worth it. \$\endgroup\$ Jul 3, 2016 at 15:35
  • \$\begingroup\$ @Jon I do want to write a CPU based code myself, but first I need to understand why they wrote that. It's quite obscure in the article. I have no idea why they create a float3, how it samples nine octaves and why you += a float3 (Vector3 in unity?) multiplied by 8. \$\endgroup\$
    – salarc
    Jul 3, 2016 at 18:39
  • \$\begingroup\$ They use a float3 (like a Vector3, but different) because it's a single variable that holds three floats. C# doesn't natively have such a thing, though you could probably just use an array of floats instead of need be. The reality is that there isn't a sane way to convert the code, even in pseudo-code, from HLSL to C# because HLSL makes assumptions about what the hardware already understands, and a CPU simply won't work with the same instruction set. This is, for all intent, like providing a C++ script for x86 and asking how to make it run on iOS... \$\endgroup\$ Jul 3, 2016 at 20:47

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .