UNITY-Changing仅改变3D模型颜色的某些部分

时间:2015-12-25 06:33:59

标签: c# unity3d 3d modeling 3d-modelling

我对unity3D真的很新,我想问一个问题 我有一个3D人体模型(默认统一模型),它具有分层骨骼结构。

我想在这里实现的是,当我按下某个触发器时,我想要用不同的颜色(只是其中一个肢体)为其中一个肢体着色。这是我想要实现的目标

enter image description here

我真的对此毫无头绪,因为我刚刚开始学习Unity大约3个月前,所以我真的需要你的帮助,这是我的渲染器的属性,如果它有帮助的话

enter image description here

2 个答案:

答案 0 :(得分:4)

我只想补充一点,使用projectors可能有更简单的方法来实现您的目标。这是统一的常用工具,用于实时绘制网格表面上的各种效果,如弹孔。使用相同的原理,您可以突出显示网格的某些区域。您可以将投影仪视为手电筒,其光线照射的一切都会改变其质感。标准资产/效果下有一些示例投影仪。你可能想从那里开始。

要创建投射器,请创建一个空游戏对象=>添加组件=>投影机。

修改

您可能想要尝试的另一个想法是使用vertex colors。除了坐标之外,网格的每个顶点还包含颜色参数,该颜色参数可通过着色器访问。因此,您可以更改特定顶点集的颜色以突出显示它们。这里有2点你需要注意:

1)大多数着色器选择忽略顶点颜色,但精灵着色器除外。您需要自定义着色器,例如this one

2)你需要知道你想要突出显示哪些顶点。你可以做的是迭代Mesh.boneWeights。例如,如果你想选择一个手臂,你需要的是所有具有权重>的顶点。 1为手臂骨指数。你怎么找到手臂骨指数?该索引对应于SkinnedMeshRenderer.bones中的索引。或者只选择一些你知道属于arm的顶点并查看其骨骼权重以找到索引。

这是一个示例脚本,它根据选定的骨骼索引更改顶点颜色。将它附加到SkinnedMeshRenderer(通常是第二级层次结构对象):

using UnityEngine;
using System.Collections;

public class BoneHiglighter : MonoBehaviour {

    public Color32 highlightColor = Color.red;
    public Color32 regularColor = Color.white;

    public SkinnedMeshRenderer smr;

    // Just for sake of demonstration
    public Transform bone;
    private Transform prevBone;


    // Find bone index given bone transform
    int GetBoneIndex(Transform bone) {
        Debug.Assert(smr != null);
        var bones = smr.bones;

        for (int i = 0; i < bones.Length; ++i) {
            if (bones[i] == bone) return i;
        }

        return -1;
    }

    // Change vertex colors highlighting given bone
    void Highlight(Transform bone) {
        Debug.Assert(smr != null);
        var idx = GetBoneIndex(bone);
        var mesh = smr.sharedMesh;
        var weights = mesh.boneWeights;
        var colors = new Color32[weights.Length];

        for (int i = 0; i < colors.Length; ++i) {
            float sum = 0;
            if (weights[i].boneIndex0 == idx && weights[i].weight0 > 0)
                sum += weights[i].weight0;
            if (weights[i].boneIndex1 == idx && weights[i].weight1 > 0)
                sum += weights[i].weight1;
            if (weights[i].boneIndex2 == idx && weights[i].weight2 > 0)
                sum += weights[i].weight2;
            if (weights[i].boneIndex3 == idx && weights[i].weight3 > 0)
                sum += weights[i].weight3;

            colors[i] = Color32.Lerp(regularColor, highlightColor, sum);
        }

        mesh.colors32 = colors;

    }

    void Start() {
        // If not explicitly specified SkinnedMeshRenderer try to find one
        if (smr == null) smr = GetComponent<SkinnedMeshRenderer>();
        // SkinnedMeshRenderer has only shared mesh. We should not modify it.
        // So we make a copy on startup, and work with it.
        smr.sharedMesh = (Mesh)Instantiate(smr.sharedMesh);

        Highlight(bone);
    }

    void Update() {
        if (prevBone != bone) {
            // User selected different bone
            prevBone = bone;
            Highlight(bone);
        }
    }
}

查看示例项目:https://www.dropbox.com/s/yfoqo44bubcr48s/HighlightBone.zip?dl=0

演示:https://dl.dropboxusercontent.com/u/16950335/bones/index.html - 点击身体部位以突出显示它们。

答案 1 :(得分:0)

如果你是初学者,你将不得不做一些阅读。在更改内容之前,请确保您完全了解模型设置:

  • 此工作人员有1个单一网格(3d模型)。
  • 此模型由1种材质渲染(蒙皮网格渲染器仅附加1种材质)
  • 此材质具有基础RGBA纹理,可为您的模型着色。现在这里有一个问题:要在3D模型上映射2D纹理,我们使用UV映射。 UV映射是一种将3D模型上的每个顶点链接到平面上的2D坐标的桥梁。在3D中我们将它们称为Vertex,在2D上我们称之为UV。因此,当您在2D平面上的一个UV周围(在photoshop,gimp等)中为区域着色时,相应的顶点将在网格上着色。 Google UV映射了解更多信息。注意:您不能在Unity中进行UV映射(除非通过脚本),它通常在外部3D建模软件中完成。
  • 最后,完成所有谷歌搜索后,您可以切换到您的任务。您现在可能已经理解需要修改模型的纹理。您需要找到模型的手被映射到的位置,然后使用脚本更改该区域的颜色。您可以使用Texture2D.GetPixels()SetPixels()
  • 执行此操作

还有另一种解决方案,需要优化的程序化程度更低,逻辑性更强,但更粗糙:

  • 将该模型导入3D建模软件
  • 分离手臂,但确保它仍受骨架控制
  • 将模型导回Unity
  • 为手臂制作新材料,您可以复制现有材料(这是为更改视觉属性的对象制作单独材料的常见做法)
  • 复制RGBA纹理并在图像编辑软件中对其进行去饱和处理。
  • 将此重复纹理指定给重复材质的颜色槽,并将重复材质指定给手臂模型。
  • 此时手臂应为灰度,因此您可以通过更改材质颜色来更改其颜色。