Merge pull request #12738 from super626/v3.7-release

Update tiny obj loader and fix empty textrue
This commit is contained in:
pandamicro 2015-07-09 14:57:10 +08:00
commit a2da5d5f9d
5 changed files with 1012 additions and 834 deletions

View File

@ -216,73 +216,24 @@ bool Bundle3D::loadObj(MeshDatas& meshdatas, MaterialDatas& materialdatas, NodeD
else
mtlPath = fullPath.substr(0, fullPath.find_last_of("\\/") + 1).c_str();
ObjLoader::shapes_t shapes;
auto ret = ObjLoader::LoadObj(shapes, fullPath.c_str(), mtlPath.c_str());
std::vector<tinyobj::shape_t> shapes;
std::vector<tinyobj::material_t> materials;
auto ret = tinyobj::LoadObj(shapes, materials, fullPath.c_str(), mtlPath.c_str());
if (ret.empty())
{
//fill data
MeshData* meshdata = new (std::nothrow) MeshData();
MeshVertexAttrib attrib;
attrib.size = 3;
attrib.type = GL_FLOAT;
if (shapes.positions.size())
{
attrib.vertexAttrib = GLProgram::VERTEX_ATTRIB_POSITION;
attrib.attribSizeBytes = attrib.size * sizeof(float);
meshdata->attribs.push_back(attrib);
}
bool hasnormal = false, hastex = false;
if (shapes.normals.size())
{
hasnormal = true;
attrib.vertexAttrib = GLProgram::VERTEX_ATTRIB_NORMAL;
attrib.attribSizeBytes = attrib.size * sizeof(float);;
meshdata->attribs.push_back(attrib);
}
if (shapes.texcoords.size())
{
hastex = true;
attrib.size = 2;
attrib.vertexAttrib = GLProgram::VERTEX_ATTRIB_TEX_COORD;
attrib.attribSizeBytes = attrib.size * sizeof(float);
meshdata->attribs.push_back(attrib);
}
auto vertexNum = shapes.positions.size() / 3;
for(unsigned int i = 0; i < vertexNum; i++)
{
meshdata->vertex.push_back(shapes.positions[i * 3]);
meshdata->vertex.push_back(shapes.positions[i * 3 + 1]);
meshdata->vertex.push_back(shapes.positions[i * 3 + 2]);
if (hasnormal)
{
meshdata->vertex.push_back(shapes.normals[i * 3]);
meshdata->vertex.push_back(shapes.normals[i * 3 + 1]);
meshdata->vertex.push_back(shapes.normals[i * 3 + 2]);
}
if (hastex)
{
meshdata->vertex.push_back(shapes.texcoords[i * 2]);
meshdata->vertex.push_back(shapes.texcoords[i * 2 + 1]);
}
}
meshdatas.meshDatas.push_back(meshdata);
//convert material
int i = 0;
char str[20];
std::string dir = "";
auto last = fullPath.rfind("/");
if (last != -1)
dir = fullPath.substr(0, last + 1);
for (const auto& it : shapes.shapes)
{
for (auto& material : materials) {
NMaterialData materialdata;
NTextureData tex;
tex.filename = it.material.diffuse_texname.empty() ? it.material.diffuse_texname : dir + it.material.diffuse_texname;
tex.filename = material.diffuse_texname.empty() ? material.diffuse_texname : dir + material.diffuse_texname;
tex.type = NTextureData::Usage::Diffuse;
tex.wrapS = GL_CLAMP_TO_EDGE;
tex.wrapT = GL_CLAMP_TO_EDGE;
@ -290,19 +241,91 @@ bool Bundle3D::loadObj(MeshDatas& meshdatas, MaterialDatas& materialdatas, NodeD
sprintf(str, "%d", i++);
materialdata.textures.push_back(tex);
materialdata.id = str;
material.name = str;
materialdatas.materials.push_back(materialdata);
meshdata->subMeshIndices.push_back(it.mesh.indices);
meshdata->subMeshAABB.push_back(calculateAABB(meshdata->vertex, meshdata->getPerVertexSize(), it.mesh.indices));
meshdata->subMeshIds.push_back(str);
auto node = new (std::nothrow) NodeData();
auto modelnode = new (std::nothrow) ModelData();
modelnode->matrialId = str;
modelnode->subMeshId = str;
node->id = it.name;
node->modelNodeDatas.push_back(modelnode);
nodedatas.nodes.push_back(node);
}
//convert mesh
i = 0;
for (auto& shape : shapes) {
auto mesh = shape.mesh;
MeshData* meshdata = new (std::nothrow) MeshData();
MeshVertexAttrib attrib;
attrib.size = 3;
attrib.type = GL_FLOAT;
if (mesh.positions.size())
{
attrib.vertexAttrib = GLProgram::VERTEX_ATTRIB_POSITION;
attrib.attribSizeBytes = attrib.size * sizeof(float);
meshdata->attribs.push_back(attrib);
}
bool hasnormal = false, hastex = false;
if (mesh.normals.size())
{
hasnormal = true;
attrib.vertexAttrib = GLProgram::VERTEX_ATTRIB_NORMAL;
attrib.attribSizeBytes = attrib.size * sizeof(float);;
meshdata->attribs.push_back(attrib);
}
if (mesh.texcoords.size())
{
hastex = true;
attrib.size = 2;
attrib.vertexAttrib = GLProgram::VERTEX_ATTRIB_TEX_COORD;
attrib.attribSizeBytes = attrib.size * sizeof(float);
meshdata->attribs.push_back(attrib);
}
auto vertexNum = mesh.positions.size() / 3;
for(unsigned int k = 0; k < vertexNum; k++)
{
meshdata->vertex.push_back(mesh.positions[k * 3]);
meshdata->vertex.push_back(mesh.positions[k * 3 + 1]);
meshdata->vertex.push_back(mesh.positions[k * 3 + 2]);
if (hasnormal)
{
meshdata->vertex.push_back(mesh.normals[k * 3]);
meshdata->vertex.push_back(mesh.normals[k * 3 + 1]);
meshdata->vertex.push_back(mesh.normals[k * 3 + 2]);
}
if (hastex)
{
meshdata->vertex.push_back(mesh.texcoords[k * 2]);
meshdata->vertex.push_back(mesh.texcoords[k * 2 + 1]);
}
}
//split into submesh according to material
std::map<int, std::vector<unsigned short> > subMeshMap;
for (size_t k = 0; k < mesh.material_ids.size(); k++) {
int id = mesh.material_ids[k];
size_t idx = k * 3;
subMeshMap[id].push_back(mesh.indices[idx]);
subMeshMap[id].push_back(mesh.indices[idx + 1]);
subMeshMap[id].push_back(mesh.indices[idx + 2]);
}
auto node = new (std::nothrow) NodeData();
node->id = shape.name;
for (auto& submesh : subMeshMap) {
meshdata->subMeshIndices.push_back(submesh.second);
meshdata->subMeshAABB.push_back(calculateAABB(meshdata->vertex, meshdata->getPerVertexSize(), submesh.second));
sprintf(str, "%d", i++);
meshdata->subMeshIds.push_back(str);
auto modelnode = new (std::nothrow) ModelData();
modelnode->matrialId = submesh.first == -1 ? "" : materials[submesh.first].name;
modelnode->subMeshId = str;
node->modelNodeDatas.push_back(modelnode);
}
nodedatas.nodes.push_back(node);
meshdatas.meshDatas.push_back(meshdata);
}
return true;
}
CCLOG("warning: load %s file error: %s", fullPath.c_str(), ret.c_str());

View File

@ -273,6 +273,9 @@ void Mesh::setTexture(Texture2D* tex)
// Texture must be saved for future use
// it doesn't matter if the material is already set or not
// This functionality is added for compatibility issues
if (tex == nullptr)
tex = getDummyTexture();
if (tex != _texture)
{
CC_SAFE_RETAIN(tex);

File diff suppressed because it is too large Load Diff

View File

@ -1,40 +1,19 @@
//
// Copyright 2012-2013, Syoyo Fujita.
// Copyright 2012-2015, Syoyo Fujita.
//
// Licensed under 2-clause BSD liecense.
//
// copied from Syoyo Fujita
// https://github.com/syoyo/tinyobjloader
#ifndef __CCOBJLOADER_H__
#define __CCOBJLOADER_H__
//https://github.com/syoyo/tinyobjloader
#ifndef _TINY_OBJ_LOADER_H
#define _TINY_OBJ_LOADER_H
#include <string>
#include <vector>
#include <map>
#include "base/ccTypes.h"
NS_CC_BEGIN
/**
* @addtogroup _3d
* @{
*/
/**
* @brief .obj file Loader
* @js NA
* @lua NA
**/
class ObjLoader
{
public:
/**
* model's material struct
**/
typedef struct
{
namespace tinyobj {
typedef struct {
std::string name;
float ambient[3];
@ -43,8 +22,8 @@ public:
float transmittance[3];
float emission[3];
float shininess;
float ior; // index of refraction
float dissolve; // 1 == opaque; 0 == fully transparent
float ior; // index of refraction
float dissolve; // 1 == opaque; 0 == fully transparent
// illumination model (see http://www.fileformat.info/format/material/)
int illum;
@ -55,61 +34,62 @@ public:
std::map<std::string, std::string> unknown_parameter;
} material_t;
/**
* model's indices struct
**/
typedef struct
{
std::vector<unsigned short> indices;
typedef struct {
std::vector<float> positions;
std::vector<float> normals;
std::vector<float> texcoords;
std::vector<unsigned short> indices;
std::vector<int> material_ids; // per-mesh material ID
} mesh_t;
/**
* model's shape struct
**/
typedef struct
{
std::string name;
material_t material;
mesh_t mesh;
typedef struct {
std::string name;
mesh_t mesh;
} shape_t;
/**
* model's shapes struct
**/
typedef struct
{
std::vector<float> positions;
std::vector<float> normals;
std::vector<float> texcoords;
class MaterialReader {
public:
MaterialReader() {}
virtual ~MaterialReader() {}
std::vector<shape_t> shapes;
void reset()
{
positions.clear();
normals.clear();
texcoords.clear();
shapes.clear();
}
}shapes_t;
virtual std::string operator()(const std::string &matId,
std::vector<material_t> &materials,
std::map<std::string, int> &matMap) = 0;
};
/**
* Loads .obj from a file.
* @param shapes will be filled with parsed shape data
* @param filename the .obj file path .
* @param mtl_basepath It's optional, and used for base path for .mtl file
* @return The function returns error string, return empty string when loading .obj success.
*/
static std::string LoadObj(
shapes_t& shapes, // [output]
const char* filename,
const char* mtl_basepath = NULL);
class MaterialFileReader : public MaterialReader {
public:
MaterialFileReader(const std::string &mtl_basepath)
: m_mtlBasePath(mtl_basepath) {}
virtual ~MaterialFileReader() {}
virtual std::string operator()(const std::string &matId,
std::vector<material_t> &materials,
std::map<std::string, int> &matMap);
private:
std::string m_mtlBasePath;
};
/// Loads .obj from a file.
/// 'shapes' will be filled with parsed shape data
/// The function returns error string.
/// Returns empty string when loading .obj success.
/// 'mtl_basepath' is optional, and used for base path for .mtl file.
std::string LoadObj(std::vector<shape_t> &shapes, // [output]
std::vector<material_t> &materials, // [output]
const char *filename, const char *mtl_basepath = NULL);
/// Loads object from a std::istream, uses GetMtlIStreamFn to retrieve
/// std::istream for materials.
/// Returns empty string when loading .obj success.
std::string LoadObj(std::vector<shape_t> &shapes, // [output]
std::vector<material_t> &materials, // [output]
std::istream &inStream, MaterialReader &readMatFn);
/// Loads materials into std::map
/// Returns an empty string if successful
std::string LoadMtl(std::map<std::string, int> &material_map,
std::vector<material_t> &materials, std::istream &inStream);
}
};
// end of 3d group
/// @}
NS_CC_END
#endif // _TINY_OBJ_LOADER_H
#endif // _TINY_OBJ_LOADER_H

View File

@ -352,8 +352,7 @@ Sprite3D* Sprite3D::createSprite3DNode(NodeData* nodedata,ModelData* modeldata,c
if (modeldata->matrialId == "" && materialdatas.materials.size())
{
const NTextureData* textureData = materialdatas.materials[0].getTextureData(NTextureData::Usage::Diffuse);
if (!textureData->filename.empty())
mesh->setTexture(textureData->filename);
mesh->setTexture(textureData->filename);
}
else
{
@ -361,9 +360,10 @@ Sprite3D* Sprite3D::createSprite3DNode(NodeData* nodedata,ModelData* modeldata,c
if(materialData)
{
const NTextureData* textureData = materialData->getTextureData(NTextureData::Usage::Diffuse);
if(textureData && !textureData->filename.empty())
if(textureData)
{
auto tex = Director::getInstance()->getTextureCache()->addImage(textureData->filename);
mesh->setTexture(textureData->filename);
auto tex = mesh->getTexture();
if(tex)
{
Texture2D::TexParams texParams;
@ -372,10 +372,8 @@ Sprite3D* Sprite3D::createSprite3DNode(NodeData* nodedata,ModelData* modeldata,c
texParams.wrapS = textureData->wrapS;
texParams.wrapT = textureData->wrapT;
tex->setTexParameters(texParams);
mesh->setTexture(tex);
mesh->_isTransparent = (materialData->getTextureData(NTextureData::Usage::Transparency) != nullptr);
}
}
}
}
@ -506,9 +504,10 @@ void Sprite3D::createNode(NodeData* nodedata, Node* root, const MaterialDatas& m
if(materialData)
{
const NTextureData* textureData = materialData->getTextureData(NTextureData::Usage::Diffuse);
if(textureData && !textureData->filename.empty())
if(textureData)
{
auto tex = Director::getInstance()->getTextureCache()->addImage(textureData->filename);
mesh->setTexture(textureData->filename);
auto tex = mesh->getTexture();
if(tex)
{
Texture2D::TexParams texParams;
@ -517,10 +516,8 @@ void Sprite3D::createNode(NodeData* nodedata, Node* root, const MaterialDatas& m
texParams.wrapS = textureData->wrapS;
texParams.wrapT = textureData->wrapT;
tex->setTexParameters(texParams);
mesh->setTexture(tex);
mesh->_isTransparent = (materialData->getTextureData(NTextureData::Usage::Transparency) != nullptr);
}
}
}
}