Search Unity

Transformed vertex?

Discussion in 'Shaders' started by Omar Rojo, May 4, 2007.

  1. Omar Rojo

    Omar Rojo

    Joined:
    Jan 4, 2007
    Posts:
    494
    I want to create a shader where the object is painted with a texture from top to bottom where the topmost vertex has the v component to 0 and the bottommost vertex has the v component to 1 (A Sphere).

    If i move it (B sphere) there is no problem, and if i rotate it (C sphere) there is also no problem. But when it came to an scale (D sphere), the texture starts to wrap.

    My knowledge tells me that the vertex i am receiving in the vertex program is transformed only by the scale, but not the rotation or the translate, is that true? How can i get the vertex pure from the model in Object Space so if I ensure the object is within the box of -1 to 1 in every axis, the texture will show as i expect ?

    Omar Rojo
     

    Attached Files:

  2. Aras

    Aras

    Unity Technologies

    Joined:
    Nov 7, 2005
    Posts:
    4,770
    Generally you can't. Vertices that come into the vertex program are already scaled.

    What you could do though is: not scale the vertices in Unity, instead expose some sort of "scale" property in the shader/material, and do the scaling in the vertex program.

    But the easiest way I think is just to UV map the object. In case of a builtin sphere, it is already UV mapped, so you can just grab the existing texture coordinate. That is the reason why UV mapping was invented, you know - to tell how the texture wraps around the object.
     
  3. Omar Rojo

    Omar Rojo

    Joined:
    Jan 4, 2007
    Posts:
    494
    Yeah sure, pretty easy, but what about if i want to morph the object ? I still think it's easy to implement a shader instead of mapping the UV in this case.

    Can you tell me why they are scaled already ? is that logical ? i mean, the object space is the object with it's initial properties and the scale is part of the model matrix, as well as his rotation and translation, right ?

    I will try that property scale though.

    PD: Don't be mean, im just learning :D

    Omar Rojo
     
  4. Aras

    Aras

    Unity Technologies

    Joined:
    Nov 7, 2005
    Posts:
    4,770
    The decision to pre-scale meshes is a tradeoff decision:

    Just letting the hardware scale the meshes is the "cleanest" solution, but in case of the programmable shaders it would require either 1) multiple shader versions for the cases where meshes are non-scaled, uniformly scaled, arbitrarily scaled or 2) a single shader that always normalizes transformed normals. The first approach is the optimal, but makes everyone create 3 times more vertex shaders. The second approach is simple, but suboptimal in performance (especially when you run on cards like Intel GMA950).

    So what Unity currently does (that of course could change in the future), is silently instantiate scale meshes on the CPU. This solves the "multiple shaders" issue. And it's pretty fast if you don't change scale at run time. Of course can be a bit slow if someone is constantly changing the scale of the objects, but that is a pretty uncommon scenario.
     
  5. Omar Rojo

    Omar Rojo

    Joined:
    Jan 4, 2007
    Posts:
    494
    Thank you very much for the explanation. Sorry for bother you that much.

    So, i should post this on a wish list ? an idea i have in mind right now is to provide a shader with the current scale of the object, or the inverse scale on a float3 that if applied give the original vertex, so the programmer can arbitrarily multiply the vertex input with the inverseScale to get the original one in the shader and keep the optimization on the scale thing without change, in case of the shaders that depends on the bounding box of the object.

    Thanks again.

    Omar Rojo
     
  6. Aras

    Aras

    Unity Technologies

    Joined:
    Nov 7, 2005
    Posts:
    4,770
    Yeah, just passing inverse scale as a shader parameter looks like the easiest solution. I'm not sure if that's worth putting as a built-in functionality though.

    Just add such a script to our object (untested):
    Code (csharp):
    1. void Update()
    2. {
    3.     var scale = transform.lossyScale;
    4.     renderer.material.SetVector( "_Scale",
    5.         Vector4(1.0/scale.x,1.0/scale.y,1.0/scale.z,1.0) );
    6. }
    And in the shader declare the variable inside Cg code:
    Code (csharp):
    1. uniform float4 _Scale;
    and you're ready to go.
     
  7. Omar Rojo

    Omar Rojo

    Joined:
    Jan 4, 2007
    Posts:
    494
    Works.

    But i have to mention that having a built-in variable in the shader will make the shader independent of the script :D :D :D :D

    Well, end of transmission here.

    Thanks!

    Omar Rojo