--- /dev/null
+g cube
+
+v 0.0 0.0 0.0
+v 0.0 0.0 1.0
+v 0.0 1.0 0.0
+v 0.0 1.0 1.0
+v 1.0 0.0 0.0
+v 1.0 0.0 1.0
+v 1.0 1.0 0.0
+v 1.0 1.0 1.0
+
+f 1 7 5
+f 1 3 7
+f 1 4 3
+f 1 2 4
+f 3 8 7
+f 3 4 8
+f 5 7 8
+f 5 8 6
+f 1 5 6
+f 1 6 2
+f 2 6 8
+f 2 8 4
Property::Map propertyMap;
propertyMap.Insert( "rendererType", "PRIMITIVE" );
propertyMap.Insert( "shape", "CUBE" );
- propertyMap.Insert( "color", color );
+ propertyMap.Insert( "shapeColor", color );
propertyMap.Insert( "slices", 10 );
propertyMap.Insert( "stacks", 20 );
propertyMap.Insert( "scaleTopRadius", 30.0f );
DALI_TEST_CHECK( value );
DALI_TEST_EQUALS( value->Get<std::string>(), "CUBE", TEST_LOCATION );
- value = resultMap.Find( "color", Property::VECTOR4 );
+ value = resultMap.Find( "shapeColor", Property::VECTOR4 );
DALI_TEST_CHECK( value );
DALI_TEST_CHECK( value->Get<Vector4>() == color );
DALI_TEST_EQUALS( value->Get<Vector4>(), color, Math::MACHINE_EPSILON_100, TEST_LOCATION );
const char* TEST_SVG_FILE_NAME = TEST_RESOURCE_DIR "/svg1.svg";
const char* TEST_OBJ_FILE_NAME = TEST_RESOURCE_DIR "/Cube.obj";
const char* TEST_MTL_FILE_NAME = TEST_RESOURCE_DIR "/ToyRobot-Metal.mtl";
+const char* TEST_SIMPLE_OBJ_FILE_NAME = TEST_RESOURCE_DIR "/Cube-Points-Only.obj";
const char* TEST_SIMPLE_MTL_FILE_NAME = TEST_RESOURCE_DIR "/ToyRobot-Metal-Simple.mtl";
Integration::Bitmap* CreateBitmap( unsigned int imageWidth, unsigned int imageHeight, unsigned int initialColor, Pixel::Format pixelFormat )
END_TEST;
}
+//Test if mesh renderer loads correctly when supplied an object file without face normals or texture points.
+//Note that this notably tests object loader functionality.
+int UtcDaliRendererFactoryGetMeshRenderer5(void)
+{
+ ToolkitTestApplication application;
+ tet_infoline( "UtcDaliRendererFactoryGetMeshRenderer5: Request mesh renderer with normal-less object file." );
+
+ RendererFactory factory = RendererFactory::Get();
+ DALI_TEST_CHECK( factory );
+
+ //Set up renderer properties.
+ Property::Map propertyMap;
+ propertyMap.Insert( "rendererType", "MESH" );
+ propertyMap.Insert( "objectUrl", TEST_SIMPLE_OBJ_FILE_NAME );
+ propertyMap.Insert( "materialUrl", TEST_MTL_FILE_NAME );
+ propertyMap.Insert( "texturesPath", TEST_RESOURCE_DIR "/" );
+
+ ControlRenderer controlRenderer = factory.CreateControlRenderer( propertyMap );
+ DALI_TEST_CHECK( controlRenderer );
+
+ //Add renderer to an actor on stage.
+ Actor actor = Actor::New();
+ actor.SetSize( 200.f, 200.f );
+ Stage::GetCurrent().Add( actor );
+ controlRenderer.SetSize( Vector2( 200.f, 200.f ) );
+ controlRenderer.SetOnStage( actor );
+
+ DALI_TEST_CHECK( actor.GetRendererCount() == 1u );
+
+ //Attempt to render to queue resource load requests.
+ application.SendNotification();
+ application.Render( 0 );
+
+ //Tell the platform abstraction that the required resources have been loaded.
+ TestPlatformAbstraction& platform = application.GetPlatform();
+ platform.SetAllResourceRequestsAsLoaded();
+
+ //Render again to upload the now-loaded textures.
+ application.SendNotification();
+ application.Render( 0 );
+
+ TestGlAbstraction& gl = application.GetGlAbstraction();
+
+ Matrix testScaleMatrix;
+ testScaleMatrix.SetIdentityAndScale( Vector3( 1.0, -1.0, 1.0 ) );
+ Matrix actualScaleMatrix;
+
+ //Test to see if the object has been successfully loaded.
+ DALI_TEST_CHECK( gl.GetUniformValue<Matrix>( "uObjectMatrix", actualScaleMatrix ) );
+ DALI_TEST_EQUALS( actualScaleMatrix, testScaleMatrix, Math::MACHINE_EPSILON_100, TEST_LOCATION );
+
+ controlRenderer.SetOffStage( actor );
+ DALI_TEST_CHECK( actor.GetRendererCount() == 0u );
+
+ END_TEST;
+}
+
//Test if mesh renderer handles the case of lacking an object file.
int UtcDaliRendererFactoryGetMeshRendererN1(void)
{
Property::Map propertyMap;
propertyMap.Insert( "rendererType", "PRIMITIVE" );
propertyMap.Insert( "shape", "CUBE" );
- propertyMap.Insert( "color", Vector4( 0.5, 0.5, 0.5, 1.0 ) );
+ propertyMap.Insert( "shapeColor", Vector4( 0.5, 0.5, 0.5, 1.0 ) );
propertyMap.Insert( "slices", 10 );
propertyMap.Insert( "stacks", 20 );
propertyMap.Insert( "scaleTopRadius", 30.0f );
Property::Map propertyMap;
propertyMap.Insert( "rendererType", "PRIMITIVE" );
propertyMap.Insert( "shape", "SPHERE" );
- propertyMap.Insert( "color", Vector4( 0.5, 0.5, 0.5, 1.0 ) );
+ propertyMap.Insert( "shapeColor", Vector4( 0.5, 0.5, 0.5, 1.0 ) );
propertyMap.Insert( "slices", 10 );
propertyMap.Insert( "stacks", 20 );
Property::Map propertyMap;
propertyMap.Insert( "rendererType", "PRIMITIVE" );
propertyMap.Insert( "shape", "CONICAL_FRUSTRUM" );
- propertyMap.Insert( "color", Vector4( 0.5, 0.5, 0.5, 1.0 ) );
+ propertyMap.Insert( "shapeColor", Vector4( 0.5, 0.5, 0.5, 1.0 ) );
propertyMap.Insert( "slices", 10 );
propertyMap.Insert( "scaleTopRadius", 30.0f );
propertyMap.Insert( "scaleBottomRadius", 40.0f );
Property::Map propertyMap;
propertyMap.Insert( "rendererType", "PRIMITIVE" );
propertyMap.Insert( "shape", "BEVELLED_CUBE" );
- propertyMap.Insert( "color", Vector4( 0.5, 0.5, 0.5, 1.0 ) );
+ propertyMap.Insert( "shapeColor", Vector4( 0.5, 0.5, 0.5, 1.0 ) );
propertyMap.Insert( "bevelPercentage", 0.7f );
//Test to see if shape loads correctly.
Property::Map propertyMap;
propertyMap.Insert( "rendererType", "PRIMITIVE" );
propertyMap.Insert( "shape", "OCTAHEDRON" );
- propertyMap.Insert( "color", Vector4( 0.5, 0.5, 0.5, 1.0 ) );
+ propertyMap.Insert( "shapeColor", Vector4( 0.5, 0.5, 0.5, 1.0 ) );
//Test to see if shape loads correctly.
TestPrimitiveRendererWithProperties( propertyMap, application );
Property::Map propertyMap;
propertyMap.Insert( "rendererType", "PRIMITIVE" );
propertyMap.Insert( "shape", "CONE" );
- propertyMap.Insert( "color", Vector4( 0.5, 0.5, 0.5, 1.0 ) );
+ propertyMap.Insert( "shapeColor", Vector4( 0.5, 0.5, 0.5, 1.0 ) );
propertyMap.Insert( "slices", 10 );
propertyMap.Insert( "scaleTopRadius", 30.0f );
propertyMap.Insert( "scaleHeight", 50.0f );
Property::Map propertyMap;
propertyMap.Insert( "rendererType", "PRIMITIVE" );
propertyMap.Insert( "shape", "SPHERE" );
- propertyMap.Insert( "color", Vector4( 0.5, 0.5, 0.5, 1.0 ) );
+ propertyMap.Insert( "shapeColor", Vector4( 0.5, 0.5, 0.5, 1.0 ) );
propertyMap.Insert( "uLightPosition", Vector3( 0.0, 1.0, 2.0 ) );
//Test to see if shape loads correctly.
if( mObjLoader.IsSceneLoaded() )
{
- mMesh = mObjLoader.CreateGeometry( GetShaderProperties( mIlluminationType ) );
+ mMesh = mObjLoader.CreateGeometry( GetShaderProperties( mIlluminationType ), true );
CreateMaterial();
LoadTextures();
{
if( mObjLoader.IsSceneLoaded() )
{
- mMesh = mObjLoader.CreateGeometry( GetShaderProperties( mIlluminationType ) );
+ mMesh = mObjLoader.CreateGeometry( GetShaderProperties( mIlluminationType ), true );
if( mRenderer )
{
return mMaterialLoaded;
}
-//TODO: Use a function that can generate more than one normal/tangent per vertex (using angle)
-void ObjLoader::CalculateTangentArray(const Dali::Vector<Vector3>& vertex,
- const Dali::Vector<Vector2>& texcoord,
- Dali::Vector<TriIndex>& triangle,
- Dali::Vector<Vector3>& normal,
- Dali::Vector<Vector3>& tangent)
+void ObjLoader::CalculateHardFaceNormals( const Dali::Vector<Vector3>& vertices, Dali::Vector<TriIndex>& triangles,
+ Dali::Vector<Vector3>& normals )
{
- Dali::Vector<Vector3> tangents;
- tangents.Resize( vertex.Size() );
+ int numFaceVertices = 3 * triangles.Size(); //Vertex per face, as each point has different normals for each face.
+ int normalIndex = 0; //Tracks progress through the array of normals.
- // Resize of a vector of Vector3 will initialise with the default constructor, setting to all zeros.
+ normals.Clear();
+ normals.Resize( numFaceVertices );
- for ( unsigned long a = 0; a < triangle.Size(); a++ )
+ //For each triangle, calculate the normal by crossing two vectors on the triangle's plane.
+ for( unsigned long i = 0; i < triangles.Size(); i++ )
{
- Vector3 tangentVector, normalVector;
+ //Triangle vertices.
+ const Vector3& v0 = vertices[triangles[i].pointIndex[0]];
+ const Vector3& v1 = vertices[triangles[i].pointIndex[1]];
+ const Vector3& v2 = vertices[triangles[i].pointIndex[2]];
+
+ //Triangle edges.
+ Vector3 edge1 = v1 - v0;
+ Vector3 edge2 = v2 - v0;
+
+ //Using edges as vectors on the plane, cross to get the normal.
+ Vector3 normalVector = edge1.Cross(edge2);
+ normalVector.Normalize();
+
+ //Assign normals to points.
+ for( unsigned long j = 0; j < 3; j++, normalIndex++ )
+ {
+ triangles[i].normalIndex[j] = normalIndex;
+ normals[normalIndex] = normalVector;
+ }
+ }
+}
- const Vector3& v0 = vertex[triangle[a].pntIndex[0]];
- const Vector3& v1 = vertex[triangle[a].pntIndex[1]];
- const Vector3& v2 = vertex[triangle[a].pntIndex[2]];
+void ObjLoader::CalculateSoftFaceNormals( const Dali::Vector<Vector3>& vertices, Dali::Vector<TriIndex>& triangles,
+ Dali::Vector<Vector3>& normals )
+{
+ int normalIndex = 0; //Tracks progress through the array of normals.
+
+ normals.Clear();
+ normals.Resize( vertices.Size() ); //One (averaged) normal per point.
+
+ //For each triangle, calculate the normal by crossing two vectors on the triangle's plane
+ //We then add the triangle's normal to the cumulative normals at each point of it
+ for( unsigned long i = 0; i < triangles.Size(); i++ )
+ {
+ //Triangle vertices.
+ const Vector3& v0 = vertices[triangles[i].pointIndex[0]];
+ const Vector3& v1 = vertices[triangles[i].pointIndex[1]];
+ const Vector3& v2 = vertices[triangles[i].pointIndex[2]];
+ //Triangle edges.
Vector3 edge1 = v1 - v0;
Vector3 edge2 = v2 - v0;
- normalVector = edge1.Cross(edge2);
+ //Using edges as vectors on the plane, cross to get the normal.
+ Vector3 normalVector = edge1.Cross(edge2);
+
+ //Add this triangle's normal to the cumulative normal of each constituent point and set the index of the normal accordingly.
+ for( unsigned long j = 0; j < 3; j++, normalIndex++ )
+ {
+ triangles[i].normalIndex[j] = triangles[i].pointIndex[j]; //Normal index matches up to vertex index, as one normal per vertex.
+ normals[triangles[i].normalIndex[j]] += normalVector;
+ }
+ }
+
+ //Normalise the normals.
+ for( unsigned long i = 0; i < normals.Size(); i++ )
+ {
+ normals[i].Normalize();
+ }
+}
+
+//TODO: Use a function that can generate more than one normal/tangent per vertex (using angle)
+void ObjLoader::CalculateTangentFrame()
+{
+ //Reset tangent and bitangent vectors to hold new values.
+ mTangents.Clear();
+ mBiTangents.Clear();
+ mTangents.Resize( mPoints.Size() );
+ mBiTangents.Resize( mPoints.Size() );
+
+ //For each triangle, calculate the tangent vector and then add it to the total tangent vector of each point.
+ for ( unsigned long a = 0; a < mTriangles.Size(); a++ )
+ {
+ Vector3 tangentVector;
- const Vector2& w0 = texcoord[triangle[a].texIndex[0]];
- const Vector2& w1 = texcoord[triangle[a].texIndex[1]];
- const Vector2& w2 = texcoord[triangle[a].texIndex[2]];
+ const Vector3& v0 = mPoints[mTriangles[a].pointIndex[0]];
+ const Vector3& v1 = mPoints[mTriangles[a].pointIndex[1]];
+ const Vector3& v2 = mPoints[mTriangles[a].pointIndex[2]];
+
+ Vector3 edge1 = v1 - v0;
+ Vector3 edge2 = v2 - v0;
+
+ const Vector2& w0 = mTextures[mTriangles[a].textureIndex[0]];
+ const Vector2& w1 = mTextures[mTriangles[a].textureIndex[1]];
+ const Vector2& w2 = mTextures[mTriangles[a].textureIndex[2]];
float deltaU1 = w1.x - w0.x;
float deltaV1 = w1.y - w0.y;
tangentVector.y = f * ( deltaV2 * edge1.y - deltaV1 * edge2.y );
tangentVector.z = f * ( deltaV2 * edge1.z - deltaV1 * edge2.z );
- tangents[triangle[a].pntIndex[0]] += tangentVector;
- tangents[triangle[a].pntIndex[1]] += tangentVector;
- tangents[triangle[a].pntIndex[2]] += tangentVector;
-
- normal[triangle[a].pntIndex[0]] += normalVector;
- normal[triangle[a].pntIndex[1]] += normalVector;
- normal[triangle[a].pntIndex[2]] += normalVector;
+ mTangents[mTriangles[a].pointIndex[0]] += tangentVector;
+ mTangents[mTriangles[a].pointIndex[1]] += tangentVector;
+ mTangents[mTriangles[a].pointIndex[2]] += tangentVector;
}
- for ( unsigned long a = 0; a < triangle.Size(); a++ )
+ //Orthogonalize tangents and set binormals.
+ for ( unsigned long a = 0; a < mTangents.Size(); a++ )
{
- for ( unsigned long j = 0; j < 3; j++ )
- {
- triangle[a].nrmIndex[j] = triangle[a].pntIndex[j];
- }
- }
-
- for ( unsigned long a = 0; a < normal.Size(); a++ )
- {
- normal[a].Normalize();
-
- const Vector3& n = normal[a];
- const Vector3& t = tangents[a];
+ const Vector3& n = mNormals[a];
+ const Vector3& t = mTangents[a];
// Gram-Schmidt orthogonalize
- Vector3 calc = t - n * n.Dot(t);
- calc.Normalize();
- tangent[a] = Vector3( calc.x,calc.y,calc.z );
+ mTangents[a] = t - n * n.Dot(t);
+ mTangents[a].Normalize();
+
+ mBiTangents[a] = mNormals[a].Cross( mTangents[a] );
}
}
-
void ObjLoader::CenterAndScale( bool center, Dali::Vector<Vector3>& points )
{
BoundingVolume newAABB;
biggestDimension = sceneSize.z;
}
-
newAABB.Init();
for( unsigned int ui = 0; ui < points.Size(); ++ui )
{
mSceneAABB = newAABB;
}
-void ObjLoader::CreateGeometryArray(Dali::Vector<Vertex> & vertices,
- Dali::Vector<Vector2> & textures,
- Dali::Vector<VertexExt> & verticesExt,
- Dali::Vector<unsigned short> & indices)
+void ObjLoader::CreateGeometryArray( Dali::Vector<Vertex> & vertices,
+ Dali::Vector<Vector2> & textures,
+ Dali::Vector<VertexExt> & verticesExt,
+ Dali::Vector<unsigned short> & indices,
+ bool useSoftNormals )
{
- //If we don't have tangents, calculate them
- //we need to recalculate the normals too, because we need just one normal,tangent, bitangent per vertex
- //In the case of a textureless object, we don't need tangents for our shader and so we skip this step
- //TODO: Use a better function to calculate tangents
- if( mTangents.Size() == 0 && mHasTexturePoints )
+ //We must calculate the tangents and bitangents if they weren't supplied, or if they don't match up.
+ bool mustCalculateTangents = mTangents.Size() == 0 || mBiTangents.Size() == 0 ||
+ mTangents.Size() != mBiTangents.Size() || mTangents.Size() != mNormals.Size() ||
+ mBiTangents.Size() != mNormals.Size();
+
+ //However, we don't need to do this if the object doesn't use textures to begin with.
+ mustCalculateTangents &= mHasTexturePoints;
+
+ //We also have to recalculate the normals if we need to calculate tangents,
+ // as we need just one normal, tangent and bitangent per vertex, rather than the supplied per-face vertices.
+ //Alternatively, we need to calculate the normals if there weren't any to begin with.
+ if( mNormals.Size() == 0 || mustCalculateTangents )
{
- mNormals.Clear();
-
- mNormals.Resize( mPoints.Size() );
- mTangents.Resize( mPoints.Size() );
- mBiTangents.Resize( mPoints.Size() );
-
- CalculateTangentArray( mPoints, mTextures, mTriangles, mNormals, mTangents );
-
- for ( unsigned int ui = 0 ; ui < mNormals.Size() ; ++ui )
+ if( useSoftNormals || mustCalculateTangents )
{
- mBiTangents[ui] = mNormals[ui].Cross(mTangents[ui]);
+ CalculateSoftFaceNormals( mPoints, mTriangles, mNormals );
}
+ else
+ {
+ CalculateHardFaceNormals( mPoints, mTriangles, mNormals );
+ }
+ }
+
+ //TODO: Use a better function to calculate tangents
+ if( mHasTexturePoints && mustCalculateTangents )
+ {
+ CalculateTangentFrame();
}
bool mapsCorrespond; //True if the sizes of the arrays necessary for the object agree.
{
for ( int j = 0 ; j < 3 ; ++j )
{
- indices[indiceIndex] = mTriangles[ui].pntIndex[j];
+ indices[indiceIndex] = mTriangles[ui].pointIndex[j];
indiceIndex++;
- vertices[mTriangles[ui].pntIndex[j]].normal = mNormals[mTriangles[ui].nrmIndex[j]];
+ vertices[mTriangles[ui].pointIndex[j]].normal = mNormals[mTriangles[ui].normalIndex[j]];
if ( mHasTexturePoints )
{
- textures[mTriangles[ui].pntIndex[j]] = mTextures[mTriangles[ui].texIndex[j]];
- verticesExt[mTriangles[ui].pntIndex[j]].tangent = mTangents[mTriangles[ui].nrmIndex[j]];
- verticesExt[mTriangles[ui].pntIndex[j]].bitangent = mBiTangents[mTriangles[ui].nrmIndex[j]];
+ textures[mTriangles[ui].pointIndex[j]] = mTextures[mTriangles[ui].textureIndex[j]];
+ verticesExt[mTriangles[ui].pointIndex[j]].tangent = mTangents[mTriangles[ui].normalIndex[j]];
+ verticesExt[mTriangles[ui].pointIndex[j]].bitangent = mBiTangents[mTriangles[ui].normalIndex[j]];
}
}
}
for ( int j = 0 ; j < 3 ; ++j )
{
Vertex vertex;
- vertex.position = mPoints[mTriangles[ui].pntIndex[j]];
- vertex.normal = mNormals[mTriangles[ui].nrmIndex[j]];
+ vertex.position = mPoints[mTriangles[ui].pointIndex[j]];
+ vertex.normal = mNormals[mTriangles[ui].normalIndex[j]];
vertices[index] = vertex;
if ( mHasTexturePoints )
{
- textures[index] = mTextures[mTriangles[ui].texIndex[j]];
+ textures[index] = mTextures[mTriangles[ui].textureIndex[j]];
VertexExt vertexExt;
- vertexExt.tangent = mTangents[mTriangles[ui].nrmIndex[j]];
- vertexExt.bitangent = mBiTangents[mTriangles[ui].nrmIndex[j]];
+ vertexExt.tangent = mTangents[mTriangles[ui].normalIndex[j]];
+ vertexExt.bitangent = mBiTangents[mTriangles[ui].normalIndex[j]];
verticesExt[index] = vertexExt;
-
}
index++;
{
for( int i = 0 ; i < 3; i++ )
{
- triangle.pntIndex[i] = ptIdx[i] - 1 - pntAcum;
- triangle.nrmIndex[i] = nrmIdx[i] - 1 - nrmAcum;
- triangle.texIndex[i] = texIdx[i] - 1 - texAcum;
+ triangle.pointIndex[i] = ptIdx[i] - 1 - pntAcum;
+ triangle.normalIndex[i] = nrmIdx[i] - 1 - nrmAcum;
+ triangle.textureIndex[i] = texIdx[i] - 1 - texAcum;
}
mTriangles.PushBack( triangle );
face++;
{
for( int i = 0 ; i < 3; i++ )
{
- triangle.pntIndex[i] = ptIdx[i] - 1 - pntAcum;
- triangle.nrmIndex[i] = nrmIdx[i] - 1 - nrmAcum;
- triangle.texIndex[i] = texIdx[i] - 1 - texAcum;
+ triangle.pointIndex[i] = ptIdx[i] - 1 - pntAcum;
+ triangle.normalIndex[i] = nrmIdx[i] - 1 - nrmAcum;
+ triangle.textureIndex[i] = texIdx[i] - 1 - texAcum;
}
mTriangles.PushBack( triangle );
face++;
for( int i = 0 ; i < 3; i++ )
{
int idx = ( i + 2 ) % numIndices;
- triangle2.pntIndex[i] = ptIdx[idx] - 1 - pntAcum;
- triangle2.nrmIndex[i] = nrmIdx[idx] - 1 - nrmAcum;
- triangle2.texIndex[i] = texIdx[idx] - 1 - texAcum;
+ triangle2.pointIndex[i] = ptIdx[idx] - 1 - pntAcum;
+ triangle2.normalIndex[i] = nrmIdx[idx] - 1 - nrmAcum;
+ triangle2.textureIndex[i] = texIdx[idx] - 1 - texAcum;
}
mTriangles.PushBack( triangle2 );
face++;
mMaterialLoaded = true;
}
-Geometry ObjLoader::CreateGeometry( int objectProperties )
+Geometry ObjLoader::CreateGeometry( int objectProperties, bool useSoftNormals )
{
Geometry surface = Geometry::New();
Dali::Vector<VertexExt> verticesExt;
Dali::Vector<unsigned short> indices;
- CreateGeometryArray( vertices, textures, verticesExt, indices );
+ CreateGeometryArray( vertices, textures, verticesExt, indices, useSoftNormals );
//All vertices need at least Position and Normal
Property::Map vertexFormat;
struct TriIndex
{
- int pntIndex[3];
- int nrmIndex[3];
- int texIndex[3];
+ int pointIndex[3];
+ int normalIndex[3];
+ int textureIndex[3];
};
struct Vertex
void LoadMaterial( char* objBuffer, std::streampos fileSize, std::string& diffuseTextureUrl,
std::string& normalTextureUrl, std::string& glossTextureUrl );
- Geometry CreateGeometry( int objectProperties );
+ Geometry CreateGeometry( int objectProperties, bool useSoftNormals );
Vector3 GetCenter();
Vector3 GetSize();
bool mHasNormalMap;
bool mHasSpecularMap;
- Dali::Vector<Vector3> mPoints;
- Dali::Vector<Vector2> mTextures;
- Dali::Vector<Vector2> mTextures2;
- Dali::Vector<Vector3> mNormals;
- Dali::Vector<Vector3> mTangents;
- Dali::Vector<Vector3> mBiTangents;
+ Dali::Vector<Vector3> mPoints;
+ Dali::Vector<Vector2> mTextures;
+ Dali::Vector<Vector2> mTextures2;
+ Dali::Vector<Vector3> mNormals;
+ Dali::Vector<Vector3> mTangents;
+ Dali::Vector<Vector3> mBiTangents;
Dali::Vector<TriIndex> mTriangles;
- void CalculateTangentArray( const Dali::Vector<Vector3>& vertex,
- const Dali::Vector<Vector2>& texcoord,
- Dali::Vector<TriIndex>& triangle,
- Dali::Vector<Vector3>& normal,
- Dali::Vector<Vector3>& tangent );
+ /**
+ * @brief Calculates normals for each point on a per-face basis.
+ *
+ * There are multiple normals per point, each corresponding to the normal of a face connecting to the point.
+ *
+ * @param[in] vertices The vertices of the object.
+ * @param[in, out] triangles The triangles that form the faces. The normals of each triangle will be updated.
+ * @param[in, out] normals The normals to be calculated.
+ */
+ void CalculateHardFaceNormals( const Dali::Vector<Vector3>& vertices,
+ Dali::Vector<TriIndex>& triangles,
+ Dali::Vector<Vector3>& normals );
+
+ /**
+ * @brief Calculates smoothed normals for each point.
+ *
+ * There is one normal per point, an average of the connecting faces.
+ *
+ * @param[in] vertices The vertices of the object.
+ * @param[in, out] triangles The triangles that form the faces. The normals of each triangle will be updated.
+ * @param[in, out] normals The normals to be calculated.
+ */
+ void CalculateSoftFaceNormals( const Dali::Vector<Vector3>& vertices,
+ Dali::Vector<TriIndex>& triangles,
+ Dali::Vector<Vector3>& normals );
+
+ /**
+ * @brief Calculates tangents and bitangents for each point of the object.
+ *
+ * These are calculated using the object's points, texture coordinates and normals, so these must be initialised first.
+ */
+ void CalculateTangentFrame();
void CenterAndScale( bool center, Dali::Vector<Vector3>& points );
-
+ /**
+ * @brief Using the data loaded from the file, create arrays of data to be used in creating the geometry.
+ *
+ * @param[in] vertices The vertices of the object.
+ * @param[in] textures The texture coordinates of the object.
+ * @param[in] verticesExt Extension to vertices, storing tangents and bitangents.
+ * @param[in] indices Indices of corresponding values to match triangles to their respective data.
+ * @param[in] useSoftNormals Indicates whether we should average the normals at each point to smooth the surface or not.
+ */
void CreateGeometryArray( Dali::Vector<Vertex> & vertices,
Dali::Vector<Vector2> & textures,
Dali::Vector<VertexExt> & verticesExt,
- Dali::Vector<unsigned short> & indices );
+ Dali::Vector<unsigned short> & indices,
+ bool useSoftNormals );
};
: ControlRenderer( factoryCache ),
mShaderType( ALL_TEXTURES ),
mUseTexture( true ),
- mUseMipmapping( true )
+ mUseMipmapping( true ),
+ mUseSoftNormals( true )
{
}
}
}
}
+
+ Property::Value* useSoftNormals = propertyMap.Find( USE_SOFT_NORMALS );
+ if( useSoftNormals )
+ {
+ useSoftNormals->Get( mUseSoftNormals );
+ }
}
void MeshRenderer::SetSize( const Vector2& size )
}
}
map.Insert( SHADER_TYPE, shaderTypeString );
+
+ map.Insert( USE_MIPMAPPING, mUseMipmapping );
+ map.Insert( USE_SOFT_NORMALS, mUseSoftNormals );
}
void MeshRenderer::InitializeRenderer()
}
//Create geometry with attributes required by shader.
- mGeometry = mObjLoader.CreateGeometry( objectProperties );
+ mGeometry = mObjLoader.CreateGeometry( objectProperties, mUseSoftNormals );
if( mGeometry )
{
*
* The following Property::Map keys are required to create a MeshRender
*
- * | %Property Name | Type | Representing |
- * |-----------------|-------------|-----------------------------------------|
- * | objectUrl | STRING | A URL to the .obj file |
- * | materialUrl | STRING | A URL to the .mtl file |
- * | texturesPath | STRING | A URL of the path to the texture images |
- * | shaderType | STRING | An enum of shader types |
+ * | %Property Name | Type | Representing |
+ * |-----------------|-------------|-----------------------------------------------------------------------|
+ * | objectUrl | STRING | A URL to the .obj file |
+ * | materialUrl | STRING | A URL to the .mtl file |
+ * | texturesPath | STRING | A URL of the path to the texture images |
+ * | shaderType | STRING | An enum of shader types |
+ * | useMipmapping | BOOLEAN | If true, use mipmaps for textures. Default true. |
+ * | useSoftNormals | BOOLEAN | If true, average normals at points for smooth textures. Default true. |
*/
class MeshRenderer: public ControlRenderer
{
bool mUseTexture;
bool mUseMipmapping;
+ bool mUseSoftNormals;
};
} // namespace Internal
*
* | %Property Name | Type | Shapes Affected |
* |-------------------|-------------|------------------------------------------|
- * | color | VECTOR4 | all |
+ * | shapeColor | VECTOR4 | all |
* | slices | INTEGER | sphere, cone, conical frustrum, cylinder |
* | stacks | INTEGER | sphere |
* | scaleTopRadius | FLOAT | conical frustrum |
const char * const TEXTURES_PATH( "texturesPath" );
const char * const SHADER_TYPE( "shaderType" );
const char * const USE_MIPMAPPING( "useMipmapping" );
+const char * const USE_SOFT_NORMALS( "useSoftNormals" );
//Primitive shape properties
const char * const PRIMITIVE_SHAPE( "shape" );
-const char * const SHAPE_COLOR( "color" );
+const char * const SHAPE_COLOR( "shapeColor" );
const char * const SLICES( "slices" );
const char * const STACKS( "stacks" );
const char * const SCALE_TOP_RADIUS( "scaleTopRadius" );
extern const char * const TEXTURES_PATH;
extern const char * const SHADER_TYPE;
extern const char * const USE_MIPMAPPING;
+extern const char * const USE_SOFT_NORMALS;
//Primitive shape properties
extern const char * const PRIMITIVE_SHAPE;
**RendererType** "MESH"
-| Property Name | Type | Required | Description |
-|----------------------------------------------|:-------:|:------------------:|--------------------------------------------------------------------------------|
-| objectUrl | STRING | Yes | The location of the ".obj" file. |
-| materialUrl | STRING | No | The location of the ".mtl" file. Leave blank for a textureless object. |
-| texturesPath | STRING | If using material | Path to the directory the textures (including gloss and normal) are stored in. |
-| [shaderType](@ref mesh-renderer-shader-type) | STRING | No | Sets the type of shader to be used with the mesh. |
+| Property Name | Type | Required | Description |
+|----------------------------------------------|:-------:|:------------------:|--------------------------------------------------------------------------------------------|
+| objectUrl | STRING | Yes | The location of the ".obj" file. |
+| materialUrl | STRING | No | The location of the ".mtl" file. Leave blank for a textureless object. |
+| texturesPath | STRING | If using material | Path to the directory the textures (including gloss and normal) are stored in. |
+| [shaderType](@ref mesh-renderer-shader-type) | STRING | No | Sets the type of shader to be used with the mesh. |
+| useMipmapping | BOOLEAN | No | Flag for whether to use mipmaps for textures or not. Default true. |
+| useSoftNormals | BOOLEAN | No | Flag for whether to average normals at each point to smooth textures or not. Default true. |
### Shader Type {#mesh-renderer-shader-type}
| Property Name | Type | Description | Default Value | Range |
|---------------------------------------|:-------:|---------------------------------------------------------------------------------|:--------------------:|:------------------------------:|
| [shape](@ref shape-details) | STRING | The specific shape to render. | "SPHERE" | [See list](@ref shape-details) |
-| color | VECTOR4 | The color of the shape. | (0.5, 0.5, 0.5, 1.0) | 0.0 - 1.0 for each |
+| shapeColor | VECTOR4 | The color of the shape. | (0.5, 0.5, 0.5, 1.0) | 0.0 - 1.0 for each |
| [slices](@ref slices-details) | INT | The number of slices as you go around the shape. | 128 | 1 - 255 |
| [stacks](@ref stacks-details) | INT | The number of stacks as you go down the shape. | 128 | 1 - 255 |
| scaleTopRadius | FLOAT | The scale of the radius of the top circle of a conical frustrum. | 1.0 | ≥ 0.0 |
map[ "rendererType" ] = "PRIMITIVE";
map[ "shape" ] = "SPHERE";
-map[ "color" ] = Vector4( 1.0, 0.5, 0.0, 1.0 );
+map[ "shapeColor" ] = Vector4( 1.0, 0.5, 0.0, 1.0 );
control.SetProperty( Dali::Toolkit::Control::Property::BACKGROUND, map );
~~~
map[ "rendererType" ] = "PRIMITIVE";
map[ "shape" ] = "CONICAL_FRUSTRUM";
-map[ "color" ] = Vector4( 1.0, 0.5, 0.0, 1.0 );
+map[ "shapeColor" ] = Vector4( 1.0, 0.5, 0.0, 1.0 );
map[ "scaleTopRadius" ] = 1.0f;
map[ "scaleBottomRadius" ] = 1.5f;
map[ "scaleHeight" ] = 3.0f;
map[ "rendererType" ] = "PRIMITIVE";
map[ "shape" ] = "BEVELLED_CUBE";
-map[ "color" ] = Vector4( 1.0, 0.5, 0.0, 1.0 );
+map[ "shapeColor" ] = Vector4( 1.0, 0.5, 0.0, 1.0 );
map[ "bevelPercentage" ] = 0.4f;
control.SetProperty( Dali::Toolkit::Control::Property::BACKGROUND, map );