简体   繁体   English

Unity Shader Graph中的Worldspace 2d纹理置换

[英]Worldspace 2d texture displacemet in Unity Shader Graph

I am working on a 2d top-down game.我正在开发一个 2d 自上而下的游戏。 I have an object that moves on a single large texture and casts shadow on it (just a blurry dark sprite).我有一个 object 在单个大纹理上移动并在其上投射阴影(只是一个模糊的暗精灵)。 However I found out that since my texture has bumps, rocks, creases etc. it looks like the shadow sprite just hovers above the ground.然而我发现,由于我的纹理有凹凸、岩石、折痕等,看起来影子精灵只是在地面上方盘旋。 So I figured out that I could use my texture as a displacement map to distort the shadow sprite depending on the surface of the texture.所以我想我可以使用我的纹理作为位移 map 来根据纹理的表面扭曲阴影精灵。 I'm trying to implement that in Shader Graph but I can't manage to get proper position and scale of the underlying texture to project the shadow on.我正在尝试在 Shader Graph 中实现它,但我无法获得正确的 position 和底层纹理的比例以投射阴影。
I tried to implement a simplified version of the shader that precisely reproduces the part of the Ground Texture that it hovers above.我试图实现一个简化版本的着色器,它可以精确地再现它悬停在上面的Ground Texture部分。

在此处输入图像描述

In this case scaling seems to be off, the resulting texture is a lot smaller than the original one.在这种情况下,缩放似乎关闭了,生成的纹理比原始纹理小很多。 I'm not sure about the position but it seems to be off as well.我不确定 position 但它似乎也关闭了。 Am I missing out something?我错过了什么吗? Or is there an easier appreach to implement this?还是有更简单的方法来实现这一点?

Thanks in advance.提前致谢。

I'm not sure whether it is the most elegant solution but I found one.我不确定这是否是最优雅的解决方案,但我找到了一个。

I should have used Tiling and Offset node to scale and shift the UV of the ground texture.我应该使用Tiling and Offset节点来缩放和移动地面纹理的 UV。 Here's the shader graph:这是着色器图:

在此处输入图像描述

Right now this shader makes the object project the part of the ground texture it is placed on onto itself.现在,此着色器使 object 将放置在其上的地面纹理部分投影到自身上。 It seems to be perfectly aligned with the texture.它似乎与纹理完美对齐。

Ground position is calculated in code:接地 position 在代码中计算:

[RequireComponent(typeof(SpriteRenderer))]
public class displaced_shadow : MonoBehaviour
{
    SpriteRenderer sr;
    Rect rect;
    MaterialPropertyBlock material_properties;
    float pixels_per_unit;

    public Vector2 Size //get size of the texture in Unity units
    {
        get { return new Vector2(rect.width * transform.localScale.x/ pixels_per_unit, rect.height * transform.localScale.y/ pixels_per_unit); } 
    }

    private void Awake()
    {
        sr = GetComponent<SpriteRenderer>();
        rect = sr.sprite.rect;
        pixels_per_unit = sr.sprite.pixelsPerUnit;
        material_properties = new MaterialPropertyBlock();
    }

    // Update is called once per frame
    void Update()
    {
        Vector2 relative_position = CalculateRelativePostion();
        FeedMaterial(relative_position);
    }

    private Vector2 CalculateRelativePostion() //calculate the position relative to the background in [0,1] range
    {
        if (background_floor.This == null) return Vector3.zero;

        Vector2 bg_position = background_floor.This.Position; //get the size and position of the background texture
        Vector2 bg_size = background_floor.This.Size;

        float origin_x1 = transform.position.x - Size.x/2f; //calculate the top left corner positions in case textures have their origins in the center
        float origin_y1 = transform.position.y - Size.y / 2f;
        float origin_x2 = bg_position.x - bg_size.x / 2f;
        float origin_y2 = bg_position.y - bg_size.y / 2f;

        float x = (origin_x1 - origin_x2) / bg_size.x; //get the [0,1] position of the object relative to the ground texture
        float y = (origin_y1 - origin_y2) / bg_size.y;

        return new Vector2(x, y);
    }

    private void FeedMaterial(Vector2 relative_position)
    {
        sr.GetPropertyBlock(material_properties);
        material_properties.SetVector("_GroundPosition", relative_position);
        sr.SetPropertyBlock(material_properties);
    }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM