TDT4230_final_project/report/log_part2_hills.md

105 lines
5.6 KiB
Markdown

# Creating the hills
To make my plane of grass I first needed a plane. I added a generator function in `glutils.cpp` which makes a segmented plane for me with as many vertices and faces as specified. This was needed since I plan to add a displacement map capability, but only do so in the vertex shader. I thus need a lot of vertexes. The other route would be to make a texel shader which divides the faces into smaller faces and use it on the plane, which would save memory bandwith. But making it from the start is the easier option.
I added the plane to the scene and set the cobble texture on it.
It didn't look right, so I went through the shader again to make sure the lighting was correct. I failed to pass the specular shininess factor properly as a uniform. I also had failed to account for the specular component being negative (before raising it to the power of the shininess). I added this check and now the lighting looks correct.
![](images/0-base.png)
While at it I added the ability to specify all the color components and the attenuation per light source. With this I'm able to create a sun far away without being bothered by attenuation.
Now for the displacement of the plane. I created a `PNGImage` generator function which generates a perlin noise texture with the amount of layers and scales specified.
This I registered as the displacement texture for the plane. In the vertex shader I added a `isDisplacementMapped` uniform shader flag which adds the normal vector multiplied by the displacement to each vertex.
![](images/1-perlin-displacement.png)
```{.shebang im_out="stdout"}
#!/usr/bin/env bash
echo A M A S I N G | boxes -d unicornsay -a c -p h10
```
I've yet to modify the normals from the displacement, so the hill currently won't cast shadows. I currently don't have a plan on how to fix this. Perhaps use the bitangents to calculate the slope of the displacement in the vertex shader?
At this point I went online a found myself a grass texture and normal map.
![](images/2-wrong-handedness.png)
```{.shebang im_out="stdout"}
#!/usr/bin/env bash
printf " Something's wrong...! \n" | cowsay -f head-in | sed -e "s/^/ /"
```
Apparently, the direction of the normal map colors aren't the same everywhere. I therefore added a flag to the image loader function which will flip the handedness. (inverting the R and G channels).
![](images/3-flipped-handedness.png)
*Much better*
Now we'll up the granularity by decreasing the UV step per vertex along the plane, and enable the displacement map:
![](images/4-fine-plane.png)
## Scrolling the field
Now, how can we scroll this plane?
I decided the easies way would be to add a uniform variable called `uvOffset` to the vertex shader. Now I can simply scroll the plane by adding to this offset to all the UV coordinates in the vertex shader before passing it to the fragment shader:
```c++
/*vec2*/plainNode->uvOffset += /*vec2*/speed * timeDelta;
```
The code above works since I added in some operator overloads for `vec2`, `vec3`, and `vec4` with scalars.
Now we unfortunately see steep cuts where the perlin noise texture repeats. This we simply fix by mirroring the texture on repeat with `GL_MIRRORED_REPEAT`:
![](images/5-gl-mirror.jpg)
An another solution to making the perlin noise repeatable is to pass the repeat size into the `glm::gtx::perlin` function as I create the texture. But as of now I chose the quick and dirty solution. It also has the added effect of creating a less repeating texture. It repeats from 0-2 instead of 0-1.
At this point I was stuck with a bug where the coordinates of the lights were doubled. After two days of debugging I found the line where I update pass the light position into the uniform in the fragment shader:
```c++
lights[id].position = vec3(node->MV * vec4(node->position, 1.0));
```
Which *should* have been
```c++
lights[id].position = vec3(node->MV * vec4(vec3(0.0), 1.0));
```
*...yeah.*
## Normal mapping the displacement
After that goober, I moved on to try to rotate the normals according the displacement map. After some playing around I landed on this solution in glsl:
\small
```c++
if (isDisplacementMapped) {
float o = texture(displaceTex, UV).r * 2 - 1;
float u = (texture(displaceTex, UV + vec2(0.0001, 0)).r*2-1 - o) / 0.0004; // magic numbers!
float v = (texture(displaceTex, UV + vec2(0, 0.0001)).r*2-1 - o) / 0.0004; // magic numbers!
TBN = mat3(
normalize(tangent + normal*u),
normalize(bitangent + normal*v),
normalize(cross(tangent + normal*u, bitangent + normal*v))
);
}
```
\normalsize
Here I find the slope along the displacement map along the `U` and `V` direction. `o` is the 'origin', and `u` and `v` are the tangent and bitangent slope cosines *(derived with the help of a few magic numbers which should be made into uniforms really,s ince they only apply for the plane as of now)*. Using these cosines I can simply add the normal vector multiplied by the cosine to the tangent and the bitangent and normalize them, giving me the new tangents. I can from here derive the new normal vector by simply computing the cross product of the two tangents.
This did however give me a pretty coarse image, so I moved the computation of the TBN matrix from the vertex shader to the fragement shader. This will give me a slight performance penalty, but I can undo the change in a simplified shader should I need the performance boost later. Here we can see how the displacement affects the normals along the displaced plane:
![](images/6-displacement-normals.png)
```{.shebang im_out="stdout"}
#!/usr/bin/env bash
echo Windows XP background incoming? | boxes -d whirly -a c -p h15
```