diff --git a/examples/shaders/vertex_displacement/glsl100/vertex_displacement.fs b/examples/shaders/vertex_displacement/glsl100/vertex_displacement.fs new file mode 100644 index 0000000..0a99e18 --- /dev/null +++ b/examples/shaders/vertex_displacement/glsl100/vertex_displacement.fs @@ -0,0 +1,18 @@ +#version 100 + +precision mediump float; + +// Input vertex attributes (from fragment shader) +varying vec2 fragTexCoord; +varying float height; + + +void main() +{ + vec4 darkblue = vec4(0.0, 0.13, 0.18, 1.0); + vec4 lightblue = vec4(1.0, 1.0, 1.0, 1.0); + // Interpolate between two colors based on height + vec4 finalColor = mix(darkblue, lightblue, height); + + gl_FragColor = finalColor; +} diff --git a/examples/shaders/vertex_displacement/glsl100/vertex_displacement.vs b/examples/shaders/vertex_displacement/glsl100/vertex_displacement.vs new file mode 100644 index 0000000..ef79097 --- /dev/null +++ b/examples/shaders/vertex_displacement/glsl100/vertex_displacement.vs @@ -0,0 +1,48 @@ +#version 100 + +precision mediump float; + +// Input vertex attributes +attribute vec3 vertexPosition; +attribute vec2 vertexTexCoord; +attribute vec3 vertexNormal; +attribute vec4 vertexColor; + +// Input uniform values +uniform mat4 mvp; +uniform mat4 matModel; +uniform mat4 matNormal; + +uniform float time; + +uniform sampler2D perlinNoiseMap; + +// Output vertex attributes (to fragment shader) +varying vec3 fragPosition; +varying vec2 fragTexCoord; +varying vec3 fragNormal; +varying float height; + +void main() +{ + // Calculate animated texture coordinates based on time and vertex position + vec2 animatedTexCoord = sin(vertexTexCoord + vec2(sin(time + vertexPosition.x * 0.1), cos(time + vertexPosition.z * 0.1)) * 0.3); + + // Normalize animated texture coordinates to range [0, 1] + animatedTexCoord = animatedTexCoord * 0.5 + 0.5; + + // Fetch displacement from the perlin noise map + float displacement = texture2D(perlinNoiseMap, animatedTexCoord).r * 7.0; // Amplified displacement + + // Displace vertex position + vec3 displacedPosition = vertexPosition + vec3(0.0, displacement, 0.0); + + // Send vertex attributes to fragment shader + fragPosition = vec3(matModel * vec4(displacedPosition, 1.0)); + fragTexCoord = vertexTexCoord; + fragNormal = normalize(vec3(matNormal * vec4(vertexNormal, 1.0))); + height = displacedPosition.y * 0.2; // Send height to fragment shader for coloring + + // Calculate final vertex position + gl_Position = mvp * vec4(displacedPosition, 1.0); +} diff --git a/examples/shaders/vertex_displacement/glsl330/vertex_displacement.fs b/examples/shaders/vertex_displacement/glsl330/vertex_displacement.fs new file mode 100644 index 0000000..b80b76e --- /dev/null +++ b/examples/shaders/vertex_displacement/glsl330/vertex_displacement.fs @@ -0,0 +1,16 @@ +#version 330 + +// Input fragment attributes (from fragment shader) +in vec2 fragTexCoord; +in float height; + +// Output fragment color +out vec4 finalColor; + +void main() +{ + vec4 darkblue = vec4(0.0, 0.13, 0.18, 1.0); + vec4 lightblue = vec4(1.0, 1.0, 1.0, 1.0); + // Interpolate between two colors based on height + finalColor = mix(darkblue, lightblue, height); +} diff --git a/examples/shaders/vertex_displacement/glsl330/vertex_displacement.vs b/examples/shaders/vertex_displacement/glsl330/vertex_displacement.vs new file mode 100644 index 0000000..c6526db --- /dev/null +++ b/examples/shaders/vertex_displacement/glsl330/vertex_displacement.vs @@ -0,0 +1,46 @@ +#version 330 + +// Input vertex attributes +in vec3 vertexPosition; +in vec2 vertexTexCoord; +in vec3 vertexNormal; +in vec4 vertexColor; + +// Input uniform values +uniform mat4 mvp; +uniform mat4 matModel; +uniform mat4 matNormal; + +uniform float time; + +uniform sampler2D perlinNoiseMap; + +// Output vertex attributes (to fragment shader) +out vec3 fragPosition; +out vec2 fragTexCoord; +out vec3 fragNormal; +out float height; + +void main() +{ + // Calculate animated texture coordinates based on time and vertex position + vec2 animatedTexCoord = sin(vertexTexCoord + vec2(sin(time + vertexPosition.x * 0.1), cos(time + vertexPosition.z * 0.1)) * 0.3); + + // Normalize animated texture coordinates to range [0, 1] + animatedTexCoord = animatedTexCoord * 0.5 + 0.5; + + // Fetch displacement from the perlin noise map + float displacement = texture(perlinNoiseMap, animatedTexCoord).r * 7.0; // Amplified displacement + + // Displace vertex position + vec3 displacedPosition = vertexPosition + vec3(0.0, displacement, 0.0); + + // Send vertex attributes to fragment shader + fragPosition = vec3(matModel * vec4(displacedPosition, 1.0)); + fragTexCoord = vertexTexCoord; + fragNormal = normalize(vec3(matNormal * vec4(vertexNormal, 1.0))); + height = displacedPosition.y * 0.2; // Send height to fragment shader for coloring + + // Calculate final vertex position + gl_Position = mvp * vec4(displacedPosition, 1.0); +} diff --git a/examples/shaders/vertex_displacement/main.go b/examples/shaders/vertex_displacement/main.go new file mode 100644 index 0000000..67a04a6 --- /dev/null +++ b/examples/shaders/vertex_displacement/main.go @@ -0,0 +1,143 @@ +/******************************************************************************************* +* +* raylib [shaders] example - Vertex displacement +* +* Example complexity rating: [★★★☆] 3/4 +* +* Example originally created with raylib 5.0, last time updated with raylib 5.5 +* +* Example originally contributed by Alex ZH (@ZzzhHe) 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) 2023-2025 Alex ZH (@ZzzhHe) +* +********************************************************************************************/ + +package main + +import ( + "fmt" + "os" + "path/filepath" + + rl "github.com/gen2brain/raylib-go/raylib" +) + +// NOTE: Usage: `PLATFORM_DESKTOP=1 go run .` +var glslVersion int + +func init() { + if v, ok := os.LookupEnv("PLATFORM_DESKTOP"); ok && v == "1" { + glslVersion = 330 + } else { // PLATFORM_ANDROID, PLATFORM_WEB + glslVersion = 100 + } +} + +// ------------------------------------------------------------------------------------ +// Program main entry point +// ------------------------------------------------------------------------------------ +func main() { + // Initialization + //-------------------------------------------------------------------------------------- + const screenWidth int32 = 800 + const screenHeight int32 = 450 + + rl.SetConfigFlags(rl.FlagMsaa4xHint) // Enable Multi Sampling Anti Aliasing 4x (if available) + + rl.InitWindow(screenWidth, screenHeight, "raylib [shaders] example - vertex displacement") + defer rl.CloseWindow() // Close window and OpenGL context + + // Set up camera + camera := rl.Camera{ + Position: rl.NewVector3(20.0, 5.0, -20.0), + Target: rl.Vector3Zero(), + Up: rl.NewVector3(0.0, 1.0, 0.0), + Fovy: 60.0, + Projection: rl.CameraPerspective, + } + + // Load vertex and fragment shaders + shaderDir := fmt.Sprintf("glsl%d", glslVersion) + + shader := rl.LoadShader( + filepath.Join(shaderDir, "vertex_displacement.vs"), + filepath.Join(shaderDir, "vertex_displacement.fs"), + ) + defer rl.UnloadShader(shader) + + timeLoc := rl.GetShaderLocation(shader, "time") + + // Load perlin noise texture + perlinNoiseImage := rl.GenImagePerlinNoise(512, 512, 0, 0, 1.0) + perlinNoiseMap := rl.LoadTextureFromImage(perlinNoiseImage) + defer rl.UnloadTexture(perlinNoiseMap) + rl.UnloadImage(perlinNoiseImage) + + // Set shader uniform location + perlinNoiseMapLoc := rl.GetShaderLocation(shader, "perlinNoiseMap") + rl.EnableShader(shader.ID) + rl.ActiveTextureSlot(1) + rl.EnableTexture(perlinNoiseMap.ID) + rl.SetUniformSampler(perlinNoiseMapLoc, 1) + + // Create a plane mesh and model + planeMesh := rl.GenMeshPlane(50, 50, 50, 50) + planeModel := rl.LoadModelFromMesh(planeMesh) + defer rl.UnloadModel(planeModel) + + // Set plane model material + planeModel.Materials.Shader = shader + + timer := float32(0) + + rl.DisableCursor() + + rl.SetTargetFPS(60) // Set our game to run at 60 frames-per-second + //-------------------------------------------------------------------------------------- + + // Main game loop + for !rl.WindowShouldClose() { // Detect window close button or ESC key + // Update + //---------------------------------------------------------------------------------- + rl.UpdateCamera(&camera, rl.CameraFree) // Update camera with free camera mode + + deltaTime := rl.GetFrameTime() + timer += deltaTime + timeValue := []float32{timer} + + rl.SetShaderValue(shader, timeLoc, timeValue, rl.ShaderUniformFloat) // Send time value to shader + //---------------------------------------------------------------------------------- + + // Draw + //---------------------------------------------------------------------------------- + rl.BeginDrawing() + + rl.ClearBackground(rl.RayWhite) + + rl.BeginMode3D(camera) + + rl.BeginShaderMode(shader) + + // Draw plane model + rl.DrawModel(planeModel, rl.Vector3Zero(), 1.0, rl.White) + + rl.EndShaderMode() + + rl.EndMode3D() + + rl.DrawText("Vertex displacement", 10, 10, 20, rl.DarkGray) + + rl.DrawFPS(10, 40) + + rl.EndDrawing() + //---------------------------------------------------------------------------------- + } + + // De-Initialization + //-------------------------------------------------------------------------------------- + // NOTE: Unload all loaded resources at this point (that are not `defer`-ed) + //-------------------------------------------------------------------------------------- +} diff --git a/examples/shaders/vertex_displacement/vertex_displacement.gif b/examples/shaders/vertex_displacement/vertex_displacement.gif new file mode 100644 index 0000000..35c1e37 Binary files /dev/null and b/examples/shaders/vertex_displacement/vertex_displacement.gif differ diff --git a/examples/shaders/vertex_displacement/vertex_displacement.png b/examples/shaders/vertex_displacement/vertex_displacement.png new file mode 100644 index 0000000..88d211c Binary files /dev/null and b/examples/shaders/vertex_displacement/vertex_displacement.png differ