Jeremy Montgomery 1 일 전
committed by GitHub
부모
커밋
9516f25ca5
No known key found for this signature in database GPG 키 ID: B5690EEEBB952194
13개의 변경된 파일580개의 추가작업 그리고 14개의 파일을 삭제
  1. +1
    -0
      examples/Makefile
  2. +1
    -0
      examples/Makefile.Web
  3. +15
    -14
      examples/README.md
  4. +64
    -0
      examples/shaders/resources/shaders/glsl100/normalmap.fs
  5. +76
    -0
      examples/shaders/resources/shaders/glsl100/normalmap.vs
  6. +62
    -0
      examples/shaders/resources/shaders/glsl120/normalmap.fs
  7. +76
    -0
      examples/shaders/resources/shaders/glsl120/normalmap.vs
  8. +67
    -0
      examples/shaders/resources/shaders/glsl330/normalmap.fs
  9. +48
    -0
      examples/shaders/resources/shaders/glsl330/normalmap.vs
  10. BIN
      examples/shaders/resources/tiles_diffuse.png
  11. BIN
      examples/shaders/resources/tiles_normal.png
  12. +170
    -0
      examples/shaders/shaders_normalmap.c
  13. BIN
      examples/shaders/shaders_normalmap.png

+ 1
- 0
examples/Makefile 파일 보기

@ -631,6 +631,7 @@ SHADERS = \
shaders/shaders_mesh_instancing \
shaders/shaders_model_shader \
shaders/shaders_multi_sample2d \
shaders/shaders_normalmap \
shaders/shaders_palette_switch \
shaders/shaders_postprocessing \
shaders/shaders_raymarching \

+ 1
- 0
examples/Makefile.Web 파일 보기

@ -513,6 +513,7 @@ SHADERS = \
shaders/shaders_mesh_instancing \
shaders/shaders_model_shader \
shaders/shaders_multi_sample2d \
shaders/shaders_normalmap \
shaders/shaders_palette_switch \
shaders/shaders_postprocessing \
shaders/shaders_raymarching \

+ 15
- 14
examples/README.md 파일 보기

@ -202,6 +202,7 @@ Examples using raylib shaders functionality, including shaders loading, paramete
| 141 | [shaders_lightmap](shaders/shaders_lightmap.c) | <img src="shaders/shaders_lightmap.png" alt="shaders_lightmap" width="80"> | ⭐️⭐️⭐️☆ | 4.5 | 4.5 | [Jussi Viitala](https://github.com/nullstare) |
| 142 | [shaders_rounded_rectangle](shaders/shaders_rounded_rectangle.c) | <img src="shaders/shaders_rounded_rectangle.png" alt="shaders_rounded_rectangle" width=80> | ⭐️⭐️⭐️☆ | 5.5 | 5.5 | [Anstro Pleuton](https://github.com/anstropleuton) |
| 143 | [shaders_view_depth](shaders/shaders_view_depth.c) | <img src="shaders/shaders_view_depth.png" alt="shaders_view_depth" width="80"> | ⭐️⭐️⭐️☆ | 5.6-dev | 5.6-dev | [Luís Almeida](https://github.com/luis605) |
| 144 | [shaders_normalmap](shaders/shaders_normalmap.c) | <img src="shaders/shaders_normalmap.png" alt="shaders_normalmap" width="80"> | ⭐️⭐️⭐️⭐️ | 5.6-dev | 5.6-dev | [Jeremy Montgomery](https://github.com/Sir-Irk) |
### category: audio
@ -209,14 +210,14 @@ Examples using raylib audio functionality, including sound/music loading and pla
| ## | example | image | difficulty<br>level | version<br>created | last version<br>updated | original<br>developer |
|----|----------|--------|:-------------------:|:------------------:|:-----------------------:|:----------------------|
| 144 | [audio_module_playing](audio/audio_module_playing.c) | <img src="audio/audio_module_playing.png" alt="audio_module_playing" width="80"> | ⭐️☆☆☆ | 1.5 | 3.5 | [Ray](https://github.com/raysan5) |
| 145 | [audio_music_stream](audio/audio_music_stream.c) | <img src="audio/audio_music_stream.png" alt="audio_music_stream" width="80"> | ⭐️☆☆☆ | 1.3 | 4.2 | [Ray](https://github.com/raysan5) |
| 146 | [audio_raw_stream](audio/audio_raw_stream.c) | <img src="audio/audio_raw_stream.png" alt="audio_raw_stream" width="80"> | ⭐️⭐️⭐️☆ | 1.6 | 4.2 | [Ray](https://github.com/raysan5) |
| 147 | [audio_sound_loading](audio/audio_sound_loading.c) | <img src="audio/audio_sound_loading.png" alt="audio_sound_loading" width="80"> | ⭐️☆☆☆ | 1.1 | 3.5 | [Ray](https://github.com/raysan5) |
| 148 | [audio_mixed_processor](audio/audio_mixed_processor.c) | <img src="audio/audio_mixed_processor.png" alt="audio_mixed_processor" width="80"> | ⭐️⭐️⭐️⭐️ | 4.2 | 4.2 | [hkc](https://github.com/hatkidchan) |
| 149 | [audio_stream_effects](audio/audio_stream_effects.c) | <img src="audio/audio_stream_effects.png" alt="audio_stream_effects" width="80"> | ⭐️⭐️⭐️⭐️ | 4.2 | 5.0 | [Ray](https://github.com/raysan5) |
| 150 [audio_sound_multi](audio/audio_sound_multi.c) | <img src="audio/audio_sound_multi.png" alt="audio_sound_multi" width="80"> | ⭐️⭐️☆☆ | 4.6 | 4.6 | [Jeffery Myers](https://github.com/JeffM2501) |
| 151 | [audio_sound_positioning](audio/audio_sound_positioning.c) | <img src="audio/audio_sound_positioning.png" alt="audio_sound_positioning" width="80"> | ⭐️⭐️☆☆ | 5.5 | 5.5 | [Le Juez Victor](https://github.com/Bigfoot71) |
| 145 | [audio_module_playing](audio/audio_module_playing.c) | <img src="audio/audio_module_playing.png" alt="audio_module_playing" width="80"> | ⭐️☆☆☆ | 1.5 | 3.5 | [Ray](https://github.com/raysan5) |
| 146 | [audio_music_stream](audio/audio_music_stream.c) | <img src="audio/audio_music_stream.png" alt="audio_music_stream" width="80"> | ⭐️☆☆☆ | 1.3 | 4.2 | [Ray](https://github.com/raysan5) |
| 147 | [audio_raw_stream](audio/audio_raw_stream.c) | <img src="audio/audio_raw_stream.png" alt="audio_raw_stream" width="80"> | ⭐️⭐️⭐️☆ | 1.6 | 4.2 | [Ray](https://github.com/raysan5) |
| 148 | [audio_sound_loading](audio/audio_sound_loading.c) | <img src="audio/audio_sound_loading.png" alt="audio_sound_loading" width="80"> | ⭐️☆☆☆ | 1.1 | 3.5 | [Ray](https://github.com/raysan5) |
| 149 | [audio_mixed_processor](audio/audio_mixed_processor.c) | <img src="audio/audio_mixed_processor.png" alt="audio_mixed_processor" width="80"> | ⭐️⭐️⭐️⭐️ | 4.2 | 4.2 | [hkc](https://github.com/hatkidchan) |
| 150 | [audio_stream_effects](audio/audio_stream_effects.c) | <img src="audio/audio_stream_effects.png" alt="audio_stream_effects" width="80"> | ⭐️⭐️⭐️⭐️ | 4.2 | 5.0 | [Ray](https://github.com/raysan5) |
| 151 | [audio_sound_multi](audio/audio_sound_multi.c) | <img src="audio/audio_sound_multi.png" alt="audio_sound_multi" width="80"> | ⭐️⭐️☆☆ | 4.6 | 4.6 | [Jeffery Myers](https://github.com/JeffM2501) |
| 152 | [audio_sound_positioning](audio/audio_sound_positioning.c) | <img src="audio/audio_sound_positioning.png" alt="audio_sound_positioning" width="80"> | ⭐️⭐️☆☆ | 5.5 | 5.5 | [Le Juez Victor](https://github.com/Bigfoot71) |
### category: others
@ -224,11 +225,11 @@ Ex150amples showing raylib misc functionality that does not fit in other categor
| ## | example | image | difficulty<br>level | version<br>created | last version<br>updated | original<br>developer |
|----|----------|--------|:-------------------:|:------------------:|:-----------------------:|:----------------------|
| 152 | [rlgl_standalone](others/rlgl_standalone.c) | <img src="others/rlgl_standalone.png" alt="rlgl_standalone" width="80"> | ⭐️⭐️⭐️⭐️ | 1.6 | 4.0 | [Ray](https://github.com/raysan5) |
| 153 | [rlgl_compute_shader](others/rlgl_compute_shader.c) | <img src="others/rlgl_compute_shader.png" alt="rlgl_compute_shader" width="80"> | ⭐️⭐️⭐️⭐️ | 4.0 | 4.0 | [Teddy Astie](https://github.com/tsnake41) |
| 154 | [easings_testbed](others/easings_testbed.c) | <img src="others/easings_testbed.png" alt="easings_testbed" width="80"> | ⭐️⭐️⭐️☆ | 2.5 | 3.0 | [Juan Miguel López](https://github.com/flashback-fx) |
| 155 | [raylib_opengl_interop](others/raylib_opengl_interop.c) | <img src="others/raylib_opengl_interop.png" alt="raylib_opengl_interop" width="80"> | ⭐️⭐️⭐️⭐️ | 3.8 | 4.0 | [Stephan Soller](https://github.com/arkanis) |
| 156 | [embedded_files_loading](others/embedded_files_loading.c) | <img src="others/embedded_files_loading.png" alt="embedded_files_loading" width="80"> | ⭐️⭐️☆☆ | 3.0 | 3.5 | [Kristian Holmgren](https://github.com/defutura) |
| 157 | [raymath_vector_angle](others/raymath_vector_angle.c) | <img src="others/raymath_vector_angle.png" alt="raymath_vector_angle" width="80"> | ⭐️⭐️☆☆ | 1.0 | 4.6 | [Ray](https://github.com/raysan5) |
| 153 | [rlgl_standalone](others/rlgl_standalone.c) | <img src="others/rlgl_standalone.png" alt="rlgl_standalone" width="80"> | ⭐️⭐️⭐️⭐️ | 1.6 | 4.0 | [Ray](https://github.com/raysan5) |
| 154 | [rlgl_compute_shader](others/rlgl_compute_shader.c) | <img src="others/rlgl_compute_shader.png" alt="rlgl_compute_shader" width="80"> | ⭐️⭐️⭐️⭐️ | 4.0 | 4.0 | [Teddy Astie](https://github.com/tsnake41) |
| 155 | [easings_testbed](others/easings_testbed.c) | <img src="others/easings_testbed.png" alt="easings_testbed" width="80"> | ⭐️⭐️⭐️☆ | 2.5 | 3.0 | [Juan Miguel López](https://github.com/flashback-fx) |
| 156 | [raylib_opengl_interop](others/raylib_opengl_interop.c) | <img src="others/raylib_opengl_interop.png" alt="raylib_opengl_interop" width="80"> | ⭐️⭐️⭐️⭐️ | 3.8 | 4.0 | [Stephan Soller](https://github.com/arkanis) |
| 157 | [embedded_files_loading](others/embedded_files_loading.c) | <img src="others/embedded_files_loading.png" alt="embedded_files_loading" width="80"> | ⭐️⭐️☆☆ | 3.0 | 3.5 | [Kristian Holmgren](https://github.com/defutura) |
| 158 | [raymath_vector_angle](others/raymath_vector_angle.c) | <img src="others/raymath_vector_angle.png" alt="raymath_vector_angle" width="80"> | ⭐️⭐️☆☆ | 1.0 | 4.6 | [Ray](https://github.com/raysan5) |
As always contributions are welcome, feel free to send new examples! Here is an [examples template](examples_template.c) to start with!

+ 64
- 0
examples/shaders/resources/shaders/glsl100/normalmap.fs 파일 보기

@ -0,0 +1,64 @@
#version 100
precision mediump float;
// Input vertex attributes (from vertex shader)
varying vec3 fragPosition;
varying vec2 fragTexCoord;
varying vec3 fragNormal; //used for when normal mapping is toggled off
varying vec4 fragColor;
varying mat3 TBN;
// Input uniform values
uniform sampler2D texture0;
uniform sampler2D normalMap;
uniform vec4 colDiffuse;
uniform vec3 viewPos;
// NOTE: Add your custom variables here
uniform vec3 lightPos;
uniform bool useNormalMap;
uniform float specularExponent;
void main()
{
vec4 texelColor = texture(texture0, vec2(fragTexCoord.x, fragTexCoord.y));
vec3 specular = vec3(0.0);
vec3 viewDir = normalize(viewPos - fragPosition);
vec3 lightDir = normalize(lightPos - fragPosition);
vec3 normal;
if (useNormalMap)
{
normal = texture(normalMap, vec2(fragTexCoord.x, fragTexCoord.y)).rgb;
//Transform normal values to the range -1.0 ... 1.0
normal = normalize(normal * 2.0 - 1.0);
//Transform the normal from tangent-space to world-space for lighting calculation
normal = normalize(normal * TBN);
}
else
{
normal = normalize(fragNormal);
}
vec4 tint = colDiffuse * fragColor;
vec3 lightColor = vec3(1.0, 1.0, 1.0);
float NdotL = max(dot(normal, lightDir), 0.0);
vec3 lightDot = lightColor * NdotL;
float specCo = 0.0;
if (NdotL > 0.0) specCo = pow(max(0.0, dot(viewDir, reflect(-lightDir, normal))), specularExponent); // 16 refers to shine
specular += specCo;
finalColor = (texelColor * ((tint + vec4(specular, 1.0)) * vec4(lightDot, 1.0)));
finalColor += texelColor * (vec4(1.0, 1.0, 1.0, 1.0) / 40.0) * tint;
// Gamma correction
gl_FragColor = pow(finalColor, vec4(1.0 / 2.2));
}

+ 76
- 0
examples/shaders/resources/shaders/glsl100/normalmap.vs 파일 보기

@ -0,0 +1,76 @@
#version 100
// Input vertex attributes
attribute vec3 vertexPosition;
attribute vec2 vertexTexCoord;
attribute vec3 vertexNormal;
attribute vec4 vertexTangent;
attribute vec4 vertexColor;
// Input uniform values
uniform mat4 mvp;
uniform mat4 matModel;
// Output vertex attributes (to fragment shader)
varying vec3 fragPosition;
varying vec2 fragTexCoord;
varying vec3 fragNormal; //used for when normal mapping is toggled off
varying vec4 fragColor;
varying mat3 TBN;
// NOTE: Add your custom variables here
// https://github.com/glslify/glsl-inverse
mat3 inverse(mat3 m)
{
float a00 = m[0][0], a01 = m[0][1], a02 = m[0][2];
float a10 = m[1][0], a11 = m[1][1], a12 = m[1][2];
float a20 = m[2][0], a21 = m[2][1], a22 = m[2][2];
float b01 = a22 * a11 - a12 * a21;
float b11 = -a22 * a10 + a12 * a20;
float b21 = a21 * a10 - a11 * a20;
float det = a00 * b01 + a01 * b11 + a02 * b21;
return mat3(b01, (-a22 * a01 + a02 * a21), (a12 * a01 - a02 * a11),
b11, (a22 * a00 - a02 * a20), (-a12 * a00 + a02 * a10),
b21, (-a21 * a00 + a01 * a20), (a11 * a00 - a01 * a10)) / det;
}
// https://github.com/glslify/glsl-transpose
mat3 transpose(mat3 m)
{
return mat3(m[0][0], m[1][0], m[2][0],
m[0][1], m[1][1], m[2][1],
m[0][2], m[1][2], m[2][2]);
}
void main()
{
// Compute binormal from vertex normal and tangent. W component is the tangent handedness
vec3 vertexBinormal = cross(vertexNormal, vertexTangent.xyz) * vertexTangent.w;
// Compute fragment normal based on normal transformations
mat3 normalMatrix = transpose(inverse(mat3(matModel)));
// Compute fragment position based on model transformations
fragPosition = vec3(matModel * vec4(vertexPosition, 1.0));
//Create TBN matrix for transforming the normal map values from tangent-space to world-space
fragNormal = normalize(normalMatrix * vertexNormal);
vec3 fragTangent = normalize(normalMatrix * vertexTangent.xyz);
fragTangent = normalize(fragTangent - dot(fragTangent, fragNormal) * fragNormal);
vec3 fragBinormal = normalize(normalMatrix * vertexBinormal);
fragBinormal = cross(fragNormal, fragTangent);
TBN = transpose(mat3(fragTangent, fragBinormal, fragNormal));
fragColor = vertexColor;
fragTexCoord = vertexTexCoord;
gl_Position = mvp * vec4(vertexPosition, 1.0);
}

+ 62
- 0
examples/shaders/resources/shaders/glsl120/normalmap.fs 파일 보기

@ -0,0 +1,62 @@
#version 120
// Input vertex attributes (from vertex shader)
varying vec3 fragPosition;
varying vec2 fragTexCoord;
varying vec3 fragNormal; //used for when normal mapping is toggled off
varying vec4 fragColor;
varying mat3 TBN;
// Input uniform values
uniform sampler2D texture0;
uniform sampler2D normalMap;
uniform vec4 colDiffuse;
uniform vec3 viewPos;
// NOTE: Add your custom variables here
uniform vec3 lightPos;
uniform bool useNormalMap;
uniform float specularExponent;
void main()
{
vec4 texelColor = texture(texture0, vec2(fragTexCoord.x, fragTexCoord.y));
vec3 specular = vec3(0.0);
vec3 viewDir = normalize(viewPos - fragPosition);
vec3 lightDir = normalize(lightPos - fragPosition);
vec3 normal;
if (useNormalMap)
{
normal = texture(normalMap, vec2(fragTexCoord.x, fragTexCoord.y)).rgb;
//Transform normal values to the range -1.0 ... 1.0
normal = normalize(normal * 2.0 - 1.0);
//Transform the normal from tangent-space to world-space for lighting calculation
normal = normalize(normal * TBN);
}
else
{
normal = normalize(fragNormal);
}
vec4 tint = colDiffuse * fragColor;
vec3 lightColor = vec3(1.0, 1.0, 1.0);
float NdotL = max(dot(normal, lightDir), 0.0);
vec3 lightDot = lightColor * NdotL;
float specCo = 0.0;
if (NdotL > 0.0) specCo = pow(max(0.0, dot(viewDir, reflect(-lightDir, normal))), specularExponent); // 16 refers to shine
specular += specCo;
finalColor = (texelColor * ((tint + vec4(specular, 1.0)) * vec4(lightDot, 1.0)));
finalColor += texelColor * (vec4(1.0, 1.0, 1.0, 1.0) / 40.0) * tint;
// Gamma correction
gl_FragColor = pow(finalColor, vec4(1.0 / 2.2));
}

+ 76
- 0
examples/shaders/resources/shaders/glsl120/normalmap.vs 파일 보기

@ -0,0 +1,76 @@
#version 120
// Input vertex attributes
attribute vec3 vertexPosition;
attribute vec2 vertexTexCoord;
attribute vec3 vertexNormal;
attribute vec4 vertexTangent;
attribute vec4 vertexColor;
// Input uniform values
uniform mat4 mvp;
uniform mat4 matModel;
// Output vertex attributes (to fragment shader)
varying vec3 fragPosition;
varying vec2 fragTexCoord;
varying vec3 fragNormal; //used for when normal mapping is toggled off
varying vec4 fragColor;
varying mat3 TBN;
// NOTE: Add your custom variables here
// https://github.com/glslify/glsl-inverse
mat3 inverse(mat3 m)
{
float a00 = m[0][0], a01 = m[0][1], a02 = m[0][2];
float a10 = m[1][0], a11 = m[1][1], a12 = m[1][2];
float a20 = m[2][0], a21 = m[2][1], a22 = m[2][2];
float b01 = a22 * a11 - a12 * a21;
float b11 = -a22 * a10 + a12 * a20;
float b21 = a21 * a10 - a11 * a20;
float det = a00 * b01 + a01 * b11 + a02 * b21;
return mat3(b01, (-a22 * a01 + a02 * a21), (a12 * a01 - a02 * a11),
b11, (a22 * a00 - a02 * a20), (-a12 * a00 + a02 * a10),
b21, (-a21 * a00 + a01 * a20), (a11 * a00 - a01 * a10)) / det;
}
// https://github.com/glslify/glsl-transpose
mat3 transpose(mat3 m)
{
return mat3(m[0][0], m[1][0], m[2][0],
m[0][1], m[1][1], m[2][1],
m[0][2], m[1][2], m[2][2]);
}
void main()
{
// Compute binormal from vertex normal and tangent. W component is the tangent handedness
vec3 vertexBinormal = cross(vertexNormal, vertexTangent.xyz) * vertexTangent.w;
// Compute fragment normal based on normal transformations
mat3 normalMatrix = transpose(inverse(mat3(matModel)));
// Compute fragment position based on model transformations
fragPosition = vec3(matModel * vec4(vertexPosition, 1.0));
//Create TBN matrix for transforming the normal map values from tangent-space to world-space
fragNormal = normalize(normalMatrix * vertexNormal);
vec3 fragTangent = normalize(normalMatrix * vertexTangent.xyz);
fragTangent = normalize(fragTangent - dot(fragTangent, fragNormal) * fragNormal);
vec3 fragBinormal = normalize(normalMatrix * vertexBinormal);
fragBinormal = cross(fragNormal, fragTangent);
TBN = transpose(mat3(fragTangent, fragBinormal, fragNormal));
fragColor = vertexColor;
fragTexCoord = vertexTexCoord;
gl_Position = mvp * vec4(vertexPosition, 1.0);
}

+ 67
- 0
examples/shaders/resources/shaders/glsl330/normalmap.fs 파일 보기

@ -0,0 +1,67 @@
#version 330
// Input vertex attributes (from vertex shader)
in vec3 fragPosition;
in vec2 fragTexCoord;
in vec3 fragNormal; //used for when normal mapping is toggled off
in vec4 fragColor;
// Input uniform values
uniform sampler2D texture0;
uniform sampler2D normalMap;
uniform vec4 colDiffuse;
uniform vec3 viewPos;
uniform vec4 tintColor;
uniform vec3 lightPos;
uniform bool useNormalMap;
uniform float specularExponent;
// Output fragment color
out vec4 finalColor;
in mat3 TBN;
void main()
{
vec4 texelColor = texture(texture0, vec2(fragTexCoord.x, fragTexCoord.y));
vec3 specular = vec3(0.0);
vec3 viewDir = normalize(viewPos - fragPosition);
vec3 lightDir = normalize(lightPos - fragPosition);
vec3 normal;
if (useNormalMap)
{
normal = texture(normalMap, vec2(fragTexCoord.x, fragTexCoord.y)).rgb;
//Transform normal values to the range -1.0 ... 1.0
normal = normalize(normal * 2.0 - 1.0);
//Transform the normal from tangent-space to world-space for lighting calculation
normal = normalize(normal * TBN);
}
else
{
normal = normalize(fragNormal);
}
vec4 tint = colDiffuse * fragColor;
vec3 lightColor = vec3(1.0, 1.0, 1.0);
float NdotL = max(dot(normal, lightDir), 0.0);
vec3 lightDot = lightColor * NdotL;
float specCo = 0.0;
if (NdotL > 0.0) specCo = pow(max(0.0, dot(viewDir, reflect(-lightDir, normal))), specularExponent); // 16 refers to shine
specular += specCo;
finalColor = (texelColor * ((tint + vec4(specular, 1.0)) * vec4(lightDot, 1.0)));
finalColor += texelColor * (vec4(1.0, 1.0, 1.0, 1.0) / 40.0) * tint;
// Gamma correction
finalColor = pow(finalColor, vec4(1.0 / 2.2));
//finalColor = vec4(normal, 1.0);
}

+ 48
- 0
examples/shaders/resources/shaders/glsl330/normalmap.vs 파일 보기

@ -0,0 +1,48 @@
#version 330
// Input vertex attributes
in vec3 vertexPosition;
in vec2 vertexTexCoord;
in vec3 vertexNormal;
in vec4 vertexTangent;
in vec4 vertexColor;
// Input uniform values
uniform mat4 mvp;
uniform mat4 matModel;
// Output vertex attributes (to fragment shader)
out vec3 fragPosition;
out vec2 fragTexCoord;
out vec3 fragNormal; //used for when normal mapping is toggled off
out vec4 fragColor;
out mat3 TBN;
void main()
{
// Compute binormal from vertex normal and tangent. W component is the tangent handedness
vec3 vertexBinormal = cross(vertexNormal, vertexTangent.xyz) * vertexTangent.w;
// Compute fragment normal based on normal transformations
mat3 normalMatrix = transpose(inverse(mat3(matModel)));
// Compute fragment position based on model transformations
fragPosition = vec3(matModel * vec4(vertexPosition, 1.0));
//Create TBN matrix for transforming the normal map values from tangent-space to world-space
fragNormal = normalize(normalMatrix * vertexNormal);
vec3 fragTangent = normalize(normalMatrix * vertexTangent.xyz);
fragTangent = normalize(fragTangent - dot(fragTangent, fragNormal) * fragNormal);
vec3 fragBinormal = normalize(normalMatrix * vertexBinormal);
fragBinormal = cross(fragNormal, fragTangent);
TBN = transpose(mat3(fragTangent, fragBinormal, fragNormal));
fragColor = vertexColor;
fragTexCoord = vertexTexCoord;
gl_Position = mvp * vec4(vertexPosition, 1.0);
}

BIN
examples/shaders/resources/tiles_diffuse.png 파일 보기

Before After
Width: 512  |  Height: 512  |  Size: 528 KiB

BIN
examples/shaders/resources/tiles_normal.png 파일 보기

Before After
Width: 512  |  Height: 512  |  Size: 663 KiB

+ 170
- 0
examples/shaders/shaders_normalmap.c 파일 보기

@ -0,0 +1,170 @@
/*******************************************************************************************
*
* raylib [shaders] example - normalmap
*
* Example complexity rating: [] 4/4
*
* NOTE: This example requires raylib OpenGL 3.3 or ES2 versions for shaders support,
* OpenGL 1.1 does not support shaders, recompile raylib to OpenGL 3.3 version.
*
* Example originally created with raylib 5.6, last time updated with raylib 5.6
*
* Example contributed by Jeremy Montgomery (@Sir_Irk) and reviewed by Ramon Santamaria (@raysan5)
*
* Example licensed under an unmodified zlib/libpng license, which is an OSI-certified,
* BSD-like license that allows static linking with closed source software
*
* Copyright (c) 2025-2025 Jeremy Montgomery (@Sir_Irk) and Ramon Santamaria (@raysan5)
*k
********************************************************************************************/
#include <raylib.h>
#include <raymath.h>
#if defined(PLATFORM_DESKTOP)
#define GLSL_VERSION 330
#else // PLATFORM_ANDROID, PLATFORM_WEB
#define GLSL_VERSION 100
#endif
//------------------------------------------------------------------------------------
// Program main entry point
//------------------------------------------------------------------------------------
int main(void)
{
// Initialization
//--------------------------------------------------------------------------------------
SetConfigFlags(FLAG_MSAA_4X_HINT);
InitWindow(800, 450, "Normal Map");
Camera camera = {0};
camera.position = (Vector3){0.0f, 2.0f, -4.0f};
camera.target = (Vector3){0.0f, 0.0f, 0.0f};
camera.up = (Vector3){0.0f, 1.0f, 0.0f};
camera.fovy = 45.0f;
camera.projection = CAMERA_PERSPECTIVE;
// Load basic normal map lighting shader
Shader shader = LoadShader(TextFormat("resources/shaders/glsl%i/normalmap.vs", GLSL_VERSION),
TextFormat("resources/shaders/glsl%i/normalmap.fs", GLSL_VERSION));
// Get some required shader locations
shader.locs[SHADER_LOC_MAP_NORMAL] = GetShaderLocation(shader, "normalMap");
shader.locs[SHADER_LOC_VECTOR_VIEW] = GetShaderLocation(shader, "viewPos");
// NOTE: "matModel" location name is automatically assigned on shader loading,
// no need to get the location again if using that uniform name
// shader.locs[SHADER_LOC_MATRIX_MODEL] = GetShaderLocation(shader, "matModel");
// This example uses just 1 point light.
Vector3 lightPosition = {0.0f, 1.0f, 0.0f};
int lightPosLoc = GetShaderLocation(shader, "lightPos");
// Load a plane model that has proper normals and tangents
Model plane = LoadModel("resources/models/plane.glb");
// Set the plane model's shader and texture maps
plane.materials[0].shader = shader;
plane.materials[0].maps[MATERIAL_MAP_DIFFUSE].texture = LoadTexture("resources/tiles_diffuse.png");
plane.materials[0].maps[MATERIAL_MAP_NORMAL].texture = LoadTexture("resources/tiles_normal.png");
// Generate Mipmaps and use TRILINEAR filtering to help with texture aliasing
GenTextureMipmaps(&plane.materials[0].maps[MATERIAL_MAP_DIFFUSE].texture);
GenTextureMipmaps(&plane.materials[0].maps[MATERIAL_MAP_NORMAL].texture);
SetTextureFilter(plane.materials[0].maps[MATERIAL_MAP_DIFFUSE].texture, TEXTURE_FILTER_TRILINEAR);
SetTextureFilter(plane.materials[0].maps[MATERIAL_MAP_NORMAL].texture, TEXTURE_FILTER_TRILINEAR);
// Specular exponent AKA shininess of the material.
float specularExponent = 8.0f;
int specularExponentLoc = GetShaderLocation(shader, "specularExponent");
// Allow toggling the normal map on and off for comparison purposes
int useNormalMap = 1;
int useNormalMapLoc = GetShaderLocation(shader, "useNormalMap");
SetTargetFPS(60); // Set our game to run at 60 frames-per-second
//--------------------------------------------------------------------------------------
// Main game loop
while (!WindowShouldClose()) // Detect window close button or ESC key
{
// Update
//----------------------------------------------------------------------------------
// Move the light around on the X and Z axis using WASD keys
Vector3 direction = {0};
if (IsKeyDown(KEY_W)) direction = Vector3Add(direction, (Vector3){0.0f, 0.0f, 1.0f});
if (IsKeyDown(KEY_S)) direction = Vector3Add(direction, (Vector3){0.0f, 0.0f, -1.0f});
if (IsKeyDown(KEY_D)) direction = Vector3Add(direction, (Vector3){-1.0f, 0.0f, 0.0f});
if (IsKeyDown(KEY_A)) direction = Vector3Add(direction, (Vector3){1.0f, 0.0f, 0.0f});
direction = Vector3Normalize(direction);
lightPosition = Vector3Add(lightPosition, Vector3Scale(direction, GetFrameTime() * 3.0f));
// Increase/Decrease the specular exponent(shininess)
if (IsKeyDown(KEY_UP)) specularExponent = Clamp(specularExponent + 40.0f * GetFrameTime(), 2.0f, 128.0f);
if (IsKeyDown(KEY_DOWN)) specularExponent = Clamp(specularExponent - 40.0f * GetFrameTime(), 2.0f, 128.0f);
// Toggle normal map on and off
if (IsKeyPressed(KEY_N)) useNormalMap = !useNormalMap;
// Spin plane model at a constant rate
plane.transform = MatrixRotateY(GetTime() * 0.5f);
// Update shader values
float lightPos[3] = {lightPosition.x, lightPosition.y, lightPosition.z};
SetShaderValue(shader, lightPosLoc, lightPos, SHADER_UNIFORM_VEC3);
float camPos[3] = {camera.position.x, camera.position.y, camera.position.z};
SetShaderValue(shader, shader.locs[SHADER_LOC_VECTOR_VIEW], camPos, SHADER_UNIFORM_VEC3);
SetShaderValue(shader, specularExponentLoc, &specularExponent, SHADER_UNIFORM_FLOAT);
SetShaderValue(shader, useNormalMapLoc, &useNormalMap, SHADER_UNIFORM_INT);
//--------------------------------------------------------------------------------------
// Draw
//----------------------------------------------------------------------------------
BeginDrawing();
ClearBackground(RAYWHITE);
BeginMode3D(camera);
BeginShaderMode(shader);
DrawModel(plane, Vector3Zero(), 2.0f, WHITE);
EndShaderMode();
//Draw sphere to show light position
DrawSphereWires(lightPosition, 0.2f, 8, 8, ORANGE);
EndMode3D();
Color textColor = (useNormalMap) ? DARKGREEN : RED;
const char *toggleStr = (useNormalMap) ? "On" : "Off";
DrawText(TextFormat("Use key [N] to toggle normal map: %s", toggleStr), 10, 30, 20, textColor);
int yOffset = 24;
DrawText("Use keys [W][A][S][D] to move the light", 10, 30 + yOffset * 1, 20, BLACK);
DrawText("Use keys [Up][Down] to change specular exponent", 10, 30 + yOffset * 2, 20, BLACK);
DrawText(TextFormat("Specular Exponent: %.2f", specularExponent), 10, 30 + yOffset * 3, 20, BLUE);
DrawFPS(10, 10);
EndDrawing();
//--------------------------------------------------------------------------------------
}
// De-Initialization
//--------------------------------------------------------------------------------------
UnloadShader(shader);
UnloadModel(plane);
CloseWindow(); // Close window and OpenGL context
//--------------------------------------------------------------------------------------
return 0;
}

BIN
examples/shaders/shaders_normalmap.png 파일 보기

Before After
Width: 800  |  Height: 450  |  Size: 262 KiB

불러오는 중...
취소
저장