首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >用Shells技术在统一中的实现

用Shells技术在统一中的实现
EN

Stack Overflow用户
提问于 2018-10-09 13:10:36
回答 1查看 2.7K关注 0票数 11

我正在努力实现与http://developer.download.nvidia.com/SDK/10.5/direct3d/Source/Fur/doc/FurShellsAndFins.pdf的统一毛皮。Fins技术被故意忽略了,因为我希望它能在低端手机上运行(主要是安卓设备),这需要OpenGL ES3.0及以上版本,而Shells技术只需要OpenGL ES 2.0。

有一个基于XNA的Shell技术的例子,我尝试将它移植到Unity中,但是它失败了。这里是XNA项目的文章。

XNA着色器:

代码语言:javascript
运行
复制
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#脚本:

代码语言:javascript
运行
复制
/// <summary>
/// This is the main type for your game
/// </summary>
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;


    /// <summary>
    /// 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.
    /// </summary>
    protected override void Initialize()
    {
        // TODO: Add your initialization logic here
        camera = new Camera(this);
        Components.Add(camera);
        base.Initialize();
    }

    /// <summary>
    /// LoadContent will be called once per game and is the place to load
    /// all of your content.
    /// </summary>
    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<Effect>("FurEffect");
        //create the texture
        furTexture = new Texture2D(GraphicsDevice,
                                                    256, 256, 1,
                                                    TextureUsage.None,
                                                    SurfaceFormat.Color);
        //fill the texture
        FillFurTexture(furTexture, density);
        furColorTexture = Content.Load<Texture2D>("bigtiger");
    }

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

    /// <summary>
    /// Allows the game to run logic such as updating the world,
    /// checking for collisions, gathering input, and playing audio.
    /// </summary>
    /// <param name="gameTime">Provides a snapshot of timing values.</param>
    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);
    }

    /// <summary>
    /// This is called when the game should draw itself.
    /// </summary>
    /// <param name="gameTime">Provides a snapshot of timing values.</param>
    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 < nrOfLayers; i++)
        {
            furEffect.Parameters["CurrentLayer"].SetValue((float)i / nrOfLayers);
            furEffect.CommitChanges();
            furEffect.CurrentTechnique.Passes[0].Begin();
            DrawGeometry();
            furEffect.CurrentTechnique.Passes[0].End();
        }
        furEffect.End();

        base.Draw(gameTime);
    }

    /// <summary>
    /// This functions prepares a texture to be used for fur rendering
    /// </summary>
    /// <param name="furTexture">This will contain the final texture</param>
    /// <param name="density">Hair density in [0..1] range </param>
    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 < totalPixels; i++)
            colors[i] = Color.TransparentBlack;

        //compute the number of opaque pixels = nr of hair strands
        int nrStrands = (int)(density * totalPixels);

        //compute the number of strands that stop at each layer
        int strandsPerLayer = nrStrands / nrOfLayers;

        //fill texture with opaque pixels
        for (int i = 0; i < nrStrands; i++)
        {
            int x, y;
            //random position on the texture
            x = rand.Next(height);
            y = rand.Next(width);

            //compute max layer
            int max_layer = i / strandsPerLayer;
            //normalize into [0..1] range
            float max_layer_n = (float)max_layer / (float)nrOfLayers;

            //put color (which has an alpha value of 255, i.e. opaque)
            //max_layer_n needs to be multiplied by 255 to achieve a color in [0..255] range
            colors[x * width + y] = new Color((byte)(max_layer_n * 255), 0, 0, 255);
        }

        //set the pixels on the texture.
        furTexture.SetData<Color>(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<VertexPositionNormalTexture>(PrimitiveType.TriangleList, vertices, 0, 2);
        }
    }

}

我仔细地移植了着色器和控制脚本的一行一行到团结。

移植的统一着色器:

代码语言:javascript
运行
复制
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#脚本:

代码语言:javascript
运行
复制
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 < nrOfLayers; i++)
        {
            material.SetFloat("CurrentLayer", (float)i / nrOfLayers);
            DrawGeometry();
        }

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

        if (firstDraw)
            firstDraw = false;
    }

    void DrawGeometry()
    {
        Quaternion rotation = Quaternion.Euler(0, 180, 0);
        Graphics.DrawMesh(verticesMesh, pos, rotation, material, 0, camera);
    }

    private VertexPositionNormalTexture[] verticesPText;
    public Mesh verticesMesh;

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

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

        verticesMesh = VertexPositionNormalTextureToUnityMesh(verticesPText);
    }

    Mesh VertexPositionNormalTextureToUnityMesh(VertexPositionNormalTexture[] vpnt)
    {
        Vector3[] vertices = new Vector3[vpnt.Length];
        Vector3[] normals = new Vector3[vpnt.Length];
        Vector2[] uvs = new Vector2[vpnt.Length];

        int[] triangles = new int[vpnt.Length];

        //Copy variables to create a mesh
        for (int i = 0; i < vpnt.Length; i++)
        {
            vertices[i] = vpnt[i].Position;
            normals[i] = vpnt[i].Normal;
            uvs[i] = vpnt[i].TextureCoordinate;

            triangles[i] = i;
        }

        Mesh mesh = new Mesh();
        mesh.vertices = vertices;
        mesh.normals = normals;
        mesh.uv = uvs;

        mesh.triangles = triangles;
        return mesh;
    }

    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
        Color32[] colors = new Color32[totalPixels];

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

        //initialize all pixels to transparent black
        for (int i = 0; i < totalPixels; i++)
            colors[i] = TransparentBlack();

        //compute the number of opaque pixels = nr of hair strands
        int nrStrands = (int)(density * totalPixels);

        //fill texture with opaque pixels
        for (int i = 0; i < nrStrands; i++)
        {
            int x, y;
            //random position on the texture
            x = rand.Next(height);
            y = rand.Next(width);
            //put color (which has an alpha value of 255, i.e. opaque)
            colors[x * width + y] = Gold();
        }

        //set the pixels on the texture.
        furTexture.SetPixels32(colors);
        // actually apply all SetPixels, don't recalculate mip levels
        furTexture.Apply();
    }

    Color32 TransparentBlack()
    {
        //http://www.monogame.net/documentation/?page=P_Microsoft_Xna_Framework_Color_TransparentBlack
        Color32 color = new Color32(0, 0, 0, 0);
        return color;
    }

    Color32 Gold()
    {
        //http://www.monogame.net/documentation/?page=P_Microsoft_Xna_Framework_Color_Gold
        Color32 color = new Color32(255, 215, 0, 255);
        return color;
    }

    Color32 CornflowerBlue()
    {
        //http://www.monogame.net/documentation/?page=P_Microsoft_Xna_Framework_Color_CornflowerBlue
        Color32 color = new Color32(100, 149, 237, 255);
        return color;
    }

    public static Vector3 UnitZ()
    {
        return new Vector3(0f, 0f, 1f);
    }
}

用于VertexPositionNormalTexture统一的移植结构

代码语言:javascript
运行
复制
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));
    }
}

移植的统一工作没有正常工作。没有外壳,输出图像是平坦的。

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

但是,我在Unity (没有shell)中看到了这一点:

最后的映像应该看起来像下面的图像,但是我不能继续移植工作,因为基本的实现在Unity中不能正常工作。

我的脚本公共变量设置:

为什么端口统一的结果是平坦的?我错过什么了吗?

编辑:

狮子座提到了可能的背景问题,因为统一使用左手坐标系,而XNA使用右手坐标系。

我翻转了UnitZ()值,并尝试倒转网格顶点,但是屏幕上什么也没有。这不太可能是问题所在。

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2018-10-11 16:26:33

团结就是对材料进行批量优化。您可以在框架调试器中看到这一点。每个DrawGeometry调用都对CurrentLayer使用相同的值。您需要在每次调用DrawMesh时使用属性块。设置一种新的材料会引起一些闪烁。

代码语言:javascript
运行
复制
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 < nrOfLayers; i++)
        {
            var propertyBlock = new MaterialPropertyBlock();

            var layer = (float)i / (float)nrOfLayers;
            propertyBlock.SetFloat("CurrentLayer", layer);
            propertyBlock.SetFloat("MaxHairLength", maxHairLength);
            propertyBlock.SetColor("_TintColor", new Color(layer, layer, layer, layer));
            DrawGeometry(propertyBlock);
        }

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

        if (firstDraw)
            firstDraw = false;
    }

    void DrawGeometry(MaterialPropertyBlock props)
    {
        var rot = Quaternion.Euler(0, 180, 0);
        Graphics.DrawMesh(verticesMesh, pos, rot, material, 0, camera, 0, props);
    }

    private VertexPositionNormalTexture[] verticesPText;
    public Mesh verticesMesh;

    private void GenerateGeometry()
    {
        var UnitZ = new Vector3(0, 0, 1);
        var verticesPText = new VertexPositionNormalTexture[6];
        verticesPText[5] = new VertexPositionNormalTexture(new Vector3(-10, 0, 0),
                                                    -UnitZ,
                                                    new Vector2(0, 0));
        verticesPText[4] = new VertexPositionNormalTexture(new Vector3(10, 20, 0),
                                                    -UnitZ,
                                                    new Vector2(1, 1));
        verticesPText[3] = new VertexPositionNormalTexture(new Vector3(-10, 20, 0),
                                                    -UnitZ,
                                                    new Vector2(0, 1));

        verticesPText[2] = verticesPText[5];
        verticesPText[1] = new VertexPositionNormalTexture(new Vector3(10, 0, 0),
                                                    -UnitZ,
                                                    new Vector2(1, 0));
        verticesPText[0] = verticesPText[4];

    }

    Mesh VertexPositionNormalTextureToUnityMesh(VertexPositionNormalTexture[] vpnt)
    {
        Vector3[] vertices = new Vector3[vpnt.Length];
        Vector3[] normals = new Vector3[vpnt.Length];
        Vector2[] uvs = new Vector2[vpnt.Length];

        int[] triangles = new int[vpnt.Length];

        //Copy variables to create a mesh
        for (int i = 0; i < vpnt.Length; i++)
        {
            vertices[i] = vpnt[i].Position;
            normals[i] = vpnt[i].Normal;
            uvs[i] = vpnt[i].TextureCoordinate;

            triangles[i] = i;
        }

        Mesh mesh = new Mesh();
        mesh.vertices = vertices;
        mesh.normals = normals;
        mesh.uv = uvs;

        mesh.MarkDynamic();


        mesh.triangles = triangles;
                    mesh.UploadMeshData(false);
        return mesh;
    }

    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
        Color32[] colors = new Color32[totalPixels];

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

        //initialize all pixels to transparent black
        for (int i = 0; i < totalPixels; i++)
            colors[i] = TransparentBlack();

        //compute the number of opaque pixels = nr of hair strands
        int nrStrands = (int)(density * totalPixels);

        //fill texture with opaque pixels
        for (int i = 0; i < nrStrands; i++)
        {
            int x, y;
            //random position on the texture
            x = rand.Next(height);
            y = rand.Next(width);
            //put color (which has an alpha value of 255, i.e. opaque)
           // colors[x * width + y] = new Color32((byte)255, (byte)x, (byte)y, (byte)255);
           colors[x * width + y] = Gold();
        }

        //set the pixels on the texture.
        furTexture.SetPixels32(colors);
        // actually apply all SetPixels, don't recalculate mip levels
        furTexture.Apply();
    }

    Color32 TransparentBlack()
    {
        //http://www.monogame.net/documentation/?page=P_Microsoft_Xna_Framework_Color_TransparentBlack
        Color32 color = new Color32(0, 0, 0, 0);
        return color;
    }

    Color32 Gold()
    {
        //http://www.monogame.net/documentation/?page=P_Microsoft_Xna_Framework_Color_Gold
        Color32 color = new Color32(255, 215, 0, 255);
        return color;
    }

    Color32 CornflowerBlue()
    {
        //http://www.monogame.net/documentation/?page=P_Microsoft_Xna_Framework_Color_CornflowerBlue
        Color32 color = new Color32(100, 149, 237, 255);
        return color;
    }

    public static Vector3 UnitZ()
    {
        return new Vector3(0f, 0f, 1f);
    }
}
}

我还修改了着色器来可视化贝壳。

代码语言:javascript
运行
复制
// 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
    }
}

}

这是在混乱参数和移动相机后的样子。

票数 13
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/52721907

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档