2
\$\begingroup\$

In a shader, I would like to know for a given projected 2D pixel if the related 3D point is visible by camera (not especially the main camera, the projection and view matrix are provided to the shader as parameters).

By visible, I mean I can shoot a ray from that 3D point to the camera position without hitting any object.

The result should be similar to the camera being a light source and test would fail where there is shadows.

I think one possible solution would be to first render scene from camera view into a texture (eg : render texture) and then use than information later in the shader for the main rendering.


EDIT : I forget to mention what I want in the end is Projective texture mapping. I have tried to implement what Stormwind describe (I did not used a Surf but a render texture) It almost works, however shadows are not aligned correctly (like they are moved by a given offset).

Here is the shader that I wrote :

float4x4 _CameraMatrix;
sampler2D _MainTex;
sampler2D _DepthTex;

v2f vert (appdata_base v)
{
    v2f o;
    o.pos = mul(UNITY_MATRIX_MVP, v.vertex);
    float4 cameraPos = mul(mul(_CameraMatrix, UNITY_MATRIX_M), v.vertex); 
    o.scrPos = ComputeScreenPos(cameraPos);
    return o;
}

half4 frag (v2f i) : COLOR
{   
    float4 cameraPos = i.scrPos; 
    cameraPos /= cameraPos.w;

    if(cameraPos.x > 0.0f && cameraPos.x < 1.0f
    && cameraPos.y > 0.0f && cameraPos.y < 1.0f)
    {
        float depth = tex2D(_DepthTex, float2(cameraPos.x,cameraPos.y)).r;
        float cameraDepth = cameraPos.z;

        if(depth > cameraDepth)
        {
            return tex2D(_MainTex, cameraPos);
        }
        else
        {
            return float4(0.0f ,0.0f ,0.0f ,1.0f);
        }
    }
    else
    {
        return float4(0.0f ,0.0f ,0.0f ,1.0f);
    }
}
\$\endgroup\$
4
  • \$\begingroup\$ You seem to have described shadow mapping. That is indeed a good way to determine whether a given 3D point is visible from some other perspective/vantage. Have you had any trouble implementing this using shadow mapping techniques? \$\endgroup\$
    – DMGregory
    Commented Apr 17, 2017 at 4:51
  • \$\begingroup\$ Shadow mapping is the term I was looking for. Do you have any link or resource to know how to implement my own ? Or can I use Unity built in shadows feature to do that ? \$\endgroup\$
    – tigrou
    Commented Apr 17, 2017 at 11:24
  • \$\begingroup\$ The web is downright packed with shadow mapping guides & examples, so I'd recommend just Googling it for starters. If you have any trouble implementing it, edit your question to narrow in on the specific aspect you need help with. \$\endgroup\$
    – DMGregory
    Commented Apr 17, 2017 at 11:27
  • \$\begingroup\$ Try including an image of your symptoms in the question itself. You'll find very few users want to download and run a whole Unity project just to see what you're asking about. \$\endgroup\$
    – DMGregory
    Commented Apr 17, 2017 at 18:52

1 Answer 1

2
\$\begingroup\$

You could use the same technique as for Shadow Mapping

  1. Have a float32 render surface (Surf) of suitable size (eg. 512x512). The surface must be depth-enabled.
  2. Let the 3D point (P) be represented by a mesh with at least one triangle, sufficiently big to occupy at least a pixel on Surf.
  3. With Surf's camera (Cam), render the mesh, ie. render a distance (a "depth") between Cam and P to Surf. Also render other objects of interest, that may hide P. Use a common depth shader for all rendering (ie. only write and care about the depth). Use Zenable and ZWriteEnable = 1.
  4. Pass Cam's WVP matrix (WVP1) to this, current (main render?) shader (Shader2).
  5. In Shader2, using WVP1 resolve the "hit point pixel" for P on Surf (Shader2 needs to know P:s world position). Then A) read that pixel value and B) "manually" calculate the distance between Cam and P (Shader2 needs to know Cam's world position too). Compare these two values, if they are practically equal, P is visible.

Note 1: One must use suitable tolerances and sizes because of numeric accuracy and surface resolution.

Note 2: From a vertex shader, output.Position is in range -1...1 (bottom -> top and left -> right), ie. mul(position, wvp) will be in that range. To then do a texture lookup with that info, one must convert it into texture coordinate addressing, ie. 0...1 (top -> bottom and left -> right) range.

\$\endgroup\$
3
  • \$\begingroup\$ Hello. Thanks for your help. I have edited OP, can you take a look at it ? \$\endgroup\$
    – tigrou
    Commented Apr 17, 2017 at 18:33
  • \$\begingroup\$ Hey. Sorry, not a Unity user. But maybe check the -1...1 vs. 1...0 range dilemma in Note 2 above? tex2D() only takes 0...1 as meaningful coordinate space. \$\endgroup\$
    – Stormwind
    Commented Apr 17, 2017 at 19:46
  • \$\begingroup\$ You are probably right. I tried what is suggested here : gamedev.stackexchange.com/questions/96335/… (notice the -1..1 1..0 range correction) and it works. However i don't understand why matrix projection is done inside the pixel shader and not the vertex shader. \$\endgroup\$
    – tigrou
    Commented Apr 17, 2017 at 22:25

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .