我正在为自定义 JSON 格式(主要用于 WebGL)制作一个简单的 Blender 2.6x 导出器,因为我可以在网上找到的现有导出器不适用于 Blender 2.6。
我几乎让它工作了,但仍然有一个我无法弄清楚的错误。在一个简单的立方体上,其一侧的纹理方向错误。立方体的其余部分纹理正确。
您可以在此处看到问题的图片(与右侧的正确立方体相比,左侧的左侧面方向错误):
是否有一些常见的误解或错误可能导致这种行为发生?
这是从 Blender 2.65 导出到我的自定义 JSON 格式的函数(错误必须在这里,但我找不到它):
def get_json(objects, scene):
""" Currently only supports one scene.
Exports with -Z forward, Y up. """
object_number = -1
scene_data = []
# for every object in the scene
for object in bpy.context.scene.objects:
# if the object is a mesh
if object.type == 'MESH':
object_number += 1
# convert all the mesh's faces to triangles
bpy.ops.object.mode_set(mode='OBJECT')
object.select = True
bpy.context.scene.objects.active = object
# triangulate using new Blender 2.65 Triangulate modifier
bpy.ops.object.modifier_add(type='TRIANGULATE')
object.modifiers["Triangulate"].use_beauty = False
bpy.ops.object.modifier_apply(apply_as="DATA", modifier="Triangulate")
bpy.ops.object.mode_set(mode='OBJECT')
object.select = False
# add data to scene_data structure
scene_data.append({
"name" : object.name,
"vertices" : [],
"indices" : [],
"normals" : [],
"tex_coords" : []
})
vertex_number = -1
# for each face in the object
for face in object.data.polygons:
vertices_in_face = face.vertices[:]
# for each vertex in the face
for vertex in vertices_in_face:
vertex_number += 1
# store vertices in scene_data structure
scene_data[object_number]["vertices"].append( object.data.vertices[vertex].co.x + object.location.x )
scene_data[object_number]["vertices"].append( object.data.vertices[vertex].co.z + object.location.z )
scene_data[object_number]["vertices"].append( -(object.data.vertices[vertex].co.y + object.location.y) )
# store normals in scene_data structure
scene_data[object_number]["normals"].append( object.data.vertices[vertex].normal.x )
scene_data[object_number]["normals"].append( object.data.vertices[vertex].normal.z )
scene_data[object_number]["normals"].append( -(object.data.vertices[vertex].normal.y) )
# store indices in scene_data structure
scene_data[object_number]["indices"].append(vertex_number)
# texture coordinates
# bug: for a simple cube, one face's texture is warped
mesh = object.to_mesh(bpy.context.scene, True, 'PREVIEW')
if len(mesh.tessface_uv_textures) > 0:
for data in mesh.tessface_uv_textures.active.data:
scene_data[object_number]["tex_coords"].append( data.uv1.x )
scene_data[object_number]["tex_coords"].append( data.uv1.y )
scene_data[object_number]["tex_coords"].append( data.uv2.x )
scene_data[object_number]["tex_coords"].append( data.uv2.y )
scene_data[object_number]["tex_coords"].append( data.uv3.x )
scene_data[object_number]["tex_coords"].append( data.uv3.y )
return json.dumps(scene_data, indent=4)
如果这有助于弄清楚,这里是运行我的导出脚本产生的导出 JSON 数据(用于呈现上图中左侧多维数据集的相同数据):
[
{
"vertices": [
-1.0203653573989868,
1.0320179611444473,
0.669445663690567,
-1.0203653573989868,
1.0320179611444473,
-1.330554336309433,
-1.0203653573989868,
-0.9679820388555527,
0.669445663690567,
-1.0203653573989868,
1.0320179611444473,
-1.330554336309433,
0.9796346426010132,
1.0320179611444473,
-1.330554336309433,
-1.0203653573989868,
-0.9679820388555527,
-1.330554336309433,
0.9796346426010132,
1.0320179611444473,
-1.330554336309433,
0.9796346426010132,
1.0320179611444473,
0.669445663690567,
0.9796346426010132,
-0.9679820388555527,
-1.330554336309433,
0.9796346426010132,
1.0320179611444473,
0.669445663690567,
-1.0203653573989868,
1.0320179611444473,
0.669445663690567,
0.9796346426010132,
-0.9679820388555527,
0.669445663690567,
-1.0203653573989868,
-0.9679820388555527,
0.669445663690567,
-1.0203653573989868,
-0.9679820388555527,
-1.330554336309433,
0.9796346426010132,
-0.9679820388555527,
0.669445663690567,
0.9796346426010132,
1.0320179611444473,
0.669445663690567,
0.9796346426010132,
1.0320179611444473,
-1.330554336309433,
-1.0203653573989868,
1.0320179611444473,
0.669445663690567,
-1.0203653573989868,
1.0320179611444473,
-1.330554336309433,
-1.0203653573989868,
-0.9679820388555527,
-1.330554336309433,
-1.0203653573989868,
-0.9679820388555527,
0.669445663690567,
0.9796346426010132,
1.0320179611444473,
-1.330554336309433,
0.9796346426010132,
-0.9679820388555527,
-1.330554336309433,
-1.0203653573989868,
-0.9679820388555527,
-1.330554336309433,
0.9796346426010132,
1.0320179611444473,
0.669445663690567,
0.9796346426010132,
-0.9679820388555527,
0.669445663690567,
0.9796346426010132,
-0.9679820388555527,
-1.330554336309433,
-1.0203653573989868,
1.0320179611444473,
0.669445663690567,
-1.0203653573989868,
-0.9679820388555527,
0.669445663690567,
0.9796346426010132,
-0.9679820388555527,
0.669445663690567,
-1.0203653573989868,
-0.9679820388555527,
-1.330554336309433,
0.9796346426010132,
-0.9679820388555527,
-1.330554336309433,
0.9796346426010132,
-0.9679820388555527,
0.669445663690567,
0.9796346426010132,
1.0320179611444473,
-1.330554336309433,
-1.0203653573989868,
1.0320179611444473,
-1.330554336309433,
-1.0203653573989868,
1.0320179611444473,
0.669445663690567
],
"normals": [
-0.5773491859436035,
0.5773491859436035,
0.5773491859436035,
-0.5773491859436035,
0.5773491859436035,
-0.5773491859436035,
-0.5773491859436035,
-0.5773491859436035,
0.5773491859436035,
-0.5773491859436035,
0.5773491859436035,
-0.5773491859436035,
0.5773491859436035,
0.5773491859436035,
-0.5773491859436035,
-0.5773491859436035,
-0.5773491859436035,
-0.5773491859436035,
0.5773491859436035,
0.5773491859436035,
-0.5773491859436035,
0.5773491859436035,
0.5773491859436035,
0.5773491859436035,
0.5773491859436035,
-0.5773491859436035,
-0.5773491859436035,
0.5773491859436035,
0.5773491859436035,
0.5773491859436035,
-0.5773491859436035,
0.5773491859436035,
0.5773491859436035,
0.5773491859436035,
-0.5773491859436035,
0.5773491859436035,
-0.5773491859436035,
-0.5773491859436035,
0.5773491859436035,
-0.5773491859436035,
-0.5773491859436035,
-0.5773491859436035,
0.5773491859436035,
-0.5773491859436035,
0.5773491859436035,
0.5773491859436035,
0.5773491859436035,
0.5773491859436035,
0.5773491859436035,
0.5773491859436035,
-0.5773491859436035,
-0.5773491859436035,
0.5773491859436035,
0.5773491859436035,
-0.5773491859436035,
0.5773491859436035,
-0.5773491859436035,
-0.5773491859436035,
-0.5773491859436035,
-0.5773491859436035,
-0.5773491859436035,
-0.5773491859436035,
0.5773491859436035,
0.5773491859436035,
0.5773491859436035,
-0.5773491859436035,
0.5773491859436035,
-0.5773491859436035,
-0.5773491859436035,
-0.5773491859436035,
-0.5773491859436035,
-0.5773491859436035,
0.5773491859436035,
0.5773491859436035,
0.5773491859436035,
0.5773491859436035,
-0.5773491859436035,
0.5773491859436035,
0.5773491859436035,
-0.5773491859436035,
-0.5773491859436035,
-0.5773491859436035,
0.5773491859436035,
0.5773491859436035,
-0.5773491859436035,
-0.5773491859436035,
0.5773491859436035,
0.5773491859436035,
-0.5773491859436035,
0.5773491859436035,
-0.5773491859436035,
-0.5773491859436035,
-0.5773491859436035,
0.5773491859436035,
-0.5773491859436035,
-0.5773491859436035,
0.5773491859436035,
-0.5773491859436035,
0.5773491859436035,
0.5773491859436035,
0.5773491859436035,
-0.5773491859436035,
-0.5773491859436035,
0.5773491859436035,
-0.5773491859436035,
-0.5773491859436035,
0.5773491859436035,
0.5773491859436035
],
"indices": [
0,
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
],
"name": "Cube",
"tex_coords": [
0.008884529583156109,
0.6587533354759216,
0.3244488537311554,
0.3412468135356903,
0.32541996240615845,
0.657782256603241,
0.008884510956704617,
0.32541996240615845,
0.007913422770798206,
0.008884549140930176,
0.32541996240615845,
0.3244488537311554,
0.9920865893363953,
0.32444891333580017,
0.675551176071167,
0.32541996240615845,
0.9911155700683594,
0.00791349820792675,
0.3412467837333679,
0.008884538896381855,
0.6577821969985962,
0.007913422770798206,
0.34221789240837097,
0.32541996240615845,
0.6587532758712769,
0.6577821969985962,
0.3422178626060486,
0.6587533354759216,
0.6577821373939514,
0.3412468135356903,
0.6745801568031311,
0.34221789240837097,
0.9911155700683594,
0.3412468135356903,
0.6755512356758118,
0.6587533354759216,
0.007913460955023766,
0.34221789240837097,
0.3244488537311554,
0.3412468135356903,
0.008884529583156109,
0.6587533354759216,
0.007913422770798206,
0.008884549140930176,
0.324448823928833,
0.007913422770798206,
0.32541996240615845,
0.3244488537311554,
0.675551176071167,
0.32541996240615845,
0.6745801568031311,
0.008884529583156109,
0.9911155700683594,
0.00791349820792675,
0.6577821969985962,
0.007913422770798206,
0.6587533354759216,
0.3244488835334778,
0.34221789240837097,
0.32541996240615845,
0.3422178626060486,
0.6587533354759216,
0.3412467837333679,
0.34221789240837097,
0.6577821373939514,
0.3412468135356903,
0.9911155700683594,
0.3412468135356903,
0.99208664894104,
0.6577821969985962,
0.6755512356758118,
0.6587533354759216
]
}
]
我目前并没有寻找方法来制作更好的功能更丰富或更高效的导出器,而是我只想最终解决这个错误,以便我可以继续做更有趣的事情,比如制作 WebGL 游戏,并了解碰撞检测等。对于我遇到的这个问题的任何帮助或建议将不胜感激!
编辑:
万一这可能是我的渲染代码,而不是问题的导出器,这里是我的 WebGL 代码中与初始化缓冲区和绘制场景相关的部分(在http://learningwebgl.com找到的一些代码的修改版本):
var gl;
var current_shader_program;
var per_vertex_shader_program;
var per_fragment_shader_program;
var modelview_matrix = mat4.create();
var modelview_matrix_stack = [];
var projection_matrix = mat4.create();
var teapot_vertex_position_buffer = new Array();
var teapot_vertex_tex_coord_buffer = new Array();
var teapot_vertex_normal_buffer = new Array();
var teapot_vertex_index_buffer = new Array();
var earth_texture;
var galvanized_texture;
var teapot_angle = 180;
var last_time = 0;
function createProgram(vertex_shader_filename, fragment_shader_filename) {
var vertex_shader_text = readFromUrl(vertex_shader_filename);
var fragment_shader_text = readFromUrl(fragment_shader_filename);
var vertex_shader = gl.createShader(gl.VERTEX_SHADER);
var fragment_shader = gl.createShader(gl.FRAGMENT_SHADER);
gl.shaderSource(vertex_shader, vertex_shader_text);
gl.shaderSource(fragment_shader, fragment_shader_text);
gl.compileShader(vertex_shader);
if (!gl.getShaderParameter(vertex_shader, gl.COMPILE_STATUS)) {
alert(gl.getShaderInfoLog(vertex_shader));
}
gl.compileShader(fragment_shader);
if (!gl.getShaderParameter(fragment_shader, gl.COMPILE_STATUS)) {
alert(gl.getShaderInfoLog(fragment_shader));
}
var shader_program = gl.createProgram();
gl.attachShader(shader_program, vertex_shader);
gl.attachShader(shader_program, fragment_shader);
gl.linkProgram(shader_program);
if (!gl.getProgramParameter(shader_program, gl.LINK_STATUS)) {
alert("Error: Unable to link shaders!");
}
shader_program.vertex_position_attribute =
gl.getAttribLocation(shader_program, "a_vertex_position");
gl.enableVertexAttribArray(shader_program.vertex_position_attribute);
shader_program.vertex_normal_attribute =
gl.getAttribLocation(shader_program, "a_vertex_normal");
gl.enableVertexAttribArray(shader_program.vertex_normal_attribute);
shader_program.tex_coord_attribute =
gl.getAttribLocation(shader_program, "a_tex_coord");
gl.enableVertexAttribArray(shader_program.tex_coord_attribute);
shader_program.projection_matrix_uniform =
gl.getUniformLocation(shader_program, "u_projection_matrix");
shader_program.modelview_matrix_uniform =
gl.getUniformLocation(shader_program, "u_modelview_matrix");
shader_program.normal_matrix_uniform =
gl.getUniformLocation(shader_program, "u_normal_matrix");
shader_program.sampler_uniform =
gl.getUniformLocation(shader_program, "u_sampler");
shader_program.material_shininess_uniform =
gl.getUniformLocation(shader_program, "u_material_shininess");
shader_program.show_specular_highlights_uniform =
gl.getUniformLocation(shader_program, "u_show_specular_highlights");
shader_program.use_textures_uniform =
gl.getUniformLocation(shader_program, "u_use_textures");
shader_program.use_lighting_uniform =
gl.getUniformLocation(shader_program, "u_use_lighting");
shader_program.ambient_color_uniform =
gl.getUniformLocation(shader_program, "u_ambient_color");
shader_program.point_lighting_location_uniform =
gl.getUniformLocation(shader_program, "u_point_lighting_location");
shader_program.point_lighting_specular_color_uniform =
gl.getUniformLocation(shader_program, "u_point_lighting_specular_color");
shader_program.point_lighting_diffuse_color_uniform =
gl.getUniformLocation(shader_program, "u_point_lighting_diffuse_color");
return shader_program;
}
function initShaders() {
per_fragment_shader_program = createProgram("per_fragment_lighting.vs", "per_fragment_lighting.fs");
}
function handleLoadedTexture(texture) {
gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, true);
gl.bindTexture(gl.TEXTURE_2D, texture);
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE,
texture.image);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR_MIPMAP_NEAREST);
gl.generateMipmap(gl.TEXTURE_2D);
gl.bindTexture(gl.TEXTURE_2D, null);
}
function initTextures() {
earth_texture = gl.createTexture();
earth_texture.image = new Image();
earth_texture.image.onload = function() {
handleLoadedTexture(earth_texture);
}
earth_texture.image.src = "earth.jpg";
galvanized_texture = gl.createTexture();
galvanized_texture.image = new Image();
galvanized_texture.image.onload = function() {
handleLoadedTexture(galvanized_texture);
};
galvanized_texture.image.src = "galvanized.jpg";
}
function setMatrixUniforms() {
gl.uniformMatrix4fv(current_shader_program.projection_matrix_uniform, false,
projection_matrix);
gl.uniformMatrix4fv(current_shader_program.modelview_matrix_uniform, false,
modelview_matrix);
var normal_matrix = mat3.create();
mat4.toInverseMat3(modelview_matrix, normal_matrix);
mat3.transpose(normal_matrix);
gl.uniformMatrix3fv(current_shader_program.normal_matrix_uniform, false,
normal_matrix);
}
function handleLoadedTeapot(teapot_data) {
for (var i = 0; i < teapot_data.length; i++)
{
teapot_vertex_normal_buffer[i] = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, teapot_vertex_normal_buffer[i]);
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(teapot_data[i].normals),
gl.STATIC_DRAW);
teapot_vertex_normal_buffer[i].item_size = 3;
teapot_vertex_normal_buffer[i].num_items =
teapot_data[i].normals.length / teapot_vertex_normal_buffer[i].item_size;
teapot_vertex_tex_coord_buffer[i] = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, teapot_vertex_tex_coord_buffer[i]);
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(teapot_data[i].tex_coords),
gl.STATIC_DRAW);
teapot_vertex_tex_coord_buffer[i].item_size = 2;
teapot_vertex_tex_coord_buffer[i].num_items =
teapot_data[i].tex_coords.length / teapot_vertex_tex_coord_buffer[i].item_size;
teapot_vertex_position_buffer[i] = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, teapot_vertex_position_buffer[i]);
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(teapot_data[i].vertices),
gl.STATIC_DRAW);
teapot_vertex_position_buffer[i].item_size = 3;
teapot_vertex_position_buffer[i].num_items =
teapot_data[i].vertices.length / teapot_vertex_position_buffer[i].item_size;
teapot_vertex_index_buffer[i] = gl.createBuffer();
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, teapot_vertex_index_buffer[i]);
gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, new Uint16Array(teapot_data[i].indices),
gl.STATIC_DRAW)
teapot_vertex_index_buffer[i].item_size = 1;
teapot_vertex_index_buffer[i].num_items =
teapot_data[i].indices.length / teapot_vertex_index_buffer[i].item_size;
}
document.getElementById("loading_text").textContent = "";
}
function loadTeapot() {
var request = new XMLHttpRequest();
request.open("GET", "untitled.json");
request.onreadystatechange = function() {
if (request.readyState == 4) {
handleLoadedTeapot(JSON.parse(request.responseText));
}
};
request.send();
}
function drawScene() {
gl.viewport(0, 0, gl.viewportWidth, gl.viewportHeight);
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
if (teapot_vertex_position_buffer[0] == null ||
teapot_vertex_normal_buffer[0] == null ||
teapot_vertex_tex_coord_buffer[0] == null ||
teapot_vertex_index_buffer[0] == null) {
return;
}
current_shader_program = per_fragment_shader_program;
gl.useProgram(current_shader_program);
var specular_highlights = document.getElementById("specular").checked;
gl.uniform1i(current_shader_program.show_specular_highlights_uniform, specular_highlights);
var lighting = document.getElementById("lighting").checked;
gl.uniform1i(current_shader_program.use_lighting_uniform, lighting);
if (lighting) {
gl.uniform3f(current_shader_program.ambient_color_uniform,
parseFloat(document.getElementById("ambient_r").value),
parseFloat(document.getElementById("ambient_g").value),
parseFloat(document.getElementById("ambient_b").value));
gl.uniform3f(current_shader_program.point_lighting_location_uniform,
parseFloat(document.getElementById("light_pos_x").value),
parseFloat(document.getElementById("light_pos_y").value),
parseFloat(document.getElementById("light_pos_z").value));
gl.uniform3f(current_shader_program.point_lighting_specular_color_uniform,
parseFloat(document.getElementById("specular_r").value),
parseFloat(document.getElementById("specular_g").value),
parseFloat(document.getElementById("specular_b").value));
gl.uniform3f(current_shader_program.point_lighting_diffuse_color_uniform,
parseFloat(document.getElementById("diffuse_r").value),
parseFloat(document.getElementById("diffuse_g").value),
parseFloat(document.getElementById("diffuse_b").value));
}
var texture = document.getElementById("texture").value;
gl.uniform1i(current_shader_program.use_textures_uniform, texture != "none");
mat4.identity(modelview_matrix);
mat4.translate(modelview_matrix, [0, 0, -10]);
mat4.rotate(modelview_matrix, degToRad(23.4), [1, 0, 0]);
mat4.rotate(modelview_matrix, degToRad(teapot_angle), [0, 1, 0]);
gl.activeTexture(gl.TEXTURE0);
if (texture == "earth") {
gl.bindTexture(gl.TEXTURE_2D, earth_texture);
}
else if (texture == "galvanized") {
gl.bindTexture(gl.TEXTURE_2D, galvanized_texture);
}
gl.uniform1i(current_shader_program.sampler_uniform, 0);
gl.uniform1f(current_shader_program.material_shininess_uniform,
parseFloat(document.getElementById("shininess").value));
for (var i = 0; i < teapot_vertex_position_buffer.length; i++)
{
gl.bindBuffer(gl.ARRAY_BUFFER, teapot_vertex_position_buffer[i]);
gl.vertexAttribPointer(current_shader_program.vertex_position_attribute,
teapot_vertex_position_buffer[i].item_size, gl.FLOAT, false, 0, 0);
gl.bindBuffer(gl.ARRAY_BUFFER, teapot_vertex_tex_coord_buffer[i]);
gl.vertexAttribPointer(current_shader_program.tex_coord_attribute,
teapot_vertex_tex_coord_buffer[i].item_size, gl.FLOAT, false, 0, 0);
gl.bindBuffer(gl.ARRAY_BUFFER, teapot_vertex_normal_buffer[i]);
gl.vertexAttribPointer(current_shader_program.vertex_normal_attribute,
teapot_vertex_normal_buffer[i].item_size, gl.FLOAT, false, 0, 0);
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, teapot_vertex_index_buffer[i]);
setMatrixUniforms();
gl.drawElements(gl.TRIANGLES, teapot_vertex_index_buffer[i].num_items,
gl.UNSIGNED_SHORT, 0);
}
}
我知道要查看的内容太多了,这就是为什么我之前没有发布它,但是有人建议渲染代码可能有问题。请注意,代码中提到的“茶壶”实际上是导出的模型(我要渲染的立方体)。