UNITY-仅更改 3D 模型颜色的某些部分
UNITY-Changing ONLY certain part of 3D model's color
我真的是 unity3D 的新手,我想问一个问题
我有一个 3D 人体模型(默认的统一模型),它具有分层骨骼结构。
我想在这里实现的是,当我按下某个触发器时,我想给它的一个肢体涂上不同的颜色(只是它的一个肢体)。这是我想要实现的目标的说明
我真的对此一无所知,因为我大约 3 个月前才开始学习 Unity,所以我真的需要你的帮助,这就是我的渲染器 属性 如果它有帮助的话
如果您是初学者,则必须阅读一些内容。在更改某些内容之前,请确保您完全了解模型设置:
- 这个工人有 1 个单一网格(3d 模型)。
- 此模型由 1 material 渲染(蒙皮网格渲染器仅附加 1 material)
- 这个 material 有一个基本的 RGBA 纹理,可以为您的模型着色。现在有一个问题:要在 3D 模型上映射 2D 纹理,我们使用 UV 映射。 UV 映射是一种将 3D 模型上的每个顶点连接到平面上的 2D 坐标的桥梁。在 3D 中我们称它们为顶点,在 2D 中我们称它们为 UV。因此,当您在 2D 平面上(在 photoshop、gimp 等中)为一个 UV 周围的区域着色时,适当的顶点将在网格上着色。 Google UV 映射了解更多信息。注意:您不能在 Unity 中进行 UV 映射(除非通过脚本),它通常在外部 3D 建模软件中完成。
- 最后,在完成所有谷歌搜索后,您可以切换到您的任务。您现在可能已经明白您需要修改模型的纹理。您需要找到模型的手映射到的位置,然后使用脚本更改该区域的颜色。您可以使用 Texture2D.GetPixels() and SetPixels().
还有另一种解决方案,更少程序化,更合乎逻辑,但需要优化的粗略方式:
- 将该模型导入 3D 建模软件
- 分离手臂但确保它仍然受骨架控制
- 将模型导入回 Unity
- 为手臂制作一个新的 material,您可以复制现有的(通常的做法是为改变视觉属性的对象制作单独的 material)
- 复制您的 RGBA 纹理并在图像编辑软件中对其进行去饱和处理。
- 将此重复纹理分配给副本 material 的颜色槽,并将副本 material 分配给手臂模型。
- 手臂现在应该是灰度的,所以你可以通过改变 material 颜色来改变它的颜色。
我只是想补充一点,使用 projectors 可能有更简单的方法来实现您想要的效果。这是unity中常用的工具,用来实时在mesh表面绘制各种效果,比如弹孔。使用相同的原理,您可以突出显示网格的某些区域。你可以把投影仪想象成手电筒,它的光照射到的所有东西都会改变它的质地。 Standard Assets / Effects 下有一些示例投影仪。您可能想从这里开始。
要创建投影仪,请创建一个空游戏 object => 添加组件 => 投影仪。
编辑
您可能想尝试的另一个想法是使用 vertex colors。除了坐标之外,网格的每个顶点还包含一个颜色参数,该参数可通过着色器访问。因此,您可以更改特定顶点集的颜色以突出显示它们。这里有2点需要注意:
1) 大多数着色器选择忽略顶点颜色,精灵着色器除外。您将需要一个自定义着色器,例如 this one.
2) 你需要以某种方式知道你想要突出显示哪些顶点。您可以做的是迭代 Mesh.boneWeights. If you want to select an arm, for example, what you need is all vertices that have weight > 1 for arm bone index. How do you find the arm bone index? This index corresponds to the index in SkinnedMeshRenderer.bones。或者只是选择一些您确定属于手臂的顶点并查看其骨骼权重以找到索引。
这里是一个示例脚本,它根据选定的骨骼索引更改顶点颜色。将其附加到您的 SkinnedMeshRenderer(通常是二级层次结构 object):
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
演示:http://jolly-squirrel.droppages.com/bones/index.html - 单击 body 部分以查看突出显示的部分。
我真的是 unity3D 的新手,我想问一个问题 我有一个 3D 人体模型(默认的统一模型),它具有分层骨骼结构。
我想在这里实现的是,当我按下某个触发器时,我想给它的一个肢体涂上不同的颜色(只是它的一个肢体)。这是我想要实现的目标的说明
我真的对此一无所知,因为我大约 3 个月前才开始学习 Unity,所以我真的需要你的帮助,这就是我的渲染器 属性 如果它有帮助的话
如果您是初学者,则必须阅读一些内容。在更改某些内容之前,请确保您完全了解模型设置:
- 这个工人有 1 个单一网格(3d 模型)。
- 此模型由 1 material 渲染(蒙皮网格渲染器仅附加 1 material)
- 这个 material 有一个基本的 RGBA 纹理,可以为您的模型着色。现在有一个问题:要在 3D 模型上映射 2D 纹理,我们使用 UV 映射。 UV 映射是一种将 3D 模型上的每个顶点连接到平面上的 2D 坐标的桥梁。在 3D 中我们称它们为顶点,在 2D 中我们称它们为 UV。因此,当您在 2D 平面上(在 photoshop、gimp 等中)为一个 UV 周围的区域着色时,适当的顶点将在网格上着色。 Google UV 映射了解更多信息。注意:您不能在 Unity 中进行 UV 映射(除非通过脚本),它通常在外部 3D 建模软件中完成。
- 最后,在完成所有谷歌搜索后,您可以切换到您的任务。您现在可能已经明白您需要修改模型的纹理。您需要找到模型的手映射到的位置,然后使用脚本更改该区域的颜色。您可以使用 Texture2D.GetPixels() and SetPixels().
还有另一种解决方案,更少程序化,更合乎逻辑,但需要优化的粗略方式:
- 将该模型导入 3D 建模软件
- 分离手臂但确保它仍然受骨架控制
- 将模型导入回 Unity
- 为手臂制作一个新的 material,您可以复制现有的(通常的做法是为改变视觉属性的对象制作单独的 material)
- 复制您的 RGBA 纹理并在图像编辑软件中对其进行去饱和处理。
- 将此重复纹理分配给副本 material 的颜色槽,并将副本 material 分配给手臂模型。
- 手臂现在应该是灰度的,所以你可以通过改变 material 颜色来改变它的颜色。
我只是想补充一点,使用 projectors 可能有更简单的方法来实现您想要的效果。这是unity中常用的工具,用来实时在mesh表面绘制各种效果,比如弹孔。使用相同的原理,您可以突出显示网格的某些区域。你可以把投影仪想象成手电筒,它的光照射到的所有东西都会改变它的质地。 Standard Assets / Effects 下有一些示例投影仪。您可能想从这里开始。
要创建投影仪,请创建一个空游戏 object => 添加组件 => 投影仪。
编辑
您可能想尝试的另一个想法是使用 vertex colors。除了坐标之外,网格的每个顶点还包含一个颜色参数,该参数可通过着色器访问。因此,您可以更改特定顶点集的颜色以突出显示它们。这里有2点需要注意:
1) 大多数着色器选择忽略顶点颜色,精灵着色器除外。您将需要一个自定义着色器,例如 this one.
2) 你需要以某种方式知道你想要突出显示哪些顶点。您可以做的是迭代 Mesh.boneWeights. If you want to select an arm, for example, what you need is all vertices that have weight > 1 for arm bone index. How do you find the arm bone index? This index corresponds to the index in SkinnedMeshRenderer.bones。或者只是选择一些您确定属于手臂的顶点并查看其骨骼权重以找到索引。
这里是一个示例脚本,它根据选定的骨骼索引更改顶点颜色。将其附加到您的 SkinnedMeshRenderer(通常是二级层次结构 object):
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
演示:http://jolly-squirrel.droppages.com/bones/index.html - 单击 body 部分以查看突出显示的部分。