-
Notifications
You must be signed in to change notification settings - Fork 2
/
index.html
156 lines (142 loc) · 5.16 KB
/
index.html
1
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
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
<!DOCTYPE html>
<html>
<head>
<title>A small 3d renderer based on js and canvas, no webgl</title>
<meta charset="UTF-8" />
<style>
body {
margin: 0;
}
form {
position: absolute;
width: 245px;
right: 0;
box-sizing: border-box;
top: 240px;
border: 1px solid white;
margin-right: 15px;
padding: 5px;
}
</style>
<script src="src/loader/obj.js"></script>
</head>
<body>
<canvas id="myCanvas" width="400" height="400"> </canvas>
<form enctype="multipart/form-data">
<label for="upload">upload a obj file</label><br />
<input id="upload" type="file" accept=".obj" name="files">
<div>
<select id="selFile">
<option value="">select obj example</option>
<option value="models/teapot.obj">teapot.obj</option>
<!-- <option value="models/CornellBox-Original.obj">CornellBox-Original.obj</option> -->
<option value="models/bunny.obj">bunny.obj</option>
<option value="models/african_head.obj">african_head.obj</option>
<option value="models/WaltHead.obj">WaltHead.obj</option>
<option value="models/tree.obj">tree.obj</option>
<option value="models/scene.obj">scene.obj</option>
<option value="models/female02/female02.obj">female02.obj</option>
<option value="models/male02/male02.obj">male02.obj</option>
<option value="models/taxis_china_taxi.obj">taxis_china_taxi.obj</option>
<!-- <option value="models/sky-box.obj">sky-box.obj</option> -->
</select>
</div>
<ul id="texture-list">
</ul>
<div>
<a href="https://github.com/xiehuiqi220/smallrenderer" target="_blank">github source code</a>
</div>
</form>
<script>
let leftLoadFileCount = 0;
let cacheObjTxt = '';
let cacheMtlTxt = '';
const ABS_PATH = 'https://raw.githubusercontent.com/xiehuiqi220/smallrenderer/main/';
const REG_OBJ = /[\w-_]+\.obj$/g;
const REG_MTL = /[\w-_]+\.mtl$/g;
let lastRequestPath = '';
function $(id) {
return document.getElementById(id);
}
//传递obj文件数据给渲染器
function transferObj(txtObj, needFetchMtl) {
const scene = txtObj ? ObjParser(txtObj) : '';
scene.materialLibraries = scene.materialLibraries || [];
$("selFile").disabled = false;
const mtlPath = scene.materialLibraries[0];
if (needFetchMtl && mtlPath) {//若存在引用mtl文件,则请求mtl文件
lastRequestPath = lastRequestPath.replace(REG_OBJ, mtlPath);
fetch(lastRequestPath).then(r => r.text()).catch(ex => alert(ex)).then(txtMtl => {
let mtl = null;
try {
mtl = MtlParser(txtMtl);
} catch (ex) {
alert(ex);
throw ex;
return;
}
window.dispatchEvent(new CustomEvent('changeScene', { detail: { scene, mtl } }));
//遍历mtl下的材质,找到是否引用了图片
if (!mtl) return;
mtl.__imageData = {};
mtl.forEach(m => {
const imagePath = m.map_Kd.file;
if (!imagePath) return;
debugger
if (mtl.__imageData[imagePath]) return;//若图片数据已经存在,说明之前请求过了,则忽略
fetch(lastRequestPath.replace(REG_MTL, imagePath)).then(r => r.blob()).catch(ex => alert(ex)).then(blob => {
const imageObjectURL = URL.createObjectURL(blob);
const image = new Image();
image.src = imageObjectURL;
const li = document.createElement("li");
li.appendChild(document.createTextNode(imagePath));
const canvas = document.createElement("canvas");
image.onload = function () {
canvas.width = image.width;//canvas宽度和图片一致
canvas.height = image.height;
const txt = canvas.getContext('2d');
txt.drawImage(image, 0, 0);
const imageData = txt.getImageData(0, 0, image.width, image.height);
mtl.__imageData[imagePath] = imageData;
}
li.appendChild(canvas);
$("texture-list").appendChild(li);
});
});
});
} else {
window.dispatchEvent(new CustomEvent('changeScene', { detail: { scene, mtl: null } }));
}
}
//选择obj文件
function changeObj(evt) {
const path = evt.target.value;
if (!path) {
transferObj();
return;
}
lastRequestPath = ABS_PATH + path;
$("selFile").disabled = true;
fetch(lastRequestPath).then(r => r.text()).catch(ex => alert(ex)).then(txt => {
transferObj(txt,true);
});
}
function uploadFile(evt) {
const files = evt.target.files;
let f = files[0];
if (!f) return;
let reader = new FileReader();
reader.onload = function (e) {
const txt = e.target.result;
transferObj(txt,false);
};
reader.readAsText(f);
}
(function main() {
$('selFile').addEventListener('change', changeObj);
$('upload').addEventListener('change', uploadFile);
})();
</script>
<script src="src/index.js"></script>
</body>
</html>