adjusting amplitude modulation / wave shaping - math

I have some working code that does amplitude modulation and plots it.
However I'm trying to change the way the modulation looks (the y variable)
so it looks like an egg shape. I found an equation/website that looks good
http://www16.ocn.ne.jp/~akiko-y/Egg/index_egg_E.html
but I'm not to sure how to convert that into matlab/octave code to change the y variable
%test_amplitude modultaion
fs=1000;
t=linspace(0,2*pi,fs);
mt=1*sin(100*t); %signal you want to use
y=mt.*(1+cos(1*t+pi));%modulation equation, use pi to shift over 90 deg to start at 0
y=y';
y_norm=(y(:,1)/max(abs(y(:,1)))*.8); %normalize signal
plot(y_norm)
PS: this is matlab/octave code

Using the equations given on the page you linked:
a = 2*pi;
b = a; % change this depending on the shape of the egg you want
mt=1*sin(100*t); %signal you want to use
y = mt.*sqrt((a-b)-2*t + sqrt(4*b*t + (a-b)^2)).*sqrt(t)/sqrt(2); % modulation
The rest of your code is A-OK, although I would probably use plot(t,y_norm) at the end.

Related

3D Projection Modification - Encode Z/W into Z

This is a little tricky to explain, so bare with me. I'm attempting to design a 2D projection matrix that takes 2D pixel coordinates along with a custom world-space depth value, and converts to clip-space.
The idea is that it would allow drawing elements based on screen coordinates, but at specific depths, so that these elements would interact on the depth buffer with normal 3D elements. However, I want x and y coordinates to remain the same scale at every depth. I only want depth to influence the depth buffer, and not coordinates or scale.
After the vertex shader, the GPU sets depth_buffer=z/w. However, it also scales x/w and y/w, which creates the depth scaling I want to avoid. This means I must make sure my final clip-space w coordinate ends up being 1.0, to avoid those things. I think I could also adopt to scale x and y by w, to cancel out the divide, but I would rather do the former, if possible.
This is the process that my 3D projection matrix uses to convert depth into clip space (d = depth, n = near distance, f = far distance)
z = f/(f-n) * d + f/(f-n) * -n;
w = d;
This is how I would like to setup my 2D projection matrix. Compared to the 3D version, it would divide both attributes by the input depth. This would simulate having z/w encoded into just the z value.
z = ( f/(f-n) * d + f/(f-n) * -n ) / d;
w = d / d;
I think this turns into something like..
r = f/(f-n); // for less crazy math
z = r + ( r * -n ) / d;
w = 1.0;
However, I can't seem to wrap my math around the values that I would need to plug into my matrix to get this result. It looks like I would need to set my matrix up to perform a division by depth. Is that even possible? Can anyone help me figure out the values I need to plug into my matrix at m[2][2] and m[3][2] (m._33 and m._43) to make something like this happen?
Note my 3D projection matrix uses the following properties to generate the final z value:
m._33 = f / (f-n); // depth scale
m._43 = -(f / (f-n)) * n; // depth offset
Edit: After thinking about this a little more, I realized that the rate of change of the depth buffer is not linear, and I'm pretty sure a matrix can only perform linear change when its input is linear. If that is the case, then what I'm trying to do wouldn't be possible. However, I'm still open to any ideas that are in the same ball park, if anyone has one. I know that I can get what I want by simply doing pos.z /= pos.w; pos.w = 1; in the vertex shader, but I was really hoping to make it all happen in the projection matrix, if possible.
In case anyone is attempting to do this, it cannot be done. Without black magic, there is apparently no way to divide values with a matrix, unless of course the diviser is a constant or etc, where you can swap out a scaler with 1/x. I resorted to performing the operation in the shader in the end.

Dot product of a sinusoid with a complex tone in Octave

I am trying to figure out how to solve this problem;
Now make a new sinusoid with amplitude 1 and frequency 1000Hz.
Calculate the dot product of this sinusoid with your complex tone
using vector multiplication between the heterodyne and the transposed
complex tone signal.
So far no good. I have managed to represent a complex tone by:
octave:65> t = [0 : 441];
octave:68> A = 0.25;
octave:69> x = A*sin(2*pi*t*441) + A*sin(2*pi*t*882) + A*sin(2*pi*t*1323) + A*sin(1764*pi*t*2);
And the new sinusoid
octave:66> y = sin(pi*2*t*1000);
Now I find myself trapped with the heterodyne concept and its application. I can tell that the vector multiplication would be like;
octave:75> abs(y*x')
However, parameter 'y' which needs to be the the heterodyne of 'y'(I guess), is driving me nuts...
Any suggestion would be appreciated

making a sine wave steeper?

I've written a a little function that gives me out a value based on a sine wave when I put in a float between 0 and 1. I'm using it to lerp things around in a game.
public static class Utilities
{
public static float SineMe(float prop)
{
float output = (prop*180f)-90f;
output = Mathf.Sin(output*Mathf.Deg2Rad);
output = (output+1f)/2f;
return output;
}
}
It works fine.. But I was wondering is there a mathematical way of altering the sine wave so I can make it 'steeper' or 'shallower' in the middle?
In the diagram below the blue curve is a sine wave, I'm wondering if I can make it more like the green line.
What you're showing already isn't really sine - the range of sine is between -1 and +1. You're applying the linear function f(x) = (x+1)/2 to change that range. So place another function between the sine and that transform.
To change the shape, you need a non-linear function. So, here's a cubic equation you might try...
g(x) = Ax^3 + Bx^2 + Cx + D
D = 0
C = p
B = 3 - 3C
A = 1 - (B + C)
The parameter p should be given a value between 0.0 and 9.0. If it's 1.0, g(x) is the identity function (the output is the unmodified input). With values between 0.0 and 1.0, it will tend to "fatten" your sine wave (push it away from 0.0 and towards 1.0 or -1.0) which is what you seem to require.
I once "designed" this function as a way to get "fractal waveforms". Using values of p between 1.0 and 9.0 (and particularly between around 3.0 and 6.0) iterative application of this formula is chaotic. I stole the idea from the population fluctuation modelling chaotic function by R. M. May, but that's a quadratic - I wanted something symmetric, so I needed a cubic function. Not really relevant here, and a pretty aweful idea as it happens. Although you certainly get chaotic waveforms, what that really means is huge problems with aliassing - change the sample rate and you get a very different sound. Still, without the iteration, maybe this will give you what you need.
If you iterate enough times with p between 0.0 and 1.0, you end up with a square wave with slightly rounded corners.
Most likely you can just choose a value of p between 0.0 and 1.0, apply that function once, then apply your function to change the range and you'll get what you want.
By the way, there's already a comment suggesting a cheat sheet of "easing functions". "Easing" is a term from animation, and computer animation software often uses Bezier curves for that purpose - the same Bezier curves that vector graphics software often uses. Bezier curves come in quadratic and cubic variants, with cubic being the more common. So what this is doing probably isn't that different. However, cubic Bezier easing gives you more control - you can control the "ease-in" independently of the "ease-out", where my function only provides one parameter.
You can use the y(x) = 1-(1-x)^n function when x = [0..1], as a transform function.
You will just have to replace x by the absolute value of your sinus and report the sign of sinus to the result. In that way you can tweak the sinus slope by increasing n. So what you want is this:
float sinus = Mathf.Sin(output*Mathf.Deg2Rad);
int sign = (sinus >= 0 ? 1 : -1);
int n = 4; // slope parameter
float waveform = sign * ( 1-Mathf.Pow(1-Mathf.Abs(sinus), n) );
You can root the sine function to make it steeper (only working for positive values). The higher the root, the steeper the sine.
Graph of a steeper sine wave function
I discovered this nifty trick for a steeper sine wave (0..1).
f(x) = cos(sin(x)^3)^10
If you need (-1..1):
2 * (f(x) - 0.5)
I think I found the solution.
(0.5+sin(x*π-π/2)/2)^((2*(1-x))^k)
in the interval x = [0.0, 1.0]
with k that control the steepness.
k=0.0 for the unmodified sinus (purple)
k=1.0 (green)
k=2.0 (blue)
https://www.desmos.com/calculator/wdtfsassev
I was looking for a similar function, not for the whole sine but just half the period.
I bumped into the Logistic function:
f(x) = L / (1 + e^(-k(x-x0)))
where
e = the natural logarithm base (also known as Euler's number),
x0 = the x-value of the sigmoid's midpoint,
L = the curve's maximum value, and
k = the steepness of the curve.
See https://en.wikipedia.org/wiki/Logistic_function
Works for me
what about
sign(sin(x))*sqrt(abs(sin(x))
https://www.desmos.com/calculator/5nn34xqkfr

Generating rolling hills of different height and width like Tiny Wings?

How can I generate rolling hills of different height and width like Tiny Wings? Right now I'm using sin() but it obviously generates uniform hills repeating forever and ever.
What's the secret?
Thanks!
Certainly not a procedural generation expert - but you could try additively combining multiple randomly generate sin/cos functions with different periods. The more you add, the more random seeming it will be.
Something like this.
Simplex noise, or any other 2d noise function that looks the way you like.
If you're set on accomplishing this with sine waves to create this variation, here's a basic overview of how to manipulate the sine function:
Say you have an x axis, a y axis, and a sine wave y = sin(x)
y = sin(x * 0.5) makes the sine wave cross the x axis half as often (frequency)
y = 0.5 * sin(x) makes the sine wave reach a height half as high (amplitude)
y = 0.5 + sin(x) moves the central axis of the sine wave up the y axis by 0.5 (translation / offset)
Using these three properties, you can construct a wide variety of different looking waves.
Now, the trick is you'll have to overlay these waves to create variation over time. An easy way to do this is to just add the waves together,
y = sin(x * 0.5) + 0.5 * sin(x) + (0.5 + sin(x))
Or, you could define different waves over a specific subset of the x axis, and create a piecewise function. This may be more controllable / art-directable:
y = {
sin(x * 0.5) for x in (0, 5],
0.5 * sin(x) for x in (5, 10],
0.5 + sin(x) for x in (10, 5] }
However, f you try this, you'll notice this produces discontinuities in your wave. You should investigate different blending options (look up linear blending first) to see if you can create smooth transitions between these piecewise functions.
BUT, in my opinion, you should also investigate spline curves and see if they would accomplish what you want. Splines are well documented part of graphics and game programming, so it would be easy to implement (or grab someone else's code), and might provide a more intuitive way to author your levels (Generate a random set of points representing knots/control points, and pass a spline through it).

I've got my 2D/3D conversion working perfectly, how to do perspective

Although the context of this question is about making a 2d/3d game, the problem i have boils down to some math.
Although its a 2.5D world, lets pretend its just 2d for this question.
// xa: x-accent, the x coordinate of the projection
// mapP: a coordinate on a map which need to be projected
// _Dist_ values are constants for the projection, choosing them correctly will result in i.e. an isometric projection
xa = mapP.x * xDistX + mapP.y * xDistY;
ya = mapP.x * yDistX + mapP.y * yDistY;
xDistX and yDistX determine the angle of the x-axis, and xDistY and yDistY determine the angle of the y-axis on the projection (and also the size of the grid, but lets assume this is 1-pixel for simplicity).
x-axis-angle = atan(yDistX/xDistX)
y-axis-angle = atan(yDistY/yDistY)
a "normal" coordinate system like this
--------------- x
|
|
|
|
|
y
has values like this:
xDistX = 1;
yDistX = 0;
xDistY = 0;
YDistY = 1;
So every step in x direction will result on the projection to 1 pixel to the right end 0 pixels down. Every step in the y direction of the projection will result in 0 steps to the right and 1 pixel down.
When choosing the correct xDistX, yDistX, xDistY, yDistY, you can project any trimetric or dimetric system (which is why i chose this).
So far so good, when this is drawn everything turns out okay. If "my system" and mindset are clear, lets move on to perspective.
I wanted to add some perspective to this grid so i added some extra's like this:
camera = new MapPoint(60, 60);
dx = mapP.x - camera.x; // delta x
dy = mapP.y - camera.y; // delta y
dist = Math.sqrt(dx * dx + dy * dy); // dist is the distance to the camera, Pythagoras etc.. all objects must be in front of the camera
fac = 1 - dist / 100; // this formula determines the amount of perspective
xa = fac * (mapP.x * xDistX + mapP.y * xDistY) ;
ya = fac * (mapP.x * yDistX + mapP.y * yDistY );
Now the real hard part... what if you got a (xa,ya) point on the projection and want to calculate the original point (x,y).
For the first case (without perspective) i did find the inverse function, but how can this be done for the formula with the perspective. May math skills are not quite up to the challenge to solve this.
( I vaguely remember from a long time ago mathematica could create inverse function for some special cases... could it solve this problem? Could someone maybe try?)
The function you've defined doesn't have an inverse. Just as an example, as user207422 already pointed out anything that's 100 units away from the camera will get mapped to (xa,ya)=(0,0), so the inverse isn't uniquely defined.
More importantly, that's not how you calculate perspective. Generally the perspective scaling factor is defined to be viewdist/zdist where zdist is the perpendicular distance from the camera to the object and viewdist is a constant which is the distance from the camera to the hypothetical screen onto which everything is being projected. (See the diagram here, but feel free to ignore everything else on that page.) The scaling factor you're using in your example doesn't have the same behaviour.
Here's a stab at trying to convert your code into a correct perspective calculation (note I'm not simplifying to 2D; perspective is about projecting three dimensions to two, trying to simplify the problem to 2D is kind of pointless):
camera = new MapPoint(60, 60, 10);
camera_z = camera.x*zDistX + camera.y*zDistY + camera.z*zDistz;
// viewdist is the distance from the viewer's eye to the screen in
// "world units". You'll have to fiddle with this, probably.
viewdist = 10.0;
xa = mapP.x*xDistX + mapP.y*xDistY + mapP.z*xDistZ;
ya = mapP.x*yDistX + mapP.y*yDistY + mapP.z*yDistZ;
za = mapP.x*zDistX + mapP.y*zDistY + mapP.z*zDistZ;
zdist = camera_z - za;
scaling_factor = viewdist / zdist;
xa *= scaling_factor;
ya *= scaling_factor;
You're only going to return xa and ya from this function; za is just for the perspective calculation. I'm assuming the the "za-direction" points out of the screen, so if the pre-projection x-axis points towards the viewer then zDistX should be positive and vice-versa, and similarly for zDistY. For a trimetric projection you would probably have xDistZ==0, yDistZ<0, and zDistZ==0. This would make the pre-projection z-axis point straight up post-projection.
Now the bad news: this function doesn't have an inverse either. Any point (xa,ya) is the image of an infinite number of points (x,y,z). But! If you assume that z=0, then you can solve for x and y, which is possibly good enough.
To do that you'll have to do some linear algebra. Compute camera_x and camera_y similar to camera_z. That's the post-transformation coordinates of the camera. The point on the screen has post-tranformation coordinates (xa,ya,camera_z-viewdist). Draw a line through those two points, and calculate where in intersects the plane spanned by the vectors (xDistX, yDistX, zDistX) and (xDistY, yDistY, zDistY). In other words, you need to solve the equations:
x*xDistX + y*xDistY == s*camera_x + (1-s)*xa
x*yDistX + y*yDistY == s*camera_y + (1-s)*ya
x*zDistX + y*zDistY == s*camera_z + (1-s)*(camera_z - viewdist)
It's not pretty, but it will work.
I think that with your post i can solve the problem. Still, to clarify some questions:
Solving the problem in 2d is useless indeed, but this was only done to make the problem easier to grasp (for me and for the readers here). My program actually give's a perfect 3d projection (i checked it with 3d images rendered with blender). I did left something out about the inverse function though. The inverse function is only for coordinates between 0..camera.x * 0.5 and 0.. camera.y*0.5. So in my example between 0 and 30. But even then i have doubt's about my function.
In my projection the z-axis is always straight up, so to calculate the height of an object i only used the vieuwingangle. But since you cant actually fly or jumpt into the sky everything has only a 2d point. This also means that when you try to solve the x and y, the z really is 0.
I know not every funcion has an inverse, and some functions do, but only for a particular domain. My basic thought in this all was... if i can draw a grid using a function... every point on that grid maps to exactly one map-point. I can read the x and y coordinate so if i just had the correct function i would be able to calculate the inverse.
But there is no better replacement then some good solid math, and im very glad you took the time to give a very helpfull responce :).

Resources