1

I started studying Rust and the "Glium" crate to use OpenGL, in the process I was trying to do something I had done before in Python when I needed to animate an asset.

In Python to animate an asset I loaded two frames of the same model in two different variables, then I did the keyframe interpolation like this:

frame1 = [0,0,..0,0,0] # The asset weighs around 50,000 points
frame2 = [1,2,..49997,49998,49999]
frame1 = np.array(frame1,np.float32)
frame2 = np.array(frame2,np.float32)
# interpolation
tframe = frame1*(1-time/ANIMATION_DURATION)+frame2*(time/ANIMATION_DURATION)
# And the OpenGL
glBufferSubData(GL_ARRAY_BUFFER, 0, len(tframe)*4, tframe)
# And Draw:
glDrawArrays(GL_TRIANGLES, 0, NUMBER_OF_POINTS)

Using this principle, I was able to get 3D models inside Python and OpenGL to be animated.

But recently I was trying to learn Rust and in the process I ended up discovering the Glium crate, which also uses OpenGL and I started testing things on it and most things worked very well. Until I try to do the interpolation there that I did in Python. To draw in Rust:

#[device(Copy,Clone)]
struct Vertex { position: [f32;3], texcoord:[f32;2] }
implement_vertex!(Vertex,position,texcoord);

And then we create a vector with the struct:

let v1 = Vertex{position:[-0.5,-0.5,0.0],texcoord:[0.0,0.0]};
let v2 = Vertex{position:[0.0,0.5,0.0],texcoord:[0.5,1.0]};
let v3 = Vertex{position:[0.5,-0.5,0.0],texcoord:[1.0,0.0]};
let shape = vec![v1,v2,v3];
let model = glium::VertexBuffer::new(&display, &shape).unwrap();

So we can draw it with the command:

target.draw(&model, &indices, &program, &u, &params).unwrap();

I already managed to make him draw, I already put texture, perspective, my doubt is not that. But how do I interpolate KeyFrames in Rust?

I tried doing it using a for loop, but it wasn't as fast as Python:

let mut vf = Vec::new();
for x in 0..50000{
    vf.push(Vertex{
        position:[
            v1[x].position[0]*(1 - time/DURATION)-v2[x].position[0]*(time/DURATION),
            v1[x].position[1]*(1 - time/DURATION)-v2[x].position[1]*(time/DURATION),
            v1[x].position[2]*(1 - time/DURATION)-v2[x].position[2]*(time/DURATION),
        ],
        texcoord:[
            v1[x].texcoord[0],
            v1[x].texcoord[1],
        ]
    });
}

I googled and even found a crate called interpolation that supposedly talks about this, but it doesn't accept vectors of structs.

I'm still new to Rust and I don't understand much of the language, but can someone tell me how I can get the interpolation thing to work? I'm talking about loading two pieces of information from the same model in different positions and then calculating the linear interpolation between them with a time variable. I just want to know how to make this work in Rust?

Arthur Sally
  • 134
  • 1
  • 10
  • Well you already seem to know how you want to interpolate (just lerp each vertex position coordinate over time, it's right there in your python). Of course you can do exactly that in rust. The simplest way to do that is by looping through your vertices, which it sounds like you've already worked out. – JMAA Apr 02 '22 at 23:57
  • As for "not as fast as python", you've not shown us what you've tried, so we can't tell you if you're doing it inefficiently. However, you're comparing to numpy, which is a specialised C library whose whole aim is to make such vectorised operations extremely fast, a hand-written loop is unlikely to be quite as fast but may be fast enough (again, we can't see the code and you've not shared timings either). – JMAA Apr 02 '22 at 23:59
  • You may want to look into numerical libraries in Rust, for example `nalgebra_glm` has a convenient [lerp function](https://docs.rs/nalgebra-glm/latest/nalgebra_glm/fn.lerp.html). You might want to look into which ones do vectorisation and/or SIMD to make best use of the hardware. Another thing to look at is you're interleaving position and UV coordinates in your vertex data, do you want to internpolate the UVs too? If not, splitting the data will mean you're cutting the data you need to work on by 2/5 ths, which will speed things up. – JMAA Apr 03 '22 at 00:04
  • 1
    A couple more thoughts: you can get interpolation "for free" by doing it in your shader instead. You'll need to pass two sets of vertex positions and set a uniform that contains the mixing parameter, but the calculation will happen on the GPU which will be so fast you won't notice. Lastly, with you "it's not fast enough" loop, have you tried compiling with `--release`? Remember, you're comparing to numpy, which is a highly optimised release binary. – JMAA Apr 03 '22 at 00:08
  • `cargo run --release` ? – hkBst Apr 05 '22 at 13:49

0 Answers0