# Zjbcool-Draggable-Texture 插件教程
这个教程我们结合示例 (opens new window)讲解可拖拽纹理插件的使用方法。
# 基础功能
DraggableTexture插件实现可拖拽纹理的过程是,首先在拼图环境下创建一张空白纹理,然后为纹理加载本地或服务器上的贴图,这个纹理通过对原生的when dragged拼图的支持,可以实现针对纹理的位移、旋转、缩放操作。
注:原生的when dragged拼图是针对物体进行拖拽,使用插件可以针对纹理进行拖拽。
此外,插件还提供了针对纹理的属性和变换操作提供了一些拼图,帮助我们实现更多纹理控制。
下面,我们首先实现示例程序中3个面片的纹理拖拽功能。
# 创建空白纹理
在创建纹理之前,在三维软件中需要在材质上指定一张贴图纹理,这个纹理的唯一功能是提供一个纹理的名字,稍后它会被替换掉,所以,可以给它一个最小的尺寸,比如1px*1px。在Blender中的操作如图:
三维软件中指定好贴图后,导出glTF。
接下来,使用插件的create texture拼图创建一张空白的可拖拽纹理。然后使用原生的材质(Material)分类下的replace texture拼图用新建纹理替换三维软件中设置的原始贴图。
# 加载贴图
现在我们需要为新建的可拖拽纹理加载图片。使用插件中的load image拼图可以从本地或远程服务器加载图片,它会返回一个HTML Image对象,可以用loaded image拼图接收它,然后使用插件的set prop拼图将加载的图片应用到可拖拽纹理。
这时,面片A上就会出现加载的图片了。这里,我们使用set prop拼图设置了纹理的image属性,你还可以用同样的方法,设置纹理的background、repeat、size等属性。
# 拖拽纹理
在原生的when dragged拼图上,通过左上角的齿轮图标打开高级设置,勾选enable start action和enable drop action选项,这时when dragged拼图会有这3个插槽:start: do 、 move: do 和 drop: do。我们分别使用插件提供的start drag texture拼图、drag texture拼图和drop texture拼图放入这3个插槽。
其中,drag texture拼图的mode参数决定拖拽的方式:位移、旋转、缩放。这里我们按照示例,分别为3个面片指定不同的拖拽方式。
至此,3个面片的功能就完成了。
# 高级功能
在实际开发中,我们一般是通过界面上的按钮去实现不同的功能的。下面,我们接着去实现示例程序中帽子自定义贴图的功能。
# 制作工具条
首先,我们使用HTML/CSS/JS制作一个工具条。HTML中我们使用无序列表来实现基本的布局。我们要实现移动、旋转、缩放、重复、重置和清除这些功能,所以要分别制作对应的按钮。
效果:
HTML:
<ul class="btn-container">
<li class="btn active" id="move">Move</li>
<li class="btn" id="rotate">Rotate</li>
<li class="btn" id="scale">Scale</li>
<li class="btn" id="repeat">Repeat</li>
<li class="btn" id="reset">Reset</li>
<li class="btn" id="clear">Clear</li>
</ul>
2
3
4
5
6
7
8
CSS:
.btn-container {
margin: 0;
padding: 0;
position: absolute;
bottom: 1rem;
left: 50%;
width: 100%;
transform: translateX(-50%);
-webkit-transform: translateX(-50%);
-moz-transform: translateX(-50%);
-ms-transform: translateX(-50%);
-o-transform: translateX(-50%);
display: flex;
flex-flow: row nowrap;
justify-content: center;
}
.btn {
list-style-type: none;
font-size: 1.2rem;
background: linear-gradient(0deg, #141415, #2f3132);
color: #a0a2a3;
border: 2px solid transparent;
width: 80px;
height: 50px;
line-height: 50px;
text-align: center;
user-select: none;
cursor: pointer;
}
.btn:first-child {
border-radius: 12px 0 0 12px;
-webkit-border-radius: 12px 0 0 12px;
-moz-border-radius: 12px 0 0 12px;
-ms-border-radius: 12px 0 0 12px;
-o-border-radius: 12px 0 0 12px;
}
.btn:last-child {
border-radius: 0 12px 12px 0;
-webkit-border-radius: 0 12px 12px 0;
-moz-border-radius: 0 12px 12px 0;
-ms-border-radius: 0 12px 12px 0;
-o-border-radius: 0 12px 12px 0;
}
.btn:hover {
background: #141415;
}
.active {
border: 2px solid #ddd;
color: #ddd;
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
JS(在exec script拼图中执行):
const btnContainer = document.querySelector('.btn-container');
btnContainer.addEventListener('mousedown', buttonHighlight , false);
btnContainer.addEventListener('touchstart', buttonHighlight , false);
function buttonHighlight(event) {
for (let btn of btnContainer.children) {
btn.className = 'btn';
if(event.target === btn) {
event.target.classList.add('active');
VARS.mode = event.target.id; // 设置拖拽模式
}
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
# 上传图片功能
首先,按照基础功能部分的步骤,先新建空白可拖拽纹理,然后使用新建纹理替换掉材质上的原有贴图。
接着,我们使用原生的add annotation拼图,在模型上添加一个注释标签,后面我们要通过点击这个注释标签实现上传图片的功能。这里同时实现了模型点击时的描边效果和注释标签的显示/隐藏效果。拼图如下:
下面我们来实现功能部分。为了同时兼容PC端和移动端,我们为注释标签(id为upload)分别添加两个监听事件,事件类型分别是:mousedown和touchstart。
使用原生的HTML分类下的open file拼图和opened file拼图可以从本地打开一张图片,结合基础功能部分讲到的,我们可以使用插件提供的load image拼图将打开的图片加载到可拖拽纹理里面。拼图如下:
注意:在图片加载完成时设置了一个imageLoaded变量,后面会用到。
至此,上传图片功能就实现了,拼图还是很简洁的,是吧。
# 拖拽纹理功能
在这里我们要在基础功能部分的基础上做出一点变化,也就是通过工具条上的按钮来切换拖拽模式。
首先,创建一个transformMode函数,参数是type,type表示拖拽模式。然后,在when dragged拼图的move: do插槽中调用这个函数,把全局变量mode作为参数传递给它。如图:
变量mode的值通过点击工具条上的按钮设置。参见制作工具条JS代码部分。
现在,当点击工具条上的位移、旋转、缩放按钮的时候,就会切换到相应的拖拽模式,从而可以直接在模型上操作纹理。同样的功能,你还可以通过设置快捷键来实现,只要按下快捷键时设置mode变量的值就可以了。
# 纹理的重复度
设置纹理的重复度是通过set prop拼图修改repeat属性实现的。拼图如下:
# 纹理重置
纹理重置即恢复纹理的默认属性设置,在这里包含恢复纹理的重复度为no-repeat,恢复纹理的变换。这两个操作我们分别使用set prop拼图和reset transform拼图来实现。
# 清除纹理
清除纹理可以使用插件提供的clear texture拼图实现。
至此,示例程序的全部功能就都实现了。这里面要留意一些小细节,比如标记图片加载状态的变量(imageLoaded)和标记图片重复度的变量(repeat),有时,你会在调试的时候发现一些小问题,就需要加入一些这样的代码。