Related
For example simple fragment shader for circle points:
void main()
{
float size = 0.5;
vec2 center = vec2(0.5);
vec2 d = gl_PointCoord - center;
float distSquared = dot(d, d);
if(distSquared < size * size)
gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);
else
discard;
}
Here gl_PointCoord always vec2(0.0, 0.0) because it requests glEnable(GL_POINT_SPRITE) but how enable that for QtQuick?
I'm trying to learn how to use react-spring. Let's say that I have three divs to animate.
<a.div style={trans1}>
<a.div style={trans2}>
<a.div style={trans3}>
and trans1 has the following configuration…
const [clicked, toggle] = useState(null)
const { x } = useSpring({
from: { x: 0 },
x: clicked ? 1 : 0,
config: { duration: 500 },
})
const trans1 = {
transform: x
.interpolate({
range: [0, 0.25, 0.35, 0.45, 0.55, 0.65, 0.75, 1],
output: [1, 0.97, 0.9, 1.1, 0.9, 1.1, 1.03, 1],
})
.interpolate((x) => `scale(${x})`),
}
What's the best way to implement the same type of animation on the second and third divs without duplicating all that code? How do I make multiple instances of the same spring for use on multiple Dom objects without triggering them all at the same time? I certainly don't want to duplicate a full set of code for each item, right?
Do I need to create a function that accepts a parameter that can switch the arguments in the config on the fly? 🤷🏽♂️
Any help is appreciated.
Here's a live example: https://codesandbox.io/s/optimistic-bassi-brnle
How do I make the left & right sides animate one at a time without creating duplicate code?
The first possibility would be to separate the style and give it to more than one div. Its drawback is, that they would behave exactly the same at the same time.
const style = {
opacity: x.interpolate({ range: [0, 1], output: [0.3, 1] }),
transform: x
.interpolate({
range: [0, 0.25, 0.35, 0.45, 0.55, 0.65, 0.75, 1],
output: [1, 0.97, 0.9, 1.1, 0.9, 1.1, 1.03, 1]
})
.interpolate(x => `scale(${x})`)
};
return (
<div onClick={() => toggle(!state)}>
<animated.div
style={style}>
click
</animated.div>
<animated.div
style={style}>
click
</animated.div>
</div>
)
The second option is, that you create a new component with the click and spring logic. This way you write the logic once and you can use it multiple time. I introduced a text attribute also to make different text for the component.
const AnimText = ({text}) => {
const [state, toggle] = useState(true)
const { x } = useSpring({ from: { x: 0 }, x: state ? 1 : 0, config: { duration: 1000 } })
return (
<div onClick={() => toggle(!state)}>
<animated.div
style={{
opacity: x.interpolate({ range: [0, 1], output: [0.3, 1] }),
transform: x
.interpolate({
range: [0, 0.25, 0.35, 0.45, 0.55, 0.65, 0.75, 1],
output: [1, 0.97, 0.9, 1.1, 0.9, 1.1, 1.03, 1]
})
.interpolate(x => `scale(${x})`)
}}>
{text}
</animated.div>
</div>
)
}
function Demo() {
return (
<div>
<AnimText text={'click1'}/>
<AnimText text={'click2'}/>
<AnimText text={'click3'}/>
</div>
)
}
here is the example: https://codesandbox.io/s/divine-water-n1b6x
After reading through the documentation, I'm still a bit confused on how to execute an animation after another one has completed. I have a timeline like so:
timeline {
keyframe(Duration.seconds(0.5)) {
keyvalue(firstImg.scaleXProperty(), 1.0, interpolator = Interpolator.EASE_BOTH)
keyvalue(firstImg.scaleYProperty(), 1.0, interpolator = Interpolator.EASE_BOTH)
keyvalue(firstImg.rotateProperty(), 0.0, interpolator = Interpolator.EASE_BOTH)
}
keyframe(Duration.seconds(0.5)) {
keyvalue(secondImg.scaleXProperty(), 1.0, interpolator = Interpolator.EASE_BOTH)
keyvalue(secondImg.scaleYProperty(), 1.0, interpolator = Interpolator.EASE_BOTH)
keyvalue(secondImg.rotateProperty(), 0.0, interpolator = Interpolator.EASE_BOTH)
}
keyframe(Duration.seconds(0.5)) {
keyvalue(thirdImg.scaleXProperty(), 1.0, interpolator = Interpolator.EASE_BOTH)
keyvalue(thirdImg.scaleYProperty(), 1.0, interpolator = Interpolator.EASE_BOTH)
keyvalue(thirdImg.rotateProperty(), 0.0, interpolator = Interpolator.EASE_BOTH)
}
keyframe(Duration.seconds(0.5)) {
keyvalue(fourthImg.scaleXProperty(), 1.0, interpolator = Interpolator.EASE_BOTH)
keyvalue(fourthImg.scaleYProperty(), 1.0, interpolator = Interpolator.EASE_BOTH)
keyvalue(fourthImg.rotateProperty(), 0.0, interpolator = Interpolator.EASE_BOTH)
}
}
This runs them all at once, but I would like to run each animation after the other one has finished! I can't quite figure out how to do this.. (sorry if this is obvious, I am very new to Kotlin and Java in general!)
I see that the keyframe has an onFinished property but I can't quite figure out what I'm supposed to actually set it to. Is there a better way to do this? Thank you!
Based on the structure proposed by #tornadofx-fan I've added builders for sequentialTransition and parallelTransition, so starting from TornadoFX 1.7.9 you can do the same like this:
class TransitionViews: View() {
val r1 = Rectangle(20.0, 20.0, Color.RED)
val r2 = Rectangle(20.0, 20.0, Color.YELLOW)
val r3 = Rectangle(20.0, 20.0, Color.GREEN)
val r4 = Rectangle(20.0, 20.0, Color.BLUE)
override val root = vbox {
button("Animate").action {
sequentialTransition {
timeline {
keyframe(0.5.seconds) {
keyvalue(r1.translateXProperty(), 50.0, interpolator = Interpolator.EASE_BOTH)
}
}
timeline {
keyframe(0.5.seconds) {
keyvalue(r2.translateXProperty(), 100.0, interpolator = Interpolator.EASE_BOTH)
}
}
timeline {
keyframe(0.5.seconds) {
keyvalue(r3.translateXProperty(), 150.0, interpolator = Interpolator.EASE_BOTH)
}
}
timeline {
keyframe(0.5.seconds) {
keyvalue(r4.translateXProperty(), 200.0, interpolator = Interpolator.EASE_BOTH)
}
}
}
}
pane {
add(r1)
add(r2)
add(r3)
add(r4)
}
}
}
The timeline builder inside of these transitions don't automatically play, while the transition itself automatically plays when the builder is completed. You can pass play=false to the transition builder to disable autoplay.
Also note the usage of 0.5.seconds to generate the Duration objects :)
There's a JavaFX class "SequentialTransition" that will run your timelines in sequence. You'll need to disable the TornadoFX autoplay with a flag passed into the timeline builder. Check out ParallelTransition if you want to run these all at once using a similar coding pattern.
class STTest : View("My View") {
val r1 = Rectangle(20.0, 20.0, Color.RED)
val r2 = Rectangle(20.0, 20.0, Color.YELLOW)
val r3 = Rectangle(20.0, 20.0, Color.GREEN)
val r4 = Rectangle(20.0, 20.0, Color.BLUE)
override val root = vbox {
button("Animate") {
setOnAction {
val t1 = timeline(false) {
keyframe(Duration.seconds(0.5)) {
keyvalue(r1.translateXProperty(), 50.0, interpolator = Interpolator.EASE_BOTH)
}
}
val t2 = timeline(false) {
keyframe(Duration.seconds(0.5)) {
keyvalue(r2.translateXProperty(), 100.0, interpolator = Interpolator.EASE_BOTH)
}
}
val t3 = timeline(false) {
keyframe(Duration.seconds(0.5)) {
keyvalue(r3.translateXProperty(), 150.0, interpolator = Interpolator.EASE_BOTH)
}
}
val t4 = timeline(false) {
keyframe(Duration.seconds(0.5)) {
keyvalue(r4.translateXProperty(), 200.0, interpolator = Interpolator.EASE_BOTH)
}
}
/* functions look better
val st = SequentialTransition()
st.children += t1
st.children += t2
st.children += t3
st.children += t4
st.play()
*/
t1.then(t2).then(t3).then(t4).play()
}
}
pane {
add(r1)
add(r2)
add(r3)
add(r4)
}
}
}
In this case where you're just setting scales and rotations, there are some nice helpers already in the library. This should work for you:
val time = 0.5.seconds
firstImg.scale(time, Point2D(1.0, 1.0), play = false).and(firstImg.rotate(time, 0.0, play = false))
.then(secondImg.scale(time, Point2D(1.0, 1.0), play = false).and(secondImg.rotate(time, 0.0, play = false)))
.then(thirdImg.scale(time, Point2D(1.0, 1.0), play = false).and(thirdImg.rotate(time, 0.0, play = false)))
.then(fourthImg.scale(time, Point2D(1.0, 1.0), play = false).and(fourthImg.rotate(time, 0.0, play = false)))
.play()
The play = false everywhere is required since these helpers were designed for simple one-off auto-playing animations.
Edit
After a discussion in Slack, these may be simplified in a future release, so the above may eventually be as easy as
val time = 0.5.seconds
listOf(
firstImg.scale(time, 1 p 1) and firstImg.rotate(time, 0),
secondImg.scale(time, 1 p 1) and secondImg.rotate(time, 0),
thirdImg.scale(time, 1 p 1) and thirdImg.rotate(time, 0),
fourthImg.scale(time, 1 p 1) and fourthImg.rotate(time, 0)
).playSequential()
Watch the release notes for more info!
Another Edit
Looks like I was over complicating things a bit. You can just use this if you like it more:
val time = 0.5.seconds
SequentialTransition(
firstImg.scale(time, Point2D(1.0, 1.0), play = false).and(firstImg.rotate(time, 0.0, play = false)).
secondImg.scale(time, Point2D(1.0, 1.0), play = false).and(secondImg.rotate(time, 0.0, play = false)),
thirdImg.scale(time, Point2D(1.0, 1.0), play = false).and(thirdImg.rotate(time, 0.0, play = false)),
fourthImg.scale(time, Point2D(1.0, 1.0), play = false).and(fourthImg.rotate(time, 0.0, play = false))
).play()
I am attempting to use the AdditiveUnscentedKalman filter from pykalman. I am given noisy x,y values, and I am trying to get the x,y,xdot,ydot out of the filter.
I am getting values out of the filter, but it is not what I expect.
State: [[ 481.65737052 477.23904382 0. 0. ]
[ 659.29999618 659.28265402 58.33365188 59.77883149]]
Obs: [478, 660, -0.4666666666666667, -0.36666666666666664, -2.4756234162106834, 1.2145259141964182]
The obs[0] and obs[1] are the measured x y and state is what is coming out of the filter. state[0][0] and state[1][0] look to be an x,y and state[0][1] and state[1][1] seem to be an x,y. I have no idea what they other numbers are supposed to be by they are not acceptable velocities.
If someone could just validate that I have am using the correct transition function it would be greatly appreciated.
transition_covariance = np.array([[100.0, 0.0, 0.0, 0.0],
[0.0, 100.0, 0.0, 0.0],
[0.0, 0.0, 100.0, 0.0],
[0.0, 0.0, 0.0, 100.0]])
observation_covariance = np.array([[0.4, 0.0],
[0.0, 0.4]])
initial_state_covariance = np.array([[100.0, 0.0, 0.0, 0.0],
[0.0, 100.0, 0.0, 0.0],
[0.0, 0.0, 1000.0, 0.0],
[0.0, 0.0, 0.0, 1000.0]])
self.ukf = AdditiveUnscentedKalmanFilter(transition_functions = self.transition_function,
observation_functions = self.observation_function,
transition_covariance = transition_covariance,
observation_covariance = observation_covariance,
initial_state_mean = initial_conditions,
initial_state_covariance = initial_state_covariance)
def get_states(self, observations):
return self.ukf.filter(observations)
# [x, y, xvel, yvel]
def transition_function(self, state):
return np.array([state[0] + state[2] * self.dt,
state[1] + state[3] * self.dt,
state[2],
state[3]])
def observation_function(self, state):
om = np.array([[1.0, 0.0, 0.0, 0.0],
[0.0, 1.0, 0.0, 0.0]])
return np.matmul(om, state)
I am confused because the output of the .filter call is a matrix of 2X4 where I would expect a 1X4.
So I am in dire need of a code read through, if someone would be so kind- I have no idea where a fault can come from- I've been comparing this code to the code from the tutorial here:
http://learningwebgl.com/lessons/lesson05/index.html
and have looked through both about 10 times- I just don't know...Need some help from the pros... Just trying to texture a square, without any of the 3d stuff that I don't care for at the moment-
<script id="shader-fs" type="x-shader/x-fragment">
precision mediump float;
varying vec2 vTextureCoord;
uniform sampler2D uSampler;
void main(void) {
gl_FragColor = texture2D(uSampler, vec2(vTextureCoord.s, vTextureCoord.t));
// gl_FragColor= vec4(0.0, 1.0, 0.0, 1.0);
}
</script>
<script id="shader-vs" type="x-shader/x-vertex">
attribute vec3 aVertexPosition;
attribute vec2 aTextureCoord;
uniform mat4 uMVMatrix;
uniform mat4 uPMatrix;
varying vec2 vTextureCoord;
void main(void) {
gl_Position = uPMatrix * uMVMatrix * vec4(aVertexPosition, 1.0);
vTextureCoord = aTextureCoord;
}
</script>
<script type="text/javascript">
var gl;
function initGL(canvas) {
try {
gl = canvas.getContext("experimental-webgl");
gl.viewportWidth = canvas.width;
gl.viewportHeight = canvas.height;
} catch (e) {
}
if (!gl) {
alert("Could not initialise WebGL, sorry :-(");
}
}
function getShader(gl, id) {
var shaderScript = document.getElementById(id);
if (!shaderScript) {
return null;
}
var str = "";
var k = shaderScript.firstChild;
while (k) {
if (k.nodeType == 3) {
str += k.textContent;
}
k = k.nextSibling;
}
var shader;
if (shaderScript.type == "x-shader/x-fragment") {
shader = gl.createShader(gl.FRAGMENT_SHADER);
} else if (shaderScript.type == "x-shader/x-vertex") {
shader = gl.createShader(gl.VERTEX_SHADER);
} else {
return null;
}
gl.shaderSource(shader, str);
gl.compileShader(shader);
if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {
alert(gl.getShaderInfoLog(shader));
return null;
}
return shader;
}
var shaderProgram;
function initShaders() {
var fragmentShader = getShader(gl, "shader-fs");
var vertexShader = getShader(gl, "shader-vs");
shaderProgram = gl.createProgram();
gl.attachShader(shaderProgram, vertexShader);
gl.attachShader(shaderProgram, fragmentShader);
gl.linkProgram(shaderProgram);
if (!gl.getProgramParameter(shaderProgram, gl.LINK_STATUS)) {
alert("Could not initialise shaders");
}
gl.useProgram(shaderProgram);
shaderProgram.vertexPositionAttribute = gl.getAttribLocation(shaderProgram, "aVertexPosition");
gl.enableVertexAttribArray(shaderProgram.vertexPositionAttribute);
shaderProgram.textureCoordAttribute=gl.getAttribLocation(shaderProgram, "aTextureCoord");
gl.enableVertexAttribArray(shaderProgram.textureCoordAttribute); //**
shaderProgram.samplerUniform= gl.getUniformLocation(shaderProgram, "uSampler");
shaderProgram.pMatrixUniform = gl.getUniformLocation(shaderProgram, "uPMatrix");
shaderProgram.mvMatrixUniform = gl.getUniformLocation(shaderProgram, "uMVMatrix");
}
var mvMatrix = mat4.create();
var pMatrix = mat4.create();
function setMatrixUniforms() {
gl.uniformMatrix4fv(shaderProgram.pMatrixUniform, false, pMatrix);
gl.uniformMatrix4fv(shaderProgram.mvMatrixUniform, false, mvMatrix);
}
var triangleVertexPositionBuffer;
var squareVertexPositionBuffer;
function initBuffers() {
squareVertexPositionBuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, squareVertexPositionBuffer);
vertices = [
1.0, 1.0, 0.0,
-1.0, 1.0, 0.0,
1.0, -1.0, 0.0,
-1.0, -1.0, 0.0
];
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertices), gl.STATIC_DRAW);
squareVertexPositionBuffer.itemSize = 3;
squareVertexPositionBuffer.numItems = 4;
squareTexPositionBuffer=gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, squareTexPositionBuffer);
texvert= [1.0, 0.0,
0.0, 0.0,
1.0, 1.0,
0.0, 1.0];
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(texvert), gl.STATIC_DRAW);
squareTexPositionBuffer.itemSize=2;
squareTexPositionBuffer.numItems=4;
}
function drawScene() {
gl.viewport(0, 0, gl.viewportWidth, gl.viewportHeight);
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
mat4.perspective(45, gl.viewportWidth / gl.viewportHeight, 0.1, 100.0, pMatrix);
mat4.identity(mvMatrix);
mat4.translate(mvMatrix, [-2.0, 0.0, -7.0]);
mat4.translate(mvMatrix, [3.0, 0.0, 0.0]);
gl.bindBuffer(gl.ARRAY_BUFFER, squareVertexPositionBuffer);
gl.vertexAttribPointer(shaderProgram.vertexPositionAttribute, squareVertexPositionBuffer.itemSize, gl.FLOAT, false, 0, 0);
gl.bindBuffer(gl.ARRAY_BUFFER, squareTexPositionBuffer);
gl.vertexAttribPointer(shaderProgram.textureCoordAttribute, squareTexPositionBuffer.itemSize, gl.FLOAT, false, 0, 0);
gl.activeTexture(gl.TEXTURE0);
gl.bindTexture(gl.TEXTURE_2D, neheTexture);
gl.uniform1i(shaderProgram.samplerUniform, 0);
setMatrixUniforms();
gl.drawArrays(gl.TRIANGLE_STRIP, 0, squareVertexPositionBuffer.numItems);
}
function handleLoadedTexture(texture) {
gl.bindTexture(gl.TEXTURE_2D, texture);
gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, true);
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, texture.image);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
gl.bindTexture(gl.TEXTURE_2D, null);
}
var neheTexture;
function initTexture(){
neheTexture = gl.createTexture();
neheTexture.image = new Image();
neheTexture.image.onload = function() {
handleLoadedTexture(neheTexture)
}
neheTexture.image.src = "nehe.gif";
}
function webGLStart() {
var canvas = document.getElementById("lesson01-canvas");
initGL(canvas);
initShaders();
initBuffers();
initTexture();
gl.clearColor(0.0, 0.0, 0.0, 1.0);
gl.enable(gl.DEPTH_TEST);
drawScene();
}
</script>
Texture won't be loaded immediately.
This is not a problem when you have an animation, because the scene will be rendered with blank texture while it's not fully loaded, and once it is the objects will become textured. You don't have animation, only one drawing call, that executes before fully loading image.
So after you load image you should make another drawing call, so the scene is drawn with texture.
So something like:
neheTexture.image.onload = function() {
handleLoadedTexture(neheTexture);
drawScene(); // <- now draw scene again, once I got my texture
}
Hope this helps. :)
Here's kind of a follow up question- Let's say I wanted to have two different shapes- one with a color buffer and another with a texture buffer, how woud I write that code out in the shaders since the tutorials made it almost like you could only have one or the other, but not both?
So like in the following code, I have something for the texture and something to make the color blue in another line of code- how would I make that differentiation in this language- I tried using ints to symbolize the choice between the two but it didn't work out very well...
<script id="shader-fs" type="x-shader/x-fragment">
precision mediump float;
varying vec2 vTextureCoord;
uniform sampler2D uSampler;
void main(void) {
gl_FragColor = texture2D(uSampler, vec2(vTextureCoord.s, vTextureCoord.t));
// gl_FragColor= vec4(0.0, 1.0, 0.0, 1.0);
}
</script>