text:
Extrude only vertices where the assigned texture is transparent?
I am looking at implementing a water surface on my spherical object and have created a texture with transparent pixels where the water should be. However, I am currently confused on how I can extrude only vertices where the texture is transparent. Do I have to test the texture at the appropriate position prior to assigning the vertex and just assign a Color.Transparent value to that vertex or am I thinking about this all wrong?

Special thanks to @Bram for helping me to answer some questions that could help clarify my specific situation.

What geometry do you extrude?

Individual vertices with a geometry, fragment, or hull shader.

What is the extrusion for?

To make waves in the water.

When I mention testing texels and then assigning colors to a vertex, I mean doing so beforehand when creating the Vertex[] object. This would be easy enough to do I suppose; I'd have to look into some samples of how to test the texture on the C# side, which is why I'd love to do it in a shader that has a similar flow as below:

Vertex Shader

Create the sphere.

Pixel Shader

Grab only vertices that have transparent pixels via TEXCOORD0.

Geometry/Fragment/Hull Shader

Extrude those vertices.

There is no 1:1 correspondence between vertices and texels. Also, what geometry do you extrude? And where? In a vertex shader? On the CPU? What is the extrusion for? To make land lay higher than the sea? To make waves?

@Bram I've edited my post and hopefully clarified some things.

I updated my answer with a shadertoy implementation, as it seemed like a fun challenge. The waves still look a little fake, but can be a good starting point for you.

@Bram That’s actually really cool! I’ll have to play with it more on Monday!

NOTE: the vertex shader would not create a sphere. It would consume the sphere vertices, and generate fragments. A fragment is kind of like a pixel on your screen, but may or may not be visible depending on fragments in front of it.
I see three possible ways of creating a globe with water and land, and have water show wave animation.
(1) Split land/water on CPU: Separate the sphere mesh into two parts: The land part, and the water part. Then use different shader programs to render them.
(2) Split land/water in vertex shader: Render the globe as a single mesh, and at render time, figure out if a vertex lies on land or water. If it is a water vertex you could perturb the vertex.
(3) Split land/water in fragment shader: In the fragment shader, you look up the texel to see if it is sea or land. If it is sea, you could apply an animated bump map, or better: procedural animation by just perturbing the surface normal a little bit.
Note that your globe geometry will have a much lower resolution than your land/sea texture. So doing a land/sea test per vertex (solution 1 and 2) will only roughly follow coast lines. Solution 3 would definitely look better.
When going for (3) you could even do something similar to "percentage-closer-filtering". Instead of a single texel lookup, you do 9 or so look-ups in its neighborhood. Then you count the number of land texels. If you see both land and sea textures, you know you are on the coast-line. And at coastlines, you can then render a white band to show the "surf" of waves breaking.
In pseudo code:
colour = texture_lookup( uv );
float delta_uv[9][2] =
{
  -e,-e,  0,-e,  e, e,
  -e, 0,  0, 0,  e, 0,
  -e, e,  0, e,  e,-e
};
int numland = 0;
for ( int i=0; i<9; ++i )
{
   samplecoord = uv + delta_uv[i];
   rgba = texture_lookup( samplecoord );
   if ( rgba.a >= 1 ) numland++;
}
if ( numland == 9 )
{
   // inland:
}
else if ( numland == 0 )
{
   // deep sea:
   PERTURB THE SURFACE NORMAL TO CREATE WAVE
   ...
}
else
{
   // coast line: render as white.
   colour = surf_colour;
}
// Shade the fragment using the surface normal, light source, colour, etc.
...

Note that you could have the surf wash in/out the coast by replacing the ( numland == 0 ) test with something more dynamic: some frames you render more surf, some frames, you render less.
UPDATE: because it seemed like a fun challenge, I implemented it on shadertoy. You can see the results and code there.


text:
Why does order matter in constant buffers?
I have a rather peculiar question remaining after solving most of my own question on StackOverflow. When creating the constant buffers used by my shaders, I've learned that the order of variables between the cbuffer and the struct representing it have to be an accurate match. I am still unsure as to why this is such an issue, and that's why I'm here.
When creating a cbuffer to hold object data, I create the cbuffer and struct like so:
cbuffer ObjectBuffer : register(b0) {
    float4x4 World;
    float4x4 WorldViewProjection;
    float4x4 WorldInverseTranspose;
}
public struct ObjectBuffer {
    public Matrix World;
    public Matrix WorldViewProjection;
    public Matrix WorldInverseTranspose;
}

This way works just fine, but if I reorder the cbuffer variables, or the struct variables and do not reflect the changes in the other, issues arise and I can't even create the buffer.
cbuffer ObjectBuffer : register(b0) {
    float4x4 WorldInverseTranspose;
    float4x4 WorldViewProjection;
    float4x4 World;
}
public struct ObjectBuffer {
    public Matrix World;
    public Matrix WorldViewProjection;
    public Matrix WorldInverseTranspose;
}

In this case, the types are exactly the same and given the fact that HLSL expects constant buffers to be in 16 byte chunks; why does the ordering matter so much?
Aren't float4x4 types the same as Matrix types where it's essentially an array of arrays?
[ 0, 0, 0, 0 ] = 16 bytes
[ 0, 0, 0, 0 ] = 16 bytes
[ 0, 0, 0, 0 ] = 16 bytes
[ 0, 0, 0, 0 ] = 16 bytes
[    TOTAL   ] = 64 bytes

Since a float is 4 bytes on its own, this would mean a float4 is 16 bytes, and thus a float4x4 is 64 bytes. So why does the order matter if the size remained the same?

Update
So I've re-visited the issue and turns out I was wrong about the issue given above. This does allow the objects to be compiled correctly but presents grotesque effects in the shaders since the variables are in the wrong order which is expected.
However, this issue came up because I misread which buffer was causing the issue initially. It was all related to my material buffer in which I have a bool and a float. When I swapped the two on either side without reflecting the changes in the other it failed to create. I presume this is due to the difference in expected types. The cbuffer is in bool-float order while the struct is the opposite. This I expect to cause an issue, but it would still be nice to know what's happening under the hood to cause it to break. Is it because bool is a single byte but perhaps allocated into a chunk of 4 bytes?

Your edit to point out that you're seeing errors at creation is useful, but it would help to then see how you are creating the buffer and what the actual error you get is (e.g., from the debug layer of the runtime). The ordering issues are problems, but they shouldn't normally prevent creation of the buffer since the creation of the buffer doesn't depend on the format of the data inside in general (but might depending on what C# wrapper method you are using?)

DirectX doesn't see your struct. When you set the uniform buffer all it sees is a bunch of bytes that it needs to map to the cbuffer definition in the shader. This is also why you may need to add padding between subsequent fields when alignments between the host language (C/C++/C#/etc.) and hlsl don't match. In particular when dealing with multi-float variables.
In effect it does a reintepret_cast on your struct to the one declared in the shader.
If the layout does not match then you get surprising behavior.

Can you elaborate a little more on this? Is this occurring when it creates the actual buffer object? Why does this matter if the types are exactly the same with no padding needed? I would expect incorrect behavior during rendering but not prior to that. For example if I have four float types that do different things, and I reorder them, they are all still floats, but now the behavior of the HLSL will change, but it should still create the buffer just fine.

source: Stack Exchange

license: Creative Commons - Attribution Share-Alike - https://creativecommons.org/licenses/by-sa/4.0/

sort: votes


text:
Typical Point Light Flow?
A Quick Note
This question assumes you have some knowledge about the overall rendering process and do not need clarification on rendering objects with HLSL and a DeviceContext. I use the SharpDX libraries to write my code in C# but I can read C++ and convert it if needed.

Overview
I am currently trying to create a prefab for a point light in my engine at work. I currently have a working directional light and can adapt from that if needed. Originally this post included some code from a pixel shader that I found on StackOverflow, but @DMGregory pointed out issues with it. I also attempted to follow a pixel shader supplied in the book Real-Time 3D Rendering with DirectX and HLSL (chapter 7 page 117); however, the HLSL in that seems to be a bit outdated since I can't use the following functions:

lit
get_vector_color_contribution
get_scalar_color_contribution

These seem to be no longer supported with ps_5_0 (the HLSL won't compile) and I can't find any documentation that provides updated equivalents. The exact error message during compilation is:

error X3004: undeclared identifier 'get_vector_color_contribution`.

This same message is presented with all three functions.
When I attempted the pixel shader found on StackOverflow, it didn't do what I expected. I eventually discovered that this is because it wasn't sampling textures. Correcting that is simple enough, but this would have to be applied per object and makes it difficult for multiple point lights. This doesn't really fit my idea of simplicity.

My Idea
I would prefer to create a point light shader that is applied to all objects capable of being illuminated in a single pass; however, I fear this isn't possible or would be incredibly difficult to achieve.
Since it is a lot of code to show the entire process, I will just include a couple relevant samples and hopefully that will help shed some light on what I currently do when rendering objects:
public class SceneObject {
    public Vector3 Position { get; set; }
    public PixelShader PixelShader { get; set; }
    public virtual void Render() { }
}
public class PointLight : SceneObject {
    public float Radius { get; set; }
    public float Intensity { get; set; }
    public Color Diffuse { get; set; }
    public Color Ambient { get; set; }
    public Color Specular { get; set; }
}
public class Scene {
    private void ChangeShader(SceneObject obj, bool setToCurrent) {
        if (setToCurrent)
            currentPixelShader = context3D.PixelShader.Get();

        if (currentPixelShader.DebugName != obj.PixelShader.DebugName)
            context3D.PixelShader.Set(obj.PixelShader);
    }
    public void Render(SceneObject obj, bool renderChildren = true) {
        if (!obj.Enabled)
            return;

        if (obj is PointLight)
            SetPointLightBuffer((PointLight)obj);

        if (obj.PixelShader != null)
            ChangeShader(obj, false);

        SetObjectBuffer(obj);

        if (obj.HasTexture)
            UpdateMaterialBuffer(true);

        obj.Render();

        if (obj.HasTexture)
            UpdateMaterialBuffer(false);

        if (renderChildren)
            foreach (SceneObject child in obj.Children)
                Render(child);
    }

    ChangeShader(obj, true);
}

There are things missing from the code I've supplied above, but this is intentional as it is a lot of code. Each object renders itself in the appropriate way. The Scene class manages the DeviceContext and other important things such as the constant buffers used by the shaders, this allows greater flexibility for future developers instead of having to learn all of the underlying DirectX code, they can focus on creating objects with prefabs instead.

Goal
The overall goal is to achieve the most simplistic implementation of a point light that I can get, to where any object that is capable of being illuminated is illuminated when in range of the light. I believe this is going to be a post process pixel shader, but I could be wrong.

Question
What is the step by step (proper) process for rendering a point light object into a scene?

Note
I don't really need code samples to answer this question unless the supplied shader is incorrect. I can figure the code out, so long as you're detailed enough about the process in your answer.

"I couldn't get it to work" - can you show us specifically what you tried, and what went wrong? Did you get a compile error or runtime error? Or a different output than you were expecting? (In what specific way did it differ?) It's also not immediately clear what kind of renderer / pass you're creating — forward, deferred, forward+, light pre-pass, etc., so can you tell us more about where you want this shader to fit into your overall rendering pipeline?

@DMGregory I've updated the post to hopefully help clarify everything; the code is as minimal as I could make it as I assume some knowledge of rendering is understood by answerers.

What specific error do you get when trying to use get_vector_color_contribution as defined here in your shader code? It doesn't look like it uses anything unusual that would be unsupported, just a little multiplication.

@DMGregory Updated the post to display that.

This is telling you that you haven't defined the function get_vector_color_contribution anywhere in the shader code you've tried to compile. It's not a built-in function, just a regular user-defined function. Have you tried declaring the function like the error message tells you to?

@DMGregory I'm not sure how I didn't notice that... Perhaps I need some more coffee this morning. I'll work on that, but that's only one part of the issue. I'll get back after trying it. Found it on page 113.

@DMGregory Do you by chance know how to implement the lit function since it doesn't work with ps_5_0 and there isn't a definition in the book that I see in nearby pages?

@DMGregory So implementing without the lit function produces a solid black object.

It looks like you're trying to just throw your light in with a jumble of other scene objects, rendered in some arbitrary order without any knowledge of one another.
Because illumination isn't an "object" per se, but an effect on the surfaces of other objects, it needs to be handled separately. Either the objects need to know about the lights, or the light needs to be able to query information about the objects.
There are two common routes to incorporating lighting: forward and deferred. Lots more specialized variants have been developed based on these, but knowing these core concepts will give you a foundation for understanding the other techniques.
Forward Rendering
In Forward Rendering, you incorporate illumination as you render each object.
So the shader for the object will expose some uniforms (or reference a data buffer) containing information about the lights shining on that object. In your rendering loop you'd check which lights illuminate each object, and populate those variables/buffers before rendering it. Then the object's shader will...

(vertex shader)

transform the model's vertices into device coordinates
compute lighting vectors for each of the lights shining on the object

(pixel shader)

sample the object's surface colour, normal map, and other textures
shade the result for each light
sum the contributions of each light into a final output colour

Advantages with this method include that it works for transparent geometry just as well as it does for opaque stuff, and you can have highly custom shader logic for each object, mixing wildly different material effects.
Disadvantages include, as you point out, it's difficult to scale to many lights. Each pass will typically have a maximum number of lights it can handle (eg. 4). When more lights affect the object, then you either need to exclude the less important lights (which can show odd discontinuities), approximate extra lights with a simpler form like spherical harmonics, or render additional passes to add-up the contributions of every light. The other downside is that overdraw can be quite high with this approach - you might spend several passes rendering lighting on one polygon, only to later cover up that polygon with a closer one that needs its own lighting.
Deferred Rendering
In Deferred Rendering, you put off lighting until the end.
As you render each object, you're not rendering its final appearance, but rather making notes for the later lighting passes to use. Typically you'll use multiple render targets collectively called a "G-Buffer" to record, for each pixel on the screen...

Depth
Normal direction
Albedo colour
Material properties like roughness/metalness/specularity (the exact details will depend on your reflectance model)

After this G-Buffer is completely populated with all the opaque objects in the scene, you can use it to compute the light reflecting off each pixel to "splat" illumination additively onto a black-cleared background,.
For each light, you render a piece of geometry representing the light's bounds, to ensure you run the lighting shader only on the pixels the light could potentially touch (this helps control overdraw when you have lots of small lights). For each pixel it covers, you read the G-buffer and decode the world position of the surface at that pixel, shading it using the current light and outputting the light bouncing off that surface pixel toward the camera for just the one light. Adding up all those passes gives you the complete light bouncing off that pixel & reaching the camera.
Advantages with this method include that it partly decouples the complexity of your scene from the complexity of your lighting. Your lighting cost is bounded by the on-screen pixel area of your lights, rather than exploding with the vertex count of your scene. This makes it more efficient to render lots and lots of lights in high-detail scenes.
Disadvantages include that this works only for opaque geometry, since it assumes there's just one (front-most) surface visible at each pixel. Deferred renderers will often include a forward pass to handle transparent objects after the opaque scene has been fully lit. It's also more complicated to handle wildly different material logic per object this way, since the shading pass is separated from the object (typically we'll try to boil down lots of material behaviours into a set of parameters for a shared reflectance model).

all_licenses: Creative Commons - Attribution Share-Alike - https://creativecommons.org/licenses/by-sa/4.0/


text:
Combination Lighting Shader?
I am currently working on writing a shader for combination lighting. The idea behind it is to apply directional light, point light, and spot light in a single pass. I believe I can do this by:

Calculate the color after directional light is applied.
Calculate the color after the point light is applied.
Calculate the color after the spot light is applied.
Return the final color of the pixel.

I believe this will allow me to have multiple point and spot lights that effect the pixel currently being handled by the pixel shader.
I believe the math for this will be:
return directional + pointLight + spot;

However, my concern is that this will create just a solid white object and I am unsure as to how to prevent that. Maybe each portion is normalized to a specific percentage of full intensity and the result would be:
directional = calcDirectional() * 0.3f;
pointLight = calcPoint() * 0.3f;
spot = calcSpot() * 0.3f;
return direction + pointLight + spot;

But again, I am not 100% sure on this.

What is the proper way to additively calculate colors in this scenario?

You just add the contributions from each light source. No normalization or reweighting required.
Think about light in the real world. If I shine a flashlight onto an object, it doesn't darken the light from the sun bouncing off of it. All I can do is light the object up more - pour on more photons, and more photons bounce off.
If you find your objects get too bright doing it this way, then you need to either...

move to an HDR system and tonemap the resulting out-of-range colours back down into your device's representable range at the end (games that have a high contrast and simulated eye adaptation between dark interiors and bright exteriors often work this way), or
reduce the intensity of your lights / make their falloff sharper so you get less total light landing on the object.


text:
How to resize a surface in Pygame?
How can I resize a Surface object in Pygame? Is there a way to bind a surface object into a Rect object, so that resizing the rect would also resize the surface (with Rect.inflate_ip method for an example)?

There's no way to do this automatically, so if you want some sort of automation for the surface rescaling, you'd need to write your own wrapper class around pygame.Rect, that owns a rectangle, and takes in a surface, and resizes the surface when a method of the wrapper is called.
The resizing function you are looking for is pygame.transform.scale. Pass it a surface and the new size you want, and it will return a new surface, or place the result into an already created surface (this is faster).

Is scale method not only for resizing of images at the toplevel? Is it ok to use it continuously (say by setting a timer) to resize many surfaces in the main loop?

You can use it wherever, just note that it can be a bit slow, but that is unavoidable with a software renderer like pygame.


text:
How do I know if I'm abstracting graphics APIs too tightly?
When making a renderer that supports multiple graphics APIs, you would typically want to abstract your code in some sort of low level library that is tied with some graphics API like OpenGL,  Vulkan, D3D11 and so on;
They work very differently from each other, so making a good generic API becomes essential;
I've read that you would typically want to use a "back-end" that implements the basic functionality for each API you want to support, and a "front-end" which is what is used by the programmer to draw stuff on the screen.
How do I know if I'm making too much of a tight abstraction?

Are you 100% certain that your wrapper + Vulkan or D3D11 is faster than just always using OpenGL?

@Mooing Duck if used correctly, yes.

I would seriously doubt that. Most of the gains in Vulkan come from being very low-level and doing things in a very peculiar, specific way. Something that is generic enough to also do the same seamlessly in OpenGL or D3D almost certainly can't do that. Reimplementing the same stuff as OpenGL does (like many Vulkan tutorials do, ironically) results in 99.99% the same performance, with 20 times the work.

@Damon that's right, but newer APIs are specifically designed (and not adapted like OpenGL) to work on modern gpus; speaking of Vulkan, you can pretty much use the same API on every supported platform, contrarily to OpenGL, where you need to use the "Embedded Systems" version. Other than less cpu overhead and fancy features we don't have much, but in the future we might have some pretty surprising techniques that may run faster using Vk or D3D12 rather than OGL or D3D11

First of all, consider if it is actually worth it to support more than one graphics API. Just using OpenGL will cover most platforms and will be "good enough" for all but the most graphically ambitious projects. Unless you work for a very large game studio which can afford to sink several thousand person-hours into implementing and testing multiple rendering backends and unless there are some DirectX or Vulcan specific features you really want to show off, it is usually not worth the hassle. Especially considering that you can save a lot of work by using an abstraction layer someone else created (a 3rd party library or game engine).
But let's assume that you already evaluated your options and came to the conclusion that it is both viable and worth the time to roll your own.
Then the main judge of your abstraction layer's software architecture are your front-end programmers.

Are they able to implement the game systems they want to implement without having to wonder about any low-level details?
Are they able to completely ignore that there is more than one graphics API?
Would it theoretically be possible to add yet another rendering backend without changing any of the front-end code?

If so, you succeeded.

One additional suggestion: is it worth emphasizing that the goal is to achieve the goals in the bullet points with the minimal level of effort--to just hit the target and go no further?  Otherwise each one of these can turn into a rabbit hole for the typical developer who (myself included) often doesn't know when to leave good-enough alone.  :)  And also that the only reliable way to judge success is to develop and test the API iteratively with actual users; it's impossible to guess accurately, and leads to a rabbit hole scenario of over-engineering.

I would add that, if you really do have to support multiple graphics libraries, there's almost certainly an off-the-shelf one that does everything you need to, so even then you really shouldn't roll your own. (Of course, there are exceptions, but if you're inexperienced enough to ask "how tight of an abstraction should I make" you're probably not working on a project that requires you to do it)

I'm not a graphics dev, but looking at compatibility frameworks from the history of databases and OSes, I'd add that it's almost certainly just not worth it to make your own general framework. The framework will almost certainly have to sacrifice performance for compatibility, which probably means you can't do much with those specialized features anyway. Existing frameworks are nearly certain to handle those issues better due to wider usage. Now, if you have the massive budget you describe and want to build a specialized framework (say for one game or series), that might be more doable.

Start by identifying what you actually need out of the "wrapper" part of the API. It's generally very, very simple: you need the basic resources (buffers, shaders, textures, pipeline state) and a way to use those resources to construct a frame by submitting some draw calls.
Try to keep any high-level logic out of the wrapper portion of the API. If you implement a clever scene culling technique in this portion of the API, well now you are on the hook to duplicate that logic in all of the backend implementations. That's a lot of extra effort, so keep it simple. Scene management should be part of a higher-level portion of the API that uses the wrapper rather than being part of the wrapper itself.
Choose the targets you will support and understand them. It's hard to write decent wrappers for "everything," and you probably don't need to (arguably you don't need to write a single wrapper, either, as noted in Philipp's answer).  It's almost impossible to write a decent wrapper if you don't know the APIs you're going to wrap already.
Evaluate the state of your API regularly. It should in general have a smaller surface area than the underlying wrapped APIs; if you find yourself creating one-to-one wrapper types for every D3D structure or every OpenGL function call you are probably veering off course.
Look at what work has gone before. Sokol and BGFX are APIs that provide levels of agnosticism that may be useful to you, and are relatively easy to understand (the former especially).

Another point not yet mentioned which you should consider is what your performance goals are.  If your goal is to have a graphics library that will yield good performance out of a cheap hardware platform, but also be usable on a variety of platforms that are vastly more powerful but use a different API, it may make sense to design your API around whatever abstractions are used natively on the platform where performance is an issue.  Even if this causes a 50% speed degradation on the more powerful platforms, it may be worth it if it allows a 20% speed improvement on the platform where performance matters most.


text:
Getting event types in Pygame
I want to have the type of an event from the event queue to decide certain actions (i.e. if it is a joystick event or a keyboard one), but the dir of events is an empty list:
for e in pygame.event.get():
    print dir(e)

Although in the documentation i read:

The queue is a regular queue of pygame.event.EventTypepygame object for representing SDL events event objects

i can't access a __dict__ attribute. The above code prints a bunch of empty lists: [] [] [] [] etc. In pygame 1.9.4 installed from pip i could run:
if e.type == pygame.JOYBUTTONDOWN:
    e.__dict__["joy"]

and i could get the number of joystick button pressed, but this is not working in 1.9.4 installed with sudo apt install (on Debian):
print event.__dict__
AttributeError: event member not defined

You should do if-elif-elif with e.type.
First import the event constants you need to check from pygame.constants
For example
from pygame.constants import QUIT, MOUSEBUTTONDOWN
while true:
    for e in pygame.event.get():
        if e.type == QUIT:
            #close the game
        elif e.type == MOUSEBUTTONDOWN:
            #mouse click

The dir() function gives the directory where a module is located, that doesn't work as you think


text:
How can I implement pathfinding that avoids obstacles on a spherical planet?

Hi everyone, I am trying to make the enemy go around the planet, towards the player (I am using Faux Gravity for the movement logic).
I tried using Unity's NavMesh tools, but because this is not a flat mesh, they didn't really get the job done;
How can I make my enemies go around the planet towards the enemy in a physics based way?
I thought about calculating the a direction from the enemy towards the player and then moving the player towards a vector perpendicular to the planet's surface (in this case transform.forward) like so:

This way I can correctly move enemies towards the player, but the AI doesn't have any notion of any possible obstacle it should avoid.
I am specifically looking for some sort of A* algorithm, that would work on a spherical surface, like the one of a planet.
Is there a better way to do this?

I am specifically looking for some sort of A* algorithm, that would work on a spherical surface

The name for an A* algorithm that can work on a spherical surface is: A*
You don't need to do anything special to make A* work on arbitrary spaces. That's already its jam. Anything you can represent as a graph of connected sites/regions will work just fine — whether those sites are on a grid, an irregular web, in 2D, 3D, 4D or more, even non-spacetime dimensions (see past notes on pathing through dimensions of bomb inventory / key debt), or yes, even on a sphere.
To make such a graph over the surface of the sphere, a popular method is to take the grid of a wireframe unit cube and project it onto the sphere, either by normalizing the position vectors, or "spherifying" them.
You could also take your current planet mesh and create a graph node for each face or vertex, and a graph edge for each mesh edge joining them. Just make sure you maintain connectivity wherever you cross a normal/UV seam.
I'd avoid a latitude-longitude based grid here, since the pinching at the poles makes the distribution of points very uneven. But if your topography lets you park the poles out of the way in non-pathable terrain like a mountain or ocean then it might be OK. ;)
Now that you have a graph of connected sites across the sphere, you can mark those occupied by obstacles as obstructed, then search the graph for an unobstructed route to your goal using the usual A*, or any of the variants of it you like.
Your heuristic function can still be Euclidean distance (ie. the length of the spherical cord joining two points), since all that's required of the heuristic is that it never overestimates the distance.
You could also use arc length as your heuristic: acos(dot(start, end)) (where start & end are unit vectors in the respective directions). This takes curvature into account so it's a tighter bound and might result in better prioritization. If you go this route, you should measure your graph edge lengths in arc distance too, to ensure they never take a shortcut smaller than the heuristic predicted.

There are many options but projecting vectors is a common and efficient way of constraining movement - possibly the most elegant way.
Another possible solution - have a dummy transform at the center of the sphere as a parent of the enemies, and rotate that dummy transform using unity's built in quaternion rotation functions. However this way seems less flexible to me, since it only works with a perfect circle and is less able to deal with obstacles. I think you're on the right track.


text:
Enabling / disabling Static objects in Unity
The Unity docs clearly explain that game objects marked static should not be moved for performance reasons but I can't find any info regarding enabling / disabling.
Almost everything in my games levels is destructible so I only use real-time GI. When the player damages a game object enough it's either removed or replaced with a damaged version of the model, usually via an object pool.
What effect does enabling or disabling a static game object have on performance?

When you set a GameObject as static, Unity starts optimising behind the scenes and assuming stuff about your objects. If for example you mark multiple objects as "batching static" you are basically telling Unity that these objects will never move. This means there is a chance on your final game all these objects will be "merged together" as one mesh, and be rendered like that, to make performance faster.
This is just one example, as far as I know the optimisation behaviour in Unity is not defined, and can be different from platform to platform as different things can be faster or slower on specific devices.
Although I can't know in detail, I image that when you are disabling/enabling static objects in a scene, you interfere with these optimisations, as it's not possible to disable part of a mesh.
A simple rule is, if your GameObject is not really static and needs to be moved or be altered in any other way, do not mark it as static. Make sure you are not trying to prematurely optimise your project, make something that works, and when that's done, only then start optimising on the most performance-intensive parts.


text:
Which part of the frustum sits at the eye position?
In Java I create a frustum projection matrix via
Matrix.frustumM(projMatrix, 0, left, right, bottom top, near, far);

and a view matrix via
Matrix.setLookAtM(viewMatrix, 0,
                               0, 0, -2.5,  // eye position
                               0, 0, 0      // look position
                               0, -1, 0);   // up direction

My question is:
Which part of the frustum originates at the eye position? Is it the tip of the pyramid, or the centre of the near plane?

The eye position is at the tip of the pyramid though the actual projection will end up on the near plane i.e the near plane will be your "screen"

So if I had a world coordinate point at (0, 0, 0) and the camera was at (0, 0, 1) looking directly at (0, 0, 0), with a near distance of 1, then that (0, 0, 0) point should appear in the centre of the screen?

Not sure because it would be in the near plane


text:
Efficient unwrapping on multi hard edge object
I'm having trouble unwrapping this without creating hundreds of seams which massively increases the vertex count in the game engine (Unity).

I've tried the various projection methods without much success. Three planar maps (45 deg looking down, 45 up and one side) yielded the leat amount but still dozens.
I've tried all sorts of manual seam drawings but can't figure out what would be optimal so I'm looking for suggestions.
Regarding the texture having contiguous seams doesn't really matter.
Cross posted on Blender Stack Exchange

This question might receive better answers on https://blender.stackexchange.com.

The UV seams here may be both inevitable, and not a big deal in practice. When we talk about trying to minimize vertex count, we're usually talking about thousands to millions of vertices, while seams from this object seem like they'd add at most a few hundred extra verts (which might need to split anyway because of differing normals). Do you have profiling figures showing that this object is a major culprit in performance problems in your game?

@DMGregory I'm coming to the end of finishing the first level of my game so I'm onto graphical optimisation. I still have occlusion culling and some LODs to finish but It's currently clocking around 4M verts on screen most of the time and rendering is a clear bottleneck in the profiler. With that in mind I'm trying to clean up as much as I can. There are only two of these in the scene and yes, I may have to let this one escape the broom but just thought I might be missing some unwrapping technique.

See also this previous Q&A that talks about the relative importance of sharing vertices vs other aspects of draw cost


text:
Help finding coordinate for left of screen in this frustum
I have a frustum with l=-2, r=2, n=0.5, f=10, corresponding to left, right, near, far respectively. I also define top and bottom too.
I've set the camera eye up at (0, 0, -2.5), looking directly at (0, 0, 0) with up (0, 1, 0).
Suppose I want to position an object centred at z=-1. I want to find the x coordinate so that under this frustum it appears exactly centred on the left edge of the screen.
I set up the following diagram to help me:
                       +z
                       |
            \          |          /
     -x<_____\_________|_________/______>x
              \____x___|-1      /
               \       |       /
                \      |      /
                 \_|l|_|     /
                  \    |    /     |near dist=n=0.5
                   \   |   /      |
                    \  |  /       |
                     \a| /        |
                      \|/         |
                       |-2.5
                       |
                       -z

So to find x I can use simple trig. Since tan a = |l|/n and tan a=x/1.5 then the formula for x is x=|l|/n*1.5=2/0.5*1.5=6, where |.| is the absolute value.
But when I use this x value to draw an object left of the centre, it does not appear centred at the edge of the screen. I can see the object but it's not on the edge. Moreover, if I increase n then the gap between the object and the left edge increases. What am I doing wrong?
UPDATE
Empirically I have discovered that if I compute x=|l|/n*2.5 then my object is correctly centred on the left edge of the device screen, and works for any n value I choose. Not sure why 2.5 works...
SOLUTION
Not really worthy of an answer, but I found in some legacy code that the renderer was set up to transalte the z forward by 1 unit, so this was undoing my -1 z value, hence why multiplying by 2.5 worked and not 1.5.
Despite this annoying fact, I'm now confident I fully understand how the frustum fits into OpenGL.

In your text you write "exactly centered on the left edge" and in the drawing you show it centered in the left half of the screen.

@Bram well, the camera is centred at (0,0,0) so (-x,0,0) should be exactly on the left edge of the screen. As you can see the left side of the frustum skims the left of the near plane so x should correspond to the left edge of the screen for z=-1.

In your example:
0.5*left / n = x / 1.5
-1 / 0.5 = x / 1.5
-2 = x / 1.5
-3 = x

Or more elaborately, if you want to go via the angle it self:
tan( a ) = 0.5*left / 0.5
a = atan( -2 )
tan( a ) = x / 1.5
tan( atan( -2 ) ) = x / 1.5
-2 = x / 1.5
-3 = x

But tan a is not equal to 0.5*left/0.5 ... it is equal to l/n... goimg by tan = opposite / adjacent

Maybe the drawing was a little confusing, please see update. Nonetheless the x value does not draw at the exact left edge of the screen. I'm sure my maths is right? So there must be some unkown i dont know about. Will take a look again.


text:
How can I defy competing games who are forcing their users to write 5 star reviews?
Background
I've developed an app in a pretty contested category. It's one of the top three games in terms of quality (out of about 200 relevant games in this category; there are no large publishers with this type of game).
The Problem
While I have the best ratings overall (4.92 of 5 stars; ~1000 reviews), nearly all competing games started to force their users to write 5 star reviews (including a minimum amount of characters). While these apps can't actually verify the rating afaik, most users are fulfilling their demand because of psychological reasons. They even write things like:

This app is ****, but I have to write this review... 5 stars.
Not that good, but I want to get XYZ, so I have to write this review... 5 stars.

Unfortunately the poor algorithms of Google Play will rank an app higher, the more ratings they have (My app does fine in Apples App Store, since the manual review process seems to punish these fraudulent apps).
But with Google, even if you are below a 4 star average, you'll rank better if you have a ton of reviews. Number of downloads and update frequency doesn't seem to count at all.
The Consequences
This all started about three years ago and since then my Play Store ranking is on a downward spiral but I refuse to join this unethical train of fake reviews. Not only that it's a huge financial loss, it's highly depressing.
From rank 1-3 my app went down to about 30 for the most relevant keywords.
What I tried
I talked to multiple people from Google, but none of them feels responsible and sends me to the Developer Policy over and over again. Some of them even had the nerve to recommend Adwords to me as a counter measure.
I also reported some of these apps using Google Plays "Report App" feature. Nothing happened.
What I have already thought about

Join the train of manipulated reviews

This would work for sure, but as stated above, it's a no-go to me.

Asking the competitors to stop

This would require massive administrative work and probably wouldn't work out well. Especially since there are many profit-oriented trash developers.

Making my users aware of this issue

Since my competitors already copied multiple unique features of my game, I know for sure they are constantly checking my app for new updates. So they would quickly notice this whiny cry for help, which could lead to a massive backlash and make things even worse. Also it's nearly as dishonorable as faked reviews.
The Question
Do you have any advices how I could preserve my game without risking its, and also my personal reputation?

When the people at Google directed you to the developer policy, what part did they send you to? There’s a part that addresses exactly this, indicating that those apps are in violation. https://play.google.com/about/storelisting-promotional/ratings-reviews-installs/

4.92 is already an truly excellent rating, so I wouldn't worry about them if I were you. Maybe report them to Google, and then ignore them.

Stop relying on store ranking systems to drive users to your game. The google play store is broken in several ways. Use other channels to promote your game and send them directly to your store page. That way they will only see the rating of your game and not the ratings of the "competition".
For more tips on how to promote your game outside of the stores, check out some of the many other questions under the marketing tag.

It's been a while since I've been developing for android, but even a few years ago, it was a violation to offer goods for good (essentially fake) reviews. Unfortunately there are plenty apps that violate rules, and the Play Store does automated checks only, so the only thing you can do for now is report them and wait.

Join the train of manipulated reviews

I mean, you can do that, but your decision means your responsibility. You'd be in the violation of Google's Developer Policy, so at any point they can ban your account and all earnings you have.

Asking the competitors to stop

You can try, you can also ask your local pizza place to stop sending leaflets to the neighbourhood, but that doesn't mean they will comply.

Making my users aware of this issue

If I use an app that says something like "We don't do X, like our competitors" I'd start being suspicious. Imagine downloading an app that says "We don't track you, we don't store your info", sure it could be true, but it would sound suspicious.
The only advice I can give, keep making awesome apps/games that do treat the user well, and do not beg for good reviews. That's your part as a developer. If one day, for example, Google decided that offering money for reviews is allowed, you can't really do anything about it, and would have to accept it. Who knows, maybe one day most of the "malicious" apps out there might get removed.


text:
Replacement for glDrawElementsBaseVertex in OpenGL ES?
I am porting my game engine(c++) to Emscripten, which unfortunately only  supports OpenGL ES 3.(Not 3.2) Therefore I don't have access to glDrawElementsBaseVertex, which is needed by my renderer(Canvas2D Renderer). It is needed because this way I can combine all my triangles in one draw call, instead of multiple hundred draw calls. So I need something that does the same. I can't just use normal draw calls, because it would be horribly slow and would require redesigning my Canvas2D class.
The reason I need so many draw calls is because the user can use a Canvas2D to draw single/multiple 2D triangles on the screen, which are then combined into one array. Because the user can also send multiple triangle set's, the indexes need an offset to work correct, which is why I need glDrawElementsBaseVertex.
Does anyone know how to replace glDrawElementsBaseVertex with something that does the same?
Thanks!

If there was something that did the same thing, why would OpenGL have even had that as a separate function?
The only thing you can do is pre-offset the indices you're assembling in your index buffer.


text:
How do I play a particle system when moving?
I have a car that I move with a Physics-based movement (AddForce(), AddTorque(), etc...) and I have a simple particle system attached behind the car as follows:

I'd like to play this ParticleSystem whenever the car moves; I tried checking if the car's rigidbody's velocity was greater than 0:
if(m_Rigidbody.velocity.z > 0)
   m_ParticleSystem.Play();

if(m_Rigidbody.velocity.z == 0 && m_ParticleSystem.isPlaying) // velocity.z == 0 is unreliable, verified with Debug.Log
   m_ParticleSystem.Stop();

I then tried using Input:
if(Input.GetAxis("Vertical") > 0) // the car is moving along the positive z axis
    m_ParticleSystem.Play();
if(Input.GetAxis("Vertical") == 0 && m_ParticleSystem.isPlaying)
    m_ParticleSystem.Stop();

These two methods don't work, I'm probably making assumptions on how Rigidbody.velocity behaves (when you stop the car for example, it becomes negative, so the particle system would keep playing until it reaches 0);

General practice is to avoid comparing floats for exact equality. Very rarely will gameplay be precise to the 10^-45 level needed to compare exactly equal to zero. Does using a range threshold help, or is there still another issue here?

No matter what I try to do, the particle system doesn't start or stop.. Is this even the way I should be doing this?

Where have you written this code?

I wrote this in Update(); It's not how this should be done though, since a statement like Input.GetAxis("Vertical") == 0 even if it was accurate, would result in multiple calls to m_ParticleSystem.Stop..

Are you familiar with the ParticleSystem’s ability to emit based on distance traveled? You may not need to do any coding at all. https://docs.unity3d.com/Manual/PartSysEmissionModule.html

Using a range and selectively stopping emission seemed to work fine in my tests:
if (Input.GetAxis("Vertical") > 0.1f) {
    if (!particles.isEmitting)
        particles.Play();
} else if(particles.isEmitting) {
    particles.Stop(true, ParticleSystemStopBehavior.StopEmitting);
}


text:
How could I make the player's movement more responsive?
I am working on an Air Hockey game;
I tried making the movement physics-based, by doing this:
using UnityEngine;

public class Player : MonoBehaviour
{
    private Rigidbody m_Rigidbody;

    private float HorizontalInput;
    private float VerticalInput;

    public float Speed = 1.0f;

    private void Start()
    {
        m_Rigidbody = GetComponent<Rigidbody>();
    }

    private void Update()
    {
        HorizontalInput = Input.GetAxisRaw("Horizontal");
        VerticalInput = Input.GetAxisRaw("Vertical");
    }

    private void FixedUpdate()
    {
        m_Rigidbody.AddForce(new Vector3(VerticalInput * Speed, 0.0f, -HorizontalInput * Speed),ForceMode.VelocityChange);
    }
}

and by adding a PhysicsMaterial to the MeshCollider attached to my player:

The movement should be quick and responsive, but it feels rather sloppy and unresponsive; I also tried using Input.GetAxisRaw(...), but the controls become quite clunky.
How can I improve on this? Is there a go-to way to do this type of movement in Unity?
(I would like the final version of the game to be played on controllers)

I know it's common advice to capture input in Update and defer acting on it until FixedUpdate, but I think this advice is overly simplistic. I don't follow it in my own games.

CAUTION: This worked in Unity versions circa 2018 when this answer was written. It does not work in 2019 versions I've tried - it looks like they updated the engine to match the documentation instead of the other way around, breaking a useful latency-reduction trick. :(
The numbered advice points later in the answer are still good practices to follow that will also have a dramatic impact on your responsiveness, so all is not lost.

Because FixedUpdate runs before Update each frame (when using the default game loop at least), doing it this way forces at least one unnecessary frame of latency:
| Frame 1                      | Frame 2                       |
| FixeUpdate...Update...Render | FixedUpdate...Update...Render |
                  ^                     ^                      ^
Input cached here |   Physics acts here |                      | Results Visible

If we check input in FixedUpdate, we can eliminate this unnecessary latency in any frames when FixedUpdate is called at least once (and we can adjust our FixedUpdate rate at or above our target framerate to ensure this is almost always the case):
| Frame 1                      |
| FixeUpdate...Update...Render |
   ^                           ^
   | Input & Physics           | Results Visible in the same frame

Now we need to be a bit cautious doing this, to ensure we don't miss or double-dip on instantaneous actions like Jumps. Here's one way we can do that:
bool hasHandledInputThisFrame = false;

void HandleInput(bool isFixedUpdate) {
    bool hadAlreadyHandled = hasHandledInputThisFrame;
    hasHandledInputThisFrame = isFixedUpdate;
    if(hadAlreadyHandled)
        return;

    /* Perform any instantaneous actions, using Time.fixedDeltaTime where necessary */
}

void FixedUpdate() {
    // If we're first at-bat, handle the input immediately and mark it already-handled.
    HandleInput(true);

    /* Apply any continuous physics changes here. */
}

void Update() {
    // Catch any missed input and reset the flag for next frame.
    HandleInput(false);
}

There, now we know we don't have unnecessary latency creeping in from the order of our update methods. What else can we do to improve responsiveness?

Since we're using physics-based movement, we can get an apparent stutter or judder in the motion due to the mismatch between the rendering framerate and the physics update. This can make the movement look low-performance.
Enabling interpolation on the Rigidbody smooths this out. Technically it can add a fraction of a physics step of latency because we're blending with a past state, but in my experience the smoothness it gives is even more important to the perception & feel of the controls - so long as your physics step isn't unusually long. As long as the player can see some effect of their recent input blending in through the interpolation, rather than no change at all or a stuttery inconsistent response, it still reduces perceived latency.
Once you do this, make sure you don't set the position/rotation via the transform component. Doing this effectively turns off interpolation and you're back to judder land. Route all transformation changes via the rigidbody to keep it smooth.
Separate your character's speed from their acceleration. Giving a high acceleration - and in particular, an even higher deceleration when stopping / changing direction, helps the controls feel snappy, even if the net movement speed stays where it is.
Here's a quick example I whipped up for my students a few weeks ago, that shows the basic idea. You can of course elaborate on this with custom acceleration curves, sliding effects, etc.

float maxAcceleration = 10f;
float maxDeceleration = 20f;
float maxSpeed = 10f;

void FixedUpdate() {
    // Handle instantaneous inputs exactly once per frame.
    HandleInput(true);

    // Now handle the continuous inputs like analog stick direction every step:

    // Capture analog stick direction (yes, this works fine in FixedUpdate).
    Vector3 analog = new Vector3(Input.GetAxis("Horizontal"), 0, Input.GetAxis("Vertical"));
    analog = Vector3.ClampMagnitude(analog, 1f);

    Vector2 targetVelocity = analog * maxSpeed;

    AccelerateToward(targetVelocity);
}

void AccelerateToward(Vector3 targetVelocity) {
    float limit = maxAcceleration;

    var deltaV = targetVelocity - body.velocity;

    // If we're stopping or reversing direction, use deceleration limit instead.
    if (Vector3.Dot(body.velocity, deltaV) < 0f)
        limit = maxDeceleration;

    // Compute an acceleration to use this frame, within our allowed limits.
    // (Since we're calling this in FixedUpdate, deltaTime gives our fixed timestep)
    var accel = deltaV / Time.deltaTime;
    accel = Vector2.ClampMagnitude(accel, limit);

    body.AddForce(accel, ForceMode.Acceleration);
}

Provide immediate feedback. The biggest ingredient in perceived latency is waiting to see evidence that the game heard you and is listening. If you use physics or animation-based movement, this could take several frames to become apparent. But if you can feed back some acknowledgement earlier, you tighten the loop between input & confirmation, and the controls feel instantly tighter even with no change in the underlying gameplay behaviour. Some forms this can take:

rotating the character in the new direction (especially if they're a circle/capsule and this has no physics impacts anyway)
If rotating the whole character is too extreme, you can try using IK to turn the character's head to look where they're going to move next, or rotate the thrust effects coming out of a spaceship....
throwing out particles like a skid effect when changing movement suddenly
sound effects (eg. a skid or heavier footfall when stopping/turning)

(1) Have you tried to increase Gravity in controller settings?
(2) And I would take Time.deltatime into account, because the movement of player should be same relative to different framerates.

The movement is physics based, so Time.deltaTime isn't helpful, since each instruction inFixedUpdate() gets executed in a complete cycle when physics stuff is processed by Unity. Gravity doesn't change much, since it's not really related to the actual motion of sliding onto the slippery surface

@GabrieleVierti including deltaTime is valuable even for FixedUpdate code, so that you retain the same behaviour even if you later change your FixedUpdate rate. You wouldn't want to have to go re-tune all your speed & acceleration parameters after making such a change. "Gravity" here doesn't have anything to do with the interaction with the surface - it's a measure of how quickly the reported value from the button input re-centers when the buttons are released. So it can have an impact on responsiveness when using a keyboard / DPad to emulate analog input, but won't affect an analog stick.

@DMGregory Ah, I didn't think about the "gravity" option in the input settings :P


text:
Get closest point on box to line

Eventually this problem will be 3D, so I would like a solution that works in 3D.
My player is looking forwards. There is an axis-aligned box on the screen (FOV is guaranteed to be 90, so boxes behind the player aren't considered.)
I want to get the coordinates of the point on box that is closest to the player's looking direction.
I.e., if the player turned towards the box, which point of the box would intersect with their line of vision first?

What will the shape be in 3d?  A rectangular solid?

@TimHolt a cuboid (an "axis-aligned box") so yeah a rectangular solid

How does this work in 3d? In 2-d, the 'edge of vision' of the player is two lines and the player sees an (infinitely long) circle sector in between. There are many generalisations of this in 3d, some of which will be much easier to work with than others.

@ScienceSnake idk what you mean

@theonlygusti I thought it was clear...?
What does the player see in 3d? Is it still along a single line only? Or is it a volume? What kind of volume is it? A pyramid or a cone or something else?

@ScienceSnake yes along a single line, imagine a player with a long pokey nose i want to know what that hits first

I wasn't happy with any of the answers here, as I wanted an answer for the 3D case, so I went ahead and wrote a shadertoy which demonstrates how to query the closest point between a line and a box.
Here's a link to the shadertoy code, as well as an image of the output:

Code:
// The MIT License
// Copyright © 2024 Nate Morrical
// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

// The below is a collection of functions to compute the closest point between
// a point / line / segment and a box / face.

// Returns the closest point from a 3D point to a 3D box
// The box is axis aligned, and centered at the origin
//   o - the query origin
//   b - the box radius (3 half side lengths)
vec3 pointBoxQuery( vec3 o, vec3 b ) {
    vec3 closest = o;
    for (int i = 0; i < 3; ++i) {
        if (o[i] < -b[i])
            closest[i] = -b[i];
        else if (o[i] > b[i])
            closest[i] = b[i];
    }
    return closest;
}

// Returns the closest point from an infinite 3D line to 3D box face, plus the closest "t" along o+t*d
// Based on https://www.geometrictools.com/Documentation/DistanceLine3Rectangle3.pdf
// The box is axis aligned, centered at the origin, and d is expected to point towards
// the first octant (reflected s.t. all d components are positive).
//   i - the indirection indices for the face
//   o - the origin of the segment
//   d - the direction along the segment (which does not need to be normalized)
//   b - the box radius (3 half side lengths)
vec4 lineFaceQuery(ivec3 i, vec3 o, vec3 d, vec3 b)
{
    vec3 PmE = o - b;
    vec3 PpE = o + b;

    vec3 bi = vec3(b[i[0]], b[i[1]], b[i[2]]);
    vec3 oi = vec3(o[i[0]], o[i[1]], o[i[2]]);
    vec3 di = vec3(d[i[0]], d[i[1]], d[i[2]]);
    vec3 PmEi = vec3(PmE[i[0]], PmE[i[1]], PmE[i[2]]);
    vec3 PpEi = vec3(PpE[i[0]], PpE[i[1]], PpE[i[2]]);

    vec4 c;
    if (di[0] * PpEi[1] >= di[1] * PmEi[0])
    {
        if (di[0] * PpEi[2] >= di[2] * PmEi[0])
        {
            // v[i1] >= -e[i1], v[i2] >= -e[i2] (distance = 0)
            c = vec4(bi[0], oi[1] - di[1] * PmEi[0] / di[0], oi[2] - di[2] * PmEi[0] / di[0], -PmEi[0] / di[0]);
        }
        else
        {
            // v[i1] >= -e[i1], v[i2] < -e[i2]
            float lenSqr = di[0] * di[0] + di[2] * di[2];
            float tmp = lenSqr * PpEi[1] - di[1] * (di[0] * PmEi[0] + di[2] * PpEi[2]);
            if (tmp <= 2. * lenSqr * bi[1])
            {
                float t = tmp / lenSqr;
                lenSqr += di[1] * di[1];
                tmp = PpEi[1] - t;
                float delta = di[0] * PmEi[0] + di[1] * tmp + di[2] * PpEi[2];
                c = vec4(bi[0], t - bi[1], -bi[2], -delta / lenSqr);
            }
            else
            {
                lenSqr += di[1] * di[1];
                float delta = di[0] * PmEi[0] + di[1] * PmEi[1] + di[2] * PpEi[2];
                c = vec4(bi[0], bi[1], -bi[2], -delta / lenSqr);
            }
        }
    }
    else
    {
        if (di[0] * PpEi[2] >= di[2] * PmEi[0])
        {
            // v[i1] < -e[i1], v[i2] >= -e[i2]
            float lenSqr = di[0] * di[0] + di[1] * di[1];
            float tmp = lenSqr * PpEi[2] - di[2] * (di[0] * PmEi[0] + di[1] * PpEi[1]);
            if (tmp <= 2. * lenSqr * bi[2])
            {
                float t = tmp / lenSqr;
                lenSqr += di[2] * di[2];
                tmp = PpEi[2] - t;
                float delta = di[0] * PmEi[0] + di[1] * PpEi[1] + di[2] * tmp;
                c = vec4(bi[0], -bi[1], t - bi[2], -delta / lenSqr);
            }
            else
            {
                lenSqr += di[2] * di[2];
                float delta = di[0] * PmEi[0] + di[1] * PpEi[1] + di[2] * PmEi[2];
                c = vec4(bi[0], -bi[1], bi[2], -delta / lenSqr);
            }
        }
        else
        {
            // v[i1] < -e[i1], v[i2] < -e[i2]
            float lenSqr = di[0] * di[0] + di[2] * di[2];
            float tmp = lenSqr * PpEi[1] - di[1] * (di[0] * PmEi[0] + di[2] * PpEi[2]);
            if (tmp >= 0.)
            {
                // v[i1]-edge is c
                if (tmp <= 2. * lenSqr * bi[1])
                {
                    float t = tmp / lenSqr;
                    lenSqr += di[1] * di[1];
                    tmp = PpEi[1] - t;
                    float delta = di[0] * PmEi[0] + di[1] * tmp + di[2] * PpEi[2];
                    c = vec4(bi[0], t - bi[1], -bi[2], -delta / lenSqr);
                }
                else
                {
                    lenSqr += di[1] * di[1];
                    float delta = di[0] * PmEi[0] + di[1] * PmEi[1] + di[2] * PpEi[2];
                    c = vec4(bi[0], bi[1], -bi[2], -delta / lenSqr);
                }
            }
            else {
                lenSqr = di[0] * di[0] +
                di[1] * di[1];
                tmp = lenSqr * PpEi[2] - di[2] * (di[0] * PmEi[0] + di[1] * PpEi[1]);
                if (tmp >= 0.)
                {
                    // v[i2]-edge is c
                    if (tmp <= 2. * lenSqr * bi[2])
                    {
                        float t = tmp / lenSqr;
                        lenSqr += di[2] * di[2];
                        tmp = PpEi[2] - t;
                        float delta = di[0] * PmEi[0] + di[1] * PpEi[1] + di[2] * tmp;
                        c = vec4(bi[0], -bi[1], t - bi[2], -delta / lenSqr);
                    }
                    else
                    {
                        lenSqr += di[2] * di[2];
                        float delta = di[0] * PmEi[0] + di[1] * PpEi[1] + di[2] * PmEi[2];
                        c = vec4(bi[0], -bi[1], bi[2], -delta / lenSqr);
                    }
                }
                else {
                    // (v[i1],v[i2])-corner is c
                    lenSqr += di[2] * di[2];
                    float delta = di[0] * PmEi[0] + di[1] * PpEi[1] + di[2] * PpEi[2];
                    c = vec4(bi[0], -bi[1], -bi[2], -delta / lenSqr);
                }
            }
        }
    }

    ivec3 map;
    map[i[0]] = 0;
    map[i[1]] = 1;
    map[i[2]] = 2;
    return vec4(c[map[0]], c[map[1]], c[map[2]], c.w);
}

// Returns the closest point from an infinite 3D line to a 3D box,  plus the closest "t" along o+t*d
//   o - the origin of the segment
//   d - the direction along the segment (which does not need to be normalized)
//   b - the box radius (3 half side lengths)
vec4 lineBoxQuery( vec3 o, vec3 d, vec3 b )
{
    vec4 closest;

    // Transform the line direction to the first octant using reflections.
    bvec3 reflected = lessThan(d, vec3(0.));
    o = mix(o, -o, reflected);
    d = mix(d, -d, reflected);

    // point minus extent
    vec3 PmE = o - b;

    // face indices
    ivec3 i;

    // line intersects planes x or z
    if (d[1] * PmE[0] >= d[0] * PmE[1])
        // line intersects x = e0 if true, z = e2 if false
        i = (d[2] * PmE[0] >= d[0] * PmE[2]) ? ivec3(0, 1, 2) : ivec3(2, 0, 1);
    // line intersects planes y or z
    else
        // line intersects y = e1 if true, z = e2 if false
        i = (d[2] * PmE[1] >= d[1] * PmE[2]) ? ivec3(1, 2, 0) : ivec3(2, 0, 1);

    // Query closest point on face
    closest = lineFaceQuery(i, o, d, b);

    // Account for previously applied reflections.
    closest.xyz = mix(closest.xyz, -closest.xyz, reflected);
    return closest;
}

// Returns the closest point from a finite 3D segment to a 3D box, plus the closest "t" along o+t*d
//   s - the start of the segment
//   e - the end of the segment
//   b - the box radius (3 half side lengths)
vec4 segmentBoxQuery( vec3 s, vec3 e, vec3 b ) {
    vec3 o = s;
    vec3 d = e - s;
    vec4 lbOutput = lineBoxQuery(o, d, b);
    // If closest is within the segment, return that result directly
    if (lbOutput.w >= 0. && lbOutput.w <= 1.)
        return lbOutput;

    // Otherwise, compute the closest point to either side of the segment
    float parameter = (lbOutput.w < 0.) ? 0. : 1.;
    vec3 pbOutput = pointBoxQuery(o + d * parameter, b);
    return vec4(pbOutput, parameter);
}

//------------------------------------------------------------

// https://iquilezles.org/articles/distfunctions
float sdBox( vec3 p, vec3 b )
{
    vec3 d = abs(p) - b;
    return min(max(d.x,max(d.y,d.z)),0.0) + length(max(d,0.0));
}

// https://iquilezles.org/articles/distfunctions
float sdSphere( vec3 p, vec3 cen, float rad )
{
    return length(p-cen)-rad;
}

// https://iquilezles.org/articles/distfunctions
float sdCapsule( vec3 p, vec3 a, vec3 b, float r )
{
    vec3 pa = p-a, ba = b-a;
    float h = clamp( dot(pa,ba)/dot(ba,ba), 0.0, 1.0 );
    return length( pa - ba*h ) - r;
}

// https://iquilezles.org/articles/distfunctions
float sdBoxFrame( vec3 p, vec3 b, float e )
{
       p = abs(p  )-b;
  vec3 q = abs(p+e)-e;

  return min(min(
      length(max(vec3(p.x,q.y,q.z),0.0))+min(max(p.x,max(q.y,q.z)),0.0),
      length(max(vec3(q.x,p.y,q.z),0.0))+min(max(q.x,max(p.y,q.z)),0.0)),
      length(max(vec3(q.x,q.y,p.z),0.0))+min(max(q.x,max(q.y,p.z)),0.0));
}

// https://iquilezles.org/articles/distfunctions
float sdCone(vec3 p, vec3 a, vec3 b, float ra, float rb)
{
    float rba  = rb-ra;
    float baba = dot(b-a,b-a);
    float papa = dot(p-a,p-a);
    float paba = dot(p-a,b-a)/baba;

    float x = sqrt( papa - paba*paba*baba );

    float cax = max(0.0,x-((paba<0.5)?ra:rb));
    float cay = abs(paba-0.5)-0.5;

    float k = rba*rba + baba;
    float f = clamp( (rba*(x-ra)+paba*baba)/k, 0.0, 1.0 );

    float cbx = x-ra - f*rba;
    float cby = paba - f;

    float s = (cbx < 0.0 && cay < 0.0) ? -1.0 : 1.0;

    return s*sqrt( min(cax*cax + cay*cay*baba,
                       cbx*cbx + cby*cby*baba) );
}

//------------------------------------------------------------
const vec3 box_rad = vec3(0.5,0.4,0.3);

vec2 map( in vec3 pos, bool showBox, bool showCapsule, in vec3 sampleLineStart, in vec3 sampleLineStop )
{
    // compute closest point to the segment on the surace of the box
    vec4 result = segmentBoxQuery(sampleLineStart, sampleLineStop, box_rad );
    vec3 closestPointOnLine = mix(sampleLineStart, sampleLineStop, result.w);
    vec3 closestPointOnBox = result.xyz;

    vec2 res = vec2(1e38f);

    // query line
    {
    float d = sdCapsule( pos, sampleLineStart, sampleLineStop, 0.015 );
    if( d<res.x ) res =  vec2( d, 1.0 );
    }

    // closest point on line
    {
    float d = sdSphere( pos, closestPointOnLine, 0.06 );
    if( d<res.x ) res = vec2( d, 1.0 );
    }

    // Closest point on box
    {
    float d = sdSphere( pos, closestPointOnBox, 0.06 );
    if( d<res.x ) res = vec2( d, 4.0 );
    }

    // box (semi-transparent)
    if( showBox )
    {
    float d = sdBox( pos, box_rad );
    if( d<res.x ) res =  vec2( d, 5.0 );
    }

    // segment from line to box
    {
    float d = sdCapsule( pos, closestPointOnLine, closestPointOnBox, 0.015 );
    if( d<res.x ) res =  vec2( d, 4.0 );
    }

    // box edges
    {
    float d = sdBoxFrame( pos, box_rad, 0.01 );
    if( d<res.x ) res =  vec2( d, 5.0 );
    }

    // Capsule demonstrating correctness.
    if (showCapsule){
    float radius = distance(closestPointOnBox, closestPointOnLine);
    float d = sdCapsule( pos, sampleLineStart, sampleLineStop, radius );
    if( d<res.x ) res =  vec2( d, 1.0 );
    }

    return res;
}

// https://iquilezles.org/articles/normalsSDF
vec3 calcNormal( in vec3 pos, in bool showBox, in bool showCapsule, in vec3 sampleLineStart, in vec3 sampleLineStop )
{
    vec2 e = vec2(1.0,-1.0)*0.5773;
    const float eps = 0.0005;
    return normalize( e.xyy*map( pos + e.xyy*eps, showBox, showCapsule, sampleLineStart, sampleLineStop ).x +
                      e.yyx*map( pos + e.yyx*eps, showBox, showCapsule, sampleLineStart, sampleLineStop ).x +
                      e.yxy*map( pos + e.yxy*eps, showBox, showCapsule, sampleLineStart, sampleLineStop ).x +
                      e.xxx*map( pos + e.xxx*eps, showBox, showCapsule, sampleLineStart, sampleLineStop ).x );
}

// https://iquilezles.org/articles/rmshadows
float calcSoftShadow( vec3 ro, vec3 rd, bool showBox, bool showCapsule, in vec3 sampleLineStart, in vec3 sampleLineStop )
{
    float res = 1.0;
    const float tmax = 2.0;
    float t = 0.001;
    for( int i=0; i<64; i++ )
    {
        float h = map(ro + t*rd, showBox, showCapsule, sampleLineStart, sampleLineStop).x;
        res = min( res, 64.0*h/t );
        t += clamp(h, 0.01,0.5);
        if( res<-1.0 || t>tmax ) break;

    }
    res = max(res,-1.0);
    return 0.25*(1.0+res)*(1.0+res)*(2.0-res); // smoothstep, in [-1,1]
}

#if HW_PERFORMANCE==0
#define AA 1
#else
#define AA 2
#endif

void mainImage( out vec4 fragColor, in vec2 fragCoord )
{
    vec3 tot = vec3(0.0);
    #if AA>1
    for( int m=0; m<AA; m++ )
    for( int n=0; n<AA; n++ )
    {
        // pixel coordinates
        vec2 o = vec2(float(m),float(n)) / float(AA) - 0.5;
        vec2 p = (2.0*(fragCoord+o)-iResolution.xy)/iResolution.y;
        // pixel sample
        ivec2 samp = ivec2(fragCoord)*AA + ivec2(m,n);
        // time sample
        float td = 0.5+0.5*sin(fragCoord.x*114.0)*sin(fragCoord.y*211.1);
        float time = iTime - 0.5*(1.0/60.0)*(td+float(m*AA+n))/float(AA*AA-1);
        #else
        // pixel coordinates
        vec2 p = (2.0*fragCoord-iResolution.xy)/iResolution.y;
        // pixel sample
        ivec2 samp = ivec2(fragCoord);
        // time sample
        float time = iTime;
        #endif

        // animate camera
        float an = 0.25*time + 6.283185*iMouse.x/iResolution.x;
        vec3 ro = vec3( 2.4*cos(an), 0.7, 2.4*sin(an) );
        vec3 ta = vec3( 0.0, -0.15, 0.0 );

        // camera matrix
        vec3 ww = normalize( ta - ro );
        vec3 uu = normalize( cross(ww,vec3(0.2,1.0,0.0) ) );
        vec3 vv = normalize( cross(uu,ww));

        // animate query line
        vec3 sampleLineStart = -sin(time*0.5*vec3(1.0,1.1,1.2)+vec3(4.0,2.0,1.0));
        vec3 sampleLineStop  = -cos(time*0.5*vec3(1.0,1.1,1.2)+vec3(4.0,2.0,1.0));

        // make box transparent
        bool showBox = ((samp.x+samp.y)&1)==0;     // 50% opaque
        bool showCapsule = ((samp.x+samp.y+1)&1)==0;

        // create view ray
        vec3 rd = normalize( p.x*uu + p.y*vv + 1.5*ww );

        // raycast
        const float tmax = 5.0;
        float t = 0.0;
        float m = -1.0;
        for( int i=0; i<256; i++ )
        {
            vec3 pos = ro + t*rd;
            vec2 hm = map(pos,showBox,showCapsule,sampleLineStart, sampleLineStop);
            m = hm.y;
            if( hm.x<0.0001 || t>tmax ) break;
            t += hm.x;
        }

        // shade background
        vec3 col = vec3(0.05)*(1.0-0.2*length(p));

        // shade objects
        if( t<tmax )
        {
            // geometry
            vec3  pos = ro + t*rd;
            vec3  nor = calcNormal(pos,showBox,showCapsule,sampleLineStart, sampleLineStop);

            // color
            vec3  mate = 0.55 + 0.45*cos( m + vec3(0.0,1.0,1.5) );

            // show distance isolines on box
            if( abs(m-5.0)<0.5 )
            {
                vec4 result = segmentBoxQuery(sampleLineStart, sampleLineStop, box_rad);
                vec3 closestPointOnLine = mix(sampleLineStart, sampleLineStop, result.w);
                vec3 closestPointOnBox = result.xyz;

                float dref = sdBox( closestPointOnLine, box_rad );
                float dsam = length(pos-closestPointOnLine);
                mate += smoothstep(0.8,0.9,sin((dsam-dref)*80.0))*exp2(-12.0*(dsam-dref)*(dsam-dref));
            }
            // Show distance isolines on open capsule
            if( abs(m-1.0)<0.6 )
            {
                vec4 result = segmentBoxQuery(sampleLineStart, sampleLineStop, box_rad);
                vec3 closestPointOnLine = mix(sampleLineStart, sampleLineStop, result.w);
                vec3 closestPointOnBox = result.xyz;

                float dref = sdCapsule( closestPointOnBox, sampleLineStart, sampleLineStop, .1 );
                float dsam = length(pos-closestPointOnBox);
                mate += smoothstep(0.8,0.9,sin((dsam-dref)*80.0))*exp2(-12.0*(dsam-dref)*(dsam-dref));
            }

            // lighting
            col = vec3(0.0);
            {
              // key light
              vec3  lig = normalize(vec3(0.3,0.7,0.2));
              float dif = clamp( dot(nor,lig), 0.0, 1.0 );
              if( dif>0.001 ) dif *= calcSoftShadow(pos+nor*0.001,lig,showBox,showCapsule,sampleLineStart,sampleLineStop);
              col += mate*vec3(1.0,0.9,0.8)*dif;
            }
            {
              // dome light
              float dif = 0.5 + 0.5*nor.y;
              col += mate*vec3(0.2,0.3,0.4)*dif;
            }
        }

        // gamma
        col = pow( col, vec3(0.4545) );
        tot += col;
    #if AA>1
    }
    tot /= float(AA*AA);
    #endif

    // cheap dithering
    tot += sin(fragCoord.x*114.0)*sin(fragCoord.y*211.1)/512.0;

    fragColor = vec4( tot, 1.0 );
}

I believe the implementation is relatively optimized, although it's a bit branchy...  (Suggestions are welcome :)). The relevant implementation would be 'segmentBoxQuery'
The idea is to compute the distance from the line to only the closest box face. We first transform the box such that its origin is at 0, then to represent the box through its extents relative to 0. Then to make determining which face is closest to the segment, we reflect the direction of the segment to fall into the first octant (and reflect back once we have the closest point).
From there, we determine which box face to test against by doing a couple line-plane intersection tests.
For querying the closest point on the plane, we break up the test into 9 cases, as explained in greater depth here):

Table 3. The regions of the partitioning. Each table entry contains the region
name, the algebraic constraints defining the region, the rectangle
point closest to \$P = C + x_0U_0 + x_1U_1 + x_2U_2\$ and the squared
distance from the rectangle to \$P\$.

$$\small
\begin{array}{c|c|c}
\begin{array}{c}
    R_{−+}, x_0 < −e_0, x_1 > e_1 \\
    C − e_0U_0 + e_1U_1 \\
    (x_0 + e_0)^2 + (x_1 − e_1)^2 + x^2_2
\end{array}
&
\begin{array}{c}
    R_{0+}, |x_0| ≤ e_0, x_1 > e_1 \\
    C + x_0U_0 + e_1U_1 \\
    (x_1 − e_1)^2 + x^2_2
\end{array}
&
\begin{array}{c}
    R_{++}, x_0 > e_0, x_1 > e_1 \\
    C + e_0U_0 + e_1U_1 \\
    (x_0 - e_0)^2 + (x_1 − e_1)^2 + x^2_2
\end{array} \\\hline
\begin{array}{c}
    R_{−0}, x_0 < −e_0, |x_1| ≤ e_1 \\
    C − e_0U_0 + x_1U_1 \\
    (x_0 + e_0)^2 + x^2_2
\end{array}
&
\begin{array}{c}
    R_{00}, |x_0| ≤ e_0, |x_1| ≤ e_1 \\
    C + x_0U_0 + x_1U_1 \\
    x^2_2
\end{array}
&
\begin{array}{c}
    R_{+0}, x_0 > e_0, |x_1| ≤ e_1 \\
    C + e_0U_0 + x_1U_1 \\
    (x_0 - e_0)^2 + x^2_2
    \end{array} \\\hline
\begin{array}{c}
    R_{−-}, x_0 < −e_0, x_1 < -e_1 \\
    C − e_0U_0 - e_1U_1 \\
    (x_0 + e_0)^2 + (x_1 + e_1)^2 + x^2_2
\end{array}
&
\begin{array}{c}
    R_{0-}, |x_0| ≤ e_0, x_1 < -e_1 \\
    C + x_0U_0 - e_1U_1 \\
    (x_1 + e_1)^2 + x^2_2
\end{array}
&
\begin{array}{c}
    R_{+-}, x_0 > e_0, x_1 < -e_1 \\
    C + e_0U_0 - e_1U_1 \\
    (x_0 - e_0)^2 + (x_1 + e_1)^2 + x^2_2
\end{array}
\end{array}
$$

Can you include the code in the body of your answer, just to defend against link rot in case the ShaderToy version ever becomes inaccessible?

You could decompose that test into four separate tests:
For each edge AB, BC, CD, DA in the box ABCD, determine the distance to the ray. The closest of all four tests is your solution.
For the edge vs ray test, you could do segment-vs-segment, and just pretend the ray is a really long segment.
I found this 2D segment vs segment test that you can use for this.
Note that if multiple edges have distance 0 to the ray, you need to compute the actual intersections, and pick the one closest to the ray origin.

That's fine for the test, but in a 3d world you would be best to also do a Dot Test to ensure the face of the box is facing the ray as another test.  The other test I would perform might be a Ray/plane test post the dot product test to eliminate parrallel rays.  The original question talks about closest then mentions intersection, so i assume the ray has to collide and therefore parallel test is required.

If I understand it correctly, the method in the link doesn't work. If the segments don't intersect, but the extension of one into a line does intersect the other segment, then it will give the wrong answer. That's because, in this case, the closest distance is between the edge of one line and the middle of the other. The link provided doesn't appear to check for that.

First thing to note is that you only need to consider corners. The player will almost always see a corner of the box before an edge. In the rare cases where the alignment is just right, the player will see an edge and a corner at the same time (because every edge obviously contains corners). So it's enough to only consider corners.
The problem can be solved with linear algebra easily in 2-D, the generalisation to 3-D needs a bit more maths but nothing particularly advanced. The basic algorithm is:
1) From the position of the player and the angle of the line, create a linear equation y = m*x + c which defines the line.
2) The minimum distance between a point and a line is given by the length of a line segment perpendicular to the original line which reaches the point. So, from y = m*x + c construct a unit vector u perpendicular to it.
3) For each corner of rectangle p, find the value t such that p + tu lies on y = mx + c.
4) If all the t's are the same sign, it means that you are on the same side of all the corners. The distance to the rectangle is therefore min(abs(t)), and the corner you will see first is the one which gave that t. If some of the t's are positive and some negative, that means that you are clockwise of some corners and anticlockwise of others, and are therefore inside the rectangle.
EDIT:
I did the maths on the back of an envelope. The value of \$t\$ is
$$
t = \cos(\theta) (p_y-y_0) - \sin(\theta)(p_x-x_0)
$$
Where \$(x_0, y_0)\$ is the coordinate of the player, \$\theta\$ is the angle from the horizontal \$+x\$ axis (measured by the direction towards the \$+y\$ axis) and \$(p_x, p_y)\$ is the coordinate of a corner. This is a shockingly simple result, if I was you I would redo the maths just to double check, it's only 6 or 7 lines of algebra.
The extension in 3-D depends on how the viewer works. Is the vision of the player a wedge or a cone?

I think in 3 dimensions you won't only see corners anywhere near as commonly

No, in 3d the player will always see an edge first. But that's a 1-d object compared to a 2-d surface bounding the player's field of view so essentially the same trick works.

2D Solution
This is pretty easy if you divide this into two cases:  line intersects object, and line doesn't intersect.
For the intersect case, as you've shown it's just a matter of finding the intersection closest to the viewer - something I assume won't be that hard to figure out.
And for the case of no intersection, a bit of illustrated rotation can help show how this can be figured out easily...
First, here is the scenario with your image...

Now rotate it so that your view vector is zero degrees and the viewer is at the origin (0,0)...

Now, all you have to do is find the corner with the smallest absolute value Y coordinate, and that is your intersection point.
There is one edge case (literally) where the view vector is parallel to an edge, and two points are equally close.  I'm guessing for your requirements,  you would choose the furthest from the viewer.  Here's an illustration...

3D Solution
The concept is somewhat similar with 3D as follows...
First, if the line intersects the 3D shape, then choose the point of intersection as your answer.
If the line does not intersect, then you must find the point that is closest to your view line.  Since you have stated that you are only solving this for rectangular solids (meaning there are only 12 edge vectors), I would probably just brute force calculate the closest distance from each edge vector to the view vector, and choose the smallest one, and the coordinate of that closest point.  Rather than explain it here, I'll point to a Mathematics stack post that discusses finding the shortest distance between lines - https://math.stackexchange.com/questions/2213165/find-shortest-distance-between-lines-in-3d.  There are probably other solutions online to be found.

Rotating it is quite computationally expensive (sin and cos) and I don't know how rotating it would "work" in 3 dimensions.

You might want to reword your question to specifically state you're looking for a solution that works in 2D and 3D.

The last statement in red is not true. The corner furthest away is the one that will be seen first. Just consider the line rotating and you'll see that it hits the furthest corner before the first one.

@theonlygusti both these concerns are lessened if you think of it as not a rotation, but a projection onto the subspace perpendicular to the ray. Then it's at most a couple of normalizations to get your basis vector(s), and then a bunch of dot products. You can apply an approximate arctangent if you want the smallest turn instead of the closest linear offset.

@DMGregory i don't see how that makes things easier in 3d

good point @ScienceSnake, I'll revise it

@theonlygusti, I want to emphasize that I'm not trying to give you code, or math, or hard exact answers here. I'm trying to give you a way to think about your problem that might lead you to an answer.   Real growth as a developer comes from figuring things out sometimes.  Keep in mind we don't know if you are an experienced programmer or not, or if you know a lot of math or not.  Me? I'm visual.  So I give you a visual answer to help you imagine how it could be solved.
I will say though that your thinking of cos/sin as computationally intensive is naive - a problem 15-20 years ago, not now.


text:
How to develop custom Unity graphics?
Processing is a Java library for working with computer graphics, providing methods by which to draw primitive objects, custom meshes, etc., as well as mathematical methods (such as Simple Harmonic Motion) by which to animate and control them.
p5.js is an equivalent library for JavaScript and working with graphics on the web. You also have openFramworks which is similar but for C++.
How can you achieve similar graphics capabilities in the Unity Game Engine?
Suppose, for example, I wanted to build a game like Duet. I can imagine how I might go about creating those graphics in Processing or p5.js, but not in Unity and C#. How can you have that kind of creative freedom to build and draw in Unity?
Thanks.

The bulk of the graphics in Duet would be straightforward to create with just the built-in primitives like Quads and Sprites. What have you tried so far and where did you get stuck? Is there a specific effect or object you've had trouble creating?

@DMGregory No. I'm not actually building Duet (or I might as a small project), I'm just wondering how you would go about creating those kinds of graphics in particular with Unity.

Try giving us one concrete example of a graphic you want to make in your game that you can't find a way to make with the graphical primitives & techniques you know so far. (I'm presuming you've worked through some basic tutorials about working with mesh objects, sprites, etc...)

This is a really broad question. Unity is a very powerful and feature-rich game engine. It provides you with several tools which can help you to create unique procedural graphic effects:

Programming your own shaders gives you a lot of freedom to develop graphic effects on the GPU
The Mesh class gives you access to the vertex and UV coordinates of your 3d models. You can use it to deform or even generate new 3d objects at runtime.
The methods GetPixels and SetPixels of the class Texture2D allow you to procedurally change or generate textures from C# scrips. But keep in mind that real-time image manipulation like that should better be done on the GPU than on the CPU. When you are going to change a texture every frame, you should rather be doing this with a shader for performance reasons.

And then there is of course a lot of cool stuff you can do with the special effect tools Unity provides to you out-of-the-box:

The post processing system can add all kinds of neat visual effects to the whole camera. You can even program your own.
Particle effects
Line Renderers
Trail Renderers

If I would want to copy Duet in particular, I would do the trails of those red and blue balls with trail renderers. For the after-image of the blocks I would try the motion blur post-processing effect first and when that doesn't give me the effect I want I would use particle effects to generate fading clones of the same sprite used for the block. Those background animations could be done by creating a couple of sprites and animate their transforms with the animation system. When I run into performance problems due to having too many game objects, I would switch to the new Entity - Component - Systems architecture for the background objects.

making a game like duet should be easily done using unity 2d game objects but any simple art program could make those too and they can be imported into unity as an asset. and if you ever run into a situation where what you want to make is outside your ability i highly reccomend the asset shop on the unity site as people put up graphics and code all the time and some of it is available to be used for free.


text:
Does playing sound effects have to be filtering enabled?
In roblox I made a sword that plays the unsheath sound when equipped. This works by using a local script tell a server script to play it when equipped. I made a whole new remote event in replicated storage just for playing this sound effect and nothing else.
Is it really true that simply playing sound effects required filtering enabled?
Is all that extra work of creating the equipted event in replicated storage actually necessary or can I just play it in a non local script in the sword?

What did you mean by filtering? I'm not familiar with the Roblox API, but when I skimmed the sound effect documentation I didn't see any mention of that term.Are you referring to the Roblox anti-exploit mechanism?

@Pikalek Yes I am

Yes, they should be. If they aren't, only the client that plays them will be able to hear them. So yes, if you want other players to be able to hear the sword coming out of the sheath, then they have to be filtering enabled.


text:
Server-side real time position calculation based on destination position
What I want to achieve is to calculate the real object position based on its speed and a destination position.
In my server, I have a MapInstance that have a list of MapLayer that have MapRegions.
To resume we have:

1 MapInstance

N MapLayers
X MapRegions

Each MapInstance will update in an asynchronous task all his map layers and the common object such as NPCs and the MapLayer will update his regions of entities (monsters/items).
On the client side, when I click somewhere on the map, it sends a packet to the server with the destination position.
Then, on the server-side I receive the position and set the entity.Movable.DestinationPosition property.
As I said earlier, each map instance are updated in an asynchronous task and updates the map layers and common entities.
My problem is, my realtime position calculation formula is wrong somewhere, and I can't find where.
To understand the problem, there is some inputs:

Entity speed: 0.08 (8%)
Position and DestinationPosition are Vector3 (class) instance, where X, Y and Z are properties.

This is my code:
public void StartUpdateTask(int delay)
{
    Task.Run(async () =>
    {
        const double FrameRatePerSeconds = 0.66666f;
        double previousTime = Environment.TickCount;

        while (true)
        {
            if (this._cancellationToken.IsCancellationRequested)
                break;

            double currentTime = Environment.TickCount;
            double deltaTime = currentTime - previousTime;
            previousTime = currentTime;

            this.GameTime = (deltaTime * FrameRatePerSeconds) / 1000f;

            lock (SyncRoot)
            {
                foreach (var entity in this.Entities)
                    Walk(entity);

                foreach (var mapLayer in this._layers)
                     mapLayer.Update();
            }

            await Task.Delay(delay, this._cancellationToken).ConfigureAwait(false);
        }
    }, this._cancellationToken);
}

mapLayer.Update() method:
public override void Update()
{
    this.GameTime = this.Parent.GameTime;

    foreach (var entity in this.Entities)
        Walk(entity);

    foreach (var region in this._regions)
    {
        if (region.IsActive && region is IMapRespawnRegion respawnRegion)
        {
            foreach (var entity in respawnRegion.Entities)
            {
                Walk(entity);
            }
        }
    }
}

And the calculation formula:
private void Walk(IMovableEntity entity)
{
    if (entity.MovableComponent.DestinationPosition.IsZero())
        return;

    if (entity.MovableComponent.DestinationPosition.IsInCircle(entity.Object.Position, 0.1f))
    {
        entity.MovableComponent.HasArrived = true;
        entity.MovableComponent.DestinationPosition.Reset();
    }
    else
    {
        entity.MovableComponent.HasArrived = false;
        double entitySpeed = entity.MovableComponent.Speed * entity.MovableComponent.SpeedFactor;
        double speed = ((entitySpeed * 100f) * entity.Context.GameTime);
        float distanceX = entity.MovableComponent.DestinationPosition.X - entity.Object.Position.X;
        float distanceZ = entity.MovableComponent.DestinationPosition.Z - entity.Object.Position.Z;
        double distance = Math.Sqrt(distanceX * distanceX + distanceZ * distanceZ);

        // Normalize
        double deltaX = distanceX / distance;
        double deltaZ = distanceZ / distance;
        double offsetX = deltaX * speed;
        double offsetZ = deltaZ * speed;

        if (Math.Abs(offsetX) > Math.Abs(distanceX))
            offsetX = distanceX;
        if (Math.Abs(offsetZ) > Math.Abs(distanceZ))
            offsetZ = distanceZ;

        entity.Object.Position.X += (float)offsetX;
        entity.Object.Position.Z += (float)offsetZ;
    }
}

With this current formula, my players and monsters arrive to destination between 1-2 seconds sooner on the server side compared to the client-side...
Do you have any idea what I'm doing wrong ? Appriciate if someone could guide me and explain me how to solve my problem. :-)
Thank you

What is the FrameRatePerSeconds supposed to accomplish in the main task update?  Game time is independent of the framerate refresh cycle and your server most probably doesn't even have display frames in the first place.  It looks like every update you're multiplying in the framerate, unless I read that wrong...

The frame rate was to achieve a fixed time step on the server side. Since the game is displaying ~60 frames per seconds, I thought a fixed time step could do the job, but apparently not... :-/

Your FrameRatePerSeconds property at 60fps should be 16.67 milliseconds, I think.  Every frame rendered at 60fps lasts for 16.67 milliseconds before the next frame.  I have no idea why "delay" is passed in and kept static, I think that what you really need is to remove that parameter and change the await to something like this: "await Task.Delay(FrameRatePerSeconds-deltaTime, this._cancellationToken).ConfigureAwait(false);"  That runs this task adjusted for 60fps taking into account how much time it took since last frame.  (I wish I had more time to format properly)  Does that sound right?

So if I understand correctly, I need to defined my FrameRatePerSeconds to 60 and then substract the tick delta in order to have a fixed timestep right? but what if the substraction is negative? like: 60fps - 73ticks this will give me -13 and my delay will not work. Should I use a Math.Abs on the result or i'm missing something on my calculation?

If you go negative then you're trying to do more than your code+hardware can handle.  In that case you need to pursue optimization and/or re-design to handle less so you never go there.

I see, it makes sense thought. But now, since we've touched the GameTime property, the speed is now wrong. I had double speed = ((entitySpeed * 100f) * entity.Context.GameTime);where entitySpeed is 0.08. Should I change the formula, or i forgot something on the GameTime calculation ?


text:
Javelin throw projectile motion
I am trying to simulate throw of javelin using projectile motion. The basic physics of projectile motion of a point was used to position the javelin. For the rotation part, I just assumed that the javelin must be tanget to the projectile path as shown below.

But, if the launch angle was extremely huge, we can see that the projectile range will be extremely small. Now, lets assume, the height of projectile was big, the projectile motion will look as shown below.

The animation looks unnatural because the stick rotates really fast because the curve is extremely steep.
So, I am sure the javelin is not always tangent to the path(of Centre of Gravity of the javelin).
So I thought maybe I need to calculate torque on the javelin. I've also tried this approach but the javelin is extremely shaky. My steps were:

$$torque = r \times \vec{F}$$
$$\vec{F} = mg + ma$$
$$ a = \frac{dv}{dt} $$ v is the
velocity of the centre of javelin at any point of time of projectile motion. We integrate the equation to find the change in torque.
$$d\vec{Torque} = r \times d\vec{force}$$
$$d\vec{Torque} = Id\vec{\omega}$$
Now, we obtain the change in angular velocity, which is then integrated to obtain the orientation of javelin.

I must have messed up somewhere because the integration is not working. Its extremely shaky and it works in some cases where launch angle is small, but fails when launch angle is huge.
So can anybody give me some pointers?

Using already derivated formulas would be easier and quicker for you. If that is not what you are looking for, this question might be a better fit for physics.se or math.se.

Any kind of solution would work for me.

To align a javelin, you should properly compute all forces.
The reason that a javelin can orient itself into its path, is because of air drag.
Note that the drag is not always asymmetric enough to induce enough torque to align it:
Sometimes a javelin lands with point sticking in the grass, sometimes it lands flat on the ground.
Note that gravity should be applied at the javelin's centre of mass, which is not the centre of the javelin.
If you drop a javelin from a tower, horizontally, then a drag force (magnitude scales with square of velocity) works along the whole length, the gravity is off-centre, causing it to nose-down.

This will do it. Essentially the change in its orientation will be proportional to the sin of the angle between travel and orientation. My answer suggested an approximation requiring no analysis

Have you ever thrown a javelin straight up? It does actually rotate quickly on top, because the pointy end is heavier. But it does so not when it reaches the top but after the velocity changes to move downward. It's built that way to ensure the pointy end hits the target ...
You can try to model torque but that gets ugly with different weights, lengths, and heads/tails compositions. A full model might produce the most accurate results, but if the goal is to have a projectile that lands pointy-end-first no matter the launch angle, then your original method is what I'd use, but maybe augmented with a small time delay.
E.g. delay the change in orientation a small amount so that it starts to travel downward before fully rotating, much like a real spear or arrow. You can have a decaying delay for best results.
If o(t) is the tangential angle you were using for the projectile at time t, then have it instead be o(t-a). Where a is minimum of t or some maximum A.

maybe you should position the javelin in such a way, that the 'nose' of the javelin is where the curve is, not in the middle, that way it might look a little 'more natural'.
or
you can add a turning delta that javelin can turn only by certain degrees that are given to it, that way it goes maybe a little bit out of sync but it will look better ;-)