Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Ground-based stations not placed on flat land #7

Closed
Brianetta opened this issue Apr 11, 2011 · 23 comments
Closed

Ground-based stations not placed on flat land #7

Brianetta opened this issue Apr 11, 2011 · 23 comments

Comments

@Brianetta
Copy link
Contributor

Original subject: Bentley Starport (Canqu [-2,-4]) is in wrong position.

Bentley Starport (Canqu [-2,-4]) is in wrong position. There is no possible to land in bay 2 due to collision with the planet surface. Alpha 9.01.

Logged by Mysibrat on SpaceSimCentral

@robn
Copy link
Member

robn commented Apr 11, 2011

The problem comes from the spaceports being placed at the desired latitude/longitude at the height of the terrain at that point. On a steep slope you end up with station embedded in the side of the hill. I think collision detection is disabled once the player is in the docking animation (ie when the pad is lowering), but it most certainly is not during the descent. If the pad is inside the mountain, the ship will crash.

A nasty hack solution would be to disable collision detection during the final descent, but that's rather game-breaking. A better solution would be to only place the entire station on flat ground, and walk outwards from the desired location until some is found. It does mean checking the entire base of the station though, not just a single point.

A further extension to this would be to have the station placement code instruct the terrain engine to force some flat terrain at that point - excavation works, if you will.

I have no idea how to make all these things happen sanely but as the terrains get more complicated it will need to be addressed in some fashion.

@s20dan
Copy link
Contributor

s20dan commented Apr 11, 2011

To further your idea rob, it may be possible to check the slope value of a specific point, in this case the center of the spaceport, which means you only need that small section to appear flat.
There may be a way of using the slope calculations from the colour fractals for this.....

@robn
Copy link
Member

robn commented Apr 26, 2011

A couple of screenshots to demonstrate the problem. The first is a station partially embedded in the terrain. This doesn't stop docking from happening (though its weird to pass through the terrain inside the dock with collisions disabled.

This shows the other side of the problem - stations can stick out of the terrain, making it possible to fly under them.

@Philbywhizz
Copy link
Contributor

I've had a look at this and it might be a little tricky to do.
Currently there is a Planet member function called GetTerrainHeight(vector3d) which returns the height at a certain point in space. What would be great would be a similar FlatTerrain (vector3d, radiusMin, radiusMax) which flattens the terrain at a given point with a random radius (so it isn't just a circle). I tried to do it, but got lost in Geosphere and Geospherestyles on how to do it. Perhaps someone else has an idea on this one.

@robn
Copy link
Member

robn commented May 28, 2011

The interface sounds right. I imagine its trickier around the edges as you don't want it to make a vertical cliff, but rather a gradual incline or something, so it needs to be hooked up to the terrain gen in some way. Or maybe you do want a cliff for a suitably cliffy terrain. Hmm.

It also occurs to me that you wouldn't necessarily want to level out a height-mapped body much/at all, and also completely flat might not always be the right thing - some amount of gentle slope might be acceptable.

Ping @s20dan. He's probably the only one that can tell you where the right places to hook are.

@s20dan
Copy link
Contributor

s20dan commented May 31, 2011

Hey I've been thinking about it somewhat, The best way might actually be to directly change the Noise settings (FracDef) based on proximity to a city. One way is to create a value that is always 1.0 unless near to a city, then it scales down to 0 the closer you get. You can multiply the lucanarity and frequency settings for all the main noise with that.

A function like the craters or volcanoes could do it too, but it would probbaly need this proximity valuie (0-1) to multiply the frequency with, otherwise your whole planet would be flat :)

Is starport information already present when we run GetTerrainHeight(vector3d) ? If it is then its no big deal to scale terrain by starport proximity.

@robn
Copy link
Member

robn commented May 31, 2011

Yes, starports are position when the system is created.

If I'm understanding correctly, this approach will still give some variation in the terrain at lower scaling values but it'll be more like "rolling hills" than "epic mountain ranges". I expect that would look quite natural, making this an excellent approach.

I assume then that we'd give GetTerrainHeight a second argument for the scaling factor?

Is there any risk that we'd still hard edges for canyons etc? ie can we guarantee that the land under the station/city will be "flat" with this approach?

@s20dan
Copy link
Contributor

s20dan commented Jun 1, 2011

Yeah you got it.. We would just scale the high frequency noise with this value, leaving the larger 'rolling hills' noise un-changed, so the area would appear flatter around the starport but not totally flat, it might be enough for it to work.

But you picked up on a valid point, it will remove canyons from the immediate vicinity in most cases. I say most cases, because there are several methods currently in-use for creating different styles of canyons and some would be un-affected unless we specifically wanted them to be.

I assume then that we'd give GetTerrainHeight a second argument for the scaling factor?

I don't think so, provided we can get the value 'distance from starport' then we can just multiply the numbers.
EDIT:// Actually your right, giving GetTerrainHeight another argument seems the best way.

EG:
case TERRAIN_MOUNTAINS_NORMAL:
{
SetFracDef(&m_fracdef[0], m_maxHeightInMeters, rand.Double(1e6, 1e7), rand, 10);
SetFracDef(&m_fracdef[1], m_maxHeightInMeters * 0.00000000001, 100.0, rand, 10);

Just add: m_maxHeightInMeters * m_starportDistance,

Or further down:

n += n * 1.25 * ridged_octavenoise(m_fracdef[6],
Clamp(h * 0.00002, 0.3, 0.7) *
ridged_octavenoise(m_fracdef[5], 0.5, p), p);

Change: Clamp(h * 0.00002 * m_starportDistance, 0.3, 0.7)

That will give flat land under the starport, but could give other unwanted features like too many cliffs, but I think its worth a try.
If you want to do it, create this distance to starport value and I can do the rest if you like.

@robn
Copy link
Member

robn commented Jun 2, 2011

So it seems we want to pass the distance through Planet::GetTerrainHeight to GeoSpherStyle::GetHeight. It can't be a member since its different for every point.

By the looks of it you want the distance to be 0.0-1.0 since its being used as a scaling factor? In that case I guess we want to define a maximum flattening area that can safely cover the starport and surrounding city. CityOnPlanet has the max radius as 5000m (via a define) so I guess we can say distance == 0 -> scaling == 0.0, distance >= 5000 -> scaling 1.0. Does that sound right>

I think to do this right we have to loop over all the surface starports on the planet and pass through the minimum of the distances from the wanted position to each starport. I can't see a better way since we don't really know where the starports are from just the height point. I don't think it has to be expensive.

@s20dan
Copy link
Contributor

s20dan commented Jun 2, 2011

That sounds great. Thats basically:
m_distance /= 5000.0;
m_distance = Clamp(m_distance, 0.0, 1.0);
Is that right?

It should work rather well, we can combine it with some forced flattening too if we really need to, but Im not sure the best way to work out the distance from multiple starports for a specific point.
Ae actually had some code he had wrote for region based patterns and colours which might possibly be adapted for this.... It was able to take a point on the surface and calculate its distance from any other point.

@robn
Copy link
Member

robn commented Jun 2, 2011

I think this:

scale = Clamp(distance, 0.0, 5000.0) / 5000.0

Clamp to the acceptable distance first, then divide down to get it to 0.0-1.0.

I'll go and learn some maths to see of there's a way to quickly find a useful midpoint of multiple vectors. Otherwise its just looping.

@ghost ghost assigned robn Jun 2, 2011
jaj22 pushed a commit to jaj22/pioneer that referenced this issue Aug 29, 2011
@ghost ghost assigned robn Sep 21, 2011
@robn
Copy link
Member

robn commented Oct 12, 2011

Some stuff from Ae_ that I don't have brain to digest right now:

//starsystems.h
 pointers, vector of doubles called position on each body..std::vector is preffered as it ensures contiguous memory, regionType {double inner,double outer, int shape,blendtype,etc, double targetheight, bool valid} (a vector of structs), an int posIDX containing the parent position/region vector index for that starport

//starsystems.cpp



/*
 * Position a surface starport anywhere. Space.cpp::MakeFrameFor() ensures it
 * is on dry land (discarding this position if necessary)
 */
static void position_settlement_on_planet(SBody *b)
{
    MTRand r(b->seed);
    // used for orientation on planet surface
    double r2 = r.Double();     // function parameter evaluation order is implementation-dependent
    double r1 = r.Double();     // can't put two rands in the same expression
    b->orbit.rotMatrix = matrix4x4d::RotateZMatrix(2*M_PI*r1) *
            matrix4x4d::RotateYMatrix(2*M_PI*r2);


    vector3d p = b.orbit.rotMatrix*..see space cpp..(0,1,0);
    b->parent->positions.push_back(p); // add position to parents list
    regionTypes r; r.valid = 0; // set valid to 0
    b->parent->regionTypes.push_back(r);
    b->posIDX = b->parent->positions.size()-1; // position is at end of vector
}

//------------------------------------------------------------------------
//space.cpp

static Frame *MakeFrameFor(SBody *sbody, Body *b, Frame *f)
{

...


if (sbody->type == SBody::TYPE_SURFACE_STARPORT) {
...
if (planet->GetTerrainHeight(pos) - planet->GetSBody()->GetRadius() <= 0.0) {
            MTRand r(sbody->seed);
            // position is under water. try some random ones
            for (tries=0; tries<100; tries++) {
                // used for orientation on planet surface
                double r2 = r.Double();     // function parameter evaluation order is implementation-dependent
                double r1 = r.Double();     // can't put two rands in the same expression
                rot = matrix4x4d::RotateZMatrix(2*M_PI*r1)
                    * matrix4x4d::RotateYMatrix(2*M_PI*r2);
                pos = rot * vector3d(0,1,0);
                height = planet->GetTerrainHeight(pos) - planet->GetSBody()->GetRadius();
                // don't want to be under water
                if (height > 0.0) break;
            }
        }
        b->SetPosition(pos * planet->GetTerrainHeight(pos));
        b->SetRotMatrix(rot);

        b->parent->regionTypes[b->posIDX].height = height;
        // the following should be moved elsewhere/done in more detail
        size = cos(citySize_m/(2*PI*b->parent->GetRadius()); // angle between city center/boundary = city size/(perimeter great circle = 2pi r)
        b->parent->regionTypes[b->posIDX].outer = size; // city center pos and current point will be dotted, and compared against size
        b->parent->regionTypes[b->posIDX].inner = 0.8*size;
        b->parent->regionTypes[b->posIDX].valid = true;

        return frame;
}
...


}

//------------------------------------------------------------------------
//geospherestyle.cpp


double GeoSphereStyle::GetHeight(const vector3d &p)
{

//std::vector <vector3d>::iterator i; 
//std::vector regionType::iterator r; // two vectors addressed so index is used instead
    for (int i = 0;i != m_Body.position.size(); i++)[ 
        if inside inner area return after checking region type is valid 
    } 

...

    case TERRAIN_HILLS_CRATERS:
    {


        ..
        old code inc return if zero
..


        for(int ii = 0; ii < m_Body->position.size();ii++){ //used for 2 vecs
        if inside outer area do a transition
        checking is just (*i).Dot(p) <= (*r).outer or element addressing in this case m_Body->position[ii]...

            if(..regionTypes[ii].valid){
                const double inner = m_Body->regionTypes[ii].inner;
                const double outer = m_Body->regionTypes[ii].outer;
                n = blend(m_Body->regionTypes[ii].height, n, m_Body->position[ii].Dot(p)/(outer-inner)); break; // blends from target height-terrain height as pos goes inner to outer
            }
        }


...
    n=(n>0.0)?:n:0.0;
    return n;
}

/* complex example
if inside region{
    if valid{
                       if r.type == 1 
                                 city flat terrain
        else if r.type == 2
            city terraced terrain..n = floor(n*40*planet radius)/planet radius //steps every 40m, needs building placement to run after setting regiontype
        else if r.type == 3 outdoor colony type setting n = log (n)/log (2)/colonywealth ;  //reduced contrast
        else if r.type == 4 crater using pos dot p as a type of radius (effects could be summed if using a separate height variable and not breaking)

        }
}         
*/


}

@gernot66
Copy link
Contributor

i can only congratulate to this decision,

usually i just worked around that issue (basements), but yes it's better to have a flattened terrain, even if i will miss the strange places then....

"chasch nüd beides ha, z'füferli und's weggli"

(you can't have everything)

@s20dan
Copy link
Contributor

s20dan commented Feb 16, 2012

#924 will solve this

@bszlrd
Copy link
Contributor

bszlrd commented Nov 5, 2015

I guess it's already know that this happens again/still, but I thought I'll report it anyway (this issue was what other similar issues referenced.)
On Io, at Dante's base this happens again, the small pads of the station are buried under ground.
Then I tried reducing the detail level, hoping that then the terrain will be better. It did, but I was still unable to land, because the ship rough landed some 60m above the pad:
screenshot-20151105-194459
Restoring to very high detail level did show that there supposed to be terrain on that spot:
screenshot-20151105-195140
So I guess the collision doesn't updated with the terrain.

@Vekkq
Copy link

Vekkq commented Dec 1, 2016

Had this bug today in Reedville, Gliese 623 .
2016-12-01 1

This issue doesn't seem that closed in the 20161129 build, even though it only appears on low fractal detail.

@Talkless
Copy link

Talkless commented Sep 8, 2017

I discovered same problem, after I switched fractal level from Medium to Low, Thebe Gas Refinery gone underground:
thebe-gas-refinery-underground

@impaktor
Copy link
Member

impaktor commented Sep 8, 2017

@fluffyfreak should this be reopened, or split (is it even possible in github?) to a new issue?

@jaj22
Copy link
Contributor

jaj22 commented Sep 8, 2017

Checked out Thebe Gas Refinery. Looks fine on Low and Medium fractal detail here, 1.3km underground on Very Low. Possibly within the range of "working as intended".

@Vekkq
Copy link

Vekkq commented Sep 9, 2017

it still breaks the game for some players. it can only be considered "working as intended", when very low fractal detail is dropped. but even then, there is still no guarantee, that this issue is solved for every ground station.

@jaj22
Copy link
Contributor

jaj22 commented Sep 9, 2017

It doesn't break anything functional, just aesthetic. You can still fly to those stations. That terrain on Thebe also looks way more interesting from the inside than the outside. I stared at it for a while.

Thebe uses TerrainHeightAsteroid, which is literally four lines of code and so pretty easy to fix, although I'm never sure what the intention was with those height fractals. In this case you could simply remove the m_fracmult multiplier from TerrainHeightAsteroid.cpp, as it's a very cheap terrain function by Pioneer's standards.

@Talkless
Copy link

Talkless commented Sep 9, 2017

You can still fly to those stations.

Well, you can't dock and finish mission.

@fluffyfreak
Copy link
Contributor

No this needs a new Issue if it needs tracking at all, I should just work out how to patch the problem for now

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging a pull request may close this issue.