diff --git a/Editor/ModelImporter_GLTF.cpp b/Editor/ModelImporter_GLTF.cpp index e63b07634..11404fb68 100644 --- a/Editor/ModelImporter_GLTF.cpp +++ b/Editor/ModelImporter_GLTF.cpp @@ -504,6 +504,13 @@ Entity ImportModel_GLTF(const std::string& fileName) } + if (state.materialArray.empty()) + { + Entity materialEntity = scene.Entity_CreateMaterial("GLTFImport_defaultMaterial"); + model.materials.insert(materialEntity); + state.materialArray.push_back(materialEntity); + } + // Create meshes: for (auto& x : state.gltfModel.meshes) { @@ -525,44 +532,45 @@ Entity ImportModel_GLTF(const std::string& fileName) const tinygltf::Buffer& buffer = state.gltfModel.buffers[bufferView.buffer]; int stride = accessor.ByteStride(bufferView); - size_t count = accessor.count; - size_t offset = mesh.indices.size(); - mesh.indices.resize(offset + count); - - assert(prim.material >= 0); + size_t indexCount = accessor.count; + size_t indexOffset = mesh.indices.size(); + mesh.indices.resize(indexOffset + indexCount); mesh.subsets.push_back(MeshComponent::MeshSubset()); - mesh.subsets.back().materialID = state.materialArray[prim.material]; - mesh.subsets.back().indexOffset = (uint32_t)offset; - mesh.subsets.back().indexCount = (uint32_t)count; + mesh.subsets.back().indexOffset = (uint32_t)indexOffset; + mesh.subsets.back().indexCount = (uint32_t)indexCount; + + mesh.subsets.back().materialID = state.materialArray[max(0, prim.material)]; + + uint32_t vertexOffset = (uint32_t)mesh.vertex_positions.size(); const unsigned char* data = buffer.data.data() + accessor.byteOffset + bufferView.byteOffset; if (stride == 1) { - for (size_t i = 0; i < count; i += 3) + for (size_t i = 0; i < indexCount; i += 3) { - mesh.indices[offset + i + 0] = data[i + 0]; - mesh.indices[offset + i + 1] = data[i + 1]; - mesh.indices[offset + i + 2] = data[i + 2]; + mesh.indices[indexOffset + i + 0] = vertexOffset + data[i + 0]; + mesh.indices[indexOffset + i + 1] = vertexOffset + data[i + 1]; + mesh.indices[indexOffset + i + 2] = vertexOffset + data[i + 2]; } } else if (stride == 2) { - for (size_t i = 0; i < count; i += 3) + for (size_t i = 0; i < indexCount; i += 3) { - mesh.indices[offset + i + 0] = ((uint16_t*)data)[i + 0]; - mesh.indices[offset + i + 1] = ((uint16_t*)data)[i + 1]; - mesh.indices[offset + i + 2] = ((uint16_t*)data)[i + 2]; + mesh.indices[indexOffset + i + 0] = vertexOffset + ((uint16_t*)data)[i + 0]; + mesh.indices[indexOffset + i + 1] = vertexOffset + ((uint16_t*)data)[i + 1]; + mesh.indices[indexOffset + i + 2] = vertexOffset + ((uint16_t*)data)[i + 2]; } } else if (stride == 4) { - for (size_t i = 0; i < count; i += 3) + for (size_t i = 0; i < indexCount; i += 3) { - mesh.indices[offset + i + 0] = ((uint32_t*)data)[i + 0]; - mesh.indices[offset + i + 1] = ((uint32_t*)data)[i + 1]; - mesh.indices[offset + i + 2] = ((uint32_t*)data)[i + 2]; + mesh.indices[indexOffset + i + 0] = vertexOffset + ((uint32_t*)data)[i + 0]; + mesh.indices[indexOffset + i + 1] = vertexOffset + ((uint32_t*)data)[i + 1]; + mesh.indices[indexOffset + i + 2] = vertexOffset + ((uint32_t*)data)[i + 2]; } } else @@ -580,47 +588,43 @@ Entity ImportModel_GLTF(const std::string& fileName) const tinygltf::Buffer& buffer = state.gltfModel.buffers[bufferView.buffer]; int stride = accessor.ByteStride(bufferView); - size_t count = accessor.count; + size_t vertexCount = accessor.count; const unsigned char* data = buffer.data.data() + accessor.byteOffset + bufferView.byteOffset; if (!attr_name.compare("POSITION")) { - size_t offset = mesh.vertex_positions.size(); - mesh.vertex_positions.resize(mesh.vertex_positions.size() + count); + mesh.vertex_positions.resize(vertexOffset + vertexCount); assert(stride == 12); - for (size_t i = 0; i < count; ++i) + for (size_t i = 0; i < vertexCount; ++i) { - mesh.vertex_positions[offset + i] = ((XMFLOAT3*)data)[i]; + mesh.vertex_positions[vertexOffset + i] = ((XMFLOAT3*)data)[i]; } } else if (!attr_name.compare("NORMAL")) { - size_t offset = mesh.vertex_normals.size(); - mesh.vertex_normals.resize(mesh.vertex_normals.size() + count); + mesh.vertex_normals.resize(vertexOffset + vertexCount); assert(stride == 12); - for (size_t i = 0; i < count; ++i) + for (size_t i = 0; i < vertexCount; ++i) { - mesh.vertex_normals[offset + i] = ((XMFLOAT3*)data)[i]; + mesh.vertex_normals[vertexOffset + i] = ((XMFLOAT3*)data)[i]; } } else if (!attr_name.compare("TEXCOORD_0")) { - size_t offset = mesh.vertex_texcoords.size(); - mesh.vertex_texcoords.resize(mesh.vertex_texcoords.size() + count); + mesh.vertex_texcoords.resize(vertexOffset + vertexCount); assert(stride == 8); - for (size_t i = 0; i < count; ++i) + for (size_t i = 0; i < vertexCount; ++i) { const XMFLOAT2& tex = ((XMFLOAT2*)data)[i]; - mesh.vertex_texcoords[offset + i].x = tex.x; - mesh.vertex_texcoords[offset + i].y = tex.y; + mesh.vertex_texcoords[vertexOffset + i].x = tex.x; + mesh.vertex_texcoords[vertexOffset + i].y = tex.y; } } else if (!attr_name.compare("JOINTS_0")) { - size_t offset = mesh.vertex_boneindices.size(); - mesh.vertex_boneindices.resize(mesh.vertex_boneindices.size() + count); + mesh.vertex_boneindices.resize(vertexOffset + vertexCount); if (stride == 4) { struct JointTmp @@ -628,14 +632,14 @@ Entity ImportModel_GLTF(const std::string& fileName) uint8_t ind[4]; }; - for (size_t i = 0; i < count; ++i) + for (size_t i = 0; i < vertexCount; ++i) { const JointTmp& joint = ((JointTmp*)data)[i]; - mesh.vertex_boneindices[offset + i].x = joint.ind[0]; - mesh.vertex_boneindices[offset + i].y = joint.ind[1]; - mesh.vertex_boneindices[offset + i].z = joint.ind[2]; - mesh.vertex_boneindices[offset + i].w = joint.ind[3]; + mesh.vertex_boneindices[vertexOffset + i].x = joint.ind[0]; + mesh.vertex_boneindices[vertexOffset + i].y = joint.ind[1]; + mesh.vertex_boneindices[vertexOffset + i].z = joint.ind[2]; + mesh.vertex_boneindices[vertexOffset + i].w = joint.ind[3]; } } else if (stride == 8) @@ -645,14 +649,14 @@ Entity ImportModel_GLTF(const std::string& fileName) uint16_t ind[4]; }; - for (size_t i = 0; i < count; ++i) + for (size_t i = 0; i < vertexCount; ++i) { const JointTmp& joint = ((JointTmp*)data)[i]; - mesh.vertex_boneindices[offset + i].x = joint.ind[0]; - mesh.vertex_boneindices[offset + i].y = joint.ind[1]; - mesh.vertex_boneindices[offset + i].z = joint.ind[2]; - mesh.vertex_boneindices[offset + i].w = joint.ind[3]; + mesh.vertex_boneindices[vertexOffset + i].x = joint.ind[0]; + mesh.vertex_boneindices[vertexOffset + i].y = joint.ind[1]; + mesh.vertex_boneindices[vertexOffset + i].z = joint.ind[2]; + mesh.vertex_boneindices[vertexOffset + i].w = joint.ind[3]; } } else @@ -662,12 +666,11 @@ Entity ImportModel_GLTF(const std::string& fileName) } else if (!attr_name.compare("WEIGHTS_0")) { - size_t offset = mesh.vertex_boneweights.size(); - mesh.vertex_boneweights.resize(mesh.vertex_boneweights.size() + count); + mesh.vertex_boneweights.resize(vertexOffset + vertexCount); assert(stride == 16); - for (size_t i = 0; i < count; ++i) + for (size_t i = 0; i < vertexCount; ++i) { - mesh.vertex_boneweights[offset + i] = ((XMFLOAT4*)data)[i]; + mesh.vertex_boneweights[vertexOffset + i] = ((XMFLOAT4*)data)[i]; } } @@ -714,7 +717,7 @@ Entity ImportModel_GLTF(const std::string& fileName) } // Create transform hierarchy, assign objects, meshes, armatures, cameras: - const tinygltf::Scene &gltfScene = state.gltfModel.scenes[state.gltfModel.defaultScene]; + const tinygltf::Scene &gltfScene = state.gltfModel.scenes[max(0, state.gltfModel.defaultScene)]; for (size_t i = 0; i < gltfScene.nodes.size(); i++) { LoadNode(&state.gltfModel.nodes[gltfScene.nodes[i]], state.modelEntity, state); @@ -775,21 +778,12 @@ Entity ImportModel_GLTF(const std::string& fileName) assert(stride == 4); - float start = FLT_MAX; - float end = 0.0f; + animationcomponent.length = 0.0f; for (size_t i = 0; i < count; ++i) { float time = ((float*)data)[i]; animationcomponent.channels.back().keyframe_times[i] = time; - start = min(start, time); - end = max(end, time); - } - - // Cut empty animation from beginning: - animationcomponent.length = end - start; - for (auto& time : animationcomponent.channels.back().keyframe_times) - { - time -= start; + animationcomponent.length = max(animationcomponent.length, time); } } diff --git a/WickedEngine/wiRenderer.cpp b/WickedEngine/wiRenderer.cpp index b8a735aac..7933ada53 100644 --- a/WickedEngine/wiRenderer.cpp +++ b/WickedEngine/wiRenderer.cpp @@ -7843,10 +7843,6 @@ wiRenderer::RayIntersectWorldResult wiRenderer::RayIntersectWorld(const RAY& ray const XMVECTOR rayOrigin = XMLoadFloat3(&ray.origin); const XMVECTOR rayDirection = XMVector3Normalize(XMLoadFloat3(&ray.direction)); - // pre allocate helper vector array: - static size_t _arraySize = 10000; - static XMVECTOR* _vertices = (XMVECTOR*)_mm_malloc(sizeof(XMVECTOR)*_arraySize, 16); - for (size_t i = 0; i < scene.objects.GetCount(); ++i) { Entity entity = scene.objects.GetEntity(i); @@ -7873,13 +7869,6 @@ wiRenderer::RayIntersectWorldResult wiRenderer::RayIntersectWorld(const RAY& ray } const MeshComponent& mesh = *scene.meshes.GetComponent(object.meshID); - if (mesh.vertex_positions.size() >= _arraySize) - { - // grow preallocated vector helper array - _mm_free(_vertices); - _arraySize = (mesh.vertex_positions.size() + 1) * 2; - _vertices = (XMVECTOR*)_mm_malloc(sizeof(XMVECTOR)*_arraySize, 16); - } const TransformComponent& transform = *scene.transforms.GetComponent(entity); @@ -7889,41 +7878,6 @@ wiRenderer::RayIntersectWorldResult wiRenderer::RayIntersectWorld(const RAY& ray const XMVECTOR rayOrigin_local = XMVector3Transform(rayOrigin, objectMat_Inverse); const XMVECTOR rayDirection_local = XMVector3Normalize(XMVector3TransformNormal(rayDirection, objectMat_Inverse)); - if (mesh.IsSkinned()) - { - const ArmatureComponent& armature = *scene.armatures.GetComponent(mesh.armatureID); - - for (size_t vertexI = 0; vertexI < mesh.vertex_positions.size(); ++vertexI) - { - XMVECTOR pos = XMLoadFloat3(&mesh.vertex_positions[vertexI]); - - const XMUINT4& ind = mesh.vertex_boneindices[vertexI]; - const XMFLOAT4& wei = mesh.vertex_boneweights[vertexI]; - - XMMATRIX sump = XMLoadFloat4x4(&armature.skinningMatrices[ind.x]) * wei.x; - sump += XMLoadFloat4x4(&armature.skinningMatrices[ind.y]) * wei.y; - sump += XMLoadFloat4x4(&armature.skinningMatrices[ind.z]) * wei.z; - sump += XMLoadFloat4x4(&armature.skinningMatrices[ind.w]) * wei.w; - - _vertices[i] = XMVector3Transform(pos, sump); - } - } - else if (mesh.IsDynamicVB()) - { - //for (size_t i = 0; i < mesh.vertices_Transformed_POS.size(); ++i) - //{ - // _vertices[i] = mesh.vertices_Transformed_POS[i].LoadPOS(); - //} - assert(0); - } - else - { - for (size_t i = 0; i < mesh.vertex_positions.size(); ++i) - { - _vertices[i] = XMLoadFloat3(&mesh.vertex_positions[i]); - } - } - int subsetCounter = 0; for (auto& subset : mesh.subsets) { @@ -7932,15 +7886,56 @@ wiRenderer::RayIntersectWorldResult wiRenderer::RayIntersectWorld(const RAY& ray uint32_t i0 = mesh.indices[subset.indexOffset + i + 0]; uint32_t i1 = mesh.indices[subset.indexOffset + i + 1]; uint32_t i2 = mesh.indices[subset.indexOffset + i + 2]; + + XMVECTOR p0 = XMLoadFloat3(&mesh.vertex_positions[i0]); + XMVECTOR p1 = XMLoadFloat3(&mesh.vertex_positions[i1]); + XMVECTOR p2 = XMLoadFloat3(&mesh.vertex_positions[i2]); + + if (mesh.IsSkinned()) + { + const ArmatureComponent& armature = *scene.armatures.GetComponent(mesh.armatureID); + + const XMUINT4& ind0 = mesh.vertex_boneindices[i0]; + const XMUINT4& ind1 = mesh.vertex_boneindices[i1]; + const XMUINT4& ind2 = mesh.vertex_boneindices[i2]; + + const XMFLOAT4& wei0 = mesh.vertex_boneweights[i0]; + const XMFLOAT4& wei1 = mesh.vertex_boneweights[i1]; + const XMFLOAT4& wei2 = mesh.vertex_boneweights[i2]; + + XMMATRIX sump; + + sump = XMLoadFloat4x4(&armature.skinningMatrices[ind0.x]) * wei0.x; + sump += XMLoadFloat4x4(&armature.skinningMatrices[ind0.y]) * wei0.y; + sump += XMLoadFloat4x4(&armature.skinningMatrices[ind0.z]) * wei0.z; + sump += XMLoadFloat4x4(&armature.skinningMatrices[ind0.w]) * wei0.w; + + p0 = XMVector3Transform(p0, sump); + + sump = XMLoadFloat4x4(&armature.skinningMatrices[ind1.x]) * wei1.x; + sump += XMLoadFloat4x4(&armature.skinningMatrices[ind1.y]) * wei1.y; + sump += XMLoadFloat4x4(&armature.skinningMatrices[ind1.z]) * wei1.z; + sump += XMLoadFloat4x4(&armature.skinningMatrices[ind1.w]) * wei1.w; + + p1 = XMVector3Transform(p1, sump); + + sump = XMLoadFloat4x4(&armature.skinningMatrices[ind2.x]) * wei2.x; + sump += XMLoadFloat4x4(&armature.skinningMatrices[ind2.y]) * wei2.y; + sump += XMLoadFloat4x4(&armature.skinningMatrices[ind2.z]) * wei2.z; + sump += XMLoadFloat4x4(&armature.skinningMatrices[ind2.w]) * wei2.w; + + p2 = XMVector3Transform(p2, sump); + } + float distance; - if (TriangleTests::Intersects(rayOrigin_local, rayDirection_local, _vertices[i0], _vertices[i1], _vertices[i2], distance)) + if (TriangleTests::Intersects(rayOrigin_local, rayDirection_local, p0, p1, p2, distance)) { XMVECTOR pos = XMVector3Transform(XMVectorAdd(rayOrigin_local, rayDirection_local*distance), objectMat); distance = wiMath::Distance(pos, rayOrigin); if (distance < result.distance) { - XMVECTOR nor = XMVector3Normalize(XMVector3TransformNormal(XMVector3Normalize(XMVector3Cross(XMVectorSubtract(_vertices[i2], _vertices[i1]), XMVectorSubtract(_vertices[i1], _vertices[i0]))), objectMat)); + XMVECTOR nor = XMVector3Normalize(XMVector3TransformNormal(XMVector3Normalize(XMVector3Cross(XMVectorSubtract(p2, p1), XMVectorSubtract(p1, p0))), objectMat)); result.entity = entity; XMStoreFloat3(&result.position, pos); diff --git a/WickedEngine/wiSceneSystem.cpp b/WickedEngine/wiSceneSystem.cpp index 2912c11f7..ff97c31f3 100644 --- a/WickedEngine/wiSceneSystem.cpp +++ b/WickedEngine/wiSceneSystem.cpp @@ -32,9 +32,30 @@ namespace wiSceneSystem } void TransformComponent::UpdateParentedTransform(const TransformComponent& parent, const XMFLOAT4X4& inverseParentBindMatrix) { - dirty = true; + XMMATRIX W; - XMMATRIX W = XMLoadFloat4x4(&world); + // Normally, every transform would be NOT dirty at this point, but... + + if (parent.dirty) + { + // If parent is dirty, that means it was tagged by animation system... + dirty = true; + + W = XMLoadFloat4x4(&world); + } + else + { + // If it is not dirty, then we still need to propagate parent's matrix to this, + // because every transform is marked as NOT dirty at the end of transform update system + // but we look up the local matrix instead, because world matrix might contain + // results from previous run of the hierarchy system... + XMVECTOR S_local = XMLoadFloat3(&scale_local); + XMVECTOR R_local = XMLoadFloat4(&rotation_local); + XMVECTOR T_local = XMLoadFloat3(&translation_local); + W = XMMatrixScalingFromVector(S_local) * + XMMatrixRotationQuaternion(R_local) * + XMMatrixTranslationFromVector(T_local); + } XMMATRIX W_parent = XMLoadFloat4x4(&parent.world); XMMATRIX B = XMLoadFloat4x4(&inverseParentBindMatrix); @@ -267,15 +288,15 @@ namespace wiSceneSystem // vertexBuffer - POSITION + NORMAL + SUBSETINDEX: { + std::vector vertex_subsetindices(vertex_positions.size()); - std::unordered_map subsetIndicesLUT; uint32_t subsetCounter = 0; for (auto& subset : subsets) { for (uint32_t i = 0; i < subset.indexCount; ++i) { uint32_t index = indices[subset.indexOffset + i]; - subsetIndicesLUT[index] = subsetCounter; + vertex_subsetindices[index] = subsetCounter; } subsetCounter++; } @@ -284,9 +305,9 @@ namespace wiSceneSystem for (size_t i = 0; i < vertices.size(); ++i) { const XMFLOAT3& pos = vertex_positions[i]; - XMFLOAT3& nor = vertex_normals[i]; + XMFLOAT3& nor = vertex_normals.empty() ? XMFLOAT3(1, 1, 1) : vertex_normals[i]; XMStoreFloat3(&nor, XMVector3Normalize(XMLoadFloat3(&nor))); - uint32_t subsetIndex = subsetIndicesLUT[(uint32_t)i]; + uint32_t subsetIndex = vertex_subsetindices[i]; vertices[i].FromFULL(pos, nor, subsetIndex); _min = wiMath::Min(_min, pos); @@ -358,6 +379,7 @@ namespace wiSceneSystem } // vertexBuffer - TEXCOORDS + if(!vertex_texcoords.empty()) { std::vector vertices(vertex_texcoords.size()); for (size_t i = 0; i < vertices.size(); ++i) @@ -1164,7 +1186,7 @@ namespace wiSceneSystem TransformComponent& transform = *transforms.GetComponent(channel.target); - if (channel.mode == AnimationComponent::AnimationChannel::Mode::STEP || (keyLeft == 0 && keyRight == 0)) + if (channel.mode == AnimationComponent::AnimationChannel::Mode::STEP || keyLeft == keyRight) { // Nearest neighbor method (snap to left): switch (channel.type)