137 lines
4 KiB
Nim
137 lines
4 KiB
Nim
|
|
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()
|