Java-Gaming.org    
Featured games (81)
games approved by the League of Dukes
Games in Showcase (498)
Games in Android Showcase (114)
games submitted by our members
Games in WIP (563)
games currently in development
News: Read the Java Gaming Resources, or peek at the official Java tutorials
 
    Home     Help   Search   Login   Register   
Pages: [1] 2
  ignore  |  Print  
  Normals very blocky  (Read 3833 times)
0 Members and 1 Guest are viewing this topic.
Offline RobinB

JGO Ninja


Medals: 44
Projects: 1
Exp: 3 years


Spacegame in progress


« Posted 2012-11-24 21:38:10 »

Hello,

Im trying to render some terrain, this works very well, but im having troubles using normals.
I just figured out how normals work and stuff, and worked out to calculate normals for my terrain.
However because an triangle only has 3 points = 3 normals, lightning appears to be really blocky with the rough edges:



I dont know if this is normal or caused by an error in my code.
Im calculating an normal for each vertex, and draw evrything with an vbo (using an trianglestrip).

So is this normal behaviour, and how can i smooth these edges?
I have googled a lot, but the solution seems to be some shader magic (with also a lot of choises about the algorithm to use).
Thank you for any help.
Offline Riven
« League of Dukes »

JGO Overlord


Medals: 799
Projects: 4
Exp: 16 years


Hand over your head.


« Reply #1 - Posted 2012-11-24 21:44:51 »

Even renormalizing normals in the fragment shader won't fix this.

The underlying problem is that your terrain is blocky. Why did you use decrete height levels?

Hi, appreciate more people! Σ ♥ = ¾
Learn how to award medals... and work your way up the social rankings
Offline RobinB

JGO Ninja


Medals: 44
Projects: 1
Exp: 3 years


Spacegame in progress


« Reply #2 - Posted 2012-11-24 23:18:29 »

Even renormalizing normals in the fragment shader won't fix this.

The underlying problem is that your terrain is blocky. Why did you use decrete height levels?

Well it was just my first try, i created an hightmap using perlin noise, and created some vertexs to render the hightmap.
What would be the best way of rendering some random terrain then?
Using more rectangles or something?


My Init:
1  
2  
3  
4  
5  
6  
7  
8  
9  
10  
11  
12  
13  
14  
15  
16  
17  
18  
19  
20  
21  
22  
23  
        float scale = 0.5f;
        int x = 0;
        for(int zpos = 0; zpos < size; zpos+=1){
            for(int xpos = 0; xpos < size; xpos+=1){
                x = zpos % 2 == 0 ? xpos : size - (xpos+1);
                int tx = x % 2 == 0 ? 0 : 1;
               
                vbo.AddVertex(x*scale, depth[x][zpos]*scale, zpos*scale);
                vbo.AddNormal(getNormal(depth, x, zpos));
                vbo.AddText(tx, 0);
               
                vbo.AddVertex(x*scale, depth[x][zpos+1]*scale, (zpos+1)*scale);
                vbo.AddNormal(getNormal(depth, x, zpos+1));
                vbo.AddText(tx, 1);
               
                if(xpos == 99){
                    vbo.AddVertex(x*scale, depth[x][zpos+1]*scale, (zpos+1)*scale);
                    vbo.AddNormal(getNormal(depth, x, zpos+1));
                    vbo.AddText(tx, 1);
                }

            }
        }
Games published by our own members! Check 'em out!
Legends of Yore - The Casual Retro Roguelike
Offline theagentd
« Reply #3 - Posted 2012-11-25 01:40:02 »

I think Riven meant that the height-map values seem to be rounded to discreet values. If the terrain wasn't made out of discrete height values, it wouldn't look that blocky. Increasing the resolution won't really fix the problem that easily. You're basically getting aliasing when the height goes
x --> x --> x +1 --> x+1 --> x+1
and vice versa. You need to make it more smoothly go from one value to another:
x --> x+0.25 --> x+0.5 --> x+0.75 --> x+1
or something. In short, don't round the values to ints. =S

Myomyomyo.
Offline Roquen
« Reply #4 - Posted 2012-11-25 06:12:42 »

The vertex normals need to be computed from the surface normals of all the shared tris.  It'd be helpful if you show a top-down wireframe view as some patterns work better than others.  Should look like squares with inscribed X's or diamonds at all levels.
Offline RobinB

JGO Ninja


Medals: 44
Projects: 1
Exp: 3 years


Spacegame in progress


« Reply #5 - Posted 2012-11-25 10:49:49 »

I think Riven meant that the height-map values seem to be rounded to discreet values. If the terrain wasn't made out of discrete height values, it wouldn't look that blocky. Increasing the resolution won't really fix the problem that easily. You're basically getting aliasing when the height goes
x --> x --> x +1 --> x+1 --> x+1
and vice versa. You need to make it more smoothly go from one value to another:
x --> x+0.25 --> x+0.5 --> x+0.75 --> x+1
or something. In short, don't round the values to ints. =S

Omg! now i noticed im rounding the values to ints (depthmap is an float array, so i didnt get what the problem was).
Thats what i get for reusing my code lol.

when removing the (int) cast the terrain looks like this:


Thanks for the help so far =)
Much better but there are still "squares with inscribed X's" like Roquen says.
What would be the best way to fix these (like creating some kind of circle or blurring it until there are no x's)?
Offline Riven
« League of Dukes »

JGO Overlord


Medals: 799
Projects: 4
Exp: 16 years


Hand over your head.


« Reply #6 - Posted 2012-11-25 10:58:30 »

Renormalize the normals in the fragment shader.

Hi, appreciate more people! Σ ♥ = ¾
Learn how to award medals... and work your way up the social rankings
Offline RobinB

JGO Ninja


Medals: 44
Projects: 1
Exp: 3 years


Spacegame in progress


« Reply #7 - Posted 2012-11-25 11:02:41 »

Renormalize the normals in the fragment shader.

Thanks.
Do you recomment any algorithms, or do you know on what terms i could search on?
Offline Riven
« League of Dukes »

JGO Overlord


Medals: 799
Projects: 4
Exp: 16 years


Hand over your head.


« Reply #8 - Posted 2012-11-25 11:12:08 »

The algorithm in GLSL is:
1  
normal = normalize(normal)


Basically search on the words I used, and maybe 'per pixel lighting'.

http://www.lighthouse3d.com/tutorials/glsl-tutorial/directional-light-per-pixel/

Hi, appreciate more people! Σ ♥ = ¾
Learn how to award medals... and work your way up the social rankings
Offline RobinB

JGO Ninja


Medals: 44
Projects: 1
Exp: 3 years


Spacegame in progress


« Reply #9 - Posted 2012-11-25 11:19:07 »

The algorithm in GLSL is:
1  
normal = normalize(normal)


Basically search on the words I used, and maybe 'per pixel lighting'.

http://www.lighthouse3d.com/tutorials/glsl-tutorial/directional-light-per-pixel/

That a lot easyer then expected, thank you.
I was looking on stuff like Gouraud shading and Phong shading.
Games published by our own members! Check 'em out!
Legends of Yore - The Casual Retro Roguelike
Offline RobinB

JGO Ninja


Medals: 44
Projects: 1
Exp: 3 years


Spacegame in progress


« Reply #10 - Posted 2012-11-26 21:37:40 »

It turned out pretty nice:


I only had to modify the shader from the example a bit:
1  
2  
3  
4  
5  
6  
7  
8  
9  
10  
11  
12  
13  
14  
15  
16  
17  
18  
varying vec4 diffuse,ambient;
varying vec3 normal,halfVector;
uniform sampler2D Texture0;

vec3 halfV;
float NdotHV;
vec4 color, c;

void main()
{
    halfV = normalize(halfVector);
    NdotHV = max(dot(normal,halfV),0.0);
    color = ambient + clamp(normal.r * (diffuse-ambient), 0, 1);
    color += gl_LightSource[0].specular * NdotHV;
   
    c = ... *text color*
    gl_FragColor = vec4(c.xyz * color.xyz, 1);
}
Offline theagentd
« Reply #11 - Posted 2012-11-26 21:57:23 »

You're still not normalizing the normal? >_>

Myomyomyo.
Offline RobinB

JGO Ninja


Medals: 44
Projects: 1
Exp: 3 years


Spacegame in progress


« Reply #12 - Posted 2012-11-26 22:37:33 »

You're still not normalizing the normal? >_>

Does it have any effect when you normalize the normal in the fragment shader instead of the vertex shader?
Just try'd both, but i dont see much diffrence, i dont even see diffrence if i comment the normalizing out.
Normalizing is just making sure the vector is between 0 and 1 am i right?
Since im normalizing the vectors before passing them to the shader, i guess it has no use anyways.
Offline theagentd
« Reply #13 - Posted 2012-11-26 22:54:47 »

A normal always has a length of 1. That's an assumption that must hold for the dot products to return correct values. Even if you normalize the normal in the vertex shader, after linear interpolation over the surface of a triangle it won't have have a length of one. You can visualize the "valid" normal values as a sphere with a radius of 1. When we linearly interpolate between two normals, we won't be following the surface of the sphere (that's called slerp and is a lot more expensive), we'll be taking a shortcut straight through the inside of the sphere between the two normals. That's why you need to normalize it again. Granted, the difference isn't very big when the normal changes slowly over the surface, but there is a big difference when the normal changes quickly from vertex to vertex since the interpolation took a faster shortcut almost straight through the sphere.

I hope that explains it. And also, normalize() is blazingly fast since it's optimized to be called for every pixel. You also shouldn't have to normalize your vertices' normals since they should already be normalized when you upload them to your VBO.

Myomyomyo.
Offline RobinB

JGO Ninja


Medals: 44
Projects: 1
Exp: 3 years


Spacegame in progress


« Reply #14 - Posted 2012-11-26 23:11:05 »

A normal always has a length of 1. That's an assumption that must hold for the dot products to return correct values. Even if you normalize the normal in the vertex shader, after linear interpolation over the surface of a triangle it won't have have a length of one. You can visualize the "valid" normal values as a sphere with a radius of 1. When we linearly interpolate between two normals, we won't be following the surface of the sphere (that's called slerp and is a lot more expensive), we'll be taking a shortcut straight through the inside of the sphere between the two normals. That's why you need to normalize it again. Granted, the difference isn't very big when the normal changes slowly over the surface, but there is a big difference when the normal changes quickly from vertex to vertex since the interpolation took a faster shortcut almost straight through the sphere.

I hope that explains it. And also, normalize() is blazingly fast since it's optimized to be called for every pixel. You also shouldn't have to normalize your vertices' normals since they should already be normalized when you upload them to your VBO.

Thank you, i get it now.
"You also shouldn't have to normalize your vertices' normals since they should already be normalized when you upload them to your VBO."
That was the part about renormalizing i didnt get, because i already send them normalized, but the story about interpolation made it very clear.
Offline Orangy Tang

JGO Kernel


Medals: 56
Projects: 11


Monkey for a head


« Reply #15 - Posted 2012-11-26 23:17:29 »

Even if your vertex normals are similar it often helps to re-normalize in the fragment shader. The difference isn't that much when you're doing nice smooth diffuse lighting, but for something like specular highlights you'll only get the nice, tight, sharp highlights if you re-normalize.

[ TriangularPixels.com - Play Growth Spurt, Rescue Squad and Snowman Village ] [ Rebirth - game resource library ]
Offline theagentd
« Reply #16 - Posted 2012-11-26 23:20:38 »

Hehe, no problem. You got some really nice results there. I wonder about the color though, that slime green makes it look like a chemical spill! xD

Myomyomyo.
Offline RobinB

JGO Ninja


Medals: 44
Projects: 1
Exp: 3 years


Spacegame in progress


« Reply #17 - Posted 2012-11-26 23:31:08 »

It was the nicest seamless texture i could find, in my way to program the shader, it have had many diffrent shades of green in my journey to create the shader Smiley
Already fixed it, i had diffuse set to 2.0 instead of 1.0

Now i need to get multitexturing to work and add water, what would i do first...
Offline theagentd
« Reply #18 - Posted 2012-11-26 23:39:01 »

You might be interested in techniques like texture splatting and soft water edges then? =S

Myomyomyo.
Offline RobinB

JGO Ninja


Medals: 44
Projects: 1
Exp: 3 years


Spacegame in progress


« Reply #19 - Posted 2012-11-26 23:58:11 »

You might be interested in techniques like texture splatting and soft water edges then? =S

Indeed.
However it seems most engines use an huge alpha maps to determine each texture for multi-textured terrain.
As first try im going to pass an byte as attribute with each vertex containing the terrain type
I hope its possible to interpolate between the types some way, otherwise ill try the alpha map (128*128 image for each chunk does not seem to bad).
Offline RobinB

JGO Ninja


Medals: 44
Projects: 1
Exp: 3 years


Spacegame in progress


« Reply #20 - Posted 2012-11-30 18:34:00 »

I have got another question, to go with the flow with the story, i will post it in my old thread.
The terrain rendering is coming along nicely, but im having an problem with interpolating in the shader.

Example (the texturing is not complete, evrything above some value is atomaticly grass, this will get replaced by an noise function):

Bigger version: http://i49.tinypic.com/fyh8i0.png

Im sending an float value using the vbo, telling the shader what points needs to blend:
1  
glVertexAttribPointer(attrib, 1, GL_FLOAT, false, stride, 32);

But because this is for each vertex, it gets blocky like shown above.
Is there an way to smooth this value out for an rounder effect, like with normals (not using splatmaps)?

Corresponding fragment-shader fragment Smiley
1  
2  
3  
4  
5  
6  
    if(t > 1){
        dist = (2-t)*0.6;

        c2 = texture2D(Texture0, vec2(gl_TexCoord[0].x+0.5, gl_TexCoord[0].y));
       c = mix(c2, c, dist);
    }


*   dirt & grass image are stored in the same texture, hence why im using +0.5 (take part 2 of texture)
** mix can also mess up textures with some combinations, need to find some replacement for that one to, but i guess thats easyer then my first problem.
Offline Best Username Ever

Junior Member





« Reply #21 - Posted 2012-11-30 19:02:54 »

Assuming 1 < t < 2, dist will be between 0 and 0.6. If t <= 1, then the texture doesn't get mixed. Shouldn't dist range from 0 to 1?
Offline RobinB

JGO Ninja


Medals: 44
Projects: 1
Exp: 3 years


Spacegame in progress


« Reply #22 - Posted 2012-11-30 19:05:30 »

Assuming 1 < t < 2, dist will be between 0 and 0.6. If t <= 1, then the texture doesn't get mixed. Shouldn't dist range from 0 to 1?

You are correct when i leave this behind, they are smoother, but are still really pointy.
multiplying by 0.6 exerragates this effect, so its easyer to show Smiley

multiplying with 1.5 gives the best effect, but its still not good enough Sad
Offline theagentd
« Reply #23 - Posted 2012-11-30 19:09:07 »

+1 to what Best Username Ever said.

Also, that's not how you usually do texture splatting. Let's say you have 3 different terrain types. 0 is grass, 1 is dirt, 2 is snow and 3 is rock. What if you want to do a transition from dirt to rock or snow to grass? With your code it's only possible to do smooth transitions between adjacent types, which limits its use case a lot. Instead, I'd recommend using 4 different values, one for each type. Bytes should be enough for it (256 different values). In the fragment shader, just sample all 4 of them (should be cheaper than branching anyway) and blend them based on the 4 values. At all times should the sum of the values equal 1.0 of course, you might have to manually ensure that since the values are interpolated. Anyway, the point is that this will give you fine control over how the terrain types are blended.

Myomyomyo.
Offline RobinB

JGO Ninja


Medals: 44
Projects: 1
Exp: 3 years


Spacegame in progress


« Reply #24 - Posted 2012-11-30 19:13:57 »

+1 to what Best Username Ever said.

Also, that's not how you usually do texture splatting. Let's say you have 3 different terrain types. 0 is grass, 1 is dirt, 2 is snow and 3 is rock. What if you want to do a transition from dirt to rock or snow to grass? With your code it's only possible to do smooth transitions between adjacent types, which limits its use case a lot. Instead, I'd recommend using 4 different values, one for each type. Bytes should be enough for it (256 different values). In the fragment shader, just sample all 4 of them (should be cheaper than branching anyway) and blend them based on the 4 values. At all times should the sum of the values equal 1.0 of course, you might have to manually ensure that since the values are interpolated. Anyway, the point is that this will give you fine control over how the terrain types are blended.

Thats clear, since i already had an float array im just using an float for siplicity while testing.
Like you are saying im indeed planning to use some bytes for multiple textures.

But thats not the problem, the problem are the ugly edges.
Offline theagentd
« Reply #25 - Posted 2012-11-30 19:39:05 »

In your fragment shader code we can only see you sampling from one texture. Can you post the full fragment shader code?

Myomyomyo.
Offline Best Username Ever

Junior Member





« Reply #26 - Posted 2012-11-30 19:58:09 »

Assuming 1 < t < 2, dist will be between 0 and 0.6. If t <= 1, then the texture doesn't get mixed. Shouldn't dist range from 0 to 1?

You are correct when i leave this behind, they are smoother, but are still really pointy.
multiplying by 0.6 exerragates this effect, so its easyer to show Smiley

multiplying with 1.5 gives the best effect, but its still not good enough Sad

If you scale the boundary between transitions, you still need to normalize the "mix" range. Given the lack of information, there is no way to know the origin of the problem if that is not it. But regardless of what the original issue is, there will be extra artifacts if that problem is not fixed.
Offline RobinB

JGO Ninja


Medals: 44
Projects: 1
Exp: 3 years


Spacegame in progress


« Reply #27 - Posted 2012-11-30 23:32:20 »

No problem, ill remove all normal calls to make it a little more clear what im doing.

Fragment shader:
1  
2  
3  
4  
5  
6  
7  
8  
9  
10  
11  
12  
13  
14  
15  
16  
17  
18  
19  
20  
uniform sampler2D Texture0;
varying float t;

vec4 c, c2;
float dist;

void main()
{  
    c = texture2D(Texture0,gl_TexCoord[0].xy);

    if(t > 1){
        dist = (2-t) * 1.6;

        c2 = texture2D(Texture0, vec2(gl_TexCoord[0].x+0.5, gl_TexCoord[0].y));
       c = mix(c2, c, dist);
    }
   
    gl_FragColor = vec4(c.xyz, 1);

}


Vertex Shader:
1  
2  
3  
4  
5  
6  
7  
8  
9  
10  
varying float t;
attribute float terrain;

void main()
{
    gl_TexCoord[0] = gl_MultiTexCoord0;  
    gl_Position = ftransform();
   
    t = terrain;
}


So each vertex has an value of the texture (float terrain) and gets passed to the fragment shader (float t).
if t > 1 then mix the second texture on the base texture.
As experiment im trying to merge multiple textures into one (so many textures next to eachother), im just telling this to explain the "missing" textures, it works like it should so dont bother about this Smiley.

However the sampling of the second texture gives very hard edges (dist = (2-t) * 1.6; gives a little smoother effect, but still not good enough).
I think this effect has the same problem as with the normals, since the triangle only has 3 values to interpolate between.
So is there any way to interpolate nicely between those values in the fragment shader like with the normals (from very blocky to perfect round)?

If you scale the boundary between transitions, you still need to normalize the "mix" range. Given the lack of information, there is no way to know the origin of the problem if that is not it. But regardless of what the original issue is, there will be extra artifacts if that problem is not fixed.
I didnt get the part about normalizing, c is the value passed to gl_FragColor.
Offline theagentd
« Reply #28 - Posted 2012-12-01 00:21:25 »

Try this code:

1  
2  
3  
4  
5  
6  
7  
8  
9  
10  
11  
12  
13  
14  
15  
16  
uniform sampler2D Texture0;
varying float t;

vec3 getSample(float tValue, vec2 texCoordOffset){
    float weight = max(1 - abs(t - tValue), 0.0);
    return texture2D(Texture0, gl_TexCoord[0].xy + texCoordOffset).xyz * weight;
}

void main()
{
    vec3 samples = getSample(0.0, vec2(0.0, 0.0)); //First sample, same as c before.
   samples += getSample(1.0, vec2(0.5, 0.0));
    //Etc for more different terrain types.

    gl_FragColor = vec4(samples, 1.0);
}

Myomyomyo.
Offline RobinB

JGO Ninja


Medals: 44
Projects: 1
Exp: 3 years


Spacegame in progress


« Reply #29 - Posted 2012-12-01 11:08:18 »

Try this code:

1  
2  
3  
4  
5  
6  
7  
8  
9  
10  
11  
12  
13  
14  
15  
16  
uniform sampler2D Texture0;
varying float t;

vec3 getSample(float tValue, vec2 texCoordOffset){
    float weight = max(1 - abs(t - tValue), 0.0);
    return texture2D(Texture0, gl_TexCoord[0].xy + texCoordOffset).xyz * weight;
}

void main()
{
    vec3 samples = getSample(0.0, vec2(0.0, 0.0)); //First sample, same as c before.
   samples += getSample(1.0, vec2(0.5, 0.0));
    //Etc for more different terrain types.

    gl_FragColor = vec4(samples, 1.0);
}


Really awsome, this did the trick.
Also cleaned up my code a great bit haha Smiley
Again i was thinking to much in the wrong direction Sad.

Also added some noise to show the new transitions better:


Its really becoming something nice, im learning loads of stuff from you guys, thanks very much again.
Pages: [1] 2
  ignore  |  Print  
 
 
You cannot reply to this message, because it is very, very old.

 

Add your game by posting it in the WIP section,
or publish it in Showcase.

The first screenshot will be displayed as a thumbnail.

BurntPizza (20 views)
2014-09-21 02:42:18

BurntPizza (14 views)
2014-09-21 01:30:30

moogie (14 views)
2014-09-21 00:26:15

UprightPath (25 views)
2014-09-20 20:14:06

BurntPizza (27 views)
2014-09-19 03:14:18

Dwinin (40 views)
2014-09-12 09:08:26

Norakomi (73 views)
2014-09-10 13:57:51

TehJavaDev (96 views)
2014-09-10 06:39:09

Tekkerue (49 views)
2014-09-09 02:24:56

mitcheeb (70 views)
2014-09-08 06:06:29
List of Learning Resources
by Longor1996
2014-08-16 10:40:00

List of Learning Resources
by SilverTiger
2014-08-05 19:33:27

Resources for WIP games
by CogWheelz
2014-08-01 16:20:17

Resources for WIP games
by CogWheelz
2014-08-01 16:19:50

List of Learning Resources
by SilverTiger
2014-07-31 16:29:50

List of Learning Resources
by SilverTiger
2014-07-31 16:26:06

List of Learning Resources
by SilverTiger
2014-07-31 11:54:12

HotSpot Options
by dleskov
2014-07-08 01:59:08
java-gaming.org is not responsible for the content posted by its members, including references to external websites, and other references that may or may not have a relation with our primarily gaming and game production oriented community. inquiries and complaints can be sent via email to the info‑account of the company managing the website of java‑gaming.org
Powered by MySQL Powered by PHP Powered by SMF 1.1.18 | SMF © 2013, Simple Machines | Managed by Enhanced Four Valid XHTML 1.0! Valid CSS!