0
\$\begingroup\$

Struggling with accurate terminology; I've got a 3D app with triangulated terrain, where it looks like a checkerboard from the top view, where every cell is two tris, and every cell is equal size (1 sq unit). I'm storing the "unit circle" slope/scalar (?) for every triangle, two for each cell, so that I can index into a cell during runtime and lookup its slope, to see if the tri I'm over is flat enough to walk on, or if I should start sliding down the slope instead. For example, a triangle with a perfect 45 degree slope, has "0.707106" saved for the "slope" value, which was calculated via dot product of the tri's normal and a World Up vector.

What I need, is to somehow convert that slope scalar to a different scalar value which needs to represent a ratio of how much to slide forward if we hypothetically fell straight down into the ground because of gravity, based on that slope value. That's hard to explain, but for example:

  • 0.707106 "slope" cell: 1 unit across, 1 units down... Needs to somehow convert to "1.0" (this first case is the perfect 45 degree slope. A value of "1.0" would mean, we translate downwards by the same exact amount we should translate forward, hence "1.0" ratio)
  • 0.447213 "slope" cell: 1 unit across, 2 units down... Needs to somehow convert to "0.5" (this second case is a steeper slope, so assuming we are still falling down at the same speed, I only need to translate forward only half as much as I fell into the floor, hence 0.5)
  • 0.316227 "slope" cell: 1 unit across, 3 units down... Needs to somehow convert to "0.3333"

enter image description here

Those were simplified examples, whereas the actual terrain is more randomized. The examples are also 2D, whereas the app is 3D. So, can I derive the ratio/scalar I'm looking for, from my "slope" dot product scalar? I've got the sliding/translating logic completed, but I'm just translating forward at the wrong rate, so I only need to understand how to properly find that missing ratio/scalar. Thank you

\$\endgroup\$

2 Answers 2

3
\$\begingroup\$

I don't understand your setup. However, 0.707106 looks familiar to me. It is approximately this:

$$\frac{1}{\sqrt{2}}$$

And you say that is a 45º slope, right? So, my hypotheses is that you have the inverse of the hypotenuse (with one side being of unit length).

If this is true, fro your case 1 unit across 2 units down, you should have:

$$\frac{1}{\sqrt{1^2+2^2}} = \frac{1}{\sqrt{1+4}} = \frac{1}{\sqrt{5}} = \frac{1}{2.2360679...} = 0.447213...$$

Yep.

The final case is 1 unit across and 3 units down:

$$\frac{1}{\sqrt{1^2+3^2}} = \frac{1}{\sqrt{1+9}} = \frac{1}{\sqrt{10}} = \frac{1}{3.162277...} = 0.316227...$$

And yep.


The number you have is the cosine of the angle. This makes sense, because the dot product has a a trigonometric identity with the cosine of the angle between the vectors: $$\vec{a}·\vec{b} = |a||b|cos(θ)$$ Where θ is the angle between the vectors.


Now, if we are always talking of one unit across, we have this equation:

$$n = \frac{1}{\sqrt{1 + x^2}}$$

And we solve for x:

$$n = \frac{1}{\sqrt{1 + x^2}}$$

$$\implies$$

$$\frac{1}{n} = \sqrt{1 + x^2}$$

$$\implies$$

$$\left(\frac{1}{n}\right)^2 = \left(\sqrt{1 + x^2}\right)^2$$

$$\implies$$

$$\frac{1}{n^2} = \left(\sqrt{1 + x^2}\right)^2$$

$$\implies$$

$$\frac{1}{n^2} = |1 + x^2|$$

$$\implies$$

$$\frac{1}{n^2} = 1 + |x^2|$$

$$\implies$$

$$\frac{1}{n^2} = 1 + x^2$$

$$\implies$$

$$\frac{1}{n^2} - 1 = 1 + x^2 - 1$$

$$\implies$$

$$\frac{1}{n^2} - 1 = x^2$$

$$\implies$$

$$\sqrt{\frac{1}{n^2} - 1} = |x|$$


Let us try it out.

For 0.707106:

$$|x| = \sqrt{\frac{1}{n^2} - 1} = \sqrt{\frac{1}{0.707106^2} - 1} = \sqrt{\frac{1}{0.499998} - 1} = \sqrt{2.000008 - 1} = \sqrt{1.000008} = 1.000004$$

For 0.447213

$$|x| = \sqrt{\frac{1}{n^2} - 1} = \sqrt{\frac{1}{0.447213^2} - 1} = \sqrt{\frac{1}{0.199999} - 1} = \sqrt{5.000025 - 1} = \sqrt{4.000025} = 2.000006$$

For 0.316227

$$|x| = \sqrt{\frac{1}{n^2} - 1} = \sqrt{\frac{1}{0.316227^2} - 1} = \sqrt{\frac{1}{0.099999} - 1} = \sqrt{10.000100 - 1} = \sqrt{9.000100} = 3.000017$$

Ok, we run into rounding problems. The good news is that we are consistently overshooting, so you can go ahead an floor the result. And of course, you want the multiplicative inverse.

The code would be something like this:

float compute_slope(float n)
{
    return 1.0/floor(sqrt((1.0/(n * n)) - 1.0));
}

This is what I get trying it out:

  • For 0.707106: 1.0
  • For 0.447213: 0.5
  • For 0.316227: 0.333333

If I follow the trigonometric approach, then what you are looking for (the slope) is the cosine over the sine of the angle. And we have the cosine, we could do this:

float compute_slope(float n)
{
    return n/sin(acos(n));
}

However, this gave me worst precision when trying it out:

  • For 0.707106: 0.999997
  • For 0.447213: 0.499999
  • For 0.316227: 0.333332

Addendum Sometimes ideas arrive when I step away from a problem. If I have the cosine and I need the sine, I can do it with this identity:

$$sin(x)^2 + cos(x)^2 = 1$$

Which gives me this code:

float compute_slope(float n)
{
    return n/(sqrt(1.0 - (n * n)));
}

And I get… The same:

  • For 0.707106: 0.999997
  • For 0.447213: 0.499999
  • For 0.316227: 0.333332

I was worth trying.

\$\endgroup\$
1
  • \$\begingroup\$ Thank you, couldn't have asked for a better answer. I used your method and stored all of the values per triangle, and now any object that's falling/sliding down a triangle can lookup that translation value. \$\endgroup\$
    – ps48
    Jan 23, 2022 at 14:44
1
\$\begingroup\$

An alternative to the method described by Theraot would be to calculate the sliding vector of the triangle. You have already calculated the normal vector, so:

LeftVec = worldUpVec X normalVec
SlidingVec = LeftVec X normalVec
Normalize(SlidingVec)

You can now multiply the SlidingVec by speed and delta time to create movement along the sliding plane of the triangle, perhaps projecting the gravity vector onto the sliding vector via the dot product to get the right speed.

\$\endgroup\$

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .