Search Unity

  1. If you have experience with import & exporting custom (.unitypackage) packages, please help complete a survey (open until May 15, 2024).
    Dismiss Notice
  2. Unity 6 Preview is now available. To find out what's new, have a look at our Unity 6 Preview blog post.
    Dismiss Notice

light and dynamic shadows with meshes for 2d game?

Discussion in 'Scripting' started by ivkoni, Jun 18, 2009.

  1. ivkoni

    ivkoni

    Joined:
    Jan 26, 2009
    Posts:
    978
    Hi,

    how would I go about implementing a light as in the image below:


    I need the light to produce real time shadows and herein lies the problem.

    I tried modelling the light as a mesh by doing raycasting to find the vertices, this worked but it is too expensive and I can't use it.
    My other idea is to model the shadows as meshes, and then project on them the backgound texture. I think this would work efficiently but the algorithm I have in mind is not trivial and before I implement it I would like to hear your suggestions.

    I have only unity basic, so it turns out I don't have real time shadows. Anyway, I would imagine spot lights with shadows are quite expensive and would be unusable for my case.

    any ideas are welcome.

    thanks a lot
     
  2. Dreamora

    Dreamora

    Joined:
    Apr 5, 2008
    Posts:
    26,601
    realtime shadows won't create the effect you are seeing there.

    What you will need is a fully custom solution that creates this umbras
    I recommend to check out this article: http://www.gamedev.net/reference/articles/article2032.asp

    In unity the gl stuff would be replaced by corresponding mesh data.
     
  3. ivkoni

    ivkoni

    Joined:
    Jan 26, 2009
    Posts:
    978
    thanks a lot,

    I had read this article and this is the approach I was planning to implement. I was curious if there was another way of doing it (maybe simpler). At least I won't wonder if this is indeed the right method here.

    thanks again.
     
  4. God-at-play

    God-at-play

    Joined:
    Nov 3, 2006
    Posts:
    330
    Another possibility would be to create a plane, aligned with the scene and cutting through the geometry, that has a slight rotation to it so it gets lit.

    Then create a shader that only renders lighting full white with both the plane and the scene geometry set to full black. Render-to-texture the result and add it on top.

    I don't have Pro yet, so no shadows, but I've attached an example screenshot.
     

    Attached Files:

  5. ivkoni

    ivkoni

    Joined:
    Jan 26, 2009
    Posts:
    978
    Thanks for the suggestion!

    I tried this too and found out that I don't have real time shadows. I also tried with a projector instead of a spot light, but of course there were no shadows.
    I am going to go with the mesh approach. It will require some math, but if I get it working this would be the best solution here...
     
  6. God-at-play

    God-at-play

    Joined:
    Nov 3, 2006
    Posts:
    330
    No problem.

    Post your results here, I'd love to see it. :)
     
  7. ivkoni

    ivkoni

    Joined:
    Jan 26, 2009
    Posts:
    978
    here you go. I couldn't use it in my case, but might be a good starting point for somebody else:

    quick demo:
    drag the "point light" or the box.
    http://www.ivkoni.net/shadow2D.html


    Code (csharp):
    1.  
    2. // this script will only work for a limited number of convex objects in 2D. You would need to have
    3. // an empty game object at each corner of the mesh that moves with the mesh.
    4. // attach this script to an empty game object that has mesh filter and mesh renderer components
    5.  
    6.  
    7. var pointLight : Transform;  // assign your point light to this variable
    8. var cornerPoint : Transform[];  // assign the mesh corners here in anticlockwise order
    9. var shadowLength : float;  // this is how far back we will project the shadow
    10. var shadowColor : Color;
    11.  
    12.  
    13.  
    14. private var vectorToLight1 : Vector3 = Vector3.zero;
    15. private var vectorToLight2 : Vector3 = Vector3.zero;
    16. private var edge1 : Vector3;
    17. private var edge2 : Vector3;
    18. private var edge1Normal : Vector2;
    19. private var edge2Normal: Vector2;
    20.  
    21. private var cutOffPoint = new Vector3[4];
    22. private var pointIndex :int = 0;
    23.  
    24. function LateUpdate () {
    25. pointIndex = 0;
    26.         for (i =0; i < cornerPoint.length; i++) {
    27.             edge1 = cornerPoint[(i+1)%cornerPoint.length].position - cornerPoint[i].position;
    28.             edge1Normal = Vector2(-edge1.y,edge1.x);
    29.             vectorToLight1 = cornerPoint[(i+1)%cornerPoint.length].position - pointLight.position;
    30.             edge2 = cornerPoint[(i+2)%cornerPoint.length].position - cornerPoint[(i+1)%cornerPoint.length].position;
    31.             edge2Normal = Vector2(-edge2.y,edge2.x);
    32.             vectorToLight2 = cornerPoint[(i+2)%cornerPoint.length].position - pointLight.position;
    33.             if(Vector2.Dot(edge1Normal,vectorToLight1)*Vector2.Dot(edge2Normal,vectorToLight2)<=0) {
    34.             if(pointIndex<4){
    35.             cutOffPoint[pointIndex] = cornerPoint[(i+1)%cornerPoint.length].position;
    36.             pointIndex++;
    37.             cutOffPoint[pointIndex] = (vectorToLight1)*shadowLength + pointLight.position;
    38.             pointIndex++;
    39.             }
    40.             }
    41.         }
    42.            
    43.         buildMesh();
    44.        
    45.     }
    46.  
    47. function buildMesh(){
    48. var mesh : Mesh = GetComponent(MeshFilter).mesh;
    49.     mesh.Clear();
    50.     var vertices = new Vector3[4];
    51.     var colors = new Color[4];
    52.     var uv = new Vector2[4];
    53.     var normals = new Vector3[4];
    54.     var triangles = new int[6];
    55.    
    56.     var localSpaceTransform = transform.worldToLocalMatrix;
    57.    
    58.     for(i =0; i<4; i++){
    59.         vertices[i] = localSpaceTransform.MultiplyPoint(cutOffPoint[i]);
    60.         colors[i] = shadowColor;
    61.         uv[i] = Vector2(0,0);
    62.         normals[i] = Vector3.forward;
    63.     }
    64.    
    65.     triangles[0] = 0;
    66.     triangles[1] = 1;
    67.     triangles[2] = 2;
    68.     triangles[3] = 2;
    69.     triangles[4] = 1;
    70.     triangles[5] = 3;
    71.    
    72.     mesh.vertices = vertices;
    73.     mesh.colors = colors;
    74.     mesh.uv = uv;
    75.     mesh.normals = normals;
    76.     mesh.triangles = triangles;
    77. }
    78.  
     

    Attached Files:

  8. ivkoni

    ivkoni

    Joined:
    Jan 26, 2009
    Posts:
    978
    forgot to mention, but if your shadow caster doesn't rotate, then you can precompute the edges' normals and only take the dot product of the vector to the point light and the normals in the update()
     
  9. God-at-play

    God-at-play

    Joined:
    Nov 3, 2006
    Posts:
    330
    Very cool. 8)

    It's exciting to think about using that in a game. What kind of object limitations have you run into? Any specific count that limits its usage?
     
  10. ivkoni

    ivkoni

    Joined:
    Jan 26, 2009
    Posts:
    978
    I haven't really tested it since it doesn't suit my immediate needs. Here are the most glaring limitations:
    1. Each shadow is a separate draw call.
    2. The object needs to be convex (some special cases with non convex objects will also work)
    3. You need to position separate empty game object for each corner of the shadow caster, so that the algorithm can compute the shadow boundary.
    4. Smooth spherical objects won't work very well. You would have to approximate the curves by positioning empty game objects along them. (spheres can be handled nicely as a special case)


    I think it's fairly light, but if there are a few lights in the scene with a few real time shadow casting objects, it will of course start to slow down.
     
  11. Jesper

    Jesper

    Joined:
    Feb 12, 2011
    Posts:
    85
    Hi Ivkoni. Ive been looking for a way to do this effect and now I've found it.very cool. :)
    One question.
    Im doing a top down game and I've been tweeking on your code, but i cannot get it to work correctly when the player object moves in x,z

    Know this is an ooooold post but i thought ill give it a try.
     
  12. Marrt

    Marrt

    Joined:
    Feb 7, 2012
    Posts:
    613
    I am also trying to get this effect, i am about to do a geometric approach:
    http://forum.unity3d.com/threads/165283-2D-Dynamic-Shadows?p=1138484#post1138484

    if i don't succeed you could combine my already finished polygon extraction with ivkoni's shadow mesh generation. Then you won't need transforms in every corner just to get the positions (makes this approach more appealing), just a mesh that has a flat bottom.