import myou_engine # A vertex modifier allows us to inject vertex shader code # while using the autogenerated vertex shader proc newWaveModifier*(engine: MyouEngine): VertexModifier = # get_code is called when a shader is created for the mesh result.get_code = proc(v: seq[Varying]): VertexModifierCodeLines = # uniform_lines go in the global scope, for uniforms # and global functions result.uniform_lines = @[ "layout(std140) uniform WaveModifier {", " float wave_time;", "};", "vec3 waveFlag(vec3 pos, float time) {", " float waveIntensity = (pos.x + 1.0) / 2.0;", " float wave = sin(pos.x * 4.0 - time * 5.0 + pos.y * 3.0) * 0.5;", " wave += sin(pos.x * 6.0 + time * 3.5) * 0.3;", " pos.z += wave * waveIntensity * 0.9;", " pos.y -= waveIntensity * waveIntensity * 0.3;", " ", " return pos;", "}", ] # body lines are inserted after reading the local vertex position # and normal, called co (vec4) and normal (vec3) respectively result.body_lines = @[ "co.xyz = waveFlag(co.xyz, wave_time);", ] # Size is 4 because of std140 requirements let ubo = engine.renderer.newUBO("WaveModifier", float32, 4) result.ubo = ubo result.update = proc(m: Mesh) = var data = ubo.storage(float32) data[0] = m.scene.time ubo.update() # Create engine, scene, camera let engine = newMyouEngine(1024, 768) let scene = engine.newScene() let cam = scene.newCamera() # this sets the active camera if there's none scene.background_color = vec4(0.1, 0.1, 0.1, 1) # Move the camera upwards (the default rotation looks down) cam.position.z = 10 # Create a grid mesh with UV # The dimensions are the amount of faces, # or the amount of vertices minus one const grid_x = 64 const grid_y = 48 var vertices: seq[float32] for y in 0 ..< grid_y + 1: for x in 0 ..< grid_x + 1: vertices.add @[ -1f + x.float32 * (2f / grid_x), -1f + y.float32 * (2f / grid_y), 0, x / grid_x, y / grid_y, ] var indices: seq[uint16] for y in 0'u16 ..< grid_y: let p = y * (grid_x + 1) for x in p ..< p + grid_x: let x2 = x + grid_x + 1 indices.add @[ x, x+1, x2, x2, x+1, x2+1, ] let grid = scene.newMesh("grid", common_attributes = {vertex, uv}, vertex_array = vertices, index_array = indices, ) # Make the object wider with a 3:2 aspect ratio grid.scale.x = 1.5 # Add the vertex modifier grid.get_mesh.add_modifier newWaveModifier(engine) # This example texture is 1 pixel wide and 8 pixels high, # to make a stripped flag # NOTE: The colors are SRGB_u8, not RGB, but we're skipping output encoding # in the shader for simplicity let width = 1 let height = 8 let format = RGB_u8 # The texture goes from bottom to top # (unless we invert the Y coordinate of the UV) let pixels = @[ 115, 41, 130, 36, 64, 142, 0, 128, 38, 255, 237, 0, 255, 140, 0, 228, 3, 3, 120, 79, 23, 0, 0, 0, ] # Create the texture, use Nearest filter # to have a sharp bands instead of a gradient doAssert width * height * 3 == pixels.len let texture = engine.newTexture("test", width = width, height = height, format = format, filter = Nearest, pixels = newArrRef[uint8](pixels).to float32) # Minimal example of a material with a UV and a texture uniform grid.materials.add engine.newMaterial("shadeless texture", fragment = """ uniform sampler2D tex; in vec2 uv; in vec3 worldpos; out vec4 glOutColor; void main(){ glOutColor = texture(tex, uv) + vec4(worldpos.z * 0.5); }""", varyings = @[ Varying(vtype: Uv, varname: "uv"), Varying(vtype: WorldPosition, varname: "worldpos"), ], textures = { "tex": texture, }.toOrderedTable, ) scene.enable_render() engine.run()