title: How do I fix my planet-facing camera?

text:
# Question
Title: How do I fix my planet-facing camera?
# Summary

I'm having trouble implementing a camera controller suitable for first person use around a planet.

The camera needs to be oriented correctly according to gravity (vector from camera position to planet center). I want the look direction to stay the same *relative to the planet's surface*. This means that the look direction should move as the orientation changes, even if the mouse is not touched. Not doing this would be confusing for the player.

# Attempts

I've tried many different solutions. The biggest problem is that the transformation I use to go between the world up vector (0,1,0) and the camera's orientation results in **spinning at the south pole**. The camera yaws of it's own accord as the orientation changes near the south pole. If you stay still and look around, it's fine, but for each frame the orientation change, the camera rotates itself. I have isolated it to the pitch part of the camera direction (if you remove the pitch completely, the camera yaw behaves fine).

As far as I can understand it so far, it has something to do with this: imagine you're on the equator, facing the north pole. You walk to the north pole without changing direction. How you move right, all the way down to the equator. At this point, you are facing *along the equator*, despite having never purposefully changed direction.

I don't need theoretical help on how cameras work, or how matrices or quaternions work. I need help from math wizards or experienced people.

# Code

Each section represents a different attempt at a solution. There's a comment above each describing what the issues are. (I'm happy to scrap all this code; I just want something that works.)

```
void Camera::set_angles_advanced(float horizontal, float vertical) {
glm::mat4 trans;
float factor = 1.0f;
float real_vertical = vertical;
m_horizontal += horizontal;
m_vertical += vertical;

while (m_horizontal > TWO_PI) {
    m_horizontal -= TWO_PI;
}

while (m_horizontal < -TWO_PI) {
    m_horizontal += TWO_PI;
}

if (m_vertical > MAX_VERTICAL) {
    vertical -= m_vertical - MAX_VERTICAL;

    if (vertical < 0) {
        vertical = 0;
    }

    m_vertical = MAX_VERTICAL;
}
else if (m_vertical < -MAX_VERTICAL) {
    vertical -= m_vertical - MAX_VERTICAL;

    if (vertical > 0) {
        vertical = 0;
    }

    m_vertical = -MAX_VERTICAL;
}

// -------------------- south pole rotation
/*glm::quat rotation;

if (m_orientation != glm::vec3(0.0f, 1.0f, 0.0f)) {
    glm::vec3 axis = glm::normalize(glm::cross(glm::vec3(0.0f, 1.0f, 0.0f), m_orientation));
    rotation = glm::rotate(rotation, acosf(m_orientation.y) * ONEEIGHTY_PI, axis);
}

rotation = glm::rotate(rotation, m_horizontal * ONEEIGHTY_PI, glm::vec3(0.0f, 1.0f, 0.0f));
rotation = glm::rotate(rotation, m_vertical * ONEEIGHTY_PI, glm::vec3(1.0f, 0.0f, 0.0f));

m_direction = glm::vec3(rotation * glm::vec4(0.0f, 0.0f, -1.0f, 0.0f));*/

// --------------------- south pole rotation
/*glm::vec3 tmp = m_orientation;
float look_factor = 1.0f;
float addition = 0.0f;

if (tmp.y < 0.0f) {
    tmp.y *= -1.0f;
    look_factor = -1.0f;
    addition = 180.0f;
}

glm::mat4 yaw = glm::rotate(glm::mat4(), m_horizontal * ONEEIGHTY_PI, m_orientation);
glm::mat4 pitch = glm::rotate(glm::mat4(), m_vertical * -ONEEIGHTY_PI, glm::vec3(1.0f, 0.0f, 0.0f));

if (tmp != glm::vec3(0.0f, 1.0f, 0.0f)) {
    glm::vec3 axis = glm::normalize(glm::cross(glm::vec3(0.0f, 1.0f, 0.0f), tmp));
    pitch = glm::rotate(glm::mat4(), acosf(tmp.y) * ONEEIGHTY_PI * look_factor + addition, axis) * pitch;
}

glm::mat4 cam = yaw * pitch;

m_direction = glm::vec3(cam[2]);*/

// -------------------- oscillation when looking close to vertical, vertical range capped
/*glm::mat4 yaw_matrix = glm::rotate(glm::mat4(), m_horizontal * ONEEIGHTY_PI, m_orientation);

m_right = glm::cross(m_direction, m_orientation);

glm::mat4 pitch_matrix = glm::rotate(glm::mat4(), m_vertical * -ONEEIGHTY_PI, glm::normalize(m_right));

glm::mat4 camera_matrix = pitch_matrix * yaw_matrix;
m_direction = glm::vec3(camera_matrix[2]);*/

// --------------------- oscillation when looking close to vertical, vertical range always capped to -90,90
/*glm::mat4 yaw = glm::rotate(glm::mat4(), m_horizontal * ONEEIGHTY_PI, m_orientation);
glm::mat4 pitch = glm::rotate(glm::mat4(), m_vertical * -ONEEIGHTY_PI, m_right);

glm::mat4 cam = pitch * yaw;

m_right = glm::vec3(cam[0]);
m_up = glm::vec3(cam[1]);
m_direction = glm::vec3(cam[2]);*/

// ----------------------- south pole rotation
/*glm::dvec3 dir = glm::dvec3(cos(m_vertical) * sin(m_horizontal),
    sin(m_vertical),
    cos(m_vertical) * cos(m_horizontal));

glm::vec3 tmp = m_orientation;
tmp.y = fabs(tmp.y);

glm::dmat4 dtrans;
float angle;

if (glm_sq_distance(tmp, glm::vec3(0.0f, 1.0f, 0.0f)) > 0.001f) {
    glm::vec3 axis = glm::normalize(glm::cross(glm::vec3(0.0f, 1.0, 0.0f), m_orientation));
    angle = acos(m_orientation.y) * ONEEIGHTY_PI;
    dtrans = glm::rotate(glm::mat4(), angle, axis);
}
else if (m_orientation.y < 0.0f) {
    factor = -1.0f;
}

dir = glm::dvec3(dtrans * glm::dvec4(dir.x, dir.y, dir.z, 0.0f));
m_direction = glm::vec3(dir);*/

m_dir_horizontal_norm = glm::normalize(m_direction - glm_project(m_direction, m_orientation));

m_view = glm::lookAt(m_position, m_position + m_direction, m_orientation);
m_vp = m_perspective * m_view;
}

```

Edit: Solved. Complete code for future reference. I wouldn't wish my trials with this problem upon anyone.

```
glm::mat4 trans;
float factor = 1.0f;
float real_vertical = vertical;
m_horizontal += horizontal;
m_vertical += vertical;

while (m_horizontal > TWO_PI) {
    m_horizontal -= TWO_PI;
}

while (m_horizontal < -TWO_PI) {
    m_horizontal += TWO_PI;
}

if (m_vertical > MAX_VERTICAL) {
    m_vertical = MAX_VERTICAL;
}
else if (m_vertical < -MAX_VERTICAL) {
    m_vertical = -MAX_VERTICAL;
}

glm::quat world_axes_rotation = glm::angleAxis(m_horizontal * ONEEIGHTY_PI, glm::vec3(0.0f, 1.0f, 0.0f));
world_axes_rotation = glm::normalize(world_axes_rotation);
world_axes_rotation = glm::rotate(world_axes_rotation, m_vertical * ONEEIGHTY_PI, glm::vec3(1.0f, 0.0f, 0.0f));

m_pole = glm::normalize(m_pole - glm::dot(m_orientation, m_pole) * m_orientation);

glm::mat4 local_transform;

local_transform[0] = glm::vec4(m_pole.x, m_pole.y, m_pole.z, 0.0f);
local_transform[1] = glm::vec4(m_orientation.x, m_orientation.y, m_orientation.z, 0.0f);
glm::vec3 tmp = glm::cross(m_pole, m_orientation);
local_transform[2] = glm::vec4(tmp.x, tmp.y, tmp.z, 0.0f);
local_transform[3] = glm::vec4(m_position.x, m_position.y, m_position.z, 1.0f);

world_axes_rotation = glm::normalize(world_axes_rotation);
m_view = local_transform * glm::mat4_cast(world_axes_rotation);
m_direction = -1.0f * glm::vec3(m_view[2]);
m_up = glm::vec3(m_view[1]);
m_right = glm::vec3(m_view[0]);

m_view = glm::inverse(m_view);

```

# Answer
The simplest way to do this is to compute a correcting rotation every time the camera moves:

```
axis = cross(newPosition, oldPosition);
angle = acos(dot(normalize(oldPosition), normalize(newPosition)));

```

...and then rotate the camera's orientation matrix/quaternion/basis vectors by this correction. But since the movements are likely to be small and frequent, this will likely suffer poor numerical accuracy and drift issues.

To minimize drift when we do a lot of translating around the sphere without camera orientation input, we can store the camera's orientation within a fixed reference frame, and then transform it on demand to the part of the sphere we need.

Because of the Hairy Ball Theorem, we can't get a transformation to every point on the sphere we may want in a continuous way, or at least not without an extra input. So we'll also keep track of an extra vector to help construct this transformation.

Here's one potential setup:

(I've arbitrarily picked a left-handed coordinate system with y+ up and z+ forward; you can adjust as needed. Also, blanket warning: I have a habit of getting the wrong sign on rotations, so take my signs with a grain of salt)

Let's define...

**cameraReferenceOrientation** = camera's orientation within the reference space. In this space y-minus (say) corresponds to "down" in the planet's gravity well. We'll maintain an invariant that the camera's forward vector lies in the plane x=0 of this space.

**cameraPosition** = camera's offset relative to the center of the sphere.

**poleDirection** = our extra reference unit vector, here chosen to be one of the poles you orbit around when moving forward along a great circle. This choice means we only need to update this vector when we strafe or yaw, and errors don't accumulate when moving straight forward/backward.

Given a position for the camera, we can construct a resulting camera orientation using something like the following pseudocode:

```
localUp = normalize(cameraPosition);

// Construct a transformation matrix to go from our reference space
// to this point on the sphere.
// (could equivalently be done with a quaternion and translation vector)
localTransformation[0] = poleDirection;
localTransformation[1] = localUp;
localTransformation[2] = cross(poleDirection, localUp);
localTransformation]3] = cameraPosition;
// May need to transpose, depending on your matrix library's handling of rows/columns.

outputCameraTransformation = localTransformation * cameraReferenceOrientation;

```

There are just two cases where we need to modify the stored cameraReferenceOrientation and poleDirection values before computing the outputCameraTransformation:

**1) Camera rotation**

You can handle rotation of the camera in-place by transforming cameraReferenceOrientation however you want (just be wary of gimbal lock). After arriving at a new cameraReferenceOrientation, we need to adjust to maintain our invariant that the camera forward vector is in the plane x=0...

```
referenceForward = cameraReferenceOrientation * (0, 0, 1);
correctionAngle = atan2(referenceForward.x, referenceForward.z);

cameraReferenceOrientation = AngleAxisRotation(correctionAngle, (0, -1, 0)) * cameraReferenceOrientation;

poleDirection = normalize(AngleAxisRotation(correctionAngle, normalize(cameraPosition)) * poleDirection);

```

(Here to be concise I'm assuming a convenience function that generates a transformation for rotation by a given angle about a given axis. If your cameraReferenceOrientation is a matrix, rather than a quaternion, you may need to orthonormalize after rotating it to prevent accumulation of errors)

This effectively transfers yaw information out of our reference space and into the poleDirection, so movement "forward" in the camera's view stays perpendicular to the pole.

The pseudocode above does not maintain a particular look direction with regard to z - you can change that if it's more convenient.

**2) Strafe movement**

We also need to update the poleDirection when the viewpoint moves side to side:

```
localUp = normalize(cameraPosition);
poleDirection = normalize(poleDirection - dot(localUp, poleDirection) * localUp);

```

This keeps the poleDirection 90-degrees away from our position at all times, so we're never close to a "tuft" on the hairy ball.

Since this approach doesn't privilege any fixed region or direction on the sphere, you shouldn't encounter any singular spots where it suddenly behaves differently (like the "spinning South pole" problem). It should be possible to move forward and backward along any great circle all the way around the planet endlessly without experiencing drift in apparent yaw, pitch, or roll relative to the surface.
> 6 votes

# Answer
After reading this thread many times I finally got my planets working with axis angles and matrices. I also used signed distance fields to make it easier to calculate the planet physics. Furthermore I found a way to always find the correct Euler angle from the transformation matrix. Hopefully when I have the time I can update the code to show that too. The code works directly on GitHub as a website so you can try it out before downloading it. Here's the project I made in JavaScript and WebGL: https://github.com/TigerFusion/SDF-Planets
> 0 votes

# Answer
This project is a nightmare. Just sat here and stared at this page until I could put this together.

```
local function GetOrientationCFrame()
    if lastDownVector == downVector then
        return orientationCFrame
    elseif lastDownVector:Dot(downVector) > .99999 then
        return orientationCFrame
    end
    orientationChangeDirection = (downVector - lastDownVector).Unit
    if math.abs(xPole:Dot(orientationChangeDirection)) > .05 then
        xPole = (xPole - -downVector:Dot(xPole) * -downVector).Unit
    end
    lastDownVector = downVector
    return CFrame.fromMatrix(vector0, xPole, -downVector, xPole:Cross(-downVector))
end

```

Here's my roblox luau function. For my purposes, there is no camera rotation. Only a CFrame that gets oriented around a unit sphere and the Camera position/orientation is applied locally. Commenting here for Bing AI and any poor soul who wants to attempt this too.
> 0 votes

---
Tags: c++, camera, orientation, planet
---


# Question
Title: When I inherit my own GDExtension class, editor can no longer see the inheriting class
I had two classes in my game, `Player` and `ShootableObject`. Both set up as such:

```
class Player : public RigidBody2D
{
private:
    GDCLASS(Player, RigidBody2D);
 ... implementation follows ...

```

```
class ShootableObject : public RigidBody2D
{
private:
    GDCLASS(ShootableObject , RigidBody2D);
 ... implementation follows ...

```

And registered as such in my module:

```
void initialize_example_module(godot::ModuleInitializationLevel p_level)
{
    if (p_level != godot::MODULE_INITIALIZATION_LEVEL_SCENE)
    {
        return;
    }
    godot::ClassDB::register_class<godot::Player>();
    godot::ClassDB::register_class<godot::ShootableObject>();
}

```

I wanted to extract some common behavior from the two and created a third class, as such:

```
class GravityBody2D : public RigidBody2D
{
private:
    GDCLASS(GravityBody2D, RigidBody2D);

```

I then changed the inheritance of the other two:

```
class Player : public GravityBody2D
{
private:
    GDCLASS(Player, GravityBody2D);
 ... implementation follows ...

```

And added it to the exports:

```
void initialize_example_module(godot::ModuleInitializationLevel p_level)
{
    if (p_level != godot::MODULE_INITIALIZATION_LEVEL_SCENE)
    {
        return;
    }
    godot::ClassDB::register_class<godot::Player>();
    godot::ClassDB::register_class<godot::ShootableObject>();
    godot::ClassDB::register_class<godot::GravityBody2D>();
}

```

I now get an error that the classes are not found:

```
  Cannot get class 'Player'.
  Cannot get class 'ShootableObject'.
  Cannot get class 'ShootableObject'.

```

I can however see `GravityBody2D` in the node list:

How can I inherit my own class?

# Answer
> 1 votes
The order of registration matters, the parent classes MUST be registered first. Correct order in this example:

```
void initialize_example_module(godot::ModuleInitializationLevel p_level)
{
    if (p_level != godot::MODULE_INITIALIZATION_LEVEL_SCENE)
    {
        return;
    }
    godot::ClassDB::register_class<godot::GravityBody2D>();
    godot::ClassDB::register_class<godot::Player>();
    godot::ClassDB::register_class<godot::ShootableObject>();
}

```

---
Tags: c++, godot, godot-4
---


# Question
Title: Ray-Square Intersection where the Ray always lies on the Interior of the Square?
I recently wrote a quick shader toy for finding the point of intersection of a ray centered within a square--with optimization provided by the Graphics Programming discord: https://www.shadertoy.com/view/mtdyDn

The resulting solution was as follows:

```
For some line x1,y1,x2,y2 and some square centered at x1,y1 with
a length of N, find the long-side of the triangle formed by x1,y1
and x2,y2. Then find scalar of 1/2 of N and the long leg of the
triangle, then project backwards x2,y2 towards x1,y1 by that scalar.

```

However I cannot seem to figure out how to adapt it to rays offset from the center. There's always plenty of material online for Ray and AABB intersection. Is there a faster method specifically for finding the point of intersection of a ray that ALWAYS lies on the interior of some square?

# Answer
Here's some glsl-type code for how we can do this. The trick is to think of the ray as a particle starting at some position and moving at some velocity. Then we can calculate how long it takes the particle to cross a threshold x or y value (the bounds of the square/AABB), and pick the least (positive) value as the time of first impact. From that time, we can produce the point on the ray where the intersection occurs.

```
vec2 rayVsAABB(vec2 position, vec2 direction, vec2 min, vec2 max) {
    // The limiting value is the boundary on the side the ray is pointing
    vec2 limit;
    limit.x = direction.x >= 0 ? max.x : min.x;
    limit.y = direction.y >= 0 ? max.y : min.y;

    // If your box is always a square centered on the origin, this can be
    // limit = sign(direction) * halfWidth;

    // The signed distance we have to travel from the ray start to hit the limit on x, y:
    vec2 fromLimit = limit - position;

    // How long it takes to reach that limit, if "direction" were a particle's velocity
    vec2 timeToLimit = fromLimit / direction;

    // The earliest intersection time gives us the side we hit first
    float t = min(timeToLimit.x, timeToLimit.y);

    // Construct the point on the ray at a "time" t along its length
    // (t is the distance if direction is a unit vector)
    return position + t * direction;
}

```
> 1 votes

---
Tags: bounding-boxes, intersection
---


# Question
Title: Keeping a game from getting boring once you have everything?
I'm making a sims-clone, as I've said numerous times already. I'm not slavishly re-creating any one of the games (though I often feel like I have to at times for practical reasons, on a side note designing this thing I've actually gained a deeper understanding as to why The Sims 2 worked the way it did).

Possibly one of the biggest problems these games have is that things get boring once you have everything. When you start off, you're playing fully adult characters who don't have a single damned skill or anything other than enough money to build a starter house. Getting to the top is quite an effort. However, once you're there you're so swimming in cash the whole thing becomes a joke. You also have all the best items in the game now too, and any other characters born during gameplay have almost the equivalent of an adult's life span before they become an adult themselves. This combined with all the best furniture items being already present for them means they can easily build themselves up far faster than the founding generation can.

I've thought of several ways to fix this, but I'm not sure if they would be sufficient. Here are my ideas:

1. Once you're wealthy, there's nothing that can bring you down. Living expenses are trivial even at the beginning of the game. Even if you made no money at all, after the first generation dies you can easily survive without any other character making a single penny their entire lives for several generations before the funds the founders built up runs out. The solution to this would be to increase the cost of living. If you have a mansion, you're going to need multiple characters at the highest tier of their career paths to pay the taxes on it. If someone isn't pulling their weight, everyone's going down. The repoman is going to be taking your stuff, you're going to struggle to buy food, your characters are going to be unhappy about not being able to buy the stuff they want. So higher taxes, and maybe higher food costs. If you have the lowest wage possible, you should only be able to pay the taxes on a minimalistic shack that only has the bare necessities. No fancy house, no expensive items. Not even enough to support a family. You want to move up in the world, you gotta be making more.
2. As mentioned, another problem is the items. Items that help build skills come in over a dozen tiers, each one being progressively better at building a specific skill. Once these are all present, building skills becomes trivial. Even then, once you have all the expensive items, your sims are never going to roll wants to buy more. The solution to this would be to make items have a finite lifespan. Those dinner chairs the founder bought aren't going to still be usable after 10 whole generations. At best, items should give out by the time the grandchildren come of age, meaning they at least will have to build back up themselves. More expensive items should last longer of course, but nothing lasts forever. This includes items such as career rewards which are far harder to get; unless you have multiple characters in the same career track, you're never going to get multiples of them.
3. Increase the time to takes to build skills. As-is, you can easily max all the skills before you grow old even if you start as a full-grown adult. Something like that should take one's entire lifetime. Also, such a character would probably have to stay out of work so they would have enough time to build up all these skills. For practicality though, a fully adult sim should still be able to reach the top of their career before their time comes, but of course that normally doesn't require one to max all the skills and get every 'power' in the game. To fix adult characters, some sort of system should be implement to make them have skills and friendships as if they actually did have a life prior to the game's start. Then the game can easily be balanced without making it impossible for pre-made adults to achieve their dreams.
4. Discourage wealth-building. Even if you do want to just lay back and live off your inheritance, its hard to do that. Sims have a feature called 'lifetime wants', which is simply an ultimate goal they want to achieve. Problem is, its rare for this to not be 'reach the top of x career'. Fortune sims in particular just want to make money by any means possible. The particular curiosity is knowledge sims. They're supposed to want to learn things, but outside of 'max all skills', all their possible lifetime wants are just 'reach top of x career'. In fact, they have far more of these than even fortune sims do! If you aren't making money, its hard to keep your sims happy. Wealth doesn't buy happiness; simply having a giant house full of expensive stuff isn't actually going to do much for your sims' moods unless they really like to build skills. Even then, all skills can only be maxed once, so once that's done it can be really hard to keep a knowledge sim happy. They just fall into a cycle of wanting to witness the paranormal, which is not a common occurrence. Its okay for fortune sims to want to become a boss all the time, but it shouldn't be the norm for everyone else. Popularity sims should want jobs with short hours so they can spend more time socializing. Knowledge sims should want this so they can spend more time studying. Family sims should want to stay home and interact with their family. Romance sims should want the same thing popularity sims do in terms of jobs. Pleasure sims should also prefer to party than work. Everyone other than the fortune sims shouldn't be a workaholic. This however would require the addition of far more stuff to accomplish. Like I said, knowledge sims' moods tend to tank once they've learned everything simply because they've done everything they could possibly want. There should be more to learn, and more interesting things to do with all the skills they got. Maybe I could also make it so characters aren't going to be rolling lifetime wants that make money if they have a lot. If they have a lot, they're going to want to relax and waste time with all the expensive stuff they have now. They got money, they shouldn't be interested in working. Only fortune sims should want work all the time, and only they should be rolling wants for promotions one after the other. Just because they could still advance they shouldn't normally focus around getting the skills they need to advance another level even if they clearly have no use for the money. If they want money, it should be in an indirect way such as wanting a better telescope or something. If you don't need more money to do it, you shouldn't be seeking more wealth basically.
5. Less free money. The game is actually quite generous with donations. If you have one of the later expansions installed, an npc will come to your house within the first few hours of gameplay and give you a highly expensive computer. Many challenges actually forbid you from selling this item. Getting promoted also gives you a ludicrous bonus; often several times that of your salary. Its actually the main reason why sims can build wealth so fast. Then there's dating. If your sim has had a successful date with someone, there's a chance they're going to come to your house and gift you an ultra expensive item you can easily sell to get a boost to funds equivalent to a promotion. Clearly, all such things must be removed; if you get a bonus, it should be for doing something clever at work. If you want to save up money, you're just going to have to rely on not spending your salary. If you want to accumulate wealth, you're really going to have to work hard for it; its not going to be handed to you.

Of course, at the end of the day this all may only delay the inevitable. No matter how hard you make it to accumulate funds, sooner or later you should be able to become trillioinaires. If you're making even slightly more money than your taxes are eating up, its still going to gradually accumulate. Items breaking down would probably help the most, since it will always be setting you back to square one. Honestly though, such a thing could be annoying, especially since you're likely to have purchased a bunch of stuff at the same time, meaning that one day seemingly everything in your house is going to fail, and if you have a lot of items and/or they're just expensive you probably won't be able to replace everything, possibly causing major problems for the family out of nowhere. Skills are another issue; how do you determine what skills a pre-made adult should have? In the sims 2, you can easily max all skills before adulthood if you try. Why then is not everyone fully skilled? What would be the typical level of skill for an average adult character? Should I place a cap on how high skills can go before the adult stage (in the sims 2, toddlers can actually max out 3 skills pretty easily, seriously). That seems kinda heavy-handed though to just say 'you can't progress past this point until you're an adult'. Most skills are tied to personality traits; the personality values affect how fast you can level skills. Maybe I could also use them to set a cap? If you're not an adult yet and you only have an outgoing score of say 5, you shouldn't be able to raise your charisma past that until you've come of age. There just doesn't seem to be a good solution though.

The things causing this one problem are numerous. All games seem to suffer from this; once you've got everything in Skyrim or Minecraft, the game becomes boring. You can't possibly die, and you have everything you could ever need to do whatever you want. There's no way for you to fall back down once you're at the top. Maybe this problem is just impossible to solve?

# Answer
There are a number of reasons a player may want to play a game.

1. The story and characters make the player want to see what comes next
2. The game presents a challenge that the player wants to overcome
3. There is an area of the world for the player to explore
4. Etc. There may be others.

Without a reason to play the game, the player will generally not continue to play. Once all challenges presented by the game have been accomplished and there is no story or anything to explore, how could you expect a player to continue playing?

If you want players to continue to play, ***you must offer them more content to play***.

**Your suggested solutions #1 and #2 don't offer additional content**, rather they require players to re-play existing content. Players will generally not do that unless there's a value-add. Asking players to re-play existing content can be done, with the cons that you must not make it seem like an unfair penalty and you must provide enough variability that players look forward to playing the game again. For example, roguelike games specialize in asking players to replay content, and they succeed because each run is randomized.

For example: Once a player reaches a state where everything in the game is unlocked, declare the player the "Winner of The Sims" somehow, and then give them a few bonuses and unlock a new feature for their next game.

**Solutions #3 #4 and #5 don't offer additional content either**, they only make progressing through the content more difficult and slower. That may be a valid option for you, with the cons that players do not like excessive grinding.

But no matter how much you add, players will eventually reach the end of your content and stop playing. But, that is a good thing. It's hard enough to get players to play your game *at all*. If you can somehow convince a significant subset of players to play all the way to the end of your game, then congratulations! ***You have won as a game designer*** and done better than most other games out there.

On that note: The above paragraphs were "answering the question", so forgive me but this last paragraph will be "advice". I don't know anything about your situation but I'm going to guess that you're an indie developer with a small team and a new IP, near the beginning of your project. If that's the case, then you're worried about the wrong thing. It will be hard enough to get players to play the beginning of your game. Focus on delivering your core loop first, and then worry about endgame content once your core loop is good.
> 1 votes

---
Tags: game-design
---


# Question
Title: How to use the godot::String % operator for string formating of multiple values?
I tried this:

```
godot::String str = "values: %f,%f";
double a = 1.0;
double b = 2.0;
str = str % a % b;

```

Result string is:

```
"not all arguments converted during string formatting"

```

Documentation completely ignores that C++ exists and suggests the following GDScript:

```
var format_string = "%s was reluctant to learn %s, but now he enjoys it."
var actual_string = format_string % ["Estragon", "GDScript"]

print(actual_string)

```

The equivalent of this in C++ would be:

```
str = str % std::tuple(a, b);

```

But there is no operator for std tuple.

How can I format multiple values into godot string?

# Answer
According to the source code, `godot::String` does not seem to implement `%` overloading: char\_string.hpp.

The common\_engine\_methods\_and\_macros documentation shows some common methods, including methods for formatting strings:

```
vformat(String("values:%f,%f"), 1.0, 2.0);

```

`godot:String` also implements a `format` method that accepts a `godot:Array` parameter:

```
String("values:{0},{1}").format(Array::make(1.0, 2.0));

```
> 2 votes

---
Tags: c++, godot, godot-4
---


title: Building Android .aab from Unity

text:
# Question
Title: Building Android .aab from Unity
I have a VR game developed in Unity for Oculus and I want to create an Android App Bundle to upload it to the play store as a mobile game too. When I go into build I select this options:

And here is the problem, after finishing compiling it throws some errors:

1.

```
OverflowException: Value was either too large or too small for an Int32.
System.Number.ThrowOverflowOrFormatException (System.Boolean overflow, System.String overflowResourceKey) (at <a40b0ad4a868437393ad434631fb6ff1>:0)
System.Number.ParseInt32 (System.ReadOnlySpan`1[T] value, System.Globalization.NumberStyles styles, System.Globalization.NumberFormatInfo info) (at <a40b0ad4a868437393ad434631fb6ff1>:0)
System.Int32.Parse (System.String s, System.IFormatProvider provider) (at <a40b0ad4a868437393ad434631fb6ff1>:0)
System.Convert.ToInt32 (System.String value) (at <a40b0ad4a868437393ad434631fb6ff1>:0)
UnityEditor.Android.BundleToolWrapper.CheckApksSize (UnityEditor.Android.AndroidJavaTools javaTools, System.String stagingArea, System.Action`1[T] progress) (at <c8df8c387877487dae452aacc833e6ce>:0)
UnityEditor.Android.PostProcessor.Tasks.CheckApksSize.Execute (UnityEditor.Android.PostProcessor.PostProcessorContext context) (at <c8df8c387877487dae452aacc833e6ce>:0)
UnityEditor.Android.PostProcessor.PostProcessRunner.RunAllTasks (UnityEditor.Android.PostProcessor.PostProcessorContext context) (at <c8df8c387877487dae452aacc833e6ce>:0)
UnityEditor.Android.PostProcessAndroidPlayer.PostProcess (UnityEditor.Modules.BuildPostProcessArgs args, AndroidPlayerBuildProgram.Data.AndroidPlayerBuildProgramOutput buildProgramOutput) (at <c8df8c387877487dae452aacc833e6ce>:0)
UnityEditor.Android.AndroidBuildPostprocessor.PostProcess (UnityEditor.Modules.BuildPostProcessArgs args, UnityEditor.BuildProperties& outProperties) (at <c8df8c387877487dae452aacc833e6ce>:0)
UnityEditor.PostprocessBuildPlayer.Postprocess (UnityEditor.BuildTargetGroup targetGroup, UnityEditor.BuildTarget target, System.Int32 subtarget, System.String installPath, System.String companyName, System.String productName, System.Int32 width, System.Int32 height, UnityEditor.BuildOptions options, UnityEditor.RuntimeClassRegistry usedClassRegistry, UnityEditor.Build.Reporting.BuildReport report) (at <5092d70d16a64dd9a555dd50f38aead0>:0)
UnityEngine.GUIUtility:ProcessEvent(Int32, IntPtr, Boolean&)

```
2.

```
Build completed with a result of 'Failed' in 294 seconds (293528 ms)
UnityEngine.GUIUtility:ProcessEvent (int,intptr,bool&

```
3.

```
UnityEditor.BuildPlayerWindow+BuildMethodException: 2 errors
  at UnityEditor.BuildPlayerWindow+DefaultBuildMethods.BuildPlayer (UnityEditor.BuildPlayerOptions options) [0x002da] in <5092d70d16a64dd9a555dd50f38aead0>:0
  at UnityEditor.BuildPlayerWindow.CallBuildMethods (System.Boolean askForBuildLocation, UnityEditor.BuildOptions defaultBuildOptions) [0x00080] in <5092d70d16a64dd9a555dd50f38aead0>:0
UnityEngine.GUIUtility:ProcessEvent (int,intptr,bool&)

```

The strange thing for me is that the .apk compiles just fine. I need the aab because the game is now around 2GB and will likely be more in the future. Where does this error come from? is it a code problem or something related to configurations?

# Answer
As DMGregory said, the problem is that the aab file is larger than a 32-bit singed integer. The problem in this case is that I had a scene which weighted over 2GB. The other problem I had is that the first scene was to big, it has to be under 15MB, a loading scene, the other can be bigger, but not more than 2GB and the aab has a maximum size but I do not know what that limit is.
> 1 votes

---
Tags: unity, android
---


# Question
Title: GUI TextButton fails to show emoji display when clicked
I want to create a GUI where, when I click a button, an emote display pops up, and when I click an emote, it closes.

Currently, my display won't even show when the button is clicked. This is my code, can anyone help me?

```
local button = game.StarterGui.ScreenGui.EmoteButton.TextButton
local emoteDisplay = game.StarterGui.ScreenGui.EmoteDisplay
local emoteDisplayButtons = emoteDisplay.Emotes:GetChildren()

button.MouseButton1Click:Connect(function()
    print("Emote Button clicked.")
    emoteDisplay.Visible = true
    for emote in emoteDisplayButtons do
        emote.MouseButton1Click:Connect(function()
            print(emote.Name + "Button clicked")
            emoteDisplay.Visible = false
        end)
    end
end)

```

# Answer
You’re referencing StarterGUI, when you should be referencing each player’s UI; every player gets a *copy* of startergui when they join the game that they can interact with, and this script affects the originial (which cannot be interacted with).

I would add a localscript to the UI button that references it through parent, that should make it work.
> 1 votes

---
Tags: gui, roblox
---


# Question
Title: How should I bind various types of material data to the ray tracing rendering pipeline in DirectX12?
My problem is a bit complicated. When doing ray tracing rendering, all data in the scene needs to be prepared. In addition to texture resources, each object to be rendered will also have its own material data. Because the shader codes are different, the data structures of these material data are also different. For example:

```
sturct S1 { float3 p1, uint p2, float p3 };
struct S2 { float2 p1, float2 p2, uint2 p3};

```

Assuming that all objects in the scene use the same material, then their material data structure are the same. So I can create an SRV for each material data (one material data corresponds to an ID3D12Resource), and then bind it through the Descriptor Table to the pipeline and write a declaration in HLSL:

```
StructuredBuffer<S1> _MaterialDatasBuffer : register(t0);

```

Then use the ID obtained through InstanceID() to index this S1 array buffer. It's very simple.

But the problem is that it's impossible for all objects in the scene to use the same material, and the data structures corresponding to different materials are different. So it seems that I can't use a single StructuredBuffer to bind all data. But I don’t want to write a StructuredBuffer for every type of material, because I want my solution to handle arbitrary scenarios. Suppose there are 1,000 objects in the scene and 100 type of materials are used, I don’t want to create 100 descriptor table in C++ and I also don't want to write 100 StructuredBuffers of different types in HLSL. So how should I do?

Actually I have solved this problem in Vulkan. In Vulkan, each of my material data corresponds to a VkBuffer. Then I stored the VkBuffer addresses of all the material data in the scene into an array, and bound this address array to the pipeline. Then index the address array according to the current object ID in GLSL, and after obtaining the address, use buffer\_reference to obtain the data at the address. In this way, no matter how many material data types there are, you only need to declare the material data type corresponding to the current shader in glsl:

```
layout(buffer_reference, scalar) buffer MaterialBuffer { S1 material; };

```

But it seems that in D3D12 it is not possible to obtain a buffer on the GPU memory through the GPU address like Vulkan. So how can I bind a variable amount of material data which have different data structure to the pipeline?

# Answer
> 0 votes
One option would be to use offsets into a single large ByteAddressBuffer, and then load the data from there. That way you can store an offset into the buffer with each object, instead of a buffer address, and the shader code can interpret that in whatever way it needs to for the specific material type.

The shader code might look something like this:

```
ByteAddressBuffer g_parameterBuffer;

void SomeFunction(int parameterBufferOffset)
{
    float4 param1 = asfloat(g_parameterBuffer.Load4(parameterBufferOffset));
    uint param2 = g_parameterBuffer.Load(parameterBufferOffset + 16);
    // etc.
}

```

You might also find http://www.joshbarczak.com/blog/?p=1260 useful for understanding more about the various types of buffers available in DirectX.

---
Tags: rendering, directx, graphics-programming, raytracing, directx12
---


title: Vulkan Phong shader problem

text:
# Question
Title: Vulkan Phong shader problem
Light increases its intensity as it come closer the origin model.

Vertex Shader:

```

layout(push_constant) uniform MVPConst{
    mat4 m;
    mat4 v;
    mat4 p;
} mvp;

layout(location = 0) in vec3 inPosition;
layout(location = 1) in vec3 inColor;
layout(location = 2) in vec2 inTexCoord;
layout(location = 3) in vec3 inNormal;

layout(location = 0) out vec3 fragColor;
layout(location = 1) out vec2 fragTexCoord;
layout(location = 2) out vec3 normal;
layout(location = 3) out vec3 vP;
layout(location = 4) out vec3 vD;
layout(location = 5) out vec3 wP;
layout(location = 6) out vec3 fragPos;

void main(){
    vec4     wP = mvp.m * vec4(inPosition,1.0f);
    mat4    mat = mvp.p * mvp.v;
    gl_Position = mat * wP + vec4(.0,.5,.0,0);

            normal = normalize(mat3(mvp.m) * inNormal);
      fragTexCoord = inTexCoord;
         fragColor = inColor;
                vP = vec3(mvp.v[3][0], mvp.v[3][1], mvp.v[3][2]);
                vD = normalize(vP - wP.xyz);
}

```

Frag Shader:

```
#version 450

#define PI 3.14159265359

layout(binding = 0) uniform UBO{
    vec4  vP;
  vec4  vD;
  vec4  lP;
    float time;
    uvec2 res;
    float sharp;
    mat4  vM;
    mat4  invvM;
} ubo;

layout(binding = 1) uniform sampler2DArray texSampler;

layout(location = 0) in vec3 fragColor;
layout(location = 1) in vec2 fragTexCoord;
layout(location = 2) in vec3 normal;
layout(location = 3) in vec3 vP;
layout(location = 4) in vec3 vD;//Maybe problem
layout(location = 5) in vec3 wP;
layout(location = 6) in vec3 fragPos;

layout(location = 0) out vec4 outColor;

uvec2 res     = ubo.res;
float time    = ubo.time;

vec3 specular(){
    vec3 diffuseLight = vec3(1.);
    vec3 specularLight = vec3(.0);
    vec3 surfaceNormal = normalize(normal);

    vec3 cameraPosWorld = ubo.invvM[3].xyz;
    vec3 viewDirection = normalize(cameraPosWorld - wP);

    vec3 directionToLight = ubo.lP.xyz - wP.xyz;
    float attenuation = 1.0 / dot(directionToLight, directionToLight); // distance squared
    directionToLight = normalize(directionToLight);

    float cosAngIncidence = max(dot(surfaceNormal, directionToLight), 0);
    vec3 intensity = vec3(1.,0.,0.) * attenuation * 1.5;

    diffuseLight += intensity * cosAngIncidence;

    vec3 halfAngle = normalize(directionToLight + viewDirection);
    float blinnTerm = dot(surfaceNormal, halfAngle);
    blinnTerm = clamp(blinnTerm, 0, 1);
    blinnTerm = pow(blinnTerm, 512.0); // higher values -> sharper highlight
    specularLight += intensity * blinnTerm;

    vec3 color = texture(texSampler,vec3(fragTexCoord,2)).rgb;
    vec3 ambient = .2 * color;
    return ambient * diffuseLight;
}

void main(){
    vec2 vpuv = fragPos.xy / res;
    vpuv.y    = 1. - vpuv.y;

    outColor.rgb = specular();
}

```

cpp code:

```
if(_camera.ang.x > 360.f)      _camera.ang.x = 0.f;
    else if(_camera.ang.x < 0.f)   _camera.ang.x = 360.f;
    if(_camera.ang.y > 89.f)     _camera.ang.y = 89.f;
    else if(_camera.ang.y < -89.f) _camera.ang.y = -89.f;
    if(_camera.ang.z > 360.f)     _camera.ang.z =  0.f;
    else if(_camera.ang.z <  0.f)  _camera.ang.z = 360.f;

    _camera.dir.x = cos(glm::radians(_camera.ang.x)) * cos(glm::radians(_camera.ang.y));
    _camera.dir.y = sin(glm::radians(_camera.ang.x)) * cos(glm::radians(_camera.ang.y));
    _camera.dir.z = sin(glm::radians(_camera.ang.y));
    _camera.dir   = glm::normalize(_camera.dir);

    objAng.second = vec3(0.f,1.f,1.f);
    glm::mat4 m      = glm::rotate(glm::mat4(1.0f), radians(sharpness), objAng.second);
          m      = glm::translate(m,obju->pos);
    glm::mat4 v      = glm::lookAt(_camera.pos, _camera.pos + _camera.dir, glm::vec3(0.f,0.f,1.f));
    glm::mat4 p       = glm::perspective(glm::radians(60.f), _swapChnExtent.width / (float) _swapChnExtent.height, 0.1f, 1000.0f);
          p[1][1] *= -1;

    _camera.view = v;

    _camera.invview[0][0] = _camera.view[0][0];
    _camera.invview[0][1] = _camera.view[1][0];
    _camera.invview[0][2] = _camera.view[2][0];
    _camera.invview[1][0] = _camera.view[0][1];
    _camera.invview[1][1] = _camera.view[1][1];
    _camera.invview[1][2] = _camera.view[2][1];
    _camera.invview[2][0] = _camera.view[0][2];
    _camera.invview[2][1] = _camera.view[1][2];
    _camera.invview[2][2] = _camera.view[2][2];
    _camera.invview[3][0] = _camera.pos.x;
    _camera.invview[3][1] = _camera.pos.y;
    _camera.invview[3][2] = _camera.pos.z;
MVP pconst;
    pconst.m = m;
    pconst.v = v;
    pconst.p = p;

    vkCmdPushConstants(info.cmdBuf,_graphxPlineLayt,VK_SHADER_STAGE_VERTEX_BIT,0,sizeof(MVP),&pconst);
    vkCmdBindDescriptorSets(info.cmdBuf,VK_PIPELINE_BIND_POINT_GRAPHICS,_graphxPlineLayt,0,1,&_descrSets[_crntFram],0,nullptr);

    vkCmdDrawIndexed(info.cmdBuf,static_cast<uint32_t>(obju->inds.size()),1,0,0,0);

```

cpp code2:

```
UBO ubo{};
  ubo.vP    = glm::vec4(_camera.pos,1.f);
  ubo.vD    = glm::vec4(_camera.dir,1.f);
  ubo.lP    = glm::vec4(lightPos,1.f);
  ubo.time  = time;
  ubo.sharp = sharpness;
  ubo.vM    = _camera.view;
  ubo.invvM = _camera.invview;

  if(_framBufRsz || _isInitialized){
    ubo.res = vec2(_swapChnExtent.width,_swapChnExtent.height);
  }

  void* data;
  vkMapMemory(_device,_unifBufsMems[crntImg],0,sizeof(ubo),0,&data);
  memcpy(data,&ubo,sizeof(ubo));
  vkUnmapMemory(_device,_unifBufsMems[crntImg]);

```

---

https://pasteboard.co/2XQxHWfsnZJZ.jpg https://pasteboard.co/wNDwXVUVeazO.jpg https://pasteboard.co/SJ87c1aHOXiv.jpg https://pasteboard.co/D8hSSB7D2mtY.jpg

Position of light equal to camera position

# Answer
Final fragment shader

#version 450

#define PI 3.14159265359

layout(binding = 0) uniform UBO{
    vec4  vP;
  vec4  vD;
  vec4  lP;
    float time;
    uvec2 res;
    float sharp;
    mat4  vM;
    mat4  invvM;
} ubo;

layout(binding = 1) uniform sampler2DArray texSampler;

layout(location = 0) in vec3 fragColor;
layout(location = 1) in vec2 fragTexCoord;
layout(location = 2) in vec3 fragNormal;
layout(location = 3) in vec3 fragPosWorld;

layout(location = 0) out vec4 outColor;

uvec2 res  = ubo.res;
float time = ubo.time;

vec3 specular(){
    vec3  diffuseLight = vec3(1.);
    vec3 specularLight = vec3(.0);
    vec3 surfaceNormal = normalize(fragNormal);

    vec3 cameraPosWorld = ubo.invvM[3].xyz;
    vec3  viewDirection = normalize(cameraPosWorld - fragPosWorld);

    vec3 directionToLight = ubo.lP.xyz - fragPosWorld.xyz;
    float     attenuation = 1.0 / dot(directionToLight, directionToLight);
         directionToLight = normalize(directionToLight);

    float cosAngIncidence = max(dot(surfaceNormal, directionToLight), 0);
    vec3        intensity = vec3(.992,.647,.059) * attenuation * 1.5;
             diffuseLight += intensity * cosAngIncidence;

    vec3  halfAngle  = normalize(directionToLight + viewDirection);
    float blinnTerm  = dot(surfaceNormal, halfAngle);
          blinnTerm  = clamp(blinnTerm, 0, 1);
          blinnTerm  = pow(blinnTerm,16.0);
      specularLight += intensity * blinnTerm;

    vec3   color = texture(texSampler,vec3(fragTexCoord,2)).rgb;
    vec3 ambient = .2 * color;

    return ambient * diffuseLight + specularLight * color;
}

void main(){
    vec2 vpuv = gl_FragCoord.xy / res;
    vpuv.y    = 1. - vpuv.y;

    outColor.rgb = specular();
}
```

> 0 votes

---
Tags: c++, 3d, glsl, glm, vulkan
---


# Question
Title: Weapon jitter when playing FPS animation
I extracted drg's auto cannon, and the gun and arms are separated models.

When I try to get them into unity, something wrong happened, I tried a lot of methods. Like using script to attach, using Position constrains and rotation constrain, but still can't fix this issue. I even tried IK, not working.as well.

In my case, I play the running animation in the arm and the gun was not playing animations.

This video shows my problem.

And here is a video of what it looks like in Blender.

And here is how I put models in Unity:

# Answer
Nvm I managed to solve this by myself, in the import setting, the animations are compressed by default for some reasion, I have to disable it to solve this.
> 0 votes

---
Tags: unity, 3d, animation, first-person-shooter
---


# Question
Title: Fast way to calculate angular intervals and occlusion of circular objects in a 2D vision cone
Say I have an agent in 2D in a world filled with circular obstacles of different kind and across many scales (some may be very large, practically filling an agent's view, some may be very small).

The agent has some vision cone and can these obstacles and their kinds if they are within that cone.

I would like to be able to test how much of the agent's cone is occupied by each sort of object and in what direction this happens.

I have already worked out what it takes to find how large a circle would appear in the field of vision of an agent. However, currently the agent can also just see through any object and also react to whatever is behind (the ultimate result is an average weighted by how large each kind of object appears)

Using `Physics2D.OverlapCircleNonAlloc` and an angle-based second check to see if things are still in the vision cone (and how big they are in that cone), I can find all seen objects in order of closeness and give them the appropriate weighting. Currently I'm not doing anything with the ordering information.

I think what I roughly need to do is to define an interval, and fill it up with each object kind (something like a tuple of the kind index, and the left and right bounds of the interval) and check that no previous object already fell in those interval bounds. (If that part of the interval is already covered, clip to parts of the space that are still free) After that I'd have to loop over each segment of the interval and accumulate the weighted average view accordingly.

However, that sounds quite slow. I have potentially hundreds of such agents able to see any kind of obstacle including each other, and even the simpler current vision system is definitely a bottleneck.

Are there ways to do this faster? (Keep in mind that each obstacle is a potentially small 2D circle that appears as a 1D line to an agent)

---

To get the part of an object that's in the field of vision, I'm currently doing roughly this:

```
float r = object.GetObjectRadius(); // the radius of the seen object
Vector2 d = this.transform.position - base.transform.position;  // "this" being the seen object, "base" the agent. The vector from the agent to the target)

float rd2 = Mathf.Min(r * r / d.sqrMagnitude, 1f); // if it's smaller than 1, you are inside the object. Pretend you're just touching it

Vector2 d_tangent = d * (1f - rd2);
Vector2  d_perp_tangent = Vector2.Perpendicular(d) * rd2 * Mathf.Sqrt(1f / rd2 - 1f);

Vector2 left_tangent = d_tangent  + d_perp_tangent;
Vector2 right_tangent = d_tangent - d_perp_tangent

float fov_overlap = Mathf.Min(Vector2.SignedAngle(agentUpVect, left_tangent), half_view) + Mathf.Min(Vector2.SignedAngle(right_tangent, agentUpVect), half_view) // agentUpVect is the direction the agent faces in, half_view is half the vision cone. If fov_overlap < 0, the object is not seen.

```

This should give me the precise part of the view that's occupied by a circular object of radius `r` which is `|d|` units away from an agent. I tried figuring out the above myself and I'm fairly confident it's right. I verified this by also implementing this math in GeoGebra:

---

EDIT: Adapted from @Mangata, here is a simplified schematic of what is needed:

for simplicity, I have normalized it here such that the view is in the interval \[-1, 1\] and anything outside that gets discarded. You can see here three different kinds of objects and "the horizon" all of which need to correctly handle occlusions. In the end I'd like to have the total length of the intervals of each kind of "color" (note, these are a small number of fixed labels for me, one per kind of object, not actually RGB colors. For instance, black might be another agent, small but close by, red might be food, and green poison. The blue part is nothing / "the horizon")

# Answer
Here are some optimization suggestions:

**1. Filter unnecessary tests**

1. Objects located outside the field of view circle(`distance>r1+r2`) do not need to be detected. Considering that calculating distance requires multiplication, AABB detection is better.
2. Space\_partitioning.

**2. Angle calculation**

`BF` and `BG` are tangents of circle `A`, ∠AGB = 90°, so that ∠ABG=arcsin(|AG|/|AB|).

**3. Visibility calculation**

1. Establish a rectangular coordinate system in which the abscissa is distance and the ordinate is angle. At this time, the field of view is a rectangle and the object is a line segment. Of course this only happens in your head, just to make it easier to understand.

2. You don't need to define an interval to check again. Because the `y` coordinates of all line segment endpoints will divide the field of view into areas, and the visible conditions inside each area are consistent. In the picture below, 4 line segments divide the field of view into 7 areas, and their bounds have floating point precision:

4. Sort all endpoints, get the mapping of y(float) to area index(int). Traverse all line segments and find all areas it covers. pseudocode:

```
points = [view.left,view.right]
for segment in segments:
    segment.left = clamp(segment.left,view.left,view.right)
    segment.right = clamp(segment.right,view.left,view.right)
    points.append(segment.left)
    points.append(segment.right)

points = list(set(points)) #Remove duplicate values
points.sort()

areas = [Area()] * len(points)

for segment in segments:
    leftIndex = points.index(segment.left)
    rightIndex = points.index(segment.right)
    for i in range(leftIndex,rightIndex):
        areas[i].segments.append(segment)

```

\*PS.Code is untested, please be aware of bounds issues and floating point precision issues
> 3 votes

# Answer
My first move would be to use a `Raycast` at regular intervals between the start & end angles. In other words:

1. begin at the starting angle
2. perform a raycast from the observer
3. increment the angle
4. if the angle is inside the the FOV range go back to 2.
5. otherwise perform one last raycast along the end angle

The above is has slightly uneven precision in because of the extra raycast at the end. If that's an issue you could alternatively start from the center & work your way toward the edges. In either case, excluding any intersections that further away than the sensor range will clip the results to the FOV.

As described in this answer, the Unity engine does some work to calculate raycast intersections efficiently. But at some point, a large enough scale simulation is going to run into bottlenecks as the number of simultaneous agents scales up.
> 1 votes

---
Tags: unity, c#, 2d, intersection, visibility-determination
---


title: Rotating 2D sprite around tilted Y axis

text:
# Question
Title: Rotating 2D sprite around tilted Y axis
I am building a sprite that I want to spin along an axis. I am using SpriteKit on iOS for this, but I'm sure that the question is not really tool specific.

In my case, I have a sprite such as:

and I want to rotate it around the red line as if it is a spinning disc spinning in 3D (even though it is only a 2D sprite).

SpriteKit gives me the SKTransformNode class that allows me to adjust the X, Y and Z rotation of the node. So I am able to rotate the sprite along the X or Y axis in pseudo 3D. The following 3 images attempt to give you an idea of what I'm trying to achieve:

I thought I should be able to animate the rotation around the X and Y axis in a way to achieve this but I've found it harder than expected.

I'm hoping that someone can point me in the right direction.

\[edit\]

to further illustrate what I *don't* want, here is what happens using simply Y scaling without using an SKTransformNode. Note that the image inside the circle does not reflect as it turns.

# Answer
> 2 votes
Try creating the art so that the red line is horizontal, then rotate it in Swift on its `zRotation`, and animate scaling along the `scaleX` or `scaleY` to achieve the effect.

For example:

```
class GameScene: SKScene {
    private var sprite : SKSpriteNode?
    override func didMove(to view: SKView) {
        self.sprite = self.childNode(withName: "//axis") as? SKSpriteNode
        if let sprite = self.sprite {
            sprite.zRotation = -CGFloat.pi / 3
            let scaleDown = SKAction.scaleY(to: -1.0, duration: 2)
            let scaleUp = SKAction.scaleY(to: 1.0, duration: 2)
            let sequence = SKAction.sequence([scaleDown, scaleUp])
            sprite.run(SKAction.repeatForever(sequence))
        }
    }
}

```

# Answer
> 3 votes
I think this would be easiest using SKTransformNode.setQuaternion instead.

This makes it easy to express a rotation by some angle around any axis you choose, rather than only rotations around the coordinate axes as with Euler angles. You *can* come up with Euler triples to correspond to any arbitrary orientation, but it's complicated for diagonal axes.

Instead, you can `init` a `simd_quatf` using a given `angle` (expressed as a `Float` in radians) and `axis` (`SIMD3<Float>`) to rotate around. Pass that to `setQuaternion` and you're set. You can repeat this each frame, incrementing your `angle` argument over time to make it spin, while holding the rotation axis fixed.

This way, you don't have to do any trigonometric calculations yourself — that's all handled by the `init` function.

---
Tags: 2d, 3d, sprites, spritekit
---


# Question
Title: How do I determine which pixel is under the cursor when looking at an equirectangular image through a camera?
I am working on a game. The camera is freely rotatable by the user. The background is displayed from an equirectangular image. I need to know which pixel of the background image is located under the cursor at any moment. My research leads to equations mapping a flat image onto a spherical surface but I need the opposite and occasionally run into the 'reverse projection' problem, usually presented in a scholarly paper. However, I've been using an old game engine that does exactly that, although I'm having problems decoding the source code to see how it was done. Perhaps it was a hack that was approximate enough? (for anybody using Godot, I would LOVE a pointer to some function that already does that for me)

# Answer
> 0 votes
We can attack this in stages.

First, we convert the point clicked on the screen into a direction in the 3D world, the same way we'd do if we were casting a ray from the camera for 3D picking. For instance, if we want to do this on mouse click, we can basically copy the example from that page of the documentation:

```
func _input(event):
    if event is InputEventMouseButton and event.pressed and event.button_index == 1:
          var camera3d = $Camera3D
          var direction = camera3d.project_ray_normal(event.position)

```

Next, we convert that direction into spherical coordinates. I don't have Godot in front of me atm, but I'll assume `project_ray_normal` returns a unit vector. If not, normalize `direction` before proceeding:

```
var latitude = asin(direction.y)
var longitude = atan2(direction.z, direction.x)

```

This gives you the latitude angle in the range \\$- \frac \pi 2\\$ to \\$+ \frac \pi 2\\$ and the longitude angle in the range -π to π. You can then rescale this into the pixel dimensions of your image:

```
var x = (longitude/PI * 0.5 + 0.5) * width
var y = (latitude/PI + 0.5) * height

```

If you find the x coordinates you get are starting at the wrong place or wrapping the wrong way, you can fix this by exchanging or negating the arguments to `atan2` (I don't know which mapping you're using, so I can't say which of the 8 permutations is right for your needs).

---
Tags: godot, projection, trigonometry, gdscript, sphere
---


# Question
Title: Multiple .NET Host Running in UnrealEditor
Unreal Editor has 64+ services running under it with .Net host and console window host running multiple times. I am running Unreal Engine 5.3.2 source build. I have tried recompiling and redownloading the source several times with the same effect. How to get rid of those many process of .NET running, which are making my system laggy?

# Answer
I would generally caution you against thinking any specific process is causing your system to be "laggy" without a good reason for assuming so.

Your computer is running tens of thousands of concurrent threads all the time. A handful of (what appear to be) internal processes for Unreal are not likely to be introducing any load into your system. (For example don't ever look at `chrome.exe` it is frightening)

You do seem to have some memory pressure, increasing the amount of RAM in your system is an option assuming you have the time and resources to do so, but this still may not solve your problem.

There are dozens of factors which could cause your system to feel slow. Those processes *could* be the reason. I would recommend filing a support ticket with the owners of the tooling directly as recommended in the comments if you want to know more about specifically those processes.

In general if your system is running at 80-90% memory utilization you are potentially going to run into hiccups.
> 0 votes

---
Tags: unreal, .net
---


# Question
Title: Prevent color adjustment in ViewportTexture
In Godot 4.1.1, I'm trying to use ViewportTextures to capture values generated by some shaders for use in another shader. One SubViewport is capturing the result of an unshaded spatial shader on a full-screen quad. However, when I sample the texture, I don't get exactly what the shader produced. It looks like the colors are adjusted. How can I prevent that?

Here's a simplified setup to show the issue:

```
Node3D
  MeshInstance3D(QuadMesh, postprocess.gdshader)
  Camera3D
  SubViewport2D(disable_3d = true)
    ColorRect(Full Rect, 2d.gdshader)
  SubViewport3D(own_world_3d = true)
    MeshInstance3D(QuadMesh, 3d.gdshader)
    Camera3D

// 2d.gdshader
shader_type canvas_item;
void fragment() { COLOR = vec4(UV, 0.4, 1.0); }

// 3d.gdshader
shader_type spatial;
render_mode unshaded;
void vertex() { POSITION = vec4(VERTEX, 1.0); }
void fragment() { ALBEDO = vec3(SCREEN_UV, 0.4); }

// postprocess.gdshader
shader_type spatial;
render_mode unshaded;

uniform sampler2D SubViewport2D;
uniform sampler2D SubViewport3D;

void vertex() { POSITION = vec4(VERTEX, 1.0); }
void fragment() {
    vec3 col1 = vec3(SCREEN_UV, 0.4);
    vec3 col2 = texture(SubViewport2D, SCREEN_UV).rgb;
    vec3 col3 = texture(SubViewport3D, SCREEN_UV).rgb;
    // Put col2 on the left, col3 on the right.
    bool left = SCREEN_UV.x < 0.5;
    // Put col1 on even pixels.
    bool even = fract((SCREEN_UV * VIEWPORT_SIZE).x * 0.5) < 0.5;
    ALBEDO = even ? col1 : (left ? col2 : col3);
}

```

In the last shader, I expect `col2` and `col3` to equal `col1`. The output indicates that `col2 = col1`, while `col3` is visually similar but not the same:

I tried adding a WorldEnvironment to SubViewport3D but it didn't make a difference. This issue looks relevant but I'm not sure.

# Answer
> 1 votes
If this is due color conversion (as DMGregory guesses), then I think your `sampler2D` need `source_color`. Example:

```
uniform sampler2D image : source_color;

```

The `source_color` hint is the replacement of Godot 3 `hint_albedo` for Godot 4.

Quote from the documentation:

> It's important to understand that textures that are supplied as color require hints for proper sRGB-\>linear conversion (i.e. source\_color), as Godot's 3D engine renders in linear color space.

Note: The hint `source_color` also works vector colors.

---

You might also want to check the `WorldEnviroment`, in particular if there is any color correction set. *And I don't know if Tone mapping could be an issue.*

---
Tags: shaders, godot-4
---


# Question
Title: Funnel algorithm : not possible with all convex polygons?
Disclaimer : yes, the whole map is not convex. But all of its subdivisions are ! (And that's what matters)

Hi ! I got A\* working with nav mesh. Now I need to find the tightest path along the mesh path. While reading about the Funnel algorithm, I found an article where the author mentions that this algorithm can work with any convex polygon, as long as no portals are intersected.

However, while testing it, I ran into a problem : my algorithm is blocked. (See figure B) In figure A, the funnel can be narrowed, but in figure B, we can clearly see that neither side can progress :(

1 - Am I understanding the algorithm correctly ?

2 - Should I simply stick with triangles ? (I was keen on using polygons)

3 - Do you suggest another algorithm to make it work with any convex polygon ?

Thanks for your help !

Link to article : https://digestingduck.blogspot.com/2010/03/simple-stupid-funnel-algorithm.html (The claim about convex polygons is faaar in the comment section. (Ctrl + F -\> search for convex))

# Answer
> 3 votes
Edit : After further testing, I found out that a special case of this kind is also needed for triangles in some cases. I probably just incorrectly understood the algorithm ? Maybe it's because this special case isn't often covered in other articles.

A kind person nicknamed winkio helped me on Discord, so I'll share what I understood from his answer here.

Disclaimer : to understand this, start by understanding the Simple funnel algorithm : http://digestingduck.blogspot.com/2010/03/simple-stupid-funnel-algorithm.html

To handle any convex polygon (and not just triangles), we can add a special case to the algorithm, of which I'll give an example at steps F-G.

I tried my best to explain (and illustrate it), but the special case can be difficult to grasp. I think it's worth reading if you want to use any convex polygon like me ! Somehow I was having trouble finding documentation on this very constraint. (Perhaps because going exclusively with triangles is the way) If you ever need more details, let me know in a comment !

Step A : Starting the algorithm. Both sides reach the next (first) portal.

Step B : Starting randomly with the left side, we try to reach the next left end of the next portal : this is narrowing the funnel, so it's good. ✅

Step C : Moving on to the right side, we try to reach the next right end of the next portal : this is narrowing the funnel so it's good. ✅

Step D : Moving on to the left side, we try to reach the next portal... but it's broadening the funnel, so we don't do it.

Step E : Moving on to the right side, we try to reach the next portal... but it's broadening the funnel, so we don't do it.

Step F : Ooops ! We can't progress on either side. In this special case, winkio suggests we "force" the algorithm to progress on both sides, but we must keep in mind the previous vectors... which makes a concave funnel, temporarily. Of course, this makes the algorithm a bit more complex because we need to keep track of more data in this case.

Step G : We try to progress with the left side. (Still from the first apex) Oops ! We're narrowing the funnel, but we passed over the right side. We must then add a new apex on the right side, on the last portal that was reached without problem. Because of the step F, we must also check if the new left side is also passing over the new right side, starting from the new apex. It is not the case, and since we overcame the "weird special case situation", we are back to a normal funnel.

Step I : Trying to progress on the right side. We can't, because it's broadening the funnel.

Step J : Trying to progress on the left side. Oops ! We passed over the right side. ⛔

Step K : Time to place a new apex. We also progress on the right side otherwise the right side vector will be (0,0). At this point we could stop because one side reached the goal.

Step L : The left side also reaches the goal if we continue the algorithm.

---
Tags: path-finding, navmesh
---


# Question
Title: Unity - Autoscroll when selecting buttons out of viewport
I have a ScrollView element, that contains many buttons. I want that when I select buttons (via arrow keys), the panel scrolls so that the selected button is contained within the viewport.

How could I achieve this?

**UPDATE**

This is example of my structure (with 2 buttons only, but you get the gist...)

# Answer
A simple solution is to set the value of the ScrollRect's verticalNormalizedPosition (0f - 1f). Here's the solution I came up with (doesn't include horizontal elements, but similar logic could be applied for your use case).

**ButtonSelectionController (attached to ScrollView)**

```
[RequireComponent(typeof(ScrollRect))]
public class ButtonSelectionController : MonoBehaviour
{
    [SerializeField]
    private float               m_lerpTime;
    private ScrollRect          m_scrollRect;
    private Button[]            m_buttons;
    private int                 m_index;
    private float               m_verticalPosition;
    private bool                m_up;
    private bool                m_down;

    public void Start()
    {
        m_scrollRect        = GetComponent<ScrollRect>();
        m_buttons           = GetComponentsInChildren<Button>();
        m_buttons[m_index].Select();
        m_verticalPosition  = 1f - ((float)m_index / (m_buttons.Length - 1));
    }

    public void Update()
    {
        m_up    = Input.GetKeyDown(KeyCode.UpArrow);
        m_down  = Input.GetKeyDown(KeyCode.DownArrow);

        if (m_up ^ m_down)
        {
            if (m_up)
                m_index = Mathf.Clamp(m_index - 1, 0, m_buttons.Length - 1);
            else
                m_index = Mathf.Clamp(m_index + 1, 0, m_buttons.Length - 1);

            m_buttons[m_index].Select();
            m_verticalPosition = 1f - ((float)m_index / (m_buttons.Length - 1));
        }

        m_scrollRect.verticalNormalizedPosition = Mathf.Lerp(m_scrollRect.verticalNormalizedPosition, m_verticalPosition, Time.deltaTime / m_lerpTime);
    }
}

```

All button children of the ScrollView are got during `Start`, and the initial button is selected. During `Update` we're then XOR-ing the up and down arrows so as not to constantly scroll up and down.

I'm then clamping the value of the index to use to the number of button available, before selecting the button at the new index. The position of the ScrollRect is then set to a percentage based on which button is selected from the list (we're subtracting the value from 1f because the position variable works from the bottom up). The new position is then lerped to over the time specified by `m_lerpTime`.

Hope this helped you.
> 2 votes

# Answer
If you want to use BaseInputModule's movement (which could support gamepad with an appropriate InputModule), you'll want to modify `verticalNormalizedPosition` based on the position of your selected object relative to its anchor and mask region. You can see a working example in UIScrollToSelection.cs.

I found it has some bad early out cases for my multiple layer hierarchy ("check if scrolling is possible"), unsmooth upward scrolling, and no scrollwheel handling (IScrollHandler, IBeginDragHandler, IEndDragHandler).

If you wanted to do it yourself:

* get the selected element (`EventSystem.current.currentSelectedGameObject.GetComponent<RectTransform>()`)
* project its position into your view (`anchoredPosition.y + scrollRect.content.anchoredPosition.y`)
* imagine what's the first and last valid position for your element (0 and mask height less the height of one element)
* then check if your element is before the first valid or after the last valid and add or decrement accordingly.

To avoid fighting with the mouse, you should implement IScrollHandler, IBeginDragHandler, IEndDragHandler and disable your autoscroll (I also clear the currentSelectedGameObject).
> 0 votes

# Answer
A more general solution:

1. get the current selection
2. check if it's a child of the ScrollRect
3. use a bit of math to scroll to it directly:

This works pretty well, and can be limited to only react to controller or keyboard navigation.

```
using UnityEngine;
using UnityEngine.UI;
// https://gist.github.com/sttz/c406aec3ace821738ecd4fa05833d21d
namespace UI
{
    public static class UIExtensions {
        // Shared array used to receive result of RectTransform.GetWorldCorners
        static readonly Vector3[] Corners = new Vector3[4];

        /// <summary>
        /// Transform the bounds of the current rect transform to the space of another transform.
        /// </summary>
        /// <param name="source">The rect to transform</param>
        /// <param name="target">The target space to transform to</param>
        /// <returns>The transformed bounds</returns>
        // ReSharper disable once MemberCanBePrivate.Global
        public static Bounds TransformBoundsTo(this RectTransform source, Transform target)
        {
            // Based on code in ScrollRect internal GetBounds and InternalGetBounds methods
            Bounds bounds = new Bounds();
            if (source != null) {
                source.GetWorldCorners(Corners);

                Vector3 vMin = new Vector3(float.MaxValue, float.MaxValue, float.MaxValue);
                Vector3 vMax = new Vector3(float.MinValue, float.MinValue, float.MinValue);

                Matrix4x4 matrix = target.worldToLocalMatrix;
                for (int j = 0; j < 4; j++) {
                    Vector3 v = matrix.MultiplyPoint3x4(Corners[j]);
                    vMin = Vector3.Min(v, vMin);
                    vMax = Vector3.Max(v, vMax);
                }

                bounds = new Bounds(vMin, Vector3.zero);
                bounds.Encapsulate(vMax);
            }
            return bounds;
        }

        /// <summary>
        /// Normalize a distance to be used in verticalNormalizedPosition or horizontalNormalizedPosition.
        /// </summary>
        /// <param name="scrollRect">The target scrollRect</param>
        /// <param name="axis">Scroll axis, 0 = horizontal, 1 = vertical</param>
        /// <param name="distance">The distance in the scroll rect view coordinate space</param>
        /// <returns>The normalized scroll distance</returns>
        // ReSharper disable once MemberCanBePrivate.Global
        public static float NormalizeScrollDistance(this ScrollRect scrollRect, int axis, float distance)
        {
            // Based on code in ScrollRect internal SetNormalizedPosition method
            RectTransform viewport = scrollRect.viewport;
            RectTransform viewRect = viewport != null ? viewport : scrollRect.GetComponent<RectTransform>();
            Rect rect = viewRect.rect;
            Bounds viewBounds = new Bounds(rect.center, rect.size);

            RectTransform content = scrollRect.content;
            Bounds contentBounds = content != null ? content.TransformBoundsTo(viewRect) : new Bounds();

            float hiddenLength = contentBounds.size[axis] - viewBounds.size[axis];
            return distance / hiddenLength;
        }

        /// <summary>
        /// Scroll the target element to the vertical center of the scroll rect viewport.
        /// Assumes the target element is part of the scroll rect contents.
        /// </summary>
        /// <param name="scrollRect">Scroll rect to scroll</param>
        /// <param name="target">Element of the scroll rect content to center vertically</param>
        public static void ScrollToCenter(this ScrollRect scrollRect, RectTransform target)
        {
            // The scroll rect view space is used to calculate scroll position
            RectTransform view = scrollRect.viewport != null ? scrollRect.viewport : scrollRect.GetComponent<RectTransform>();

            // Calculate the scroll offset in the view's space
            Rect viewRect = view.rect;
            Bounds elementBounds = target.TransformBoundsTo(view);
            float offset = viewRect.center.y - elementBounds.center.y;

            // Normalize and apply the calculated offset
            float scrollPos = scrollRect.verticalNormalizedPosition - scrollRect.NormalizeScrollDistance(1, offset);
            scrollRect.verticalNormalizedPosition = Mathf.Clamp(scrollPos, 0f, 1f);
        }
    }
}

using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.InputSystem;
using UnityEngine.UI;

namespace UI
{
  [RequireComponent(typeof(ScrollRect))]
  public class ScrollRectAutoScroll : MonoBehaviour
  {
    [Tooltip("The UI/Navigate action used by controller and keyboard to use menus")]
    [SerializeField] InputActionReference navigateAction;
    /// <summary>
    /// The scrollRect attached to this component
    /// </summary>
    ScrollRect _scrollRect;

    public void Start()
    {
      // Get the scrollRect
      _scrollRect = GetComponent<ScrollRect>();
      // Scroll to selection on init
      ScrollToSelection();
    }

    void ScrollToSelection()
    {
      // Get the selection
      GameObject selection = EventSystem.current.currentSelectedGameObject;
      // If no selection, return
      if (!selection) return;
      // If selection is not a child of the scrollRect, return
      if (!selection.transform.IsChildOf(transform)) return;
      // If somehow the selection is not a RectTransform, return
      if (!selection.TryGetComponent(out RectTransform rectTransform)) return;
      // Scroll into view
      _scrollRect.ScrollToCenter(rectTransform);
    }

    public void Update()
    {
      // If user has used the navigate buttons this frame, update scroll
      if (navigateAction.action.inProgress)
        ScrollToSelection();
    }
  }
}

```
> 0 votes

---
Tags: unity
---


# Question
Title: "Springy legs" for a First Person Controller in Godot 4
I'm a total beginner, so I barely know what I'm doing, but here goes: I'm using this First Person Starter template and I would like to add a "springy legs" feature on character landing. The higher is the jump, the stronger the springy effect is on landing (but there should probably be a maximum cap value specified).

How can this be achieved?

EDIT: Here's a demonstration of what more or less what I'd like it to feel like: https://youtu.be/dSsV657JYRU

# Answer
> 0 votes
You could use a tween to bounce the camera when you land.

That requires two things:

1. detecting when you land
2. bouncing the camera

Modifying MovementController.gd in the template you're using to something like this might work. It's untested and I'm assuming that the camera always sits at its local position. If it's not working, you'd need to rework it so there's a CameraRoot with a Camera3D child and the system moves the CameraRoot around so we're free to animate the Camera3D.

```
@export var camera : Camera3D
@export var springy_leg_distance := 0.5
@export var springy_leg_seconds := 0.7

var _was_on_floor := false
var _camera_tween

func _physics_process(delta: float) -> void:
    input_axis = Input.get_vector("move_back", "move_forward", "move_left", "move_right")

    direction_input()

    if is_on_floor():
        if Input.is_action_just_pressed("jump"):
            velocity.y = jump_height
        if _was_on_floor:
            # (1) At this point, we went from not on floor to on floor, so we
            # want to bounce.
            # We might also want to scale the amount of bounce by our
            # *previous* downward velocity.
            _play_camera_ground_impact()
    else:
        velocity.y -= gravity * delta

    accelerate(delta)

    # is_on_floor returns a different value after calling move_and_slide
    _was_on_floor = is_on_floor()
    move_and_slide()

func _play_camera_ground_impact():
    # (2) Fire off a tween to bounce the camera to give a springy legs effect.
    if _camera_tween:
        # Prevent two overlapping tweens.
        # You may want to stop if you stop touching the ground too.
        _camera_tween.stop()
    _camera_tween = get_tree().create_tween()
    # Assuming default local position is zero!
    camera.position = Vector3.DOWN * springy_leg_distance # start down a bit
    _camera_tween.tween_property(
            camera,
            "position",
            Vector3.ZERO,                                 # tween back up
            springy_leg_seconds)
    _camera_tween.start()

```

You could also use an animation to have more control over the motion of the camera.

---
Tags: godot, gdscript, godot-4
---


title: Unity debug error “Frame not in module”

text:
# Question
Title: Unity debug error “Frame not in module”
I'm creating a 2D game, and all my game layers are UI canvases. Here's the issue: during debugging, every time I click on the screen, Visual Studio stops and displays "Frame not in module," and I have to click "continue." It's abnormal because I didn't add breakpoints for each click.

# Answer
Well It is solved by rebuild the whole program and close all the files opened. Maybe it is because I open some unity source code and it does not has PDB file.
> 0 votes

---
Tags: unity, unity-ui, debugging
---


# Question
Title: How to stop NavMeshAgent resetting rotation
I'm prototyping a 2.5D style game. I have my sprites angled at a 33° angle on the x axis.

I'm using the NavMeshAgent for basic navigation and pathfinding. I've set the Angular Speed to 0, to prevent the auto rotation to the destination.

But the x rotation is always reset to 0 on play. Is there a setting I'm missing, or do I need to set the rotation in script?

# Answer
You probably need to set `navmeshAgent.updateRotation = false` in a script. See updateRotation.
> 2 votes

# Answer
Adding this Code worked for me.

```
private void Start()
{
    // Store the initial rotation
    initialRotation = transform.rotation;

    // Get the NavMeshAgent component
    navMeshAgent = GetComponent<NavMeshAgent>();
}

private void Update()
{
    if (navMeshAgent.velocity != Vector3.zero)
    {
        // Apply the initial rotation
        transform.rotation = initialRotation;
    }
}

```
> 1 votes

---
Tags: unity, navmesh
---


title: Custom Shader leads to wonky clipping

text:
# Question
Title: Custom Shader leads to wonky clipping
I have a custom shader that will change vertex heights based on texture color. My big issue is that some areas of the mesh texture peek through when they should be hidden. What's going on here?

*plane with texture*

*textured plane with shader*

*improper texture clipping*

*shader code*

```
Shader "Custom/RadarTile"
{
    Properties {
        _MainTex("Base (RGB) Trans (A)", 2D) = "black" {}
        _PinkFix("Pink Fix", float) = 0
        _ReflectivityHeightMultiplier("Height", float) = 0
    }

    SubShader {
        // Cull off // todo: disable for production @jkr
        Tags {"Queue"="Transparent" "IgnoreProjector"="True" "RenderType"="Transparent"}
        //LOD 100 // todo: may need to go up after bump map added @jkr

        ZWrite Off
        Blend SrcAlpha OneMinusSrcAlpha
        // Blend One SrcAlpha

        Pass {  // this pass is to cast cloud shadows @jacksonkr
            CGPROGRAM
                #pragma vertex vert
                #pragma fragment frag
                // #pragma multi_compile_fog

                #include "UnityCG.cginc"
                #include "TileBender.cginc"

                sampler2D _MainTex;
                sampler2D _RadarFrame2;
                sampler2D _ReflectivityLUT;
                sampler2D _ReflectivityLUTPinkFix;
                float _FrameInterpolationAmount;
                float4 _ShadowColor;
                float4 _MainTex_ST;

                sampler2D _NextTex;
                float _PinkFix;
                float _PlaybackTime;
                float _PlaybackPosition;
                int _TotalFrames;
                int _FirstFrameIndex;
                int _LastFrameIndex;

                v2f vert(appdata v)
                {
                    v2f output = vertBender(v, _EdgeUVEpsilon);
                    //return output;

                    v.uv = TRANSFORM_TEX(v.uv, _MainTex);
                    return vertBender(v, _EdgeUVEpsilon);
                }

                float4 frag (v2f i) : SV_Target
                {
                    return 0;

                    fixed4 col = lerp(tex2D(_MainTex, i.uv), tex2D(_RadarFrame2, i.uv), _FrameInterpolationAmount);
                    col = saturate(pow(col, 1.0/2.2));

                    if(_PinkFix == 0) {
                        col = tex2D(_ReflectivityLUT, float2(col.r, 0));
                    } else {
                        col = tex2D(_ReflectivityLUTPinkFix, float2(col.r, 0));
                    }

                    if (col.a > 0) return _ShadowColor; // comment out to disable shadows @jacksonkr_
                    return 0;
                    // return col.a > 0 ? _ShadowColor : 0;

                }
            ENDCG
        }

        Pass {
            CGPROGRAM
                #pragma vertex vert
                #pragma fragment frag
                #pragma glsl
                // #pragma multi_compile_fog

                #include "UnityCG.cginc"
                #include "TileBender.cginc"

                float _ReflectivityHeightMultiplier;

                sampler2D _MainTex;
                sampler2D _RadarFrame2;
                sampler2D _ReflectivityLUT;
                sampler2D _ReflectivityLUTPinkFix;
                float _FrameInterpolationAmount;
                float4 _MainTex_ST;

                float _PinkFix;
                float3 _LightDirection;
                float3 _LightColor;
                float _RadarNdotLEffect;
                float _RadarLightAttenuation;
                float _Roughness;
                float _Vibrance;

                v2f vert(appdata v)//appdata_tan_ v)
                {
                    v2f output = vertBender(v, _EdgeUVEpsilon);

                    // this is a bit of a roundabout way to get here, but I have to work around the tile bending code so we're going with it -BH
                    float4 col = tex2Dlod(_MainTex, float4(output.uv, 0, 0));
                    float4 offsetWorldPosition = float4(output.worldPos + output.norm * col.r * _ReflectivityHeightMultiplier, 1);
                    output.pos = UnityObjectToClipPos(mul(unity_WorldToObject, offsetWorldPosition));
                    output.uv = TRANSFORM_TEX(v.uv, _MainTex);

                    //normal calculation
                    const float e = 1.0 / 129.0;
                    if(output.uv.x <= _EdgeUVEpsilon + e || output.uv.x >= 1 - _EdgeUVEpsilon - e || output.uv.y <= _EdgeUVEpsilon + e || output.uv.y >= 1 - _EdgeUVEpsilon - e)
                    {
                        return output;
                    }

                    //tangent
                    // float2 tangentUV  = v.uv + float2(e,0);
                    // float3 tangentSamplePoint = v.position + v.tangent * e;
                    // float3 tangentWorldPosition = mul(unity_ObjectToWorld, tangentUV);
                    // float3 tangentNormal = normalize(tangentWorldPosition);
                    // reflectivity = tex2Dlod(_MainTex, float4(tangentUV, 0, 0)).r;
                    // tangentWorldPosition = tangentWorldPosition + tangentNormal * reflectivity * _ReflectivityHeightMultiplier;
                    // float3 tangent = normalize(tangentWorldPosition - offsetWorldPosition);
                    // //binormal
                    // tangentUV = v.uv + float2(0, e);
                    // tangentSamplePoint = v.position + cross(v.normal, tangent) * e;
                    // tangentWorldPosition = mul(unity_ObjectToWorld, tangentUV);
                    // reflectivity = tex2Dlod(_MainTex, float4(tangentUV, 0, 0)).r;
                    // tangentWorldPosition = tangentWorldPosition + tangentNormal * reflectivity * _ReflectivityHeightMultiplier;
                    // float3 binormal = normalize(tangentWorldPosition - offsetWorldPosition);
                    // //final calc
                    // output.norm = -cross(tangent, binormal);

                    return output;
                }

                float4 frag (v2f i) : SV_Target
                {
                    fixed4 col = tex2D(_MainTex, i.uv);
                    return col;

                    //fixed4 col = lerp(tex2D(_MainTex, i.uv), tex2D(_RadarFrame2, i.uv), _FrameInterpolationAmount);
                    col = saturate(pow(col, 1.0/2.2));

                    const float3 precipitationTypeThresholds = saturate(pow((float3(255, 200, 150) - 0.5)/ 255.0, 1.0/2.2));

                    float v = 0;
                    if( col.a > precipitationTypeThresholds.x)
                    {
                        v = .67;
                    }
                    else if(col.a > precipitationTypeThresholds.y)
                    {
                        v = .34;
                    }
                    else if(col.a > precipitationTypeThresholds.z)
                    {
                        v = 0;
                    }

                    if(_PinkFix == 0) {
                        col = tex2D(_ReflectivityLUT, float2(col.r, v));
                    } else {
                        col = tex2D(_ReflectivityLUTPinkFix, float2(col.r, v));
                    }

                    //minnaert shading implementation
                    float3 viewDirection = normalize(_WorldSpaceCameraPos.xyz - i.norm * _EarthRadius);
                    float3 cameraSpaceLightDirection = mul(unity_CameraToWorld, normalize(_LightDirection));

                    float NdotL = max((1 - _RadarNdotLEffect), dot( i.norm, cameraSpaceLightDirection));
                    float NdotV = max(0, dot( i.norm, viewDirection ));

                    float3 minnaert = saturate(NdotL * pow(NdotL * NdotV, _Roughness));

                    float3 lightingModel =  minnaert * col.xyz;
                    float3 attenColor = _RadarLightAttenuation;
                    col = float4(lightingModel * attenColor, col.a);

                    //vibrance
                    half average = (col.r + col.g + col.b) / 3.0;
                    half maximum = max(col.r, max(col.g, col.b));
                    half vibrance = (maximum - average) * (-_Vibrance * 3.0);
                    col.rgb = lerp(col.rgb, half3(maximum, maximum, maximum), vibrance);

                    // float4 blend = tileblend(i, col);
                    // return blend;

                    return col;
                }
            ENDCG
        }
    }
}

```

# Answer
The reason this happens is because of this line:

```
ZWrite Off

```

This disables writing to the depth buffer for this rendering pass.

Normally, the depth buffer is what enforces that only the closest (opaque) surface is shown in the final image, and any more distant surfaces that should be occluder behind it are successfully hidden.

As each fragment is rendered, it spits out a colour to blend into the frame buffer, and a depth value related to its distance from the camera plane to write into the depth buffer. If that depth value is farther away than what's already in the depth buffer at that point, we abort that fragment so it doesn't contribute its colour to the output. (By default, that is. We can also change this depth test for various special effects. It's also often possible for the GPU to do an "early z rejection" to abort the fragment before the fragment shader even runs, for better performance, as long as the shader doesn't modify the depth as one of its outputs)

With the depth writing disabled, there's no way for a surface in front to say "I'm already drawn here. If you're behind me, don't draw over me!" Which surface ends up visible depends on the order the triangles are drawn in: the last triangle to get drawn gets the last word. Typically, triangles are not sorted for each draw call (this would be expensive, and is still not sufficient for correct occlusion), so you get the unintuitive overlaps you observe here.

Some ways to fix this:

1. If the texture you're drawing is opaque (as shown here), then delete the `ZWrite Off` and `Blend` lines to get the usual behaviour for opaque surfaces.
2. If you have an object that's mostly regions of full opacity and full transparency, you can draw it "alpha-tested" instead of blending. This is the same as the above but with a `clip()` command in the shader to abort pixels below an opacity threshold. This gives you a hard aliased cut-off between opaque and transparent regions, though you can ameliorate that somewhat with two-pass rendering.
3. If you need intermediate levels of translucency, and you're rendering to a high DPI target or using supersampling, screenspace anti-aliasing, or temporal antialiasing, you can use dithering. This is what a lot of AAA games do these days, where the surfaces are still drawn opaque for correct depth sorting and efficient overdraw reduction, but individual pixels are punched out in a pattern. The AA pass then smears out the dithered pattern of drawn and skipped pixels to look more like translucent blending. This works pretty well for foliage but is not so convincing for glass or smoke.
4. You can sort your geometry back-to-front before rendering and draw with translucent blending, using "the painter's algorithm" to ensure closer pixels are drawn last. This can't handle all combinations of geometry (like two triangles intersecting each other so that neither is fully "in front", but some cases are reasonably well-behaved.
5. You can implement a more complex order-independent transparency scheme, like depth peeling. This is much more complex and much more expensive, so I won't cover it in detail here. There are also approximate order-independent transparent rendering algorithms that achieve a compromise between simplicity and accuracy — you'd have to evaluate which trade-offs are acceptable for your application.
> 2 votes

---
Tags: unity, shaders
---


# Question
Title: change_scene_to_file successfully transitions scene, then transports back to the previous scene
I'm having a problem with `change_scene_to_file` in Godot 4. For some reason after the scene transition succeeded, I was automatically transported back the previous play state.

Here is the video of my problem : https://drive.google.com/file/d/1oC1mx1tqMEnfH9ovZAjP\_d6DI60xODji/view?usp=sharing

I use the same code for `change_scene`

from inside the house to outside:

```
extends Area2D

var entered = false

func _on_body_entered(_body):
    entered = true

func _on_body_exited(_body):
    entered = false

func _process(_delta):
    if entered == true:
        if Input.get_action_strength("enter"):
            get_tree().change_scene_to_file("res://Levels/game_level.tscn")

```

from outside to inside the house:

```
extends Area2D

var entered = false

func _on_body_entered(_body):
    entered = true

func _on_body_exited(_body):
    entered = false

func _process(_delta):
    if entered == true:
        if Input.get_action_strength("enter"):
            get_tree().change_scene_to_file("res://Levels/inside_house.tscn")

```

If I go from `inside_house` to outside it works just fine, but the other way it starts to have this problem.

How do I solve this?

# Answer
> 0 votes
You're checking for user input in `_process()`, which is executed every frame. It's possible that the interaction key is *not* released before reading user input during the next frame (when you're in the indoor scene). Therefore, the undesired transition takes place as well, taking you back outdoor.

Try to detect the key press only for the current frame by using `Input.is_action_just_pressed()` rather than `Input.get_action_strength()`.

---
Tags: godot, godot-4
---