# Question
Title: How To Convert World Space Normal To Tangent Space?
This question is a continuation of this post on How To Make Seamless Custom CubeMap?

The idea is to create a cube map with procedurally generated noise, extract the noise and a normal map of the noise for all six sides via a render target and a orthographic camera, download it as an image, and then read it back as a texture.

The problem is when reading back the normal map it produces seams, so the recommendation is to use noise that also produces derivatives along with the height called Analytical Derivatives. These derivatives are world space normals. I'm trying to convert the world space normal noise to tangent space before writing each side of the cube to its own render target.

I know that to compute the tangent space, you need three vectors: the tangent, bitangent, and normal, to form the TBN matrix, as stated in OpenGL Tutorial 13 : Normal Mapping

The library I'm using is Three.js, which has a method that computes the tangent for you, already defined here and sets it as a attribute to be passed to the shader. This makes my life a lot easier. I can then compute the TBN matrix like this:

vertex shader

```
attribute vec4 tangent;
varying   mat3 TBN;

...
vec3 _tangent = tangent.xyz;
vec3 bitangent = normalize(cross(_tangent,normal));
TBN = mat3(_tangent,bitangent,normalize(normal));

```

fragment shader

```
varying  mat3 TBN;
// IQ's version returns noise value in x, gradient in yzw.
float height = noise;
vec3 gradient = grad;
// Zero out component perpendicular to the sphere.
vec3 onSphere = gradient - dot(sampleDir, gradient) * sampleDir;
// Normal vector tilts away from "uphill" direction.
vec3 normal = normalize(sampleDir - onSphere * .1);//<---- worldspaceNormal

normal = normalize(TBN*normal); //<---- tangentSpaceNormal
gl_FragColor = vec4(vec3(normal), 1.0);

```

When outputting the tangent space results, there seems to be no difference between the world space and tangent space, besides a change in the direction of the green color.

world space normal:

TBN * world space normal:

I'm under the assumption that if I did it correctly, my normal map would look like the image on the left for the entire object. Instead, I still have my normals in world space.

```
let camera,scene,mesh,renderer

// Create a custom shader material
const vertexShader = `
attribute vec4 tangent;
varying  mat3 TBN;
varying vec3 grad;
varying float noise;
varying vec3 sampleDir;
varying vec2 vUv;
uniform vec3 center;

${mod289()}
${taylorInvSqrt()}
${permute()}
${snoise()}

vec3 orthogonal(vec3 n){
 return normalize(
 abs(n.x)>abs(n.z) ? vec3(-n.y,n.x,0.) : vec3(0.,-n.z,n.y)
 );
}

void main() {
  vUv = uv;

  vec4 worldPosition = modelMatrix * vec4(position, 1.0);
  vec3 sphere  = 50.*normalize(position-center)+center;  // This transforms cube into a sphere.
  sampleDir    = normalize(worldPosition.xyz-center);    // Need to use world space so the noise on each quad can align.
  vec3 shift   = vec3(0.,0.,0.);                         // this just offsets the noise in any direction.
  vec3 shiftedSample = sampleDir + shift;
  vec4 noiseGrad = snoise(shiftedSample,vec3(0.));
  noise = noiseGrad.x;
  grad  = noiseGrad.yzw;

 //compute the TBN matrix
   vec3 _tangent = tangent.xyz;
   vec3 bitangent = normalize(cross(_tangent,normal));
   TBN = mat3(_tangent,bitangent,normalize(normal));

  vec3 sphereD = sphere + 5.0 * noise * normalize(position-center); // add displacement to the sphere.
  gl_Position  = projectionMatrix * modelViewMatrix * vec4(sphereD, 1.0);
}
`;

const fragmentShader = `
varying  mat3 TBN;

uniform vec3 center;
varying vec3 grad;
varying float noise;
varying vec3 sampleDir;
varying vec2 vUv;

float lightv2(vec3 normalMap, vec3 lightPosition, vec3 cP) {

    vec3 lightDirection = normalize(lightPosition - normalMap.xyz);
    vec3 viewDirection = normalize(cP - normalMap.xyz);
    vec3 ambientColor = vec3(0.2, 0.2, 0.2);  // Ambient light color
    vec3 diffuseColor = vec3(0.2, 0.2, 0.2);  // Diffuse light color
    vec3 specularColor = vec3(0.2, 0.2, 0.2); // Specular light color
    float shininess = 0.0;  // Material shininess factor

    // Ambient lighting calculation
    vec3 ambient = ambientColor;

    // Diffuse lighting calculation
    float diffuseIntensity = max(dot(normalMap.xyz, lightDirection), 0.0);
    vec3 diffuse = diffuseColor * diffuseIntensity;

    // Specular lighting calculation
    vec3 reflectionDirection = reflect(-lightDirection, normalMap.xyz);
    float specularIntensity = pow(max(dot(reflectionDirection, viewDirection), 0.0), shininess);
    vec3 specular = specularColor * specularIntensity;

    // Final lighting calculation
    vec3 finalColor = ambient + diffuse + specular;
    return clamp(dot(normalMap.xyz, lightDirection), 0.0, 1.0) * max(max(finalColor.r, finalColor.g), finalColor.b);
}

void main() {

// IQ's version returns noise value in x, gradient in yzw.
float height = noise;
vec3 gradient = grad;
// Zero out component perpendicular to the sphere.
vec3 onSphere = gradient - dot(sampleDir, gradient) * sampleDir;
// Normal vector tilts away from "uphill" direction.
vec3 normal = normalize(sampleDir - onSphere * .1);//<---- worldspaceNormal

normal = normalize(TBN*normal); //<---- tangentSpaceNormal

vec3 lightDirection = vec3(0.,0.,100.);
vec3 cameraPosition = vec3(0.,0.,0.);
float finalColor = lightv2(normal,lightDirection,cameraPosition);

gl_FragColor = vec4(vec3(normal), 1.0);

}
`;

// animation
init()

function init(){
//-----------Basic setUp
renderer = new THREE.WebGLRenderer( { antialias: true } );
renderer.setSize( window.innerWidth, window.innerHeight );
renderer.setAnimationLoop( animation );
document.body.appendChild( renderer.domElement );
renderer.setClearColor( 'white' )

camera = new THREE.PerspectiveCamera( 70, window.innerWidth / window.innerHeight, 0.01, 1000 );
camera.position.z = 100;
var controls = new THREE.OrbitControls(camera, renderer.domElement);
scene = new THREE.Scene();

/********
- set creat mesh
- set transfroms
- set unifroms for undoing of transfoms
*********/
let widthHeight = 10

//------------front
let frontUnifrom = {ignoreFront:{value:0}}
let front = createPlaneMesh(0,0,0,0,0,0,frontUnifrom)
scene.add( front );
//-----------back
let bz    = -widthHeight
let bry   = Math.PI
var undorotationMatrix = new THREE.Matrix4();
undorotationMatrix.makeRotationY(-bry);
let backUnifrom = {rm:{value:undorotationMatrix},undoPoition:{value:new THREE.Vector3(bz*2,0,bz)},ignoreFront:{value:1}}
let back  = createPlaneMesh(0,0,bz,0,bry,0,backUnifrom)
scene.add( back );
//---------right
let rz    = -(widthHeight)/2;
let rx    =  (widthHeight)/2;
let rry   =  Math.PI/2;
var undorotationMatrix = new THREE.Matrix4();
undorotationMatrix.makeRotationY(-rry);
let rightUnifrom = {rm:{value:undorotationMatrix},undoPoition:{value:new THREE.Vector3(-rx,0,-rz)},ignoreFront:{value:1}}
let right = createPlaneMesh(rx,0,rz,0,rry,0,rightUnifrom)
scene.add( right );
//---------left
let lz    =  -(widthHeight)/2;
let lx    =  -(widthHeight)/2;
let lry   =  -Math.PI/2;
var undorotationMatrix = new THREE.Matrix4();
undorotationMatrix.makeRotationY(-lry);
let leftUnifrom = {rm:{value:undorotationMatrix},undoPoition:{value:new THREE.Vector3(-lx,0,-lz)},ignoreFront:{value:1}}
let left  = createPlaneMesh(lx,0,lz,0,lry,0,leftUnifrom)
scene.add( left );
//--------top
let tz    =  -(widthHeight)/2;
let ty    =  (widthHeight)/2;
let trx   =  -Math.PI/2;
var undorotationMatrix = new THREE.Matrix4();
undorotationMatrix.makeRotationX(-trx);
let topUnifrom = {rm:{value:undorotationMatrix},undoPoition:{value:new THREE.Vector3(0,-ty,-tz)},ignoreFront:{value:1}}
let top  = createPlaneMesh(0,ty,tz,trx,0,0,topUnifrom)
scene.add( top );
//---------bottom
let boz   =  -(widthHeight)/2;
let boy   =  -(widthHeight)/2;
let borx  =  Math.PI/2;
var undorotationMatrix = new THREE.Matrix4();
undorotationMatrix.makeRotationX(-borx);
let boUnifrom = {rm:{value:undorotationMatrix},undoPoition:{value:new THREE.Vector3(0,-boy,-boz)},ignoreFront:{value:1}}
let bo    = createPlaneMesh(0,boy,boz,borx,0,0,boUnifrom)
scene.add( bo );
}

//--------build mesh
function createPlaneMesh(x, y, z, rotationX, rotationY, rotationZ, uniforms) {
// Create a plane geometry
const planeGeometry = new THREE.PlaneGeometry(10, 10, 150, 150);
planeGeometry.computeTangents ()

uniforms.center = {value:new THREE.Vector3(0,0,-5)}
const planeMaterial = new THREE.ShaderMaterial({
    uniforms: uniforms,
    vertexShader: vertexShader,
    fragmentShader: fragmentShader,
});
// Create the plane mesh
const planeMesh = new THREE.Mesh(planeGeometry, planeMaterial);
// Set the position of the mesh
planeMesh.position.set(x, y, z);
// Set the rotation of the mesh
planeMesh.rotation.set(rotationX, rotationY, rotationZ);
planeMesh.frustumCulled = false
return planeMesh;
}

//-----------noise functions

function mod289(){
  return  `
vec3 mod289(vec3 x) {
  return x - floor(x * (1.0 / 289.0)) * 289.0;
}

vec4 mod289(vec4 x) {
  return x - floor(x * (1.0 / 289.0)) * 289.0;
}
  `
 }

function permute(){
  return  `
vec4 permute(vec4 x) {
     return mod289(((x*34.0)+10.0)*x);
}
  `
 }
function taylorInvSqrt(){
return     `
vec4 taylorInvSqrt(vec4 r)
{
  return 1.79284291400159 - 0.85373472095314 * r;
}
    `
}
function snoise(){
return `
vec4 snoise(vec3 v,  vec3 gradient)
{
  const vec2  C = vec2(1.0/6.0, 1.0/3.0) ;
  const vec4  D = vec4(0.0, 0.5, 1.0, 2.0);

// First corner
  vec3 i  = floor(v + dot(v, C.yyy) );
  vec3 x0 =   v - i + dot(i, C.xxx) ;

// Other corners
  vec3 g = step(x0.yzx, x0.xyz);
  vec3 l = 1.0 - g;
  vec3 i1 = min( g.xyz, l.zxy );
  vec3 i2 = max( g.xyz, l.zxy );

  //   x0 = x0 - 0.0 + 0.0 * C.xxx;
  //   x1 = x0 - i1  + 1.0 * C.xxx;
  //   x2 = x0 - i2  + 2.0 * C.xxx;
  //   x3 = x0 - 1.0 + 3.0 * C.xxx;
  vec3 x1 = x0 - i1 + C.xxx;
  vec3 x2 = x0 - i2 + C.yyy; // 2.0*C.x = 1/3 = C.y
  vec3 x3 = x0 - D.yyy;      // -1.0+3.0*C.x = -0.5 = -D.y

// Permutations
  i = mod289(i);
  vec4 p = permute( permute( permute(
             i.z + vec4(0.0, i1.z, i2.z, 1.0 ))
           + i.y + vec4(0.0, i1.y, i2.y, 1.0 ))
           + i.x + vec4(0.0, i1.x, i2.x, 1.0 ));

// Gradients: 7x7 points over a square, mapped onto an octahedron.
// The ring size 17*17 = 289 is close to a multiple of 49 (49*6 = 294)
  float n_ = 0.142857142857; // 1.0/7.0
  vec3  ns = n_ * D.wyz - D.xzx;

  vec4 j = p - 49.0 * floor(p * ns.z * ns.z);  //  mod(p,7*7)

  vec4 x_ = floor(j * ns.z);
  vec4 y_ = floor(j - 7.0 * x_ );    // mod(j,N)

  vec4 x = x_ *ns.x + ns.yyyy;
  vec4 y = y_ *ns.x + ns.yyyy;
  vec4 h = 1.0 - abs(x) - abs(y);

  vec4 b0 = vec4( x.xy, y.xy );
  vec4 b1 = vec4( x.zw, y.zw );

  //vec4 s0 = vec4(lessThan(b0,0.0))*2.0 - 1.0;
  //vec4 s1 = vec4(lessThan(b1,0.0))*2.0 - 1.0;
  vec4 s0 = floor(b0)*2.0 + 1.0;
  vec4 s1 = floor(b1)*2.0 + 1.0;
  vec4 sh = -step(h, vec4(0.0));

  vec4 a0 = b0.xzyw + s0.xzyw*sh.xxyy ;
  vec4 a1 = b1.xzyw + s1.xzyw*sh.zzww ;

  vec3 p0 = vec3(a0.xy,h.x);
  vec3 p1 = vec3(a0.zw,h.y);
  vec3 p2 = vec3(a1.xy,h.z);
  vec3 p3 = vec3(a1.zw,h.w);

//Normalise gradients
  vec4 norm = taylorInvSqrt(vec4(dot(p0,p0), dot(p1,p1), dot(p2, p2), dot(p3,p3)));
  p0 *= norm.x;
  p1 *= norm.y;
  p2 *= norm.z;
  p3 *= norm.w;

// Mix final noise value
  vec4 m = max(0.5 - vec4(dot(x0,x0), dot(x1,x1), dot(x2,x2), dot(x3,x3)), 0.0);
  vec4 m2 = m * m;
  vec4 m4 = m2 * m2;
  vec4 pdotx = vec4(dot(p0,x0), dot(p1,x1), dot(p2,x2), dot(p3,x3));

// Determine noise gradient
  vec4 temp = m2 * m * pdotx;
  gradient = -8.0 * (temp.x * x0 + temp.y * x1 + temp.z * x2 + temp.w * x3);
  gradient += m4.x * p0 + m4.y * p1 + m4.z * p2 + m4.w * p3;
  gradient *= 105.0;

  float n =  105.0 * dot(m4, pdotx);
  return vec4(n,gradient);
}
      `
}
//-------------

function animation( time ) {
    renderer.render( scene, camera );

}
```

```
<script src="https://cdn.jsdelivr.net/npm/three@0.132.2/build/three.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/three@0.132.2/examples/js/controls/OrbitControls.js"></script>
```

UPDATE: For anyone curious, this code shows how to generate noise in tangent space without seams. The drawback is that you have to sample the noise 3 times. I didn't use this as an answer because it doesn't show how to convert from world space normals to tangent space. That problem still persists:

```
  vec3 noiseNormal(vec3 worldPosition,vec3 normal, vec4 tangent){
    float noise = snoise3D(worldPosition.xyz);

    vec3 displacedPosition = worldPosition.xyz + normal * noise;

    float offset   = 0.01;
    vec3 tangent_  = tangent.xyz;
    vec3 bitangent = normalize(cross(normal, tangent_));
    vec3 neighbour1 =  worldPosition.xyz + tangent_ * offset;
    vec3 neighbour2 =  worldPosition.xyz + bitangent * offset;
    vec3 displacedNeighbour1 = neighbour1 + normal * snoise3D(neighbour1);
    vec3 displacedNeighbour2 = neighbour2 + normal * snoise3D(neighbour2);

    vec3 displacedTangent = displacedNeighbour1 - displacedPosition;
    vec3 displacedBitangent = displacedNeighbour2 - displacedPosition;

    vec3 displacedNormal = normalize(cross(displacedTangent, displacedBitangent));
    return displacedNormal;

  }

```

# Answer
Your coordinate conversions are incorrect.

The `tangent` and `normal` attributes that three.js provide to you are in *object* space. For your planes, that means the tangent is always `(1, 0, 0)` (+x), and the normal is `(0, 0, 1)` (+z).

You need to map this to world space by multiplying it by your model matrix. That's how it will account for each plane being oriented differently for the six faces of the cube.

Then the matrix you form from `mat3(tangent, bitangent, normal)` will convert *from* tangent space *to* world space.

To map the other way, encoding a world space normal *into* tangent space, you need its inverse. Fortunately, for an orthonormal matrix (which this is by construction), that's just the transpose.

Working this way, you'd have one consistent tangent frame for the entire cube face. Strictly speaking, this tangent frame is correct only in the center of the face. After puffing your cube out into a sphere, this is the only spot where the surface normal and tangent still point straight out along axis-aligned directions. The rest of the round surface naturally curves away from that axis-aligned frame. So if you use this to encode your normals into tangent space, you'll get that familiar pale blue only in the middle of each chart, and they'll tint to pink/green/purple toward the edges, as the normal map is forced to encode the curvature of the sphere that you didn't account for in your TBN matrix.

If you want to get more uniform behaviour over the surface, you can compute a unique tangent frame at each point, taking into account the local orientation of the sphere there. Here's a function that does this:

```
// Takes a point on the unit cube centered at the origin
// and a worldspace tangent for the cube face we're rendering,
// then computes a surface normal for the corresponding point
// on the unit sphere, and a tangent perpendicular to that normal.
void sphereBasis(in vec3 cubePosition, inout vec3 tangent, out vec3 normal) {
    float scale = dot(cubePosition, cubePosition);

    normal = cubePosition/sqrt(scale);

    tangent = normalize(tangent * scale - cubePosition * dot(tangent, cubePosition));
}

```

You can then use the cross trick to get a bitangent to complete the orthonormal TBN matrix. This is correct across the u direction, but doesn't match the v direction to the actual curvature of the mesh (look at the corners of the cube after it's puffed into a sphere: the lines along its edges point 120 degrees from each other, rather than the usual 90). But this inaccuracy may be worthwhile for still giving you the cheap and easy transpose-to-invert.

If you want the binormal to splay out to match the "vertical" grid lines along each cube face, you can use the same formula we used for tangent, just swapping the binormal instead. But then inverting the matrix is a little messier, since the tangent and bitangent directions are no longer orthogonal. There might be a fast formula for this, since two of the three pairs of axes are still orthonormal, I just don't know it off the top of my head

---

Here's a sample showing that this correctly maps the world space normal we get from our noise function into a reasonable tangent space at each point, and back, seamlessly. You can change the `noiseOctaves` variable to see how it looks with both high-frequency detail and smooth gradients.

* At the back, you can see the generated tangent space normal maps, laid out as the net of the cube. We create these by sampling a noise function to get a world space normal, constructing a tangent space using the code above, and using the transpose of the TBN matrix to map the world space normal into a tangent space version to write into the texture.

Don't worry about the visible seams between charts in the net. Just like in the previous Q&A, this is due to the projection changing abruptly at those edges - they're tangent space seams. The projection back onto a sphere and mapping back into world space using the TBN matrix will undo this projection and bring adjacent sides back into agreement, as confirmed by the two spheres:
* On the left, there's a sphere showing world space normals computed directly from the noise function.
* On the right, there's a sphere showing normals read from the tangent space normal maps, then mapped back to world space using the same TBN matrix we used to encode them. If there were an error in the mapping, we'd expect visible seams in this cube, or dramatic differences from the cube on the left. (Minor differences are inevitable due to rasterization and quantization artifacts when saving the continuous noise output to an 8bpc texture, but I'd say this looks quite adequate for typical shading needs).

---

If you're curious about the derivation, it comes from this - taking the partial derivative of our "spherify" function \\$s\\$ (also called `normalize()`) to see how our on-sphere position changes as our input x coordinate increases:

$$ s(\begin{bmatrix}x\\y\\z\end{bmatrix}) =\frac 1 {\sqrt{x^2 + y^2 + z^2}} \begin{bmatrix}x\\y\\z\end{bmatrix}\\ \text{let} \\, l = \sqrt{x^2 + y^2 + z^2}\\ \frac \delta {\delta x} l = \frac 1 2 l^{-1} \cdot 2 x = \frac x l\\ \begin{align} s(\begin{bmatrix}x\\y\\z\end{bmatrix}) &= \frac 1 l\begin{bmatrix}x\\y\\z\end{bmatrix}\\ \frac \delta {\delta x} s(\begin{bmatrix}x\\y\\z\end{bmatrix}) &= \left(l \begin{bmatrix}1\\0\\0\end{bmatrix} - \frac x l \begin{bmatrix}x\\y\\z\end{bmatrix}\right) \frac 1 {l^2}\\ l^3\frac \delta {\delta x} s(\begin{bmatrix}x\\y\\z\end{bmatrix}) &= l^2 \begin{bmatrix}1\\0\\0\end{bmatrix}\ - x \begin{bmatrix}x\\y\\z\end{bmatrix}\\ \end{align} $$

I pulled the \\$l^3\\$ term to the left side at the end because we're going to normalize the vector anyway, so we don't care about a scalar length factor, and this makes the expression on the right much simpler. The code version just generalizes this to the case where the tangent is an axis-aligned unit vector, not necessarily always `(1, 0, 0)`.

As it turns out, conveniently, both the normal and tangent vectors change linearly over the face, so you could do this calculation in the vertex shader and interpolate the result, but you'd still have to normalize them and compute the bitangent per-fragment, so you might not gain much from taking up the extra interpolator slot (particularly on mobile, where tile-based rendering can make fatter vertices more costly).
> 2 votes

---
Tags: glsl, normals, cubemap
---


# Question
Title: Networking issue with photon, Joined room success but other player not seen
I am trying to add networking to my game via Photon Realtime and have a unity scene set up with this script attached to one of my game objects :

```
public class Multiplayer : MonoBehaviourPunCallbacks
{
// Start is called before the first frame update
void Start()
{
    PhotonNetwork.ConnectUsingSettings();
}

public override void OnConnectedToMaster()
{
    Debug.Log("OnConnectedToMaster() was called by PUN.");
    RoomOptions roomOptions = new RoomOptions();
    roomOptions.IsVisible = false;
    roomOptions.MaxPlayers = 4;
    PhotonNetwork.JoinOrCreateRoom("ChunckyMonkey", roomOptions, TypedLobby.Default);
}

public override void OnJoinedRoom()
{
    base.OnJoinedRoom();
    Debug.Log("Room was Joined.");
}

public override void OnJoinRoomFailed(short returnCode, string message)
{
    base.OnJoinRoomFailed(returnCode, message);
}
}

```

I can see the corresponding logs in unity's output but when I run the game with two oculus headsets I do not see the other player. So it seems to be working according to photon but I don't see it. This is using quest 2 unity version 2019.4.31f1. Could photon be configured incorrectly or sending each player to a new room ?

# Answer
Well, that was silly of me. In addition to needing the room `isVisible` to be set to `true`, you have to set `isOpen` to `true` for others to be able to join. Makes sense.
> 0 votes

---
Tags: unity, photon
---


# Question
Title: Unity Burst Compiler failed — could not load System.Diagnostics.Tracing
I am using Unity 2023.3.f1 When building an Android app I get the following. I have zero idea what this means. I've tried searching elsewhere but found nothing to fix it.

```
Building Library\Bee\artifacts\Android\AsyncPluginsFromLinker failed with output:
UnityEditor.Build.BuildFailedException: Burst compiler (1.8.4) failed running

stdout:
Error: Failed to find entry-points:
System.Exception: Error while hashing assembly C:\Program Files\Unity\Hub\Editor\2022.3.1f1\Editor\Data\PlaybackEngines\AndroidPlayer\Variations\mono\Managed\UnityEngine.dll ---> System.AggregateException: One or more errors occurred. ---> System.IO.FileNotFoundException: Could not load file or assembly 'System.Diagnostics.Tracing, Version=4.2.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a' or one of its dependencies. The system cannot find the file specified. ---> System.IO.FileNotFoundException: Could not load file or assembly 'System.Diagnostics.Tracing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a' or one of its dependencies. The system cannot find the file specified.
   --- End of inner exception stack trace ---
   at System.Buffers.DefaultArrayPool`1.Rent(Int32 minimumLength)
   at Burst.Compiler.IL.Hashing.Storage.StringCollection.AddString(String value)
   at Burst.Compiler.IL.Hashing.CacheBuilder.ILHasher.ProcessAssemblyReference(AssemblyReferenceHandle assemblyReferenceHandle, StringCollection strings)
   at Burst.Compiler.IL.Hashing.CacheBuilder.ILHasher.ProcessAssemblyReferences(StringCollection strings)
   at Burst.Compiler.IL.Hashing.CacheBuilder.ILHasher.<>c__DisplayClass13_0.<HashImpl>b__3()
   at System.Threading.Tasks.Task.Execute()
   --- End of inner exception stack trace ---
   at System.Threading.Tasks.Task.WaitAll(Task[] tasks, Int32 millisecondsTimeout, CancellationToken cancellationToken)
   at Burst.Compiler.IL.Hashing.CacheBuilder.ILHasher.HashImpl()
   at Burst.Compiler.IL.Hashing.CacheBuilder.ILHasher.HashAssembly(String filePath, TaskFactory taskFactory)
   --- End of inner exception stack trace ---
   at Burst.Compiler.IL.Hashing.CacheBuilder.ILHasher.HashAssembly(String filePath, TaskFactory taskFactory)
   at Burst.Compiler.IL.Hashing.CacheRuntime.HashCacheLoader.CreateHashingResult(AssemblyNameReference assemblyNameReference, AssemblyLoader assemblyLoader, DebugLogWriter debugLogWriter)
   at Burst.Compiler.IL.Hashing.CacheRuntime.HashCacheAssemblyStore.GetAssemblyState(String assemblyName, AssemblyLoader assemblyLoader)
   at Burst.Compiler.IL.Server.EntryPointMethodFinder.LoadAllAssemblyReferences(AssemblyDefinition asmDef, Dictionary`2 visited, Dictionary`2 jobProducers, HashCacheAssemblyStore assemblyStore, AssemblyLoader assemblyLoader)
   at Burst.Compiler.IL.Server.EntryPointMethodFinder.FindEntryPoints(String[] rootAssemblyNames, HashCacheAssemblyStore assemblyStore, AssemblyLoader assemblyLoader, NativeCompilerOptions options, ProfileDelegate profileCallback, Boolean includeRootAssemblyReferences, Boolean splitTargets)
   at Burst.Compiler.IL.Server.FindMethodsJob.Execute(CompilerServerJobExecutionContext context)
stderr:

  at Unity.Burst.Editor.BurstAotCompiler+BclRunner.RunProgram (UnityEditor.Utils.Program p, System.String exe, System.String args, System.String workingDirectory, UnityEditor.Scripting.Compilers.CompilerOutputParserBase parser) [0x00237] in .\Library\PackageCache\com.unity.burst@1.8.4\Editor\BurstAotCompiler.cs:1706
  at Unity.Burst.Editor.BurstAotCompiler+BclRunner.RunManagedProgram (System.String exe, System.String args, System.String workingDirectory, UnityEditor.Scripting.Compilers.CompilerOutputParserBase parser) [0x0004d] in .\Library\PackageCache\com.unity.burst@1.8.4\Editor\BurstAotCompiler.cs:1583
  at Unity.Burst.Editor.BurstAotCompiler+BclRunner.RunManagedProgram (System.String exe, System.String args, UnityEditor.Scripting.Compilers.CompilerOutputParserBase parser) [0x00001] in .\Library\PackageCache\com.unity.burst@1.8.4\Editor\BurstAotCompiler.cs:1558
  at Unity.Burst.Editor.BurstAotCompiler.OnPostBuildPlayerScriptDLLsImpl (Unity.Burst.Editor.BurstAotCompiler+BurstAOTSettings settings, UnityEditor.Compilation.Assembly[] playerAssemblies) [0x00a76] in .\Library\PackageCache\com.unity.burst@1.8.4\Editor\BurstAotCompiler.cs:706
  at Unity.Burst.Editor.BurstAOTCompilerPostprocessor.DoGenerate (UnityEditor.Compilation.Assembly[] assemblies) [0x0001b] in .\Library\PackageCache\com.unity.burst@1.8.4\Editor\BurstAotCompiler.cs:265
  at Unity.Burst.Editor.BurstAOTCompilerPostprocessor.GenerateNativePluginsForAssemblies (UnityEditor.Build.IGenerateNativePluginsForAssemblies+GenerateArgs args) [0x0008a] in .\Library\PackageCache\com.unity.burst@1.8.4\Editor\BurstAotCompiler.cs:179
  at UnityEditor.Modules.BeeBuildPostprocessor.GenerateNativePluginsForAssemblies (PlayerBuildProgramLibrary.Data.GenerateNativePluginsForAssembliesArgs args) [0x00050] in <582c35e8f45345d395e99f8e72e3c16d>:0
  at Bee.BeeDriver.BuildRequest+<>c__DisplayClass63_0`1[T].<RegisterRPCCallback>b__0 (System.Object o) [0x00000] in <cbc6cae0703746c08eee7f40dbc1e66c>:0
  at Bee.BeeDriver.BeeDriver_RunBackend+<>c__DisplayClass1_0.<ProcessRPCRequest>b__0 () [0x00021] in <cbc6cae0703746c08eee7f40dbc1e66c>:0
  at System.Threading.Tasks.Task.InnerInvoke () [0x0000f] in <6aa56e57ab504395b555cf3ed50fa53d>:0
  at System.Threading.Tasks.Task.Execute () [0x00000] in <6aa56e57ab504395b555cf3ed50fa53d>:0
--- End of stack trace from previous location where exception was thrown ---

  at Bee.BeeDriver.BeeDriver_RunBackend.ProcessRPCRequest (Bee.BinLog.RPCActionMessage msg, Bee.BeeDriver.BuildRequest+RPCCallback rpcCallback, IPCConnection ipcConnection, System.Threading.Tasks.Task writePipeConnectionTask, Bee.BeeDriver.InternalState state) [0x00111] in <cbc6cae0703746c08eee7f40dbc1e66c>:0
,
UnityEngine.GUIUtility:ProcessEvent (int,intptr,bool&)

```

I am also getting the error:

```
Library\Bee\artifacts\Android\AsyncPluginsFromLinker: Failed to find entry-points:
    UnityEngine.GUIUtility:ProcessEvent (int,intptr,bool&)

```

But am not sure if it is connected

# Answer
In the end, as DMGregory suggested, I did a complete uninstall and reinstall of Unity. Also, made sure to remove all previous versions in order to be 100% sure there was no residue.

I then reinstalled and it works perfectly.
> 0 votes

---
Tags: unity, android, burst
---


# Question
Title: How to keep an object that rotates around another at the same height when the radius changes?
In my game, I have one object that rotates around another using `transform.RotateAround`, and I need to change the radius of its orbit.

The behavior now is that the orbiting object moves to the larger radius, but it also changes its height.

Both when running this code the first time or when changing the radius value at runtime, I want it to move to the new radius like it does now, but also to keep the current height.

```
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class RotateAroundPoint : MonoBehaviour
{
    public Transform objectToRotateAround;
    public Vector3 axis;
    public float rotationSpeed;
    public float moveToRadiusSpeed;
    [SerializeField] private float radius;

    private float lastRadius;

    private void Start()
    {
        ApplyRadius();
    }

    private void Update()
    {
        if (!Mathf.Approximately(radius, lastRadius))
        {
            ApplyRadius();
        }

        transform.RotateAround(objectToRotateAround.position, axis, rotationSpeed * Time.deltaTime);
    }

    private void ApplyRadius()
    {
        Vector3 direction = (transform.position - objectToRotateAround.position).normalized;
        Vector3 targetPosition = objectToRotateAround.position + direction * radius;

        float step = moveToRadiusSpeed * Time.deltaTime;
        transform.position = Vector3.MoveTowards(transform.position, targetPosition, step);

        if (Mathf.Abs(radius - lastRadius) < 0.001f)
        {
            transform.position = targetPosition;
            lastRadius = radius;
        }
    }
}

```

I tried to change the code in the Update to this:

```
Vector3 direction = (transform.position - objectToRotateAround.position).normalized;

float currentDistance = Vector3.Distance(transform.position, objectToRotateAround.position);

float currentHeight = Mathf.Sqrt(Mathf.Pow(currentDistance, 2f) - Mathf.Pow(radius, 2f));

Vector3 newPosition = objectToRotateAround.position + direction * radius;

float step = moveToRadiusSpeed * Time.deltaTime;
transform.position = Vector3.MoveTowards(transform.position, newPosition + Vector3.up * currentHeight, step);

if (Mathf.Abs(radius - lastRadius) < 0.001f)
{
    transform.position = newPosition + Vector3.up * currentHeight;
    lastRadius = radius;
}

```

But this makes the orbiting object just to move up quickly and without stopping. It does rotate, but not around the target (`objectToRotateAround`).

# Answer
I would solve this by turning the one GameObject into two with a parent-child relationship.

1. Place the parent on the center of the orbit
2. Use the transform.rotation of the parent to control the direction where the child appears
3. Use the transform.localPosition of the child to control the radius/height.
4. Any renderers, colliders etc. would be on the child, of course.
> 1 votes

# Answer
You need to change your ApplyRadius method to change the offset only in this horizontal plane.

```
private void ApplyRadius()
{
    // Get offset between this object and its target.
    Vector3 offset = transform.position - objectToRotateAround.position;

    // Extract just the height, leaving the horizontal offset in the XZ plane.
    float height = offset.y;
    offset.y = 0f;

    // Use Pythagorean Theorem to get the adjacent side that,
    // combined with height as our opposite side,
    // makes our hypotenuse match the desired total radius.
    float horizontalRadius = Mathf.sqrt(radius * radius - height * height);

    // Construct our new offset and apply it.
    offset = offset.normalized * horizontalRadius;
    offset.y = height;

    Vector3 targetPosition = objectToRotateAround.position + offset;

    // ... the rest of your code

```

If your "height" can be non-vertical, you can do the same thing with an arbitrary axis like so (here I assume other code ensures `axis` is unit length, so we don't redundantly re-normalize it every frame)

```
private void ApplyRadius()
{
    // Get offset between this object and its target.
    Vector3 offset = transform.position - objectToRotateAround.position;

    // Extract component parallel to axis, leaving offset in rotation plane.
    float height = Vector3.Dot(offset, axis);
    offset -= axis * height;

    // Use Pythagorean Theorem to get the adjacent side that,
    // combined with height as our opposite side,
    // makes our hypotenuse match the desired total radius.
    float horizontalRadius = Mathf.sqrt(radius * radius - height * height);

    // Construct our new offset and apply it.
    offset = offset.normalized * horizontalRadius;
    offset += axis * height;

    Vector3 targetPosition = objectToRotateAround.position + offset;

    // ... the rest of your code

```

However, note that you can accumulate errors using `RotateAround`. Myself, I would implement this in a way where I calculate the position with a little trig, so I know I'll maintain my target orbit exactly.

```
[SerializeField] Transform objectToRotateAround;
[SerializeField] Vector3 axis;
[SerializeField] float targetRadius;
[SerializeField] float degreesPerSecond;
[SerializeField] float moveToRadiusSpeed;

float _angleRadians;
Quaternion _rotationSpace;

// Gets current displacement from the pivot object
// in a coordinate space where the rotation axis is +z.
Vector3 GetRotationSpaceOffset() {
    return Quaternion.Inverse(_rotationSpace)
           * (transform.position - objectToRotateAround.position);
}

// Update axis and angle on start-up / if axis is changed in Inspector.
void OnValidate() {
    _rotationSpace = Quaternion.LookRotation(axis);
    if (objectToRotateAround != null) {
        var offset = GetRotationSpaceOffset();
        angleRadians = Mathf.Atan2(offset.y, offset.x);
    }
}

void Start() {
    // Initialize rotation coordinate space and angle.
    OnValidate();
}

void Update() {
    // Get our offset from the pivot in a coordinate space where our
    // rotation axis is along the z+ direction.
    var offset = GetRotationSpaceOffset();

    // As before, extract the component parallel to the axis.
    float height = offset.z;
    offset.z = 0f;

    // Blend our current radius toward the target.
    float radius = Mathf.MoveTowards(offset.magnitude, targetRadius,
                                     moveToRadiusSpeed * Time.deltaTime);

    // Advance our angle, and keep it wrapped close to zero for best precision.
    _angleRadians += degreesPerSecond * Mathf.Deg2Rad * Time.deltaTime;
    _angleRadians = _angleRadians % (2 * Mathf.PI);

    // Construct a unit vector in our rotation plane at that angle.
    offset = new Vector3(Mathf.Cos(_angleRadians), Mathf.Sin(_angleRadians), 0);

    // Extend it to our desired orbit radius and offset parallel to the axis.
    offset *= radius;
    offset.z = height;

    // Map offset back to world space and apply it to get our new position.
    transform.position = objectToRotateAround.position + _rotationSpace * offset;
}

```
> 0 votes

---
Tags: unity, c#, rotation, transformation
---


# Question
Title: Why does volumetric fog require two checkboxes?
In the Unity High Definition Rendering Pipeline, when adding Volumetric Fog, there's a checkbox to enable the Volumetric Fog, and then there's an additional checkbox to the right of it that also has to be checked to enable it. Why is there the second checkbox? It feels a bit redundant.

Initially, I didn't have the second checkbox checked (indeed, I'm not certain it was initially visible), and the Volumetric fog simply did not work. I just ran into someone else who had the same problem.

# Answer
> 3 votes
I also posted this question on the official Unity forums, and received the following response:

> The left checkbox you are talking about is used for overriding any value from the default value. If that checkbox isn't ticked, that means you don't want to override it, and Unity will just use the values from the default Volume Profile Asset.
>
> In your case, it seems like Volumetric Fog is turned off in your default Volume Profile Asset. You then added an override volume, said "I want to override this" by ticking the left checkbox, and then overrode the default value by ticking Volumetric Fog on.
>
> In essence, the left checkbox is "I want to override this", and the checkbox to the right of that is what you want the override to be.
>
> You can see your default Volume Profile Asset settings in Edit -\> Project Settings -\> HDRP Global Settings.

---
Tags: unity, fog, hdrp, volumetric-light
---


# Question
Title: Intellisense broken after installing Unity VSCode extension
I didn't use VSCode since two weeks ago. Today, I opened my Unity Project. VSCode updated some extensions and unhappily, **Intellisense** doesn't work anymore. I didn't change VSCode settings — all configuration is the same as before. I don't know how to fix it. I noticed that the C# icon has changed too. An extension called Unity has been installed too.

I'm using VSCode 1.81 and Unity 2022.3

# Answer
> 1 votes
I recently updated my VSCode extensions too. Here's what I did to ultimately get intellisense working again - note that I haven't tested exhaustively to see if all steps are required or if some had nothing to do with fixing the problem.

1. **Remove old VSCode C# extensions**. I read that the old Omnisharp-based C# support is incompatible with the new C# Dev Kit versions based on Roslyn. I kept the following installed (all with the Microsoft developer checkmark):

* C# - Base language support for C# (ms-dotnettools.csharp)
    * C# Dev Kit - Official C# extension from Microsoft (ms-dotnettools.csdevkit)
    * Unity - Integrates Visual Studio Code with Unity (visualstudiotoolsforunity.vstuc)

I then closed VS Code for the next steps.
2. In Unity package manager, **ensure Visual Studio Editor package is installed and updated to the latest version** (2.0.20 at the time of writing).

Yes, that's the Visual Studio (not Code) package - according to the Unity VSCode extension docs, the new extension relies on this package, and the old "Visual Studio Code Editor" package is no longer maintained.
3. In Unity File -\> Preferences -\> External Tools, **set External Script Editor to Visual Studio Code** (version 1.81.0 at the time of writing). Note the "Visual Studio Editor v2.0.20 enabled" text below the drop-down.
4. Click the "**Regenerate project files**" button just below that section in the preferences dialog.
5. **Re-launch VSCode** by double-clicking on a C# script in the Unity Project tab.

Check the VSCode terminal pane - it does some initialization steps, including downloading the .NET runtime if your version doesn't match, and that can take some time. So your intellisense might not kick in until you see the confirmation that the projects have loaded successfully:

---
Tags: unity, c#, visual-studio-code, source-code
---


# Question
Title: Get selected string from TextMeshPro input field/text on Android
i am trying to create a tag system for a journal i'm making and that requires being able to select specific parts from either an input field or a text element with the finger (drag and select) and then save that selection into a list.

The issue is i don't know how to do it! i did some google research in terms of "saving selected text from input fields" and similar searches but i couldn't find something to help me out.

The flow should be : user types something like "hello world" , then he drags his finger on the screen highlighting the word "World" and once highlighted it is saved into an empty string which then i can add to the list i want.

Can i get some help or recommendations on what to read to make it happen? Thank you!

# Answer
> 0 votes
I have not worked with mobile yet. But you can find the selection something like:

```
int start = your_inputfield.selectionAnchorPosition;

int end~ = your_inputfield.selectionStringFocusPosition;

```

From there you would want a context popup or something with a button to save selection.

```
tmp_inputfield.selectionAnchorPosition {Get; Set;}

tmp_inputfield.selectionStringFocusPosition {Get; Set;}

```

The two properties of `tmp_inputfield` can be treated like variables if you are unfamiliar.

---
Tags: unity, android, text-mesh-pro
---


title: How to start particle from skybox

text:
# Question
Title: How to start particle from skybox
I'm trying to create a lightning particle system but I want to make the top of the particles at the skybox and the bottom on the ground.

**Is this possible?**

# Answer
No, this is not possible, because the skybox isn't an *actual* 3d box with well-defined vertex coordinates. Geometrically-speaking, its distance from the camera is undefined. If you wanted to place a 3d game object *on* the skybox, it would need to have an infinite distance from the camera.

All you can do is make the starting point of the lightning bolt high enough that the player can not tell the difference.
> 0 votes

---
Tags: unity, particles
---


# Question
Title: How to debug UnityGfxDeviceWorker (34): EXC_RESOURCE RESOURCE_TYPE_MEMORY error on an iOS device?
How does one debug this Xcode error on an iOS device?

`Debug - UnityGfxDeviceWorker (34): EXC_RESOURCE RESOURCE_TYPE_MEMORY`

# Answer
> 0 votes
Along with a plethora of other reasons, your computer has more memory at it's disposal compared to your phone/tablet so you're unlikely to experience "out of memory" errors. Because this error is happening an iOS device you'll want to use Xcode to further debug your situation. Specifically it sounds like you are dealing with a memory leak, which in your case is likely creating more game objects than you are removing `(GameObject.Destroy(myObject)`

Just like unity has profiling tools for itself, Xcode has profiling tools (instruments) for mac & iOS devices. I'm attaching a links for 1) how to find memory leaks using the Unity profiler and 2) how to find memory leaks using xcode

1. https://unity.com/how-to/use-memory-profiling-unity
2. https://developer.apple.com/library/archive/documentation/Performance/Conceptual/ManagingMemory/Articles/FindingLeaks.html

Keep in mind that a there is a lot of content & video covering memory leaks so if the links I posted seem tricky to follow you may have better luck searching the web & youtube.

Cheers~

---
Tags: unity, ios, mobile, memory, xcode
---


# Question
Title: Actual time-based plant growth even when game is off
I am developing a game in Unity, and I want a plant to grow based on actual time passed. Basically, if the player turns the game off and turns it back on one day after, the plant should be grown. I'm assuming I would have to somehow access the actual time and compare it. However I'm not sure how this data should be saved. How could I do this? I would appreciate a brief explanation on what function I could use. Thank you :)

# Answer
> 3 votes
All the different ways where and how to store savegame data in Unity are already covered well enough by many other questions on this website, so I won't get into that aspect. I will instead focus on how to update plant growth.

I assume that you currently have some Update method somewhere that looks something like this:

```
void Update() {
    // update plant growth
    growth += Time.deltaTime;
    // check if the plant reached the next growth stage
    while (growthLevel < maxGrowthLevel && growth > growthRequiredForNextLevel[growthLevel]( {
        growthLevel++;
        mySpriteRenderer.Sprite = SpriteForGrowthLevel[growthLevel]
    }
}

```

This growing mechanic would need to be refactored into a new method, so that it can process growth progress from any source, not just Time.deltaTime:

```
void Update() {
    CalculateGrowth(Time.deltaTime);
}

public void CalculateGrowth(float secondsPassed) {
    growth += secondsPassed;
    while (growthLevel < maxGrowthLevel && growth > growthRequiredForNextLevel[growthLevel]( {
        growthLevel++;
        mySpriteRenderer.Sprite = SpriteForGrowthLevel[growthLevel]
    }
}

```

Now this method can be called from your savegame loading method to process the time that has passed since the savegame was saved.

How do you find that out? Via the standard C# class `DateTime`. You can get the number of "Ticks" (ten millionth of seconds) that elapsed since the beginning of the century (according to the date and time of the users device) with `DateTime.Now.Ticks`. So you just need to store that number in the savegame. When you load the savegame, you again sample the current time by getting that number again and subtract the number from the savegame, using that to instantiate a `TimeSpan` object:

```
long savedTime = // get the number from the savegame data
long currentTime = DateTime.Now.Ticks;
TimeSpan elapsedSpan = new TimeSpan(currentTime - savedTime);

```

You can then use that TimeSpan object to calculate the number of seconds since the player saved the game, and feed that number to the `CalculateGrowth(float SecondsPassed)` method:

```
plant.CalculateGrowth((float)elapsedSpan.TotalSeconds):

```

# Answer
> 0 votes
Here's a way to estimate growth while the game is off:

* When the game is on, do things as normal.
* When the game is about to close, save the current time. You can do that by saving it in a file, or whichever else other way your project handles saved data.
* Next time the game is turned on, get current time, read the time the last time the game closed (by reading the file it was saved in) and compare them.
* Based on the result, apply the changes in your game that would have happened if the game was on the whole time, based on the above result.

This way you can give the illusion to the player that the game was on the whole time and the plant was growing while the player was away.

This has its drawbacks of course, the biggest one being the player could meddle with the system time and confuse the game. There are solutions to these, but once you have the above implementation working, it should be easy to update it to cover any undesired edge cases.

# Answer
> -1 votes
You could save the data on a server (using HTTP requests) when the user turns the game off, then the server calculates, and fetch the data when they turn it on again. Using a server is better than using a temporary game file since game files can be hacked/edited, server files not so easy.

---
Tags: unity, savegame
---


title: Scoring with 2 values

text:
# Question
Title: Scoring with 2 values
working with mobile sokoban-style puzzle where player scored with 2 values:

1. time (how many seconds is taken to clear level)
2. move (how many moves is taken to clear level)

**scoring with stars** is no problem i can evaluate this by:

```
var record := {"move": 10, "time": 5}
var move := 9
var time := 4
var star := 1

if time < record.time:
   star += 1  # beated record time
if move < record.move:
   star += 1  # beated record move

```

**scoring with points** are problem: how evaluate time and move variables to achieve fair scoring, where skilled player gets more points and unskilled player less points.

i could do this:

```
var move = 10.0 * 300  # multiplied with score per move
var time = 5.0 * 100   # multiplied with score per sec
var pnts = (move / time * 1000)  # 6000

```

but scoring points like this makes no sense, you can beat level with more **time** and **move** that records and get more points and 1 star (because you didn't beat records)

# Answer
Myself, I'd avoid non-linearity in the scoring system. It's hard for a player to do division in their head to understand how they got a particular score or predict how much finishing a little faster would change their score. Division also gives you a steep hyperbolic scoring curve with a long shallow tail, meaning you have to deal with a very wide range of scoring values, even though most scores from not-great to not-good will be very similar. That can be demotivating for a player who gets a meh score, sees astronomical scores in the leaderboard, but makes only modest gains when they re-try the challenge: it seems like they'll never get to those top scores.

Instead, I'd recommend keeping your scoring system linear. Add together a Move Bonus and a Time Bonus. Each one starts at a high value, and you subtract an increment from it for each move taken or each second elapsed. Something like...

```
moveBonus = max(1000 - 25 * movesTaken, 0)

timeBonus = max(1000 - 1 * secondsTaken, 0)

score = moveBonus + timeBonus

```

This keeps the scores bounded in a controllable range (here 0-2000), and the rate of score improvement is uniform over that whole range. So a player who shaves 1 move off their solution always gets 25 more points, whether it was their 30th move they eliminated or their 10th. A player who finishes 1 second faster always gets 1 more point. That makes it easy for players to understand, and anticipate how their score can improve, so they're more motivated to keep climbing up the high scores table.

It also makes it easy to reason about the relative value of different kinds of optimization. If shaving off a move earns 25 points and shaving off a second earns 1 point, then it's worth going up to 24 seconds out of your way if it saves you a move, or you'd have to be 26 seconds faster to be worth taking a 1-move-longer route that's easier to speedrun.

This does have a downside though: somewhere, that straight line linear falloff bottoms-out where it hits zero. With the numbers I've chosen above, that's at \\$\frac {1000} {25} = 40\\$ moves and \\$\frac {1000} {1 \cdot 60 \frac s {\text{min}}} = 16:40\\$ minutes. Players who take more moves or more time than this won't earn any bonus points, or see any benefit from improving their solutions by a small amount. To minimize the impact of this, you generally want to choose your max bonus and falloff increment so that this bottoming-out point sits beyond the first attempt results you see from most new players - so most people will only see a zero time bonus if they go AFK mid game or something.
> 1 votes

---
Tags: scoring
---


# Question
Title: How to make a sky with gradient color in OpenGL?
I'm making a game with OpenGL and would like to add dynamic sky colors with gradients. However, I don't know how to achieve this. Here's an example (in Minecraft) of what I would like to have:

>

In this screenshot, we can see the blue sky gets gradually more orange-ish the closer it is to the sun.

My first idea to achieve this was to use a skybox and calculate the color of each pixel according to its position relative to the sun/moon. But I don't have any clues on how I could do the math for this, and I don't think this is the most optimal way to achieve a sky gradient.

I searched for similar questions but found nothing helpful. All the results I got were about Atmospheric Scattering, which is not really what I want (if my understanding of AS is correct).

So here's my questions: How can I implement a dynamic sky with color gradients related to the sun and moon position in OpenGL, like in the screenshot above?

# Answer
You are going to need the (unit) direction vector for the point in the sky you need to shade.

Assuming the sky has no actual geometry, and it is supposed to have infinite size, then you get the direction from the camera and the fragment coordinates.

On the other hand, if the sky has actual geometry, position and size in the world, you can give it a texture that encodes the direction, so you can query it when shading.

---

Then, you need a (unit) direction vector for the pole of the gradient (e.g. the sun position), which I'm going to guess you can compute (e.g. form time of the day).

With those two vectors, you can get their dot product. The dot product of the vectors (assuming they are unit vectors) is the cosine of the angle between them. *If you rather with with angles, you can go ahead an compute the inverse of the cosine (`acos`).*

For dynamic orientation, it is a matter of updating the direction vector for the pole.

And for the color, you would take the angle (or dot product) as input for a function that picks the color.

And yes, you could have multiple poles, get the angle (or dot product) to their directions, and use them as arguments for the function that computes the color.

---

I guess from there it is optimization. For example, one idea is to use a 1D texture to lookup the angle instead of doing `acos`... In fact, if you are going to have 1D texture to lookup with the dot product, you might instead have a 1D texture with to lookup the colors directly, and that way you don't need a function for that either.

And, if you need extra arguments you could make it a 2D texture, or even a 3D texture (where the components to query the texture in the extra dimensions are your extra arguments).
> 1 votes

# Answer
The Skydome enables you to create the gradient effect and you can combine it with a texture. The Skydome is created using half of a sphere which is placed at the location of the camera so that the viewer is always in the center of it. The sphere itself can be created programmatically or offline using a tool like Blender. If the radius of the sphere is 1 you can simply forward the local space Y coordinate to the fragment shader and use it to interpolate between two color and achieve the gradient effect. I've recently published a video about this technique: https://youtu.be/I0jI\_d1jORc.
> 1 votes

---
Tags: opengl, sky
---


# Question
Title: How to make enemy turn to face the player while attacking?
I need help making this code work. It is made for the enemy AI to move and patrol, chase the player and attack the player.

The problem is when it starts to attack the player, then the player can move around the enemy and the enemy will not turn to face the player but just keeps attacking in front of him.

```
using System.Collections;
using System.Collections.Generic;
using UnityEditor.Experimental.GraphView;
using UnityEngine;
using UnityEngine.AI;
using UnityEngine.EventSystems;

public class EnemyAI : MonoBehaviour
{
    public float minRandomDistance = 5.0f;
    public float maxRandomDistance = 10.0f;
    public float patrolSpeed = 2.0f;
    public float chaseSpeed = 5.0f;
    public float chaseRange = 10.0f;
    public float attackRange = 1f;
    public float rotationSpeed = 2f;
    public Transform player;

    private Animator animator;
    private NavMeshAgent navAgent;
    private Vector3 randomDestination;
    private bool isChasing = false;
    private bool isAttacking = false;
    private string[] attackAnimation = { "isAttacking1", "isAttacking2" };

    private void Start()
    {
        navAgent = GetComponent<NavMeshAgent>();
        animator = GetComponent<Animator>();
        SetRandomDestination();
    }

    private void Update()
    {
        if (isChasing)
        {
            ChasePlayer();
        }
        else
        {
            Patrol();
        }
        FaceMovementDirection();
    }

    private void Patrol()
    {
        if (!navAgent.pathPending && navAgent.remainingDistance < 0.5f)
        {
            SetRandomDestination();
        }

        // Check if the player is within chase range
        if (Vector3.Distance(transform.position, player.position) < chaseRange)
        {
            isChasing = true;
            navAgent.speed = chaseSpeed;
            animator.SetBool("isRunning", true);
        }
        else
        {
            isChasing = false;
            navAgent.speed = patrolSpeed;
            animator.SetBool("isRunning", false);
        }

        if (Vector3.Distance(transform.position, player.position) < attackRange)
        {
            isAttacking = true;
            navAgent.isStopped = true;

        }
        else
        {
            isAttacking = false;
            navAgent.isStopped = false;
        }
        foreach (string attackParam in attackAnimation)
        {
            animator.SetBool(attackParam, isAttacking);
        }
    }

    private void ChasePlayer()
    {
        // Move towards the player's position
        navAgent.SetDestination(player.position);

        // Check if the player is out of chase range
        if (Vector3.Distance(transform.position, player.position) > chaseRange)
        {
            isChasing = false;
            navAgent.speed = patrolSpeed;
            animator.SetBool("isRunning", false);
        }
        if (Vector3.Distance(transform.position, player.position) < attackRange)
        {
            isAttacking = true;
            navAgent.isStopped = true;

            // Rotate to face the player's position
            Vector3 directionToPlayer = player.position - transform.position;
            directionToPlayer.y = 0;

            Quaternion targetRotation = Quaternion.LookRotation(directionToPlayer);
            transform.rotation = Quaternion.RotateTowards(transform.rotation, targetRotation, Time.deltaTime * rotationSpeed);

            foreach (string attackParam in attackAnimation)
            {
                animator.SetBool(attackParam, isAttacking);
            }
        }
        else
        {
            isAttacking = false;
            navAgent.isStopped = false;
        }
        foreach (string attackParam in attackAnimation)
        {
            animator.SetBool(attackParam, isAttacking);
        }

    }

    private void SetRandomDestination()
    {
        // Generate a random direction and distance within the specified range
        Vector3 randomDirection = Random.insideUnitSphere;
        randomDirection.y = 0; // Keep the movement on the same plane
        Vector3 targetPosition = transform.position + randomDirection.normalized * Random.Range(minRandomDistance, maxRandomDistance);

        // Set the NavMeshAgent's destination
        navAgent.SetDestination(targetPosition);
    }
    private void FaceMovementDirection()
    {
        Vector3 moveDirection = navAgent.velocity.normalized;

        if (moveDirection.magnitude > 0.1f)
        {
            Quaternion targetRotation = Quaternion.LookRotation(-moveDirection);
            transform.rotation = Quaternion.RotateTowards(transform.rotation, targetRotation, Time.deltaTime * 500.0f);
        }

    }

}

```

# Answer
> 0 votes
You already have code in the `ChasePlayer()` function that looks fine:

```
Quaternion targetRotation = Quaternion.LookRotation(directionToPlayer);
transform.rotation = Quaternion.RotateTowards(transform.rotation, targetRotation, Time.deltaTime * rotationSpeed);

```

I tested your script in Unity, and it works - it's just *very slow*. The problem is that you set the default `rotationSpeed` to 2. That's 2 *degrees per second*. There are 360 degrees in a circle, so at that speed it would take the enemy 180 seconds (3 full *minutes*) to turn in a full circle. Try using a much larger `rotationSpeed` like 90 or 180.

There's another problem too: `FaceMovementDirection()` makes the enemy look *away* from the direction it's moving:

```
 Quaternion targetRotation = Quaternion.LookRotation(-moveDirection);

```

Notice the negative before `moveDirection`? If this looks correct in the game, that means your character model is backwards. The code in `ChasePlayer()` that rotates the enemy to face the player makes the enemy look towards the player instead of away from the player. So currently, your enemies will walk backwards towards the player and then turn around to face the player.

---
Tags: unity, c#, rotation, movement, ai
---


title: Interacting with World Space UI

text:
# Question
Title: Interacting with World Space UI
Been struggling with this one for a while. I've found a few other posts across Stack Exchange and the Unity forums that seem to have the same problem, but their solutions don't work for me (at least as far as I can tell).

I have a World Space canvas in my scene with a load of buttons as its children. Each button has an onClick function assigned.

Here are the settings for one of the buttons:

And here are the settings for the canvas itself:

I also have an Event System with a Standalone Input Module with these settings:

By all accounts I've seen, this should be everything I need to interact with the buttons through the player camera. But when I look at the buttons, they don't change to the highlighted color, and pressing Mouse 0 (or Enter) doesn't click them.

(EDIT: Per DMGregory's comment, this is in a first-person view with an no visible cursor, and the reticle/center of the screen should behave like a cursor)

I feel like I'm missing something really obvious, but the documentation for this feature is so lacking I have no idea what it might be.

# Answer
I think there should be a neater way to do this, but here's what I have working so far (based on a more involved example with curved UI here)....

We'll remove the usual `StandaloneInputModule`, which uses the mouse as the cursor position, and replace it with our own version that always treats the mouse as being in the center of the screen - at the reticle.

```
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.EventSystems;

public class FPSInputModule : StandaloneInputModule {
    protected override MouseState GetMousePointerEventData(int id = 0)
    {
        var reticlePosition = new Vector2(Screen.width/2, Screen.height/2);

        MouseState mouseState = new MouseState();

        PointerEventData leftData;
        var created = GetPointerData(kMouseLeftId, out leftData, true);

        leftData.Reset();

        leftData.delta = reticlePosition - leftData.position;
        leftData.position = reticlePosition;
        leftData.scrollDelta = Input.mouseScrollDelta;
        leftData.button = PointerEventData.InputButton.Left;
        eventSystem.RaycastAll(leftData, m_RaycastResultCache);
        var raycast = FindFirstRaycast(m_RaycastResultCache);
        leftData.pointerCurrentRaycast = raycast;
        m_RaycastResultCache.Clear();

        // copy the apropriate data into right and middle slots
        PointerEventData rightData;
        GetPointerData(kMouseRightId, out rightData, true);
        CopyFromTo(leftData, rightData);
        rightData.button = PointerEventData.InputButton.Right;

        PointerEventData middleData;
        GetPointerData(kMouseMiddleId, out middleData, true);
        CopyFromTo(leftData, middleData);
        middleData.button = PointerEventData.InputButton.Middle;

        mouseState.SetButtonState(PointerEventData.InputButton.Left, StateForMouseButton(0), leftData);
        mouseState.SetButtonState(PointerEventData.InputButton.Right, StateForMouseButton(1), rightData);
        mouseState.SetButtonState(PointerEventData.InputButton.Middle, StateForMouseButton(2), middleData);

        return mouseState;
    }
}

```

This correctly handles clicking, but it's currently not working for hover. I think it's because as the camera rotates to bring the cursor over a new point in space, the cursor's positional delta is still zero - it's still in the center of the screen - so the event system doesn't realize it needs to re-evaluate the hover states of UI elements.
> 0 votes

# Answer
I've struggled with this too. I found a kind of roundabout way to make it work, though.

So, the camera interacting with the canvas presumes it's overlaid the camera. None of the functionality works for world-space canvases. The documentation is lacking because they presume you want your UI elements to work directly on your camera with your cursor, not using your mouse position in the world, via your first-person camera

You need some sort of script to actually get that functionality back.

```
public GraphicRaycaster raycaster;
PointerEventData pointerData;
EventSystem eventSystem;

void Start()
{
    raycaster = GetComponent<GraphicRaycaster>();
    eventSystem = GetComponent<EventSystem>();
}

void Update()
{
    pointerData = new PointerEventData(eventSystem);
    pointerData.position = Input.mousePosition;
    //Create a list of Raycast Results
    List<RaycastResult> results = new List<RaycastResult>();

    //Raycast using the Graphics Raycaster and mouse click position
    raycaster.Raycast(pointerData, results);

    foreach (RaycastResult result in results)
       {
          Debug.Log("Hit " + result.gameObject.name);
       }

}

```

So basically you need to track pointer event data, and then theoretically what's here SHOULD let you tell you if you're hovering over a thing. You can swap that out by making the button change color on hit, by getting the buttons and then making them do what you want.

Then you can add (Input.GetMouseButtonDown(0)) and functionality after the fact to have them do things.

DMGregory's has the same basic idea but I think it's a bit more convoluted, depending on what exactly you're trying to accomplish
> 0 votes

---
Tags: unity, gui, unity-ui
---


title: Make night sky with moon

text:
# Question
Title: Make night sky with moon
I want to make skybox with moon (texture 2d) with shader graph and be able to modify moon radius.

Moon Texture 2d :

# Answer
Here's a shader that does this (click for a larger version so you can read the text):

And the result in a Unity scene:

The strategy is similar to my previous answer with the cubemap. We'll use the object space view vector (the vector pointing from the fragment being shaded back at the camera, in the object's local space) to make it easy to control the positioning and twist of the moon image: you can rotate the skybox itself. The moon will get drawn wherever the object's local z+ axis (blue arrow on the local translation gizmo) points, extended to infinity. You can use a world space view vector to sample the starfield if you want to angle the two independently.

We use the X and Y components of the view vector as texture coordinates to look up into our moon texture. First, dividing them by our desired moon radius (so at the desired radius, the length of the XY vector becomes 1), then multiplying them by a half and adding a half to bring them into the 0-1 texture coordinate range. I also negate them in this step, because otherwise we'd draw the moon rotated 180 degrees.

I also put a conditional branch in here so we only sample the moon texture when it will contribute to the image, and skip that work for the majority of the sky.
> 0 votes

---
Tags: unity, unity-shader-graph
---


# Question
Title: Skybox looks distorted when camera nears sides of the cube
I created a cubemap for skybox, but there were problems with displaying UV for it. when I appear in the world, everything looks fine as it should, BUT when I approach one of the sides of the cube, its UV begins to shrink down.

```
// Matrix for skybox( SkyMatrix in hlsl )
DirectX::XMMATRIX m;
m = DirectX::XMMatrixTranslation( -g_playerOrigin.x, -g_playerOrigin.y, -g_playerOrigin.z );

```

Vertex shader hlsl:

```
SkyPixel_t main(SkyVertex_t vs)
{
    SkyPixel_t ps;
    ps.position = mul(MVP, vs.position);
    ps.TexCoord = mul(SkyMatrix, vs.position).xyz;
    return ps;
}

```

Pixel shader hlsl

```
float4 main(SkyPixel_t ps) : SV_TARGET
{
    float4 finalColor = SkyTexture.Sample(SkySampler, ps.TexCoord);
    return finalColor;
}

```

You can see in the screenshot that the right side of the cliff is going down. And if I start walking backwards, everything goes back to normal.

**Who knows what my mistake is?**

**EDIT***

// Initialize

```
void InitSkyBox( )
{
    // Make cubemap texture from 6 textures
    m_pTexture = MakeSkyBox( "skyBox" );

    // Sampler state
    skyState = CreateSamplerState( D3D11_FILTER_MIN_MAG_MIP_LINEAR, D3D11_TEXTURE_ADDRESS_CLAMP, 0, 0, 1 );
}

```

// Render

```
void RenderSky( )
{
    if( sky_surfaces )
    {
        // Set sky shader
        auto shaders = g_pShaderSystem->GetShader( "BaseSkyShader" );
        if( !shaders )
            return;

        g_pRender->GetDeviceContext( )->VSSetShader( shaders->pVertexShader, 0, 0 );
        g_pRender->GetDeviceContext( )->PSSetShader( shaders->pPixelShader, 0, 0 );
        g_pRender->GetDeviceContext( )->IASetInputLayout( shaders->pInputLayout );
        g_pRender->GetDeviceContext( )->PSSetShaderResources( 0, 1, &m_pTexture );
        g_pRender->GetDeviceContext( )->PSSetSamplers( 0, 1, &skyState );

        // update constant buffer
        DirectX::XMMATRIX m;

        // Set translation for SkyMatrix ( this translation apply on UV )
        m = DirectX::XMMatrixTranslation( -g_playerOrigin[ 0 ], -g_playerOrigin[ 1 ], -g_playerOrigin[ 2 ] );

        SkyConstantBuffer cb;
        cb.sky = m;
        g_pRender->GetDeviceContext( )->UpdateSubresource( m_pContantBuffer, 0, nullptr, &cb, 0, 0 );

        // Insert in slot 1 because in slot 0 MVP matrix
        g_pRender->GetDeviceContext( )->VSSetConstantBuffers( 1, 1, &m_pContantBuffer );

        RenderSky( sky_surfaces );
    }

```

# Answer
> 0 votes
I have found a solution to my question. My camera has 'viewheight' variable which is 32 in the normal state. So, if you add this 'viewheight' to the Z component when creating the matrix, has such artifacts will disappear. By the way, when the player sit down the 'viewheight' becomes 16, and this also works.

Most likely this is hack and I'm still studying this issue in more detail

```
g_playerOrigin.z += g_movement.viewHeight;
m = DirectX::XMMatrixTranslation( -g_playerOrigin[ 0 ], -g_playerOrigin[ 1 ], -g_playerOrigin[ 2 ] );
...

```

# Answer
> 0 votes
You should never be *able* to approach the edge of a skybox, because you always render the skybox as though it's centered at the camera / infinitely far away.

The easiest way to do that, if your skybox model is a full cube centered at the origin, is to zero-out the vertex position's `w` component when multiplying by the view matrix (and model matrix, if necessary). This blocks any translation due to object positioning or camera movement from taking effect, so the object always gets rendered as though it's centered on the camera (but rotation can still take effect).

```
SkyPixel_t main(SkyVertex_t vs)
{
    SkyPixel_t ps;
    float4 viewspace = mul(MV, float4(vs.position.xyz, 0) );
    viewspace.w = 1;
    ps.position = mul(Projection, viewspace);
    ps.TexCoord = vs.position.xyz;
    return ps;
}

```

It's been a while since I tinkered with DirectX projection matrices directly, but I think they might need the `w=1`, which is why I've done the transformation in two steps above - stripping out the `w` for the model and view matrices and putting it back for the final operation. I'm not 100% sure that's required though - test and confirm!

Note that once you've done this, you don't need your math modifying the UV coordinates based on view position. You can let your UV coordinates just take the object space positions unchanged and save yourself a uniform and a matrix multiply.

You can also adjust the z position here to ensure it's always drawn flat along your far plane, and never clips out of view or occludes nearer geometry. If I recall correctly, the way to do that is to set `ps.position.z = ps.position.w`, so that after the perspective divide, this comes out as 1 = "at far plane", unless you're using a reversed depth buffer.

---
Tags: c++, 3d, directx11, uv-mapping, skybox
---


# Question
Title: _ready(): Node not found: "Pivot/Camera" + player falls through the floor
I'm relatively new to Godot 4.0.3. I have two problems which seem to depend on each other so I put both of them into one single question.

I know, these issues have been reported multiple times on other forums, but none of their solutions worked for me and when I try to fix one of them the other one occurs again or gives errors.

**My first problem (`_ready(): Node not found: "Pivot/Camera"`):**

my full script:

```
extends CharacterBody3D

@onready var camera = $Pivot/Camera

var gravity = -30
var max_speed = 8
var mouse_sensitivity = 0.002  # radians/pixel

#var velocity = Vector3()

func get_input():
    var input_dir = Vector3()
    # desired move in camera direction
    if Input.is_action_pressed("ui_up"):
        input_dir += -global_transform.basis.z
    if Input.is_action_pressed("ui_down"):
        input_dir += global_transform.basis.z
    if Input.is_action_pressed("ui_left"):
        input_dir += -global_transform.basis.x
    if Input.is_action_pressed("ui_right"):
        input_dir += global_transform.basis.x
    input_dir = input_dir.normalized()
    return input_dir

func _unhandled_input(event):
    if event is InputEventMouseMotion and Input.get_mouse_mode() == Input.MOUSE_MODE_CAPTURED:
        rotate_y(-event.relative.x * mouse_sensitivity)
        $Pivot.rotate_x(-event.relative.y * mouse_sensitivity)
        $Pivot.rotation.x = clamp($Pivot.rotation.x, -1.2, 1.2)

func _physics_process(delta):
    velocity.y += gravity * delta
    var desired_velocity = get_input() * max_speed

    velocity.x = desired_velocity.x
    velocity.z = desired_velocity.z
    move_and_slide()

```

Error:

```
E 0:00:00:0961   main.gd:3 @ _ready(): Node not found: "Pivot/Camera" (relative to "/root/Root/Player").
  <C++ Error>    Method/function failed. Returning: nullptr
  <C++ Source>   scene/main/node.cpp:1364 @ get_node()
  <Stack Trace>  main.gd:3 @ _ready()

```

(I got the code from https://kidscancode.org/godot\_recipes/3.x/g101/3d/101\_3d\_07/index.html and edited it to hopefully fix some errors)

What I've tried:

Removing the `@` on `@onready` (I've seen `onready` without the `@` on other forums too):

```
Error at (3, 1): Unexpected "Identifier" in class body.

```

Removing the entire `@onready`:

```
Parser Error: The default value is using "$" which won't return nodes in the scene tree before "_ready()" is called. Use the "@onready" annotation to solve this. (Warning treated as error.)

```

**My second problem (player falls through floor):**

I have a `MeshInstance` (the floor mesh) inside a `CollisionShape3D`, and also the player has two `CollisionShape3D`s, but none of the colliders actually work.

I tried changing the last lines of my code (see first problem) to this:

```
func _physics_process(delta):
    velocity.y += gravity * delta
    var desired_velocity = get_input() * max_speed

    velocity.x = desired_velocity.x
    velocity.z = desired_velocity.z
    velocity = move_and_slide(velocity, Vector3.UP)

```

But then it crashes:

```
Too many arguments for move_and_slide() call. Expected at most 0 but received 2.

```

When I change the `@onready` to `onready`, it works, but I will get an error:

```
Error at (3, 1): Unexpected "Identifier" in class body.

```

My node structure is like this:

```
Root (Node3D)
  Collider (CollisionShape3D)
    Terrain (MeshInstance3D)
  Player (CharacterBody3D)
    Body (CollisionShape3D)
    Feet (CollisionShape3D)
    Pivot (Node3D)
      Camera (Camera3D)
  Light (DirectionalLight3D)

```

(The `Root/Player/Pivot` node is a `Node3D` since I don't know how to create a `Spatial`)

What am I doing wrong and how can I fix these issues?

# Answer
> 7 votes
---

## On picking your tutorials

You seem to have been mixing Godot 3 and Godot 4 tutorials. So be careful which one the tutorial is for. *Chances are that tutorials prior to Godot 4 don't specify.*

*At the time of writing, in the kidscancode.org website you can tell by the 3.x or 4.x banner on the top right. Also, at the time of writing, the Godot 4 tutorials might be missing parts.*

In this case, the following is Godot 3:

* `onready` is a keyword.
* The 3D `Node` class is called `Spatial`.
* The characters in 3D are made with `KinematicBody`.
* `move_and_slide` returns a velocity, and takes a velocity as first parameter among other things. So code looks like this:

```
velocity = move_and_slide(velocity, Vector3.UP)

```

And these are Godot 4:

* `@onready` is an annotation.
* The 3D `Node` class is called `Node3D`.
* The characters in 3D are made with `CharacterBody3D`.
* `move_and_slide` takes no parameter, returns if there was a collision (`bool`) and works with the properties of the `CharacterBody3D` (such as `velocity` and `up_direction`). So code looks like this:

```
move_and_slide()

```

*Since you are working on Godot 4, the rest of this answer will be only about Godot 4 (although similar concepts apply in Godot 3, the class names are differences).*

---

## On the floor collider

The floor problem is the easier to address, although it begets some explanation.

First of all, `CollisionShape3D` do nothing on their own. They work as children of a `CollisionObject3D`.

So you need a `CollisionObject3D`, of which there are a few: `Area3D`, `CharacterBody3D`, `RigidBody3D`, `StaticBody3D`. IN THIS CASE, you are making a floor, so I would guess you would want an `StaticBody3D`.

*In other context you would need a different kind of `CollisionObject3D` depending on what you are doing. I cover that with a bit more depth elsewhere.*

---

Thus, modify your scene tree from this:

```
Root (Node3D)
  Collider (CollisionShape3D)
    Terrain (MeshInstance3D)

```

To this:

```
Root (Node3D)
  Floor (StaticBody3D)
    Collider (CollisionShape3D)
      Terrain (MeshInstance3D)

```

In fact, I would make the `MeshInstance3D` a sibling:

```
Root (Node3D)
  Floor (StaticBody3D)
    Collider (CollisionShape3D)
    Terrain (MeshInstance3D)

```

*Pick names that make sense to you, of course.*

---

## On the node not found

I don't know what is the issue with the following line:

```
@onready var camera = $Pivot/Camera

```

It looks correct to me, assuming it is in the `CharacterBody3D` in this configuration on the scene tree:

```
  Player (CharacterBody3D)
    Pivot (Node3D)
      Camera (Camera3D)

```

Which seems to be the case given the information in the question.

As for making the line work, the best I can suggest is to double check the names, and that you are not getting other errors on the script.

However, **I do not see where you are using `camera` on your script, so you might be able to just remove the line.**

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


title: glm::frustum vs glm::perspectiveFov

text:
# Question
Title: glm::frustum vs glm::perspectiveFov
When I use `glm::perspectiveFov(90.0f,512.0f,512.0f,1.0f,256.0f)` I receive a working perspective projection with 90° in both x and y, as seen below (camera is in center of cube, facing towards a side)

However, when I use `glm::frustum(-256.0f,256.0f,-256.0f,256.0f,1.0f,256.0f)` I receive something that is either scaled beyond recognition or some kind of 180° view?

I would expect atleast a square projection.
What am I missing or doing wrong?

```
auto projection = glm::perspectiveFov(to_rad(90.0f), float(cube_resolution), float(cube_resolution), 1.0f/1024.0f, 256.0f);
//projection = glm::frustum(-float(cube_resolution),float(cube_resolution),-float(cube_resolution),float(cube_resolution),1/1024.0f,256.0f);
auto view_projection = projection * view;

```

# Answer
> 1 votes
When you use `perspectiveFov`, the angle of spread in the vertical direction is set by the `fov` parameter, and the horizontal angle is related to it by the width and height parameters:

```
fov_horizontal_radians = 2 * atan(tan(fov_vertical_radians/2) * width / height)

```

(Docs aren't as explicit as I'd like about whether that vertical `fov` parameter is the full bottom-to-top angle, or half that - the center-to-top angle. I've seen APIs use both these conventions. I wrote the above assuming it's the full bottom-to-top angle, but if I got that wrong, you can delete the two 2s to get the correct formula for the half angle version)

You can see here that all that matters is the aspect radio of width:height - their absolute magnitudes don't affect the shape of the frustum, since that's fixed by our `fov` angle.

`frustum` is different. Because we don't specify any angles in that form, we need to work out the shape of the frustum from the `left`/`right`/`top`/`bottom` values - and that means their absolute magnitudes matter, not only their ratios. In this case, these are taken to be coordinates on the near clipping plane, which in your case is a distance of 1 from the camera. So the closer the near clipping plane, the wider the frustum spreads.

If `near = 1`, `left = -256`, and `right = 256`, then our total horizontal field of view is...

```
fov_left  = atan(-left/near);                  // 1.567 rad =  89.776°
fov_right = atan(right/near);                  // 1.567 rad =  89.776°
fov_horizontal_radians = fov_left + fov_right; // 3.134 rad = 179.552°

```

So that's why you're getting something more like a 180 degree field of view with your `frustum` code.

To get just a 90 degree field of view, scale down your arguments to the size of the near clipping plane at the narrow end of the frustum, eg.

```
glm::frustum(-near,near,-near,near,near,256.0f)

```

That means to reach the top edge of the near plane, we go `near` units along the view direction and `near` units up (rise = run means this is 45°). To reach the bottom edge of the near plane, we do the same but down instead, so that's another 45°. Adding those up, that's a 90° field of view vertically, and the same argument goes for the horizontal axis.

---
Tags: 3d, projection, glm, projection-matrix
---


# Question
Title: Can I add texture transparency and still use alpha clip in shader graph?
I have this simple shader that will "fade out" and object using alpha clip, for this to work the alpha has to be set to 0.5.

I want to add a texture to this shader but I cannot figure out how to add transparent texture and still keep my other function of fading out using alpha clip.

Can this be done?

# Answer
> 1 votes
Here's a shader graph that combines these effects:

(Don't mind the banding in the animation above - that's just an artifact of saving it as an animated gif, and is not visible when the effect is rendered live)

The idea is that we'll keep our Alpha Clip Threshold low - at zero - so it only clips away completely transparent pixels.

Then we'll mix our smoothly varying translucent texture alpha with a 0/1 threshold signal coming from our dissolve effect. Wherever the dissolve zeroes-out the texture alpha, the pixel will be clipped, while preserving the entire (0, 1\] range above that for translucent blending as normal.

You can adjust the threshold used for dissolving using "Edge" the input to the Step function, so it can be controlled independently from the Alpha Clip Threshold applied to the resulting alpha.

---
Tags: unity, shaders
---


# Question
Title: How to apply sampler2Darray textures to different locations of a single mesh?
In openGL, I have a 3D terrain composed of a grid of 255x255 vertices. The vertex of the lower left corner is at coordinates (-127;-127) and the one of the upper right corner is at coordinates (127;127). All the other points (vertices) are distributed evenly between these 2 points to form a square and regular grid.

I gathered in a sampler2Darray several textures (aerial photos, all having a resolution of 1024x1024) that I would like to display at different places of the mesh according to precise coordinates (i.e. 30.25; 23.37). The rest of the mesh (the one not covered in textures) would use a solid color (i.e. green).

I have 2 questions:

* Is using a sampler2Darray the right thing to do?
* How to pass the coordinates of each sampler2Darray texture and retrieve them in the fragment shader?

# Answer
I might solve this with an index texture, similar to this tilemap approach I presented earlier.

Set aside an extra texture that covers your whole terrain with a resolution of about 1 texel per aerial photo width - so it's very low res compared to the photos themselves.

For each of these index texels that overlaps a photo location, choose the closest photo, and encode the UV coordinates of its center point in the red and green components of the index texel, and the photo's array index in the blue component.

The center point can be stored as an offset from this texel's location, in units where 1.0 = 1 photo width, so even at 1 byte per channel, you can finely position photos within a precision of 1/256th of their width (4 pixels at 1024 resolution). You can bump up to larger texel formats for even higher precision if needed. You can use a special value like (1, 1, 1) to indicate "no photo nearby".

When drawing the terrain, sample the four closest texels in the index texture, with sample filtering set to point/nearest so they don't blend together. From this, you get the coordinates and array indices of the 4 closest aerial photos. Select the closest one to sample, or fall back on your default colour if none of them are close enough to overlap this fragment.

The advantage of this approach over sending coordinates as uniforms is that it scales up to large numbers of photos well: the work per fragment remains constant at 4 taps from the index texture and at most 1 tap from the photo array, and you don't have to iterate over a list of all photos.

The advantage of this approach over encoding the information in vertex attributes is that you can transition between photos in the middle of a polygon, rather than being restricted to the resolution of the mesh subdivision.
> 1 votes

---
Tags: opengl, textures, tiles, opengl-es, fragment-shader
---


# Question
Title: How can I set up a 3D camera for a top-down game like Enter the Gungeon?
DodgeRollGames, the developers of Enter the Gungeon, tweeted that the game was in fact made in 3D

They tried to explain how they set their camera in this reddit post. Basically what they said was :

> so the walls are tilted 45 degrees toward the camera, and the floors are tilted 45 degrees away from the camera, meaning that each should experience sqrt(2) distortion because of the additional length along the z-axis. However, the vertical (y-axis) floor length shouldn't be perceptually changed.
>
> The camera is not tilted at all.
>
> Camera: 0 degree tilt.
>
> Walls: +45 degrees tilt.
>
> Floor: -45 degrees tilt.

My question is : What do they mean by "However, the vertical (y-axis) floor length shouldn't be perceptually changed". If I tilt the walls and floors by 45 degrees and -45 degrees as said, the sqrt(2) distorted walls (the walls have Z depth and are perpendicular to the ground) line up nicely, but the ground gets distorted (obviously). So I distort the ground tiles by sqrt(2) but this essentially stretches the ground by 40% so every vertical movement now has to be increased by 40%.

Can somebody explain what's going on? Any help would be highly appreciated.

# Answer
I'd say it's easier to keep all your content arranged orthogonally, tilt the camera 45°, and then just correct for the foreshortening in your camera projection. Here's an example (using Kenney's Tiny Dungeon tileset):

You can see all the floor/roof tiles are sitting flat in the horizontal (XZ) plane, and the walls/characters are standing straight upright in the XY plane. The camera looks down on them at a 45° angle, so normally it would see them foreshortened.

To counter this, we slap this little script on the camera:

```
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

[ExecuteInEditMode]
[RequireComponent(typeof(Camera))]
public class AntiForeshorten : MonoBehaviour
{
    [SerializeField, HideInInspector]
    Camera _camera;

    void OnValidate() {
        TryGetComponent(out _camera);
    }

    // Technically this only needs to happen once at start-up,
    // or when the window is being resized, but it's cheap
    // enough to do every frame in the absence of a built-in
    // OnProjectionChanged event.
    void LateUpdate() {
        // Get the default projection matrix for this camera.
        _camera.ResetProjectionMatrix();
        var mat = _camera.projectionMatrix;

        // Scale the vertical axis by 1/sin(angle).
        mat[1, 1] *= Mathf.Sqrt(2);

        // Use our modified matrix.
        _camera.projectionMatrix = mat;
    }
}

```

This applies the correction factor on the GPU during rendering, so we don't need to complicate any of our level layout or gameplay scripts with correction factors. The projection matrix is already used during rendering anyway, so we have not added any extra cost to the rendering pipeline - just the miniscule cost to update the matrix once per frame (which you can even eliminate if you're on a platform without a resizable window, like mobile or console)

Now 1 unit along the X axis, 1 unit along the Y axis, and 1 unit along the Z axis are all the same on-screen distance for that oblique top-down look, and none of the angles, scales, or movement speeds in your game world need to be fudged to fit. Positioning objects remains easy: want to place a crate two tiles ahead of the player? That's just `z = player_z + 2` \- no need to break out the trigonometry or nested coordinate spaces.
> 1 votes

# Answer
I'm missing a bit on how player movement works, but this image further down the reddit thread clarifies the setup a lot for me. When they say that the floor is tilted 45 degrees away from the camera, that's referring to the floor plane of the entire world, not individual tiles or sections.

Now as for the stretching issue, the easiest way to understand might be to look at this for yourself in Unity. Set up a test scene with a plane perpendicular to an orthographic camera, and some textured cubes for walls. As you rotate the camera, the walls will become distorted. You need to figure out how to un-distort them. They appear shorter so you need to stretch the height. sqrt(2) is the amount referenced because that's the length of the diagonal (i.e. 45 degrees) of a 1x1 square. So a wall at 0 or 90 degrees in relation to the camera would be our reference point for the wall's size, in other words `wallsize * 1`. Stretching the height of the quad by `1.4142...` should therefore appear to be the correct height.

Here's a horrible paint illustration if that isn't clear:

The part I'm unclear on is exactly how the player moves, but they could just be moving in local space relative to the floor plane, or they could be doing the math manually, or something else.

You should also note that as they said, they started developing the game when Unity's 2D tools were just getting started (over five years ago now), so there may be much easier ways to achieve the same effects now, depending on exactly what you're trying to replicate.
> 0 votes

---
Tags: unity, 2d, 3d, camera, sprites
---


# Question
Title: Camera Calibration custom Model-View-Projection matrix in Unity?
Coming from this topic

I have a Model-View-Projection Matrix obtained from a Camera Calibration method, from where I want to render the scene:

```
-4.7415   -2.3964   -2.4075  253.0431
-2.7923    6.1067    6.1569  143.6573
 0.0000    0.0000    1.0000    1.0000
 0.0061   -0.0094    0.0145    1.0000

```

As far as I saw, all documentation shows methods to load ModelView and load Projection independently. I was hoping to find something like:

```
GL.PushMatrix();
GL.MultMatrix(theMVPMatrix);

-> draw/load all the scene

GL.PopMatrix();

```

All examples I found show this would run OnPostRender(), but assuming there is a camera, at this point the camera has already rasterized the image. I guess?

*edited to make my steps clearer:*

Starting a new unity scene. A camera calibration algorithm returns me a matrix \\$C\\$ such:

```
 0.00166351   -0.00917993    0.0216692   0.885074
 -0.0120409     0.0087226    0.0119709   0.464458
-1.5839E-05  -1.43059E-05  1.55468E-05  0.0013842

```

I add a new camera object to the unity scene and name it "projector".

After decomposing \\$C\\$ into \\$R\\$, \\$K\\$ and |T| I can apply rotation and transformation on newly added unity camera, and also extract the projection to apply on the same camera, following this and this steps.

\\$R\\$

```
 0.703018  -0.00551996  0.711151
-0.38204    0.8405      0.384195
-0.599843  -0.541784    0.588778

```

\\$K\\$

```
 629.808  -0.986886   633.74
  0        626.035    361.485
  0          0        1

```

applying position and rotation from R and |T|

```
projector.transform.position = new Vector3(-30.2851,-30.2294, 30.3633);
projector.transform.rotation = Quaternion.Euler(new Vector3(33.126,-45.329,-0.45));
//Ground truth camera position: 30,30,-30 ; rotation: 33,-45,0

```

ProjMat:

```
0.98408 0.00154 0.00978 0.00000
0.0     1.73899 0.00413 0.00000
0.0     0.0     1.001   0.10005
0.0     0.0     -1.0    0.00000

```

I apply this projection matrix to the unity as suggest:

```
Projector.projectionMatrix = ProjMat;

```

Although not constant for each calibration matrix, so far I obtain projector(pink) and ground\_truth(green) cameras almost matching.

```
// Undo view matrix 'V'
var antiView = Projector.transform.localToWorldMatrix;

// Undo model matrix 'M' (assuming this object is not batched).
var antiModel = transform.localToWorldMatrix;

//the moment I enable the line below, my "projector" camera frustum collapses into a line and points somewhere away from the projection center (orange) and values go strange.

Projector.projectionMatrix = ProjMat * antiModel * antiView;

```

edit2: Added the comparison between Unity and Processing screens while adjusting the calibration points. I am still aiming to obtain a stable matrix transformation, as seen in the Processing window.

# Answer
The simplest way to do this is probably to override the camera's projection matrix (see another recent answer), since that will automatically work with any shaders you're already using. You can have a function like this...

```
public static OverrideProjection(Camera camera, Matrix4x4 newProjection) {
    camera.projectionMatrix = newProjection;
}

```

This replaces the default projection matrix for your camera, `P`, with your new matrix, `N`. So the MVP matrix you render with changes from `P * V * M` to `N * V * M`.

But even though this is stacked on the end, you can override the `M` and `V` matrices too if you need, something like so:

```
// Invoked on a MonoBehaviour just before the object gets rendered.
void OnWillRenderObject() {
    // Capture the camera currently being used for rendering.
    var camera = Camera.current;

    // Undo view matrix 'V'
    var antiView = camera.transform.localToWorldMatrix;

    // Undo model matrix 'M' (assuming this object is not batched).
    var antiModel = transform.localToWorldMatrix;

    camera.projectionMatrix = newMatrix * antiModel * antiView;
}

```

When this is combined with the other matrices in the rendering pipeline, you get...

$$N M^{-1} V^{-1} V M = N M^{-1} M = N$$

So we cancel out the built-in matrices in the pipeline and substitute our own.

If you do this, I'd recommend still trying to position the camera and objects used for rendering reasonably close to their effective arrangement after your matrix substitution. The reason for this is that culling and level of detail are performed based on how objects sit inside the unmodified camera frustum - that system doesn't see your custom matrix, so it might conclude an object is out of view and skip rendering it, even if your custom matrix would have brought it into view.

---

Another way you can approach this is to write your own shaders for the objects you're rendering, and just directly replace the vertex transformation.

If you make a new unlit shader, you'll see some code like this:

```
sampler2D _MainTex;
float4 _MainTex_ST;

v2f vert (appdata v)
{
    v2f o;
    o.vertex = UnityObjectToClipPos(v.vertex);
    o.uv = TRANSFORM_TEX(v.uv, _MainTex);
    UNITY_TRANSFER_FOG(o,o.vertex);
    return o;
}

```

That `UnityObjectToClipPos()` is basically a macro that maps to `mul(UNITY_MATRIX_MVP, v.vertex)` (plus some adjustment for stereoscopic rendering when you're using it). We can replace it with our own custom matrix:

```
sampler2D _MainTex;
float4 _MainTex_ST;
float4x4 _CustomMatrix;

v2f vert (appdata v)
{
    v2f o;
    o.vertex = mul(_CustomMatrix, v.vertex);
    o.uv = TRANSFORM_TEX(v.uv, _MainTex);
    UNITY_TRANSFER_FOG(o,o.vertex);
    return o;
}

```

You can assign a value to this `_CustomMatrix` uniform with either `Material.SetMatrix()`, if you want it to affect just one material/object, or `Shader.SetGlobalMatrix()`, if you want to set the matrix once and use the same version across all materials.

You can also chain it with any of Unity's built-in matrices, if you don't want to completely replace the model or view matrices.
> 1 votes

---
Tags: unity, rendering, camera, projection
---


# Question
Title: My Update method is shown as unused, yet I'm coding within it
I'm doing a game lesson to get basic player movement working using Unity "Lesson 2.1: Player Positioning". I started with creating the public variables and getting the axis and the horizontal movement. The issue started with the if statement. The main idea is to use the if statement to keep the player inbounds and prevent the player from going off the side of the screen with an if-then statement. But it is not working at all; it just goes right and disappears all around the map. I've compared my script with theirs, and it's the same.

```
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class PlayerController : MonoBehaviour
{
 public float horizontalInput;
 public float speed = 10.0f;

 // Update is called once per frame
 void Update()
 {
     if (transform.position.x < -10)
     {
         transform.position = new Vector3(-10,
         transform.position.y,
        transform.position.z);
     }
     horizontalInput = Input.GetAxis("Horizontal");
     transform.Translate(speed * Time.deltaTime * Vector3.right);
  }
 }

```

# Answer
Your code is not the same as in the tutorial. Step 4 in the tutorial uses `horizontalInput` in the `Translate`. If you don't use the input of your player, of course your character is not reacting to what you tell it to do. Your line 18 should be

```
transform.Translate(speed * horizontalInput * Time.deltaTime * Vector3.right);

```

Unused code or variables should be colored gray, not a darker shade of pink. Update() is always called, as long as it is named Update() and your class is a MonoBehaviour.
> 0 votes

---
Tags: unity, c#
---


# Question
Title: What is the name for the types of assets used in games like "Brotato"?
What type of assets are used in games like "Brotato"?

Brotato steam page

Video of gameplay

Would these be called vector graphics or are they just really smooth looking sprites? I'm interested in any search terms I could use to learn more about this type of art and how it is made. Thanks for any advice.

# Answer
> 2 votes
Vector graphics are not a type of art style. Vector graphics just means it can be scalabled with no loss of quality.

The art style looks similar to that of Binding of Isaac (Edmund McMillen), but in the end, it is some kind of pixel graphic. Search terms like `hd smooth pixel grafic` will turn up sprites in a similar kind. You can always add more descriptors like `hd dark rpg smooth pixel grafic` to get more specific results.

As for how they are made? Either you hire an artist (and give some example arts for the style you want), search an asset store or go to the drawing board yourself.

Creating art is a skill for itself. You can always start with some simple pixel art (search for a tutorial on the video platform of your choice) and improve from there with training. There is not really a shortcut for making great looking art besides practise and even more practise.

---
Tags: sprites, vector-art
---