<p>If it’s on the wrong side of the normal, you don’t have to throw it away—negating it will give you a vector that’s in the visible hemisphere.</p>
<p>Answering your comment, to get a vector that’s within some angle θ of the normal, this should work (GLSL):</p>
<pre><code>vec3 direction(vec3 normal, vec2 randomValues, float maxTheta) {
    // pick an orthogonal tangent vector using the method described here: http://lolengine.net/blog/2013/09/21/picking-orthogonal-vector-combing-coconuts
    vec3 tangent = (normal.x &gt; normal.z) ? vec3(-normal.y, normal.x, 0.0) : vec3(0.0, -normal.z, normal.y);
    // and a bitangent vector orthogonal to both
    vec3 bitangent = cross(normal, tangent);

    float phi = 2.0 * PI * randomValues.x;
    float theta = randomValues.y * maxTheta;
    float sinTheta = sin(theta);
    return tangent * cos(phi) * sinTheta + bitangent * sin(phi) * sinTheta + normal * cos(theta);
}
</code></pre>

CC BY-SA 4.0
2021-02-02T21:06:03.633Z
Thanks. I think that's a super simply and effective way of doing what I explained. However, what if the goal is to generate random direction vectors that are within `θ` degrees of the `Normal`?
Amir
CC BY-SA 4.0
2021-02-02T21:38:20.203Z
Added a way to do that to the answer.
Noah Witherspoon
CC BY-SA 4.0
2021-02-02T20:57:33.453Z
2021-02-02T21:37:58.557Z
2021-02-02T21:37:58.557Z
Noah Witherspoon
<p>Given a surface <code>Normal</code> vector of an intersection point, how can one generate a random direction vector that is guaranteed to be in the visible hemisphere? The way I am currently doing this is to sample a random direction vector <code>d</code> and <code>dot</code> it with the <code>Normal</code> and keep that vector if the <code>dot</code> product is greater than 0. This method is not guaranteed to generate a vector in the visible hemisphere of BRDF as ~50% of the random vectors would have a <code>0</code> or negative <code>dot</code> product result.</p>
<p>I saw somewhere that there is a way to transform the randomly generated vector <code>d</code> to place it in the visible hemisphere using a transformation matrix but I don't know how to do it. Can someone write a [pseudo]code for how one generate a direction vector using the transformation method?</p>

<rendering><transformations><pathtracing><brdf><pbr>
Path tracing: How to ensure we are sampling a direction vector within the visible hemisphere of a surface?
Amir
# Path tracing: How to ensure we are sampling a direction vector within the visible hemisphere of a surface?

(Asked by: username_0 on 2021-02-02)

Given a surface `Normal` vector of an intersection point, how can one generate a random direction vector that is guaranteed to be in the visible hemisphere? The way I am currently doing this is to sample a random direction vector `d` and `dot` it with the `Normal` and keep that vector if the `dot` product is greater than 0. This method is not guaranteed to generate a vector in the visible hemisphere of BRDF as ~50% of the random vectors would have a `0` or negative `dot` product result.

I saw somewhere that there is a way to transform the randomly generated vector `d` to place it in the visible hemisphere using a transformation matrix but I don't know how to do it. Can someone write a [pseudo]code for how one generate a direction vector using the transformation method?

**Tags:** rendering, transformations, pathtracing, brdf, pbr


---

## 1 answers

### Answer by username_1 on 2021-02-02. Score: 2 | Accepted answer

If it’s on the wrong side of the normal, you don’t have to throw it away—negating it will give you a vector that’s in the visible hemisphere.

Answering your comment, to get a vector that’s within some angle θ of the normal, this should work (GLSL):

```
vec3 direction(vec3 normal, vec2 randomValues, float maxTheta) {
    // pick an orthogonal tangent vector using the method described here: http://lolengine.net/blog/2013/09/21/picking-orthogonal-vector-combing-coconuts
    vec3 tangent = (normal.x > normal.z) ? vec3(-normal.y, normal.x, 0.0) : vec3(0.0, -normal.z, normal.y);
    // and a bitangent vector orthogonal to both
    vec3 bitangent = cross(normal, tangent);

    float phi = 2.0 * PI * randomValues.x;
    float theta = randomValues.y * maxTheta;
    float sinTheta = sin(theta);
    return tangent * cos(phi) * sinTheta + bitangent * sin(phi) * sinTheta + normal * cos(theta);
}

```

> **Comments:**
> **username_0**: Thanks. I think that's a super simply and effective way of doing what I explained. However, what if the goal is to generate random direction vectors that are within `θ` degrees of the `Normal`?  
> **username_1**: Added a way to do that to the answer.  

---

