热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

在Unity中使用Shell技术实现Fur

如何解决《在Unity中使用Shell技术实现Fur》经验,为你挑选了1个好方法。

我正在尝试使用Shells技术在Unity中实现毛发.Fins技术是故意遗漏的,因为我希望它在低端手机(主要是Android设备)上运行,并且需要OpenGL ES 3.0及更高版本,而Shells技术只需要OpenGL ES 2.0.

有一个基于XNA的Shell技术的例子,我试图将它移植到Unity但它无法工作.这是XNA项目的文章.

XNA着色器:

float4x4 World;
float4x4 View;
float4x4 Projection;

float CurrentLayer; //value between 0 and 1
float MaxHairLength; //maximum hair length

texture FurTexture;
sampler FurSampler = sampler_state
{
    Texture = (FurTexture);
    MinFilter = Point;
    MagFilter = Point;
    MipFilter = Point;
    AddressU = Wrap;
    AddressV = Wrap;
};


struct VertexShaderInput
{
    float3 Position : POSITION0;
    float3 Normal : NORMAL0;
    float2 TexCoord : TEXCOORD0;
};

struct VertexShaderOutput
{
    float4 Position : POSITION0;
    float2 TexCoord : TEXCOORD0;
};

VertexShaderOutput FurVertexShader(VertexShaderInput input)
{
    VertexShaderOutput output;
    float3 pos;
    pos = input.Position + input.Normal * MaxHairLength * CurrentLayer;

    float4 worldPosition = mul(float4(pos,1), World);
    float4 viewPosition = mul(worldPosition, View);
    output.Position = mul(viewPosition, Projection);

    output.TexCoord = input.TexCoord;
    return output;
}

float4 FurPixelShader(VertexShaderOutput input) : COLOR0
{
    return tex2D(FurSampler, input.TexCoord);
}

technique Fur
{
    pass Pass1
    {
        AlphaBlendEnable = true;
        SrcBlend = SRCALPHA;
        DestBlend = INVSRCALPHA;
        CullMode = None;

        VertexShader = compile vs_2_0 FurVertexShader();
        PixelShader = compile ps_2_0 FurPixelShader();
    }
}

控制着色器的XNA C#脚本:

/// 
/// This is the main type for your game
/// 
public class Game1 : Microsoft.Xna.Framework.Game
{
    GraphicsDeviceManager graphics;
    SpriteBatch spriteBatch;

    public Game1()
    {
        graphics = new GraphicsDeviceManager(this);
        Content.RootDirectory = "Content";
    }

    //simple camera for use in the game
    Camera camera;
    //texture containing fur data
    Texture2D furTexture;
    //effect for fur shaders
    Effect furEffect;
    //number of layers of fur
    int nrOfLayers = 60;
    //total length of the hair
    float maxHairLength = 2.0f;
    //density of hair
    float density = 0.2f;
    Texture2D furColorTexture;

    //movement vectors
    Vector3 gravity = new Vector3(0, -1.0f, 0);
    Vector3 forceDirection = Vector3.Zero;
    //final displacement for hair
    Vector3 displacement;


    /// 
    /// Allows the game to perform any initialization it needs to before starting to run.
    /// This is where it can query for any required services and load any non-graphic
    /// related content.  Calling base.Initialize will enumerate through any components
    /// and initialize them as well.
    /// 
    protected override void Initialize()
    {
        // TODO: Add your initialization logic here
        camera = new Camera(this);
        Components.Add(camera);
        base.Initialize();
    }

    /// 
    /// LoadContent will be called once per game and is the place to load
    /// all of your content.
    /// 
    protected override void LoadContent()
    {
        // Create a new SpriteBatch, which can be used to draw textures.
        spriteBatch = new SpriteBatch(GraphicsDevice);
        //generate the geometry
        GenerateGeometry();
        //load the effect
        furEffect = Content.Load("FurEffect");
        //create the texture
        furTexture = new Texture2D(GraphicsDevice,
                                                    256, 256, 1,
                                                    TextureUsage.None,
                                                    SurfaceFormat.Color);
        //fill the texture
        FillFurTexture(furTexture, density);
        furColorTexture = Content.Load("bigtiger");
    }

    /// 
    /// UnloadContent will be called once per game and is the place to unload
    /// all content.
    /// 
    protected override void UnloadContent()
    {
        // TODO: Unload any non ContentManager content here
    }

    /// 
    /// Allows the game to run logic such as updating the world,
    /// checking for collisions, gathering input, and playing audio.
    /// 
    /// Provides a snapshot of timing values.
    protected override void Update(GameTime gameTime)
    {
        // Allows the game to exit
        if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed)
            this.Exit();

        // TODO: Add your update logic here

        base.Update(gameTime);
    }

    /// 
    /// This is called when the game should draw itself.
    /// 
    /// Provides a snapshot of timing values.
    protected override void Draw(GameTime gameTime)
    {
        forceDirection.X = (float)Math.Sin(gameTime.TotalGameTime.TotalSeconds) * 0.5f;
        displacement = gravity + forceDirection;
        furEffect.Parameters["Displacement"].SetValue(displacement);

        graphics.GraphicsDevice.Clear(Color.CornflowerBlue);

        furEffect.Parameters["World"].SetValue(Matrix.CreateTranslation(0, -10, 0));
        furEffect.Parameters["View"].SetValue(camera.View);
        furEffect.Parameters["Projection"].SetValue(camera.Projection);
        furEffect.Parameters["MaxHairLength"].SetValue(maxHairLength);
        furEffect.Parameters["FurTexture"].SetValue(furTexture);
        furEffect.Parameters["Texture"].SetValue(furColorTexture);

        furEffect.Begin();
        for (int i = 0; i 
    /// This functions prepares a texture to be used for fur rendering
    /// 
    /// This will contain the final texture
    /// Hair density in [0..1] range 
    private void FillFurTexture(Texture2D furTexture, float density)
    {
        //read the width and height of the texture
        int width = furTexture.Width;
        int height = furTexture.Height;
        int totalPixels = width * height;

        //an array to hold our pixels
        Color[] colors;
        colors = new Color[totalPixels];

        //random number generator
        Random rand = new Random();

        //initialize all pixels to transparent black
        for (int i = 0; i (colors);
    }


    VertexPositionNormalTexture[] vertices;

    private void GenerateGeometry()
    {
        vertices = new VertexPositionNormalTexture[6];
        vertices[0] = new VertexPositionNormalTexture(
                                                                    new Vector3(-10, 0, 0),
                                                                    -Vector3.UnitZ,
                                                                    new Vector2(0, 0));
        vertices[1] = new VertexPositionNormalTexture(
                                                                    new Vector3(10, 20, 0),
                                                                    -Vector3.UnitZ,
                                                                    new Vector2(1, 1));
        vertices[2] = new VertexPositionNormalTexture(
                                                                    new Vector3(-10, 20, 0),
                                                                    -Vector3.UnitZ,
                                                                    new Vector2(0, 1));

        vertices[3] = vertices[0];
        vertices[4] = new VertexPositionNormalTexture(
                                                                    new Vector3(10, 0, 0),
                                                                    -Vector3.UnitZ,
                                                                    new Vector2(1, 0));
        vertices[5] = vertices[1];
    }

    private void DrawGeometry()
    {
        using (VertexDeclaration vdecl = new VertexDeclaration(
                                                                    GraphicsDevice,
                                                                    VertexPositionNormalTexture.VertexElements))
        {
            GraphicsDevice.VertexDeclaration = vdecl;
            GraphicsDevice.DrawUserPrimitives(PrimitiveType.TriangleList, vertices, 0, 2);
        }
    }

}



我小心地将着色器和控制脚本逐行移植到Unity.

Ported Unity着色器:

Shader "Programmer/Fur Shader"
{
    Properties
    {
        _MainTex("Texture", 2D) = "white" {}
    //_TintColor("Tint Color", Color) = (1,1,1,1)
    }
        SubShader
    {
        Tags{ "Queue" = "Transparent" "RenderType" = "Transparent" }
        LOD 100
        Blend SrcAlpha One
        Blend DstAlpha OneMinusSrcAlpha
        ZWrite Off
        Cull Off

        Pass
    {
        CGPROGRAM
#pragma vertex vert
#pragma fragment frag
        // make fog work
        //#pragma multi_compile_fog

#include "UnityCG.cginc"

        //In
        struct appdata
    {
        float4 vertex : POSITION;
        float2 uv : TEXCOORD0;
    };

    //Out
    struct v2f
    {
        float2 uv : TEXCOORD0;
        UNITY_FOG_COORDS(1)
            float4 vertex : SV_POSITION;
    };

    struct VertexShaderInput
    {
        float3 Position : POSITION0;
        float3 Normal : NORMAL0;
        float2 TexCoord : TEXCOORD0;
    };

    struct VertexShaderOutput
    {
        float4 Position : POSITION0;
        float2 TexCoord : TEXCOORD0;
    };

    sampler2D _MainTex;
    float4 _MainTex_ST;

    //Test variable/delete after
    float4 _TintColor;

    //The variables
    float4x4 World;
    float4x4 View;
    float4x4 Projection;

    float CurrentLayer; //value between 0 and 1
    float MaxHairLength; //maximum hair length

    VertexShaderOutput vert(VertexShaderInput input)
    {
        VertexShaderOutput output;
        float3 pos;
        pos = input.Position + input.Normal * MaxHairLength * CurrentLayer;

        float4 worldPosition = mul(float4(pos, 1), World);
        float4 viewPosition = mul(worldPosition, View);
        output.Position = mul(viewPosition, Projection);

        output.TexCoord = input.TexCoord;
        return output;
    }

    float4 frag(VertexShaderOutput  i) : COLOR0
    {
        return tex2D(_MainTex,  i.TexCoord);
    }
        ENDCG
    }
    }
}

用于控制着色器的移植Unity C#脚本:

public class Game1 : MonoBehaviour
{
    public Material material;


    public Vector3 pos = new Vector3(0f, 0.98f, -9.54f);


    //simple camera for use in the game
    private new Camera camera;
    //texture containing fur data
    public Texture2D furTexture;
    //effect for fur shaders
    //Effect furEffect;
    //number of layers of fur
    public int nrOfLayers = 40;
    //total length of the hair
    public float maxHairLength = 2.0f;
    //density of hair
    public float density = 0.2f;

    //[Space(20)]
    //public Vector3 dirWorldVal = new Vector3(0, -10, 0);

    void Start()
    {
        Initialize();
        GenerateGeometry();
    }

    public void Update()
    {
        Draw();
    }


    void Initialize()
    {

        //Initialize the camera
        camera = Camera.main;

        //create the texture
        furTexture = new Texture2D(256, 256, TextureFormat.ARGB32, false);
        furTexture.wrapModeU = TextureWrapMode.Repeat;
        furTexture.wrapModeV = TextureWrapMode.Repeat;
        furTexture.filterMode = FilterMode.Point;

        //fill the texture
        FillFurTexture(furTexture, density);

        /*XNA's SurfaceFormat.Color is ARGB.
        //https://gamedev.stackexchange.com/a/6442/98839*/


        if (material.mainTexture != null)
        {
            material.mainTexture.wrapModeU = TextureWrapMode.Repeat;
            material.mainTexture.wrapModeV = TextureWrapMode.Repeat;
            material.mainTexture.filterMode = FilterMode.Point;
        }
    }

    bool firstDraw = true;

    protected void Draw()
    {
        camera.backgroundColor = CornflowerBlue();

        Matrix4x4 worldValue = Matrix4x4.Translate(pos);
        Matrix4x4 viewValue = camera.projectionMatrix;
        // viewValue = camera.worldToCameraMatrix;
        Matrix4x4 projectiOnValue= camera.projectionMatrix;

        material.SetMatrix("World", worldValue);
        material.SetMatrix("View", viewValue);
        material.SetMatrix("Projection", projectionValue); //Causes object to disappear

        material.SetFloat("MaxHairLength", maxHairLength);

        if (firstDraw)
            material.SetTexture("_MainTex", furTexture);

        //furEffect.Begin();
        for (int i = 0; i 

Unity的移植VertexPositionNormalTexture结构

public struct VertexPositionNormalTexture
{
    public Vector3 Position;
    public Vector3 Normal;
    public Vector2 TextureCoordinate;
    //public static readonly VertexDeclaration VertexDeclaration;
    public VertexPositionNormalTexture(Vector3 position, Vector3 normal, Vector2 textureCoordinate)
    {
        this.Position = position;
        this.Normal = normal;
        this.TextureCoordinate = textureCoordinate;
    }

    public override int GetHashCode()
    {
        // TODO: FIc gethashcode
        return 0;
    }

    public override string ToString()
    {
        return string.Format("{{Position:{0} Normal:{1} TextureCoordinate:{2}}}", new object[] { this.Position, this.Normal, this.TextureCoordinate });
    }

    public static bool operator ==(VertexPositionNormalTexture left, VertexPositionNormalTexture right)
    {
        return (((left.Position == right.Position) && (left.Normal == right.Normal)) && (left.TextureCoordinate == right.TextureCoordinate));
    }

    public static bool operator !=(VertexPositionNormalTexture left, VertexPositionNormalTexture right)
    {
        return !(left == right);
    }

    public override bool Equals(object obj)
    {
        if (obj == null)
        {
            return false;
        }
        if (obj.GetType() != base.GetType())
        {
            return false;
        }
        return (this == ((VertexPositionNormalTexture)obj));
    }
}

移植的Unity工作无法正常工作.没有炮弹和输出图像是平的.

这是XNA中预期结果(工作正常):

在此输入图像描述

但这是我在Unity中看到的(没有炮弹):

在此输入图像描述

最终的图像应该看起来像下面的图像,但我不能继续进行移植工作,因为基本实现在Unity中无法正常工作.

在此输入图像描述

我的脚本公共变量设置:

在此输入图像描述

为什么移植的Unity结果是平的?我错过了什么吗?

编辑:

Leo提到了可能的背面问题,因为Unity使用左手坐标系,而XNA使用右手坐标系.

我翻转了UnitZ()值并尝试反转网格顶点,但屏幕上没有任何内容.这不太可能是问题.



1> Leo Bartkus..:

Unity正在对材料进行批量优化.您可以在帧调试器中看到这一点.每个DrawGeometry调用对CurrentLayer使用相同的值.每次调用DrawMesh时都需要使用propertyblock.设置新材料会导致一些闪烁.

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;

namespace foo {
public class FurBehavior : MonoBehaviour
{
    public Material material;


    public Vector3 pos = new Vector3(0f, 0.98f, -9.54f);


    //simple camera for use in the game
    private new Camera camera;
    //texture containing fur data
    public Texture2D furTexture;
    //effect for fur shaders
    //Effect furEffect;
    //number of layers of fur
    public int nrOfLayers = 40;
    //total length of the hair
    public float maxHairLength = 2.0f;
    //density of hair
    public float density = 0.2f;

    //[Space(20)]
    //public Vector3 dirWorldVal = new Vector3(0, -10, 0);

    void Start()
    {
        this.transform.position = new Vector3(0f, 0.98f, -9.54f);
        this.transform.rotation = Quaternion.Euler(0, 180, 0);
        Initialize();
        GenerateGeometry();
    }

    public void Update()
    {
        Draw();

    }


    void Initialize()
    {

        //Initialize the camera
        camera = Camera.main;

        //create the texture
        furTexture = new Texture2D(256, 256, TextureFormat.ARGB32, false);
        furTexture.wrapModeU = TextureWrapMode.Repeat;
        furTexture.wrapModeV = TextureWrapMode.Repeat;
        //furTexture.filterMode = FilterMode.Point;

        //fill the texture
        FillFurTexture(furTexture, density);

        /*XNA's SurfaceFormat.Color is ARGB.
        //https://gamedev.stackexchange.com/a/6442/98839*/


        if (material.mainTexture != null)
        {
            material.mainTexture.wrapModeU = TextureWrapMode.Repeat;
            material.mainTexture.wrapModeV = TextureWrapMode.Repeat;
           // material.mainTexture.filterMode = FilterMode.Point;
        }
    }

    bool firstDraw = true;

    protected void Draw()
    {
        var pos = this.transform.position;

        camera.backgroundColor = CornflowerBlue();

        Matrix4x4 worldValue = Matrix4x4.Translate(pos);
        Matrix4x4 viewValue = camera.projectionMatrix;
        // viewValue = camera.worldToCameraMatrix;
        Matrix4x4 projectiOnValue= camera.projectionMatrix;

        material.SetMatrix("World", worldValue);
        material.SetMatrix("View", viewValue);
        material.SetMatrix("Projection", projectionValue); //Causes object to disappear

        material.SetFloat("MaxHairLength", maxHairLength);

        //if (firstDraw)
            material.SetTexture("_MainTex", furTexture);

        //furEffect.Begin();
        for (int i = 0; i 

我还修改了着色器以显示shell.

// Upgrade NOTE: replaced 'mul(UNITY_MATRIX_MVP,*)' with 
'UnityObjectToClipPos(*)'

Shader "Programmer/Fur Shader"
{
Properties
{
    _MainTex("Texture", 2D) = "white" {}
_TintColor("Tint Color", Color) = (1,1,1,1)
}
SubShader
{
    Tags{ "Queue" = "Transparent" "RenderType" = "Transparent" }
    LOD 100
    //Blend SrcAlpha One
    //Blend DstAlpha OneMinusSrcAlpha
    Blend SrcAlpha OneMinusSrcAlpha
    ZWrite Off
    Cull Off

    Pass
    {
        CGPROGRAM
        #pragma vertex vert
        #pragma fragment frag
                // make fog work
                //#pragma multi_compile_fog

        #include "UnityCG.cginc"

        //In
        struct appdata
        {
            float4 vertex : POSITION;
            float2 uv : TEXCOORD0;
        };

    //Out
        struct v2f
        {
            float2 uv : TEXCOORD0;
            UNITY_FOG_COORDS(1)
                float4 vertex : SV_POSITION;
        };

        struct VertexShaderInput
        {
            float3 Position : POSITION0;
            float3 Normal : NORMAL0;
            float2 TexCoord : TEXCOORD0;
        };

        struct VertexShaderOutput
        {
            float4 Position : POSITION0;
            float2 TexCoord : TEXCOORD0;
            float4 Tint: COLOR1;
        };

        sampler2D _MainTex;
        float4 _MainTex_ST;

        //Test variable/delete after
        float4 _TintColor;

        //The variables
        float4x4 World;
        float4x4 View;
        float4x4 Projection;

        float CurrentLayer; //value between 0 and 1
        float MaxHairLength; //maximum hair length

        VertexShaderOutput vert(VertexShaderInput input)
        {
            VertexShaderOutput output;
            float3 pos;
            pos = input.Position + input.Normal * MaxHairLength * CurrentLayer;

            //float4 worldPosition = mul(float4(pos, 1), World);
            //float4 viewPosition = mul(worldPosition, View);
            output.Position = UnityObjectToClipPos(pos);

            output.TexCoord = input.TexCoord;
            output.Tint = float4(CurrentLayer, CurrentLayer, 0, 1);
            return output;
        }

        float4 frag(VertexShaderOutput  i) : COLOR0
        {
            float4 t = tex2D(_MainTex,  i.TexCoord) * i.Tint;
            return t;//float4(t, i.x, i.y, 1);
        }
        ENDCG
    }
}

}

这是在弄乱参数并稍微移动相机后的样子.

从{0,0,-10}左右看它


推荐阅读
  • 成功安装Sabayon Linux在thinkpad X60上的经验分享
    本文分享了作者在国庆期间在thinkpad X60上成功安装Sabayon Linux的经验。通过修改CHOST和执行emerge命令,作者顺利完成了安装过程。Sabayon Linux是一个基于Gentoo Linux的发行版,可以将电脑快速转变为一个功能强大的系统。除了作为一个live DVD使用外,Sabayon Linux还可以被安装在硬盘上,方便用户使用。 ... [详细]
  • 本文讨论了在openwrt-17.01版本中,mt7628设备上初始化启动时eth0的mac地址总是随机生成的问题。每次随机生成的eth0的mac地址都会写到/sys/class/net/eth0/address目录下,而openwrt-17.01原版的SDK会根据随机生成的eth0的mac地址再生成eth0.1、eth0.2等,生成后的mac地址会保存在/etc/config/network下。 ... [详细]
  • 本文介绍了Java工具类库Hutool,该工具包封装了对文件、流、加密解密、转码、正则、线程、XML等JDK方法的封装,并提供了各种Util工具类。同时,还介绍了Hutool的组件,包括动态代理、布隆过滤、缓存、定时任务等功能。该工具包可以简化Java代码,提高开发效率。 ... [详细]
  • Spring特性实现接口多类的动态调用详解
    本文详细介绍了如何使用Spring特性实现接口多类的动态调用。通过对Spring IoC容器的基础类BeanFactory和ApplicationContext的介绍,以及getBeansOfType方法的应用,解决了在实际工作中遇到的接口及多个实现类的问题。同时,文章还提到了SPI使用的不便之处,并介绍了借助ApplicationContext实现需求的方法。阅读本文,你将了解到Spring特性的实现原理和实际应用方式。 ... [详细]
  • 自动轮播,反转播放的ViewPagerAdapter的使用方法和效果展示
    本文介绍了如何使用自动轮播、反转播放的ViewPagerAdapter,并展示了其效果。该ViewPagerAdapter支持无限循环、触摸暂停、切换缩放等功能。同时提供了使用GIF.gif的示例和github地址。通过LoopFragmentPagerAdapter类的getActualCount、getActualItem和getActualPagerTitle方法可以实现自定义的循环效果和标题展示。 ... [详细]
  • Android自定义控件绘图篇之Paint函数大汇总
    本文介绍了Android自定义控件绘图篇中的Paint函数大汇总,包括重置画笔、设置颜色、设置透明度、设置样式、设置宽度、设置抗锯齿等功能。通过学习这些函数,可以更好地掌握Paint的用法。 ... [详细]
  • 单页面应用 VS 多页面应用的区别和适用场景
    本文主要介绍了单页面应用(SPA)和多页面应用(MPA)的区别和适用场景。单页面应用只有一个主页面,所有内容都包含在主页面中,页面切换快但需要做相关的调优;多页面应用有多个独立的页面,每个页面都要加载相关资源,页面切换慢但适用于对SEO要求较高的应用。文章还提到了两者在资源加载、过渡动画、路由模式和数据传递方面的差异。 ... [详细]
  • 用Vue实现的Demo商品管理效果图及实现代码
    本文介绍了一个使用Vue实现的Demo商品管理的效果图及实现代码。 ... [详细]
  • express工程中的json调用方法
    本文介绍了在express工程中如何调用json数据,包括建立app.js文件、创建数据接口以及获取全部数据和typeid为1的数据的方法。 ... [详细]
  • 本文讨论了在shiro java配置中加入Shiro listener后启动失败的问题。作者引入了一系列jar包,并在web.xml中配置了相关内容,但启动后却无法正常运行。文章提供了具体引入的jar包和web.xml的配置内容,并指出可能的错误原因。该问题可能与jar包版本不兼容、web.xml配置错误等有关。 ... [详细]
  • 本文介绍了如何在Jquery中通过元素的样式值获取元素,并将其赋值给一个变量。提供了5种解决方案供参考。 ... [详细]
  • 本文介绍了DataTables插件的官方网站以及其基本特点和使用方法,包括分页处理、数据过滤、数据排序、数据类型检测、列宽度自动适应、CSS定制样式、隐藏列等功能。同时还介绍了其易用性、可扩展性和灵活性,以及国际化和动态创建表格的功能。此外,还提供了参数初始化和延迟加载的示例代码。 ... [详细]
  • 花瓣|目标值_Compose 动画边学边做夏日彩虹
    篇首语:本文由编程笔记#小编为大家整理,主要介绍了Compose动画边学边做-夏日彩虹相关的知识,希望对你有一定的参考价值。引言Comp ... [详细]
  • 关于如何快速定义自己的数据集,可以参考我的前一篇文章PyTorch中快速加载自定义数据(入门)_晨曦473的博客-CSDN博客刚开始学习P ... [详细]
  • centos6.8 下nginx1.10 安装 ... [详细]
author-avatar
丽春院少爷
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有