- CastShadow can be used to make an object cast shadow or not.
- ReceiveShadow can be used to make an object be not drawn any shadow on its surface.
- Model and ModelNode have the methods.
- If Model's method is called, it is inherited to its current child ModelNode.
- If ModelNode's method is called, it is only affects the ModelNode itself.
- The ModelNode's property changes do not affect its parent Model's property.
Change-Id: I8ebeeed9ed814718a38ad7f69c43a4814a5a70ae
Signed-off-by: Seungho Baek <sbsh.baek@samsung.com>
DALI_TEST_EQUALS(gl.CheckUniformValue<float>(Scene3D::Loader::NodeDefinition::GetIblScaleFactorUniformName().data(), expectIblFactor), true, TEST_LOCATION);
END_TEST;
+}
+
+int UtcDaliModelCastShadow(void)
+{
+ ToolkitTestApplication application;
+
+ Scene3D::Model model = Scene3D::Model::New();
+ application.GetScene().Add(model);
+
+ Scene3D::ModelNode modelNode = Scene3D::ModelNode::New();
+ model.AddModelNode(modelNode);
+
+ DALI_TEST_EQUALS(model.IsShadowCasting(), true, TEST_LOCATION);
+
+ DALI_TEST_EQUALS(modelNode.IsShadowCasting(), true, TEST_LOCATION);
+
+ auto shadowCastingIndex = modelNode.GetPropertyIndex("uIsShadowCasting");
+ DALI_TEST_EQUALS(modelNode.GetProperty<int>(shadowCastingIndex), 1, TEST_LOCATION);
+
+ model.CastShadow(false);
+
+ DALI_TEST_EQUALS(model.IsShadowCasting(), false, TEST_LOCATION);
+
+ DALI_TEST_EQUALS(modelNode.IsShadowCasting(), false, TEST_LOCATION);
+
+ DALI_TEST_EQUALS(modelNode.GetProperty<int>(shadowCastingIndex), 0, TEST_LOCATION);
+
+ Scene3D::ModelNode modelNode2 = Scene3D::ModelNode::New();
+ model.AddModelNode(modelNode2);
+
+ DALI_TEST_EQUALS(modelNode2.IsShadowCasting(), true, TEST_LOCATION);
+
+ auto shadowCastingIndex2 = modelNode2.GetPropertyIndex("uIsShadowCasting");
+ DALI_TEST_EQUALS(modelNode2.GetProperty<int>(shadowCastingIndex2), 1, TEST_LOCATION);
+
+ modelNode.CastShadow(true);
+
+ DALI_TEST_EQUALS(modelNode.IsShadowCasting(), true, TEST_LOCATION);
+
+ DALI_TEST_EQUALS(model.IsShadowCasting(), false, TEST_LOCATION);
+
+ model.CastShadow(false);
+
+ DALI_TEST_EQUALS(model.IsShadowCasting(), false, TEST_LOCATION);
+
+ DALI_TEST_EQUALS(modelNode.IsShadowCasting(), false, TEST_LOCATION);
+
+ DALI_TEST_EQUALS(modelNode.GetProperty<int>(shadowCastingIndex), 0, TEST_LOCATION);
+
+ DALI_TEST_EQUALS(modelNode2.GetProperty<int>(shadowCastingIndex2), 0, TEST_LOCATION);
+ END_TEST;
+}
+
+int UtcDaliModelReceiveShadow(void)
+{
+ ToolkitTestApplication application;
+
+ Scene3D::Model model = Scene3D::Model::New();
+ application.GetScene().Add(model);
+
+ Scene3D::ModelNode modelNode = Scene3D::ModelNode::New();
+ model.AddModelNode(modelNode);
+
+ DALI_TEST_EQUALS(model.IsShadowReceiving(), true, TEST_LOCATION);
+
+ DALI_TEST_EQUALS(modelNode.IsShadowReceiving(), true, TEST_LOCATION);
+
+ auto shadowReceivingIndex = modelNode.GetPropertyIndex("uIsShadowReceiving");
+ DALI_TEST_EQUALS(modelNode.GetProperty<int>(shadowReceivingIndex), 1, TEST_LOCATION);
+
+ model.ReceiveShadow(false);
+
+ DALI_TEST_EQUALS(model.IsShadowReceiving(), false, TEST_LOCATION);
+
+ DALI_TEST_EQUALS(modelNode.IsShadowReceiving(), false, TEST_LOCATION);
+
+ DALI_TEST_EQUALS(modelNode.GetProperty<int>(shadowReceivingIndex), 0, TEST_LOCATION);
+
+ Scene3D::ModelNode modelNode2 = Scene3D::ModelNode::New();
+ model.AddModelNode(modelNode2);
+
+ DALI_TEST_EQUALS(modelNode2.IsShadowReceiving(), true, TEST_LOCATION);
+
+ auto shadowReceivingIndex2 = modelNode2.GetPropertyIndex("uIsShadowReceiving");
+ DALI_TEST_EQUALS(modelNode2.GetProperty<int>(shadowReceivingIndex2), 1, TEST_LOCATION);
+
+ modelNode.ReceiveShadow(true);
+
+ DALI_TEST_EQUALS(modelNode.IsShadowReceiving(), true, TEST_LOCATION);
+
+ DALI_TEST_EQUALS(model.IsShadowReceiving(), false, TEST_LOCATION);
+
+ model.ReceiveShadow(false);
+
+ DALI_TEST_EQUALS(model.IsShadowReceiving(), false, TEST_LOCATION);
+
+ DALI_TEST_EQUALS(modelNode.IsShadowReceiving(), false, TEST_LOCATION);
+
+ DALI_TEST_EQUALS(modelNode.GetProperty<int>(shadowReceivingIndex), 0, TEST_LOCATION);
+
+ DALI_TEST_EQUALS(modelNode2.GetProperty<int>(shadowReceivingIndex2), 0, TEST_LOCATION);
+ END_TEST;
}
\ No newline at end of file
mIblDiffuseResourceReady(true),
mIblSpecularResourceReady(true),
mIblDiffuseDirty(false),
- mIblSpecularDirty(false)
+ mIblSpecularDirty(false),
+ mIsShadowCasting(true),
+ mIsShadowReceiving(true)
{
}
}
}
+void Model::CastShadow(bool castShadow)
+{
+ mIsShadowCasting = castShadow;
+ UpdateCastShadowRecursively(mModelRoot, mIsShadowCasting);
+}
+
+bool Model::IsShadowCasting() const
+{
+ return mIsShadowCasting;
+}
+
+void Model::ReceiveShadow(bool receiveShadow)
+{
+ mIsShadowReceiving = receiveShadow;
+ UpdateReceiveShadowRecursively(mModelRoot, mIsShadowReceiving);
+}
+
+bool Model::IsShadowReceiving() const
+{
+ return mIsShadowReceiving;
+}
+
+
///////////////////////////////////////////////////////////
//
// Private methods
mModelRoot.SetProperty(Dali::Actor::Property::ANCHOR_POINT, Vector3::ONE - mModelPivot);
}
+void Model::UpdateCastShadowRecursively(Scene3D::ModelNode node, bool castShadow)
+{
+ if(!node)
+ {
+ return;
+ }
+
+ GetImplementation(node).CastShadow(castShadow);
+ uint32_t childrenCount = node.GetChildCount();
+ for(uint32_t i = 0; i < childrenCount; ++i)
+ {
+ Scene3D::ModelNode childNode = Scene3D::ModelNode::DownCast(node.GetChildAt(i));
+ if(!childNode)
+ {
+ continue;
+ }
+ UpdateCastShadowRecursively(childNode, castShadow);
+ }
+}
+
+void Model::UpdateReceiveShadowRecursively(Scene3D::ModelNode node, bool receiveShadow)
+{
+ if(!node)
+ {
+ return;
+ }
+
+ GetImplementation(node).ReceiveShadow(receiveShadow);
+ uint32_t childrenCount = node.GetChildCount();
+ for(uint32_t i = 0; i < childrenCount; ++i)
+ {
+ Scene3D::ModelNode childNode = Scene3D::ModelNode::DownCast(node.GetChildAt(i));
+ if(!childNode)
+ {
+ continue;
+ }
+ UpdateReceiveShadowRecursively(childNode, receiveShadow);
+ }
+}
+
void Model::UpdateImageBasedLightTextureRecursively(Scene3D::ModelNode node, Dali::Texture diffuseTexture, Dali::Texture specularTexture, float iblScaleFactor, uint32_t specularMipmapLevels)
{
if(!node)
void SetMotionData(Scene3D::MotionData motionData);
/**
+ * @copydoc Model::CastShadow()
+ */
+ void CastShadow(bool castShadow);
+
+ /**
+ * @copydoc Model::IsShadowCasting()
+ */
+ bool IsShadowCasting() const;
+
+ /**
+ * @copydoc Model::ReceiveShadow()
+ */
+ void ReceiveShadow(bool receiveShadow);
+
+ /**
+ * @copydoc Model::IsShadowReceiving()
+ */
+ bool IsShadowReceiving() const;
+
+ /**
* @copydoc Scene3D::Model::MeshHitSignal()
*/
Scene3D::Model::MeshHitSignalType& MeshHitSignal()
void FitModelPosition();
/**
+ * @brief Makes the input node cast shadow or not.
+ */
+ void UpdateCastShadowRecursively(Scene3D::ModelNode node, bool castShadow);
+
+ /**
+ * @brief Makes the input node receive shadow or not.
+ */
+ void UpdateReceiveShadowRecursively(Scene3D::ModelNode node, bool receiveShadow);
+
+ /**
* @brief Changes IBL information of the input node.
*/
void UpdateImageBasedLightTextureRecursively(Scene3D::ModelNode node, Dali::Texture diffuseTexture, Dali::Texture specularTexture, float iblScaleFactor, uint32_t specularMipmapLevels);
bool mIblSpecularResourceReady;
bool mIblDiffuseDirty;
bool mIblSpecularDirty;
+ bool mIsShadowCasting;
+ bool mIsShadowReceiving;
};
} // namespace Internal
// For Shadow Map
uniform lowp int uIsShadowEnabled;
uniform sampler2D sShadowMap;
+uniform lowp int uIsShadowReceiving;
#ifdef SL_VERSION_LOW
uniform int uShadowMapWidth;
uniform int uShadowMapHeight;
}
}
- if(float(uIsShadowEnabled) * uShadowIntensity > 0.0)
+ if(float(uIsShadowReceiving) * float(uIsShadowEnabled) * uShadowIntensity > 0.0)
{
mediump float exposureFactor = 0.0;
if(uEnableShadowSoftFiltering > 0)
uniform sampler2D sAlbedoMetal;
#endif
+uniform int uIsShadowCasting;
+
lowp vec3 linear(lowp vec3 color)
{
return pow(color, vec3(2.2));
void main()
{
+ if(uIsShadowCasting == 0)
+ {
+ discard;
+ }
+
#ifdef THREE_TEX
// The albedo may be defined from a base texture or a flat color
#ifdef BASECOLOR_TEX
void ModelNode::OnInitialize()
{
+ Actor self = Self();
+ self.RegisterProperty("uIsShadowCasting", static_cast<int>(mIsShadowCasting));
+ self.RegisterProperty("uIsShadowReceiving", static_cast<int>(mIsShadowReceiving));
}
void ModelNode::OnSceneConnection(int depth)
}
}
+void ModelNode::CastShadow(bool castShadow)
+{
+ if(mIsShadowCasting == castShadow)
+ {
+ return;
+ }
+
+ mIsShadowCasting = castShadow;
+
+ Actor self = Self();
+ self.RegisterProperty("uIsShadowCasting", static_cast<int>(mIsShadowCasting));
+}
+
+bool ModelNode::IsShadowCasting() const
+{
+ return mIsShadowCasting;
+}
+
+void ModelNode::ReceiveShadow(bool receiveShadow)
+{
+ if(mIsShadowReceiving == receiveShadow)
+ {
+ return;
+ }
+
+ mIsShadowReceiving = receiveShadow;
+
+ Actor self = Self();
+ self.RegisterProperty("uIsShadowReceiving", static_cast<int>(mIsShadowReceiving));
+}
+
+bool ModelNode::IsShadowReceiving() const
+{
+ return mIsShadowReceiving;
+}
+
void ModelNode::SetImageBasedLightTexture(Dali::Texture diffuseTexture, Dali::Texture specularTexture, float iblScaleFactor, uint32_t specularMipmapLevels)
{
mDiffuseTexture = diffuseTexture;
void SetShadowMapTexture(Dali::Texture shadowMapTexture);
/**
+ * @copydoc Dali::Scene3D::ModelNode::CastShadow()
+ */
+ void CastShadow(bool castShadow);
+
+ /**
+ * @copydoc Dali::Scene3D::ModelNode::IsShadowCasting()
+ */
+ bool IsShadowCasting() const;
+
+ /**
+ * @copydoc Dali::Scene3D::ModelNode::ReceiveShadow()
+ */
+ void ReceiveShadow(bool receiveShadow);
+
+ /**
+ * @copydoc Dali::Scene3D::ModelNode::IsShadowReceiving()
+ */
+ bool IsShadowReceiving() const;
+
+ /**
* @brief Sets the diffuse and specular image-based lighting textures for a ModelNode.
*
* @param[in] diffuseTexture The diffuse texture.
float mIblScaleFactor{1.0f};
uint32_t mSpecularMipmapLevels{1u};
+ bool mIsShadowCasting{true};
+ bool mIsShadowReceiving{true};
/// @endcond
};
GetImpl(*this).SetMotionData(motionData);
}
+void Model::CastShadow(bool castShadow)
+{
+ GetImpl(*this).CastShadow(castShadow);
+}
+
+bool Model::IsShadowCasting() const
+{
+ return GetImpl(*this).IsShadowCasting();
+}
+
+void Model::ReceiveShadow(bool receiveShadow)
+{
+ GetImpl(*this).ReceiveShadow(receiveShadow);
+}
+
+bool Model::IsShadowReceiving() const
+{
+ return GetImpl(*this).IsShadowReceiving();
+}
+
Model::MeshHitSignalType& Model::MeshHitSignal()
{
return GetImpl(*this).MeshHitSignal();
ModelNode FindChildModelNodeByName(std::string_view nodeName);
/**
- * @brief Retrieve the list of blendshape name that current Model hold.
+ * @brief Retrieves the list of blendshape name that current Model hold.
* The name will be appended end of input list.
*
* @SINCE_2_2.34
void RetrieveBlendShapeNames(std::vector<std::string>& blendShapeNames) const;
/**
- * @brief Retrieve the list of ModelNode that contains given blend shape name.
+ * @brief Retrieves the list of ModelNode that contains given blend shape name.
* The ModelNode will be appended end of input list.
*
* @SINCE_2_2.34
void RetrieveModelNodesByBlendShapeName(std::string_view blendShapeName, std::vector<ModelNode>& modelNodes) const;
/**
- * @brief Generate specific animation of this Model by inputed MotionData.
+ * @brief Generates specific animation of this Model by inputed MotionData.
*
* @SINCE_2_2.34
* @param[in] motionData the data of motion animation.
Dali::Animation GenerateMotionDataAnimation(MotionData motionData);
/**
- * @brief Set specific values of this Model by inputed MotionData.
+ * @brief Sets specific values of this Model by inputed MotionData.
* @note If MotionValue's ValueType is ValueType::KEY_FRAMES, the last value will be set.
*
* @SINCE_2_2.34
void SetMotionData(Scene3D::MotionData motionData);
/**
+ * @brief Sets whether this Model casts shadow or not.
+ * If it is true, this model is drawn on Shadow Map.
+ *
+ * @SINCE_2_3.99
+ * @param[in] castShadow Whether this Model casts shadow or not.
+ * @note This method affects all of the child ModelNode.
+ * However, same property of each child ModelNode can be changed respectively and it not changes parent's property.
+ */
+ void CastShadow(bool castShadow);
+
+ /**
+ * @brief Retrieves whether the Model casts shadow or not for Light.
+ *
+ * @SINCE_2_3.99
+ * @return True if this model casts shadow.
+ * @note IBL does not cast any shadow.
+ */
+ bool IsShadowCasting() const;
+
+ /**
+ * @brief Sets whether this Model receives shadow or not.
+ * If it is true, shadows are drawn on this model.
+ *
+ * @SINCE_2_3.99
+ * @param[in] receiveShadow Whether this Model receives shadow or not.
+ * @note This method affects all of the child ModelNode.
+ * However, same property of each child ModelNode can be changed respectively and it not changes parent's property.
+ */
+ void ReceiveShadow(bool receiveShadow);
+
+ /**
+ * @brief Retrieves whether the Model receives shadow or not for Light.
+ *
+ * @SINCE_2_3.99
+ * @return True if this model receives shadow.
+ */
+ bool IsShadowReceiving() const;
+
+ /**
* @brief This signal is emitted when the collider mesh is touched/hit.
*
* A callback of the following type may be connected:
return Internal::GetImplementation(*this).HasColliderMesh();
}
+void ModelNode::CastShadow(bool castShadow)
+{
+ Internal::GetImplementation(*this).CastShadow(castShadow);
+}
+
+bool ModelNode::IsShadowCasting() const
+{
+ return Internal::GetImplementation(*this).IsShadowCasting();
+}
+
+void ModelNode::ReceiveShadow(bool receiveShadow)
+{
+ Internal::GetImplementation(*this).ReceiveShadow(receiveShadow);
+}
+
+bool ModelNode::IsShadowReceiving() const
+{
+ return Internal::GetImplementation(*this).IsShadowReceiving();
+}
+
} // namespace Scene3D
} // namespace Dali
*/
[[nodiscard]] bool HasColliderMesh() const;
+ /**
+ * @brief Sets whether this ModelNode casts shadow or not.
+ * If it is true, this ModelNode is drawn on Shadow Map.
+ *
+ * @SINCE_2_3.99
+ * @param[in] castShadow Whether this ModelNode casts shadow or not.
+ * @note This method affects only for this ModelNode.
+ */
+ void CastShadow(bool castShadow);
+
+ /**
+ * @brief Retrieves whether the ModelNode cast shadow or not for Light.
+ *
+ * @SINCE_2_3.99
+ * @return True if this ModelNode cast shadow.
+ * @note IBL does not cast any shadow.
+ */
+ bool IsShadowCasting() const;
+
+ /**
+ * @brief Sets whether this ModelNode receives shadow or not.
+ * If it is true, shadows are drawn on this ModelNode.
+ *
+ * @SINCE_2_3.99
+ * @param[in] receiveShadow Whether this ModelNode receives shadow or not.
+ * @note This method affects only for this ModelNode.
+ */
+ void ReceiveShadow(bool receiveShadow);
+
+ /**
+ * @brief Retrieves whether the ModelNode receives shadow or not for Light.
+ *
+ * @SINCE_2_3.99
+ * @return True if this ModelNode receives shadow.
+ */
+ bool IsShadowReceiving() const;
+
public: // Not intended for application developers
/// @cond internal
/**