Skip to content

szabolcsdombi/heightmap-multitexture-terrain

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

3 Commits
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Multitexture Terrain rendering using ModernGL

Small project using ModernGL for terrain rendering.

This example is using ModernGL 4.x.x please install with

pip install "ModernGL<5.0.0"

Screenshots

Screenshot-1.png Screenshot-2.png Screenshot-3.png

VertexShader

#version 330

uniform mat4 Mvp;
uniform sampler2D Heightmap;

in vec2 vert;

out vec2 v_text;

void main() {
	vec4 vertex = vec4(vert - 0.5, texture(Heightmap, vert).r * 0.2, 1.0);
	gl_Position = Mvp * vertex;
	v_text = vert;
}

Fragment Shader

#version 330

uniform sampler2D Heightmap;

uniform sampler2D Color1;
uniform sampler2D Color2;

uniform sampler2D Cracks;
uniform sampler2D Darken;

in vec2 v_text;

out vec4 f_color;

void main() {
	float height = texture(Heightmap, v_text).r;
	float border = smoothstep(0.5, 0.7, height);

	vec3 color1 = texture(Color1, v_text * 7.0).rgb;
	vec3 color2 = texture(Color2, v_text * 6.0).rgb;

	vec3 color = color1 * (1.0 - border) + color2 * border;

	color *= 0.8 + 0.2 * texture(Darken, v_text * 3.0).r;
	color *= 0.5 + 0.5 * texture(Cracks, v_text * 5.0).r;
	color *= 0.5 + 0.5 * height;

	f_color = vec4(color, 1.0);
}

The entire code

import math
import struct

import GLWindow
import ModernGL
from PIL import Image
from pyrr import Matrix44

wnd = GLWindow.create_window()
ctx = ModernGL.create_context()

prog = ctx.program([
    ctx.vertex_shader('''
        #version 330

        uniform mat4 Mvp;
        uniform sampler2D Heightmap;

        in vec2 vert;

        out vec2 v_text;

        void main() {
            vec4 vertex = vec4(vert - 0.5, texture(Heightmap, vert).r * 0.2, 1.0);
            gl_Position = Mvp * vertex;
            v_text = vert;
        }
    '''),
    ctx.fragment_shader('''
        #version 330

        uniform sampler2D Heightmap;

        uniform sampler2D Color1;
        uniform sampler2D Color2;

        uniform sampler2D Cracks;
        uniform sampler2D Darken;

        in vec2 v_text;

        out vec4 f_color;

        void main() {
            float height = texture(Heightmap, v_text).r;
            float border = smoothstep(0.5, 0.7, height);

            vec3 color1 = texture(Color1, v_text * 7.0).rgb;
            vec3 color2 = texture(Color2, v_text * 6.0).rgb;

            vec3 color = color1 * (1.0 - border) + color2 * border;

            color *= 0.8 + 0.2 * texture(Darken, v_text * 3.0).r;
            color *= 0.5 + 0.5 * texture(Cracks, v_text * 5.0).r;
            color *= 0.5 + 0.5 * height;

            f_color = vec4(color, 1.0);
        }
    '''),
])

img0 = Image.open('data/heightmap.jpg').convert('L').transpose(Image.FLIP_TOP_BOTTOM)
img1 = Image.open('data/grass.jpg').convert('RGB').transpose(Image.FLIP_TOP_BOTTOM)
img2 = Image.open('data/rock.jpg').convert('RGB').transpose(Image.FLIP_TOP_BOTTOM)
img3 = Image.open('data/cracks.jpg').convert('L').transpose(Image.FLIP_TOP_BOTTOM)
img4 = Image.open('data/checked.jpg').convert('L').transpose(Image.FLIP_TOP_BOTTOM)

tex0 = ctx.texture(img0.size, 1, img0.tobytes())
tex1 = ctx.texture(img1.size, 3, img1.tobytes())
tex2 = ctx.texture(img2.size, 3, img2.tobytes())
tex3 = ctx.texture(img3.size, 1, img3.tobytes())
tex4 = ctx.texture(img4.size, 1, img4.tobytes())

tex0.build_mipmaps()
tex1.build_mipmaps()
tex2.build_mipmaps()
tex3.build_mipmaps()
tex4.build_mipmaps()

tex0.use(0)
tex1.use(1)
tex2.use(2)
tex3.use(3)
tex4.use(4)

prog.uniforms['Heightmap'].value = 0
prog.uniforms['Color1'].value = 1
prog.uniforms['Color2'].value = 2
prog.uniforms['Cracks'].value = 3
prog.uniforms['Darken'].value = 4

index = 0
vertices = bytearray()
indices = bytearray()

for i in range(64 - 1):
    for j in range(64):
        vertices += struct.pack('2f', i / 64, j / 64)
        indices += struct.pack('i', index)
        index += 1

        vertices += struct.pack('2f', (i + 1) / 64, j / 64)
        indices += struct.pack('i', index)
        index += 1

    indices += struct.pack('i', -1)

vbo = ctx.buffer(vertices)
ibo = ctx.buffer(indices)

vao = ctx.vertex_array(prog, [(vbo, '2f', ['vert'])], ibo)

while wnd.update():
    angle = wnd.time * 0.5
    width, height = wnd.size
    proj = Matrix44.perspective_projection(45.0, width / height, 0.01, 10.0)
    look = Matrix44.look_at((math.cos(angle), math.sin(angle), 0.8), (0.0, 0.0, 0.1), (0.0, 0.0, 1.0))
    prog.uniforms['Mvp'].write((proj * look).astype('float32').tobytes())

    ctx.enable(ModernGL.DEPTH_TEST)
    ctx.viewport = wnd.viewport
    ctx.clear(1.0, 1.0, 1.0)
    vao.render(ModernGL.TRIANGLE_STRIP)

Textures

Heightmap

heightmap.jpg

Grass

grass.jpg

Rock

rock.jpg

Checked

checked.jpg

Cracks

cracks.jpg

About

Small project using ModernGL for terrain rendering

Topics

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages