For example, I have an object that follows mouse horizontally, its minimum position is 100 and the maximum is 200.
Within this range, it follows mouse linearly, meaning 1 unit of mouse position equals to 1 unit of object position.
Now, if the mouse is outside of the range (below 100, or above 200), I want it to start applying friction, so the object gracefully stops the further it is from range, for example:
Mouse position | Object position
200 200
220 205
240 209
260 212
280 215
300 217
320 218
340 219
360 220
380 220
400 220
...
I managed to implement it like this within mouse-move handler:
if (mousePosition > 200 || mousePosition < 100) {
delta = mousePosition - objectPosition;
objectPosition += delta * 0.25; // 0.25 if friction factor
}
But is there a better way? How to implement function outside of mouse-move handler:
getObjectPosition(mousePosition) {
return // ???
}
The question is language agnostic.
You can calculate your the object position as a piecewise function of the mouse position:
getObjectPosition(mousePosition) {
if(mousePosition < 100)
return 100 - friction(100 - mousePosition);
if(mousePosition > 200)
return 200 + friction(mousePosition - 200);
return mousePosition;
}
Where friction is a function to calculate the "soft" function you want. A simple one would be:
friction(x) {
return 0.25*x;
}
which would reduce the object speed by 0.25 when its beyond the [100, 200] bounds. Your function seems to approach some kind of asymptote though. You can achieve it with, for example, a quadratic:
friction(x) {
M = 160;
x = min(x, M);
return x*(1 - x/(2*M));
}
Here the object will gradually slow down, and stop completely when the mouse is outside the [-60, 360] interval.
Related
My problem is when I scroll camera works good but closer to the end its stopping moving smoothly.
At this video I will show how its should work.
I was inspired by this web-site :)
And as I said, I have some little problems..
My glitch code: https://glitch.com/edit/#!/field-polished-border
This how this think is work right now:
gsap.to(camera.position, {
x: 1,
ease: "none",
scrollTrigger:{
trigger: sections[8],
},
})
Your if statements are pretty disorganized, so they eventually start conflicting with each other.
if(scrollTop >= 1400){
// rotate to y: -11
}
else{
// rotate to y: -9.5
}
if(scrollTop >= 3700){
// rotate to y: -12.5
}
This means that when scrollTop reaches 3701, it is both greater than 1400 and 3700, so it'll try to execute both rotations, fighting with each other and giving you glitchy behavior. You should clean up your if statements and make them more organized so they don't contradict each other:
if (scrollTop < 1400){
// rotate to y: -9.5 when less than 1400
}
else if (scrollTop < 3700) {
// rotate to y: -11 when between 1400 and 3700
}
else {
// rotate to y: -12.5 when greater than 3700
}
I'm making an appointments app.
I have this gradient structure (created in Pixelmator), with which I want to mark the times of day:
In the intended scheme, 8am would be solid green, 12 noon would be solid yellow, and 8pm would be solid blue.
I need an algorithm to take the times of day and turn them into those colors, but I can't figure it out, particularly from noon to evening.
These colors are composed using the HSB value system: all colors have S and B at 100%, and from left to right the hue values are 121 (green), 60 (yellow), and 229 (blue).
The progression from the green to yellow is (morning to noon) is straightforward, because it's just a linear scaling from 121 to 60, but from yellow to blue (noon to evening), is not; this is clear if you think about the fact that going from 60 to 229 in a linear fashion would first duplicate the green-to-yellow gradient, just in reverse order, and then would go to from green to blue. In other words, a strictly linear progression would make the gradient look more like this:
Can anyone point me in the right direction to understanding how to make the algorithm I need here? Do I have to use a different color value system, like RGB?
Thanks in advance for any and all help!
Pablo-No gives a reasonable answer if it's OK for the yellow->blue transition to go through red. But the OP's original picture doesn't go through red, it goes through some kind of grey. Perhaps the saturation S should be used to try to achieve this:
// Assume time is a real value between 8 (8am) and 20 (8pm)
// H is between 0 and 360
// S and B are between 0 and 100
B = 255;
if (time < 12)
{
// Before noon, linearly go from H=121 (green) to H=60 (yellow)
H = (time - 8) * (60-121)/4.0 + 121;
S = 100;
}
else
{
// After noon, linearly go from H=60 (green) to H=229 (blue)
// But in the middle, where the color goes green, linearly scale
// Saturation down to zero and back to 100.
H = (time - 12) * (229-60)/8.0 + 60;
auto secondGreenTime = (121-60)*8.0/(229-60) + 12;
if (time < secondGreenTime)
S = (time - 12) * (-100.0)/(secondGreenTime-12) + 100;
else
S = (time - secondGreenTime) * 100.0/(20-secondGreenTime);
}
Pixelmator looks like it's using RGB gradients. Demo:
const canvas = document.getElementById("gradient");
const ctx = canvas.getContext("2d");
for (let i = 0; i < canvas.width; i++) {
const alpha = (i + 0.5) / canvas.width;
const r = 2 * Math.min(alpha, 1 - alpha);
const g = Math.min(1, 2 * (1 - alpha));
const b = Math.max(0, 2 * alpha - 1);
ctx.fillStyle = `rgba(${255*r},${255*g},${255*b})`
ctx.fillRect(i, 0, 1, canvas.height);
}
<canvas id="gradient" width="240" height="40">
Here is an algorithm for that:
Convert the hour to 24 hour and pass minutes and seconds to a fraction or a decimal number (i.e 8:30 -> 8.5, 8:20 -> 25/3)
Substract 8 to the hour (now we have a number from 0 to 12)
If the hour, h, is between 0 and 4 we will do ((-h+4)*(61/4))+60
else we will do ((-h+12)*(191/8))-131
If the value is negative we'll add 360
The value we obtain will be the hue value of the color
I'm trying to make the balls falling at a random speed but the speed is changing only when I reload the page/script, I would like to get a random speed dynamically, one ball comes at 5, the next one 1.4, next 2.6 and so on...
https://codepen.io/Le-future/pen/gKNoEE
I tried to use the following :
// set how fast the objects will fall
var spawnRateOfDescent = Math.random() * (5 - 0.5) + 0.5;
Each ball should have its own unique speed property. You can add it as follows:
First adjustment (lines 72-73):
image: images[Math.floor(Math.random()*images.length)], // add a comma here
speed: Math.random() * 10 + 3 // add this line and tweak the numbers to taste
Second adjustment in your animate function (line 107 [or 108 if you added a line]):
object.y += object.speed; // instead of: object.y += spawnRateOfDescent;
I am trying to make a gauge in Qt Quick that has sections that "light up" from 0 to the needle's position.
One way I can think of doing this is by having an image of the segment and painting it and rotating it many times from code. However, I don't know how this can be done in QML.
It doesn't have to be QML and it doesn't have to be Qt Quick; it could be anything as long as I can use it with Qt and within Qt creator and preferably works accross platforms.
Edit: Made rough sketch but StackOverflow requires me to have 10 reputation to post them, so I am placing links.
No segments illuminated ---------------------------- Some segments illuminated
-
You could easily use a Canvas element to draw an arc stroke with control over its start and end position. Just compose that below the scale of the gauge.
Here is an example how to do that using a value from 0 to 1 to select how "full" the gauge is.
ApplicationWindow {
visible: true
width: 500
height: 500
Canvas {
id: canvas
anchors.fill: parent
rotation: -90
onPaint: {
var c = getContext('2d')
c.clearRect(0, 0, width, height)
c.beginPath()
c.lineWidth = 30
c.strokeStyle = "red"
c.arc(250, 250, 250 - 15, 0, Math.PI * 2 * circ.value)
c.stroke()
}
}
Slider {
id: circ
minimumValue: 0
maximumValue: 1
value: maximumValue / 2
onValueChanged: canvas.requestPaint()
}
}
As requested by Mitch, I explain - the canvas is rotated at 90 CCW degree because of the way Qt draws arcs - they do not start at "12 o'clock" but at 3. You can remove the rotation of the canvas just in case you might want to draw extra stuff, cuz you wouldn't want to make all your drawing offset at 90 degree just to sit right with the rotated canvas, all you need to do to get rid of the rotation is draw the arc in range -Math.PI * 0.5 to Math.PI * 1.5 to account for the art starting at 3 o'clock.
I am doing frame based animation for 300 frames in opengl es 2.0
I want a rectangle to translate by +200 pixels in X axis and also scaled up by double (2 units) in the first 100 frames.
For example, the initial value (frame 0) of the rectangle's centre point is at 100 pixels (i.e. rectCenterX = 100) on the screen;
At 100th frame, rectCenterX = 300 (100 + 200) pixels. Also the rect size is doubled the original size.
Then, the animated rectangle has to stay there for the next 100 frames (without any animation). i.e. the rectCenterX = 300 pixels for frames 101 to 200.
At 101st frame, rectCenterX = 300 pixels. the rect size is double the original size.
At 200th frame, rectCenterX = 300 pixels. the rect size is double the original size.
Then, I want the same animated rectangle to translate by +200 pixels in X axis and also scaled down by half (0.5 units) in the last 100 frames.
At 300th frame, rectCenterX = 500 pixels.the rect size is again as the original size.
I am using simple linear interpolation to calculate the delta-animation value for each frame.
In short,
Animation-Type Animation-Value Start-Frame End-Frame
1.Translate +200 0 100
2.Scale +2 0 100
3.Translate +200 201 300
4.Scale +0.5 201 300
Pseudo code:
The below drawFrame() is executed for 300 times (300 frames) in a loop.
float RectMVMatrix[4][4] = {1, 0, 0, 0,
0, 1, 0, 0,
0, 0, 1, 0,
0, 0, 0, 1
}; // identity matrix
int totalframes = 300;
float translate-delta; // interpolated translation value for each frame
float scale-delta; // interpolated scale value for each frame
// The usual code for draw is:
void drawFrame(int iCurrentFrame)
{
// mySetIdentity(RectMVMatrix); // comment this line to retain the animated position.
mytranslate(RectMVMatrix, translate-delta, X_AXIS); // to translate the mv matrix in x axis by translate-delta value
myscale(RectMVMatrix, scale-delta); // to scale the mv matrix by scale-delta value
... // opengl calls
glDrawArrays(...);
eglswapbuffers(...);
}
The above code will work fine for first 100 frames. in order to retain the animated rectangle during the frames 101 to 200, i removed the "mySetIdentity(RectMVMatrix);" in the above drawFrame().
Now on entering the drawFrame() for the 2nd frame, the RectMVMatrix will have the animated value of first frame
e.g. RectMVMatrix[4][4] = { 1.01, 0, 0, 2,
0, 1, 0, 0,
0, 0, 1, 0,
0, 0, 0, 1
};// 2 pixels translation and 1.01 units scaling after first frame
This RectMVMatrix is used for mytranslate() in 2nd frame. The translate function will affect the value of "RectMVMatrix[0][0]". Thus translation affects the scaling values also.
Eventually output is getting wrong.
How to retain the animated position without affecting the current ModelView matrix?
Although a direct answer would be to save the matrix you will need later I need to propose a different system as yours is extremely unclean and even if you make it for this animation you might have problems maintaining this code, adding animations or changing it.
To have an object animatable in terms of position, scale, rotations or even whole matrix I suggest you to create each of those parameters in the object itself (on the CPU) then on each and every frame set the matrix to identity and then recreate it from the parameters the object owns.
So for instance an object would have a vector called position which is animatable. What you need is hold 3 position parameters as in positionCurrent, positionStart, positionEnd. Now on the object you should call something like animateWithFrameCount As this method is called you need to set:
positionStart = positionCurrent;
positionEnd = input;
currentFrame = 0;
frameCount = inputFrameCount;
Then implement a method such as onFrame where
currentFrame++;
positionCurrent = positionStart + (positionEnd-positionStart)*(currentFrame/frameCount); //linear interpolation
if(currentFrame >= frameCount) {
currentFrame = 0;
frameCount = 0;
positionStart = currentPosition = positionEnd;
}
If you implement this system for all animatable parameters you want all you now need is get the model matrix which again should be a models method (pseudocode):
Matrix16f getModelMatrix {
Matrix16f toReturn = Matrix16f.identity();
toReturn.translate(currentPosition);
toReturn.scale(currentScale);
...
return toReturn;
}
So now your drawFrame becomes quite straight forward. On all your models you need to call onFrame, set the matrix to identity (or maybe some other matrix), multiply the current matrix with the one received from the model and then just draw the thing. No issues with retaining, no conditional statements in your main code...