虚幻4渲染编程(图元汇编篇)【第六卷:与场景交互的软体果冻】

我的专栏目录:

小IVan:专题概述及目录​zhuanlan.zhihu.com图标

软体在游戏里是一个比较少见的效果,也是很多策划梦寐以求的效果。如果需要跟场景交互,仅仅通过shader是无法完美完成这项任务的(近似抖一下还是可以的)。下面在图元汇编阶段做文章,来完成这一效果。

先还是上效果吧:

v2-e8d0497dc631fb0888d2269dede37c2c_b.gif
v2-8d5bdc61e20dfd4bc7973832adb4c610_b.gif

这一节是承接上一节的内容,其实就是把韦尔莱的约束改一下,让整个粒子结构比布料更加稳定即可构建出软体粒子。下面上一张原理图

v2-4e0ad59955f60f0014d58f39a410b6d7_b.jpg

按照上述的构建方法把图元构建出来就可以了

下面是我的图形构建代码

void UVCubeComponent::BuildParticleMesh_Cloth()
{

	int32 XSideNum = 10;
	int32 YSideNum = 10;
	int32 TestParticleNum = XSideNum * YSideNum;
	int32 ConstrainNum = (4 * TestParticleNum - 2 * XSideNum - 2 * YSideNum) * 0.5;

	ShowPoints.Reset();
	TestParticles.Reset();
	Constrains.Reset();
	ShowPoints.AddUninitialized(TestParticleNum);
	TestParticles.AddUninitialized(TestParticleNum);
	Constrains.AddUninitialized(ConstrainNum);

	for (int32 Y = 0; Y < YSideNum; Y++)
	{
		for (int32 X = 0; X < XSideNum; X++)
		{
			TestParticles[Y * XSideNum + X].CurPos = FVector(X * 50, Y * 50, 0);

			if ((Y == 0 && X == 0) || (Y == 0 && X == XSideNum - 1))
			{
				TestParticles[Y * XSideNum + X].bFree = false;
			}
		}
	}

	//  @---@---@---@ constrain
	int32 XXSideConstrainNum = XSideNum - 1;
	int32 XYSideConstrainNum = YSideNum;
	for (int32 Y = 0; Y < XYSideConstrainNum; Y++)
	{
		for (int32 X = 0; X < XXSideConstrainNum; X++)
		{
			Constrains[Y * XXSideConstrainNum + X].BuildConstrain(TestParticles[Y * XSideNum + X], TestParticles[Y * XSideNum + X + 1], 50.0f);
		}
	}

	//  @||@||@||@ constrain
	int32 YXSideConstrainNum = XSideNum;
	int32 YYSideConstrainNum = YSideNum - 1;
	for (int32 Y = 0; Y < YYSideConstrainNum; Y++)
	{
		for (int32 X = 0; X < YXSideConstrainNum; X++)
		{
			Constrains[Y * YXSideConstrainNum + X + XXSideConstrainNum * XYSideConstrainNum].BuildConstrain(TestParticles[Y * YXSideConstrainNum + X], TestParticles[Y * YXSideConstrainNum + X + XSideNum], 50.0f);
		}
	}
}

void UVCubeComponent::BuildParticleMesh_SimpleBox()
{
	int32 TestParticleNum = 4;
	int32 ConstrainNum = 6;

	ShowPoints.Reset();
	TestParticles.Reset();
	Constrains.Reset();
	ShowPoints.AddUninitialized(TestParticleNum);
	TestParticles.AddUninitialized(TestParticleNum);
	Constrains.AddUninitialized(ConstrainNum);

	TestParticles[0].CurPos = FVector(0, 0, 0);
	TestParticles[1].CurPos = FVector(100, 0, 0);
	TestParticles[2].CurPos = FVector(0, 100, 0);
	TestParticles[3].CurPos = FVector(0, 0, 100);

	Constrains[0].BuildConstrain(TestParticles[0], TestParticles[1], 100.0f);
	Constrains[1].BuildConstrain(TestParticles[1], TestParticles[2], 141.42f);
	Constrains[2].BuildConstrain(TestParticles[2], TestParticles[0], 100.0f);
	Constrains[3].BuildConstrain(TestParticles[3], TestParticles[2], 141.42f);
	Constrains[4].BuildConstrain(TestParticles[3], TestParticles[1], 141.42f);
	Constrains[5].BuildConstrain(TestParticles[3], TestParticles[0], 100.0f);
}

void UVCubeComponent::BuildPartcileMesh_SimpleCube()
{
	int32 TestParticleNum = 8;
	int32 ConstrainNum = 24;

	ShowPoints.Reset();
	TestParticles.Reset();
	Constrains.Reset();
	ShowPoints.AddUninitialized(TestParticleNum);
	TestParticles.AddUninitialized(TestParticleNum);
	Constrains.AddUninitialized(ConstrainNum);

	TestParticles[0].CurPos = FVector(0, 0, 0);
	TestParticles[1].CurPos = FVector(100, 0, 0);
	TestParticles[2].CurPos = FVector(100, 100, 0);
	TestParticles[3].CurPos = FVector(0, 100, 0);

	TestParticles[4].CurPos = FVector(0, 0, 100);
	TestParticles[5].CurPos = FVector(100, 0, 100);
	TestParticles[6].CurPos = FVector(100, 100, 100);
	TestParticles[7].CurPos = FVector(0, 100, 100);

	Constrains[0].BuildConstrain(TestParticles[0], TestParticles[1], 100.0f);
	Constrains[1].BuildConstrain(TestParticles[1], TestParticles[2], 100.0f);
	Constrains[2].BuildConstrain(TestParticles[2], TestParticles[3], 100.0f);
	Constrains[3].BuildConstrain(TestParticles[3], TestParticles[0], 100.0f);
	Constrains[4].BuildConstrain(TestParticles[4], TestParticles[5], 100.0f);
	Constrains[5].BuildConstrain(TestParticles[5], TestParticles[6], 100.0f);
	Constrains[6].BuildConstrain(TestParticles[6], TestParticles[7], 100.0f);
	Constrains[7].BuildConstrain(TestParticles[7], TestParticles[4], 100.0f);
	Constrains[8].BuildConstrain(TestParticles[4], TestParticles[0], 100.0f);
	Constrains[9].BuildConstrain(TestParticles[5], TestParticles[1], 100.0f);
	Constrains[10].BuildConstrain(TestParticles[6], TestParticles[2], 100.0f);
	Constrains[11].BuildConstrain(TestParticles[7], TestParticles[3], 100.0f);
	Constrains[12].BuildConstrain(TestParticles[4], TestParticles[1], SqrtTwo * 100.0f);
	Constrains[13].BuildConstrain(TestParticles[5], TestParticles[0], SqrtTwo * 100.0f);
	Constrains[14].BuildConstrain(TestParticles[5], TestParticles[2], SqrtTwo * 100.0f);
	Constrains[15].BuildConstrain(TestParticles[6], TestParticles[1], SqrtTwo * 100.0f);
	Constrains[16].BuildConstrain(TestParticles[6], TestParticles[3], SqrtTwo * 100.0f);
	Constrains[17].BuildConstrain(TestParticles[7], TestParticles[2], SqrtTwo * 100.0f);
	Constrains[18].BuildConstrain(TestParticles[7], TestParticles[0], SqrtTwo * 100.0f);
	Constrains[19].BuildConstrain(TestParticles[4], TestParticles[3], SqrtTwo * 100.0f);
	Constrains[20].BuildConstrain(TestParticles[4], TestParticles[6], SqrtTwo * 100.0f);
	Constrains[21].BuildConstrain(TestParticles[7], TestParticles[5], SqrtTwo * 100.0f);
	Constrains[22].BuildConstrain(TestParticles[0], TestParticles[2], SqrtTwo * 100.0f);
	Constrains[23].BuildConstrain(TestParticles[3], TestParticles[1], SqrtTwo * 100.0f);
}

void UVCubeComponent::BuildParticleMesh_BoxHolder()
{
	int32 BoxHolderSecNum = 5;
	float BoxWidthAndHeight = 70.0f;
	float BoxLength = 90.0f;
	float BoxThirdSide = FMath::Sqrt(BoxLength* BoxLength + BoxWidthAndHeight * BoxWidthAndHeight);

	int32 TestParticleNum = (BoxHolderSecNum + 1) * 4;
	int32 ConstrainNum = BoxHolderSecNum * 18 + 6;
	
	ShowPoints.Reset();
	TestParticles.Reset();
	Constrains.Reset();
	ShowPoints.AddUninitialized(TestParticleNum);
	TestParticles.AddUninitialized(TestParticleNum);
	Constrains.AddUninitialized(ConstrainNum);

	TestParticles[0].bFree = false;
	TestParticles[1].bFree = false;
	TestParticles[2].bFree = false;
	TestParticles[3].bFree = false;

	for (int32 i = 0; i <= BoxHolderSecNum; i++)
	{
		FVector ZeroSide = FVector(BoxLength * i, 0, 0);
		FVector OneSide = FVector(BoxLength * i, BoxWidthAndHeight, 0);
		FVector TwoSide = FVector(BoxLength * i, BoxWidthAndHeight, BoxWidthAndHeight);
		FVector ThreeSide = FVector(BoxLength * i, 0, BoxWidthAndHeight);

		TestParticles[4 * i].CurPos = ZeroSide;
		TestParticles[4 * i + 1].CurPos = OneSide;
		TestParticles[4 * i + 2].CurPos = TwoSide;
		TestParticles[4 * i + 3].CurPos = ThreeSide;
	}

	for (int32 sec = 0; sec < BoxHolderSecNum; sec++)
	{
		Constrains[18 * sec].BuildConstrain(TestParticles[4 * sec], TestParticles[4 * sec + 1], BoxWidthAndHeight);
		Constrains[18 * sec + 1].BuildConstrain(TestParticles[4 * sec + 1], TestParticles[4 * sec + 2], BoxWidthAndHeight);
		Constrains[18 * sec + 2].BuildConstrain(TestParticles[4 * sec + 2], TestParticles[4 * sec + 3], BoxWidthAndHeight);
		Constrains[18 * sec + 3].BuildConstrain(TestParticles[4 * sec + 3], TestParticles[4 * sec], BoxWidthAndHeight);

		Constrains[18 * sec + 4].BuildConstrain(TestParticles[4 * sec + 1], TestParticles[4 * sec + 5], BoxWidthAndHeight);
		Constrains[18 * sec + 5].BuildConstrain(TestParticles[4 * sec + 2], TestParticles[4 * sec + 6], BoxWidthAndHeight);
		Constrains[18 * sec + 6].BuildConstrain(TestParticles[4 * sec + 3], TestParticles[4 * sec + 7], BoxWidthAndHeight);
		Constrains[18 * sec + 7].BuildConstrain(TestParticles[4 * sec], TestParticles[4 * sec + 4], BoxWidthAndHeight);

		Constrains[18 * sec + 8].BuildConstrain(TestParticles[4 * sec + 1], TestParticles[4 * sec + 3], SqrtTwo * BoxWidthAndHeight);
		Constrains[18 * sec + 9].BuildConstrain(TestParticles[4 * sec], TestParticles[4 * sec + 2], SqrtTwo * BoxWidthAndHeight);

		Constrains[18 * sec + 10].BuildConstrain(TestParticles[4 * sec + 2], TestParticles[4 * sec + 5], SqrtTwo * BoxWidthAndHeight);
		Constrains[18 * sec + 11].BuildConstrain(TestParticles[4 * sec + 1], TestParticles[4 * sec + 6], SqrtTwo * BoxWidthAndHeight);

		Constrains[18 * sec + 12].BuildConstrain(TestParticles[4 * sec], TestParticles[4 * sec + 7], SqrtTwo * BoxWidthAndHeight);
		Constrains[18 * sec + 13].BuildConstrain(TestParticles[4 * sec + 4], TestParticles[4 * sec + 3], SqrtTwo * BoxWidthAndHeight);

		Constrains[18 * sec + 14].BuildConstrain(TestParticles[4 * sec + 3], TestParticles[4 * sec + 6], SqrtTwo * BoxWidthAndHeight);
		Constrains[18 * sec + 15].BuildConstrain(TestParticles[4 * sec + 2], TestParticles[4 * sec + 7], SqrtTwo * BoxWidthAndHeight);

		Constrains[18 * sec + 16].BuildConstrain(TestParticles[4 * sec], TestParticles[4 * sec + 5], SqrtTwo * BoxWidthAndHeight);
		Constrains[18 * sec + 17].BuildConstrain(TestParticles[4 * sec + 1], TestParticles[4 * sec + 4], SqrtTwo * BoxWidthAndHeight);
	}

	Constrains[ConstrainNum - 6].BuildConstrain(TestParticles[TestParticleNum - 4], TestParticles[TestParticleNum - 3], BoxWidthAndHeight);
	Constrains[ConstrainNum - 5].BuildConstrain(TestParticles[TestParticleNum - 3], TestParticles[TestParticleNum - 2], BoxWidthAndHeight);
	Constrains[ConstrainNum - 4].BuildConstrain(TestParticles[TestParticleNum - 2], TestParticles[TestParticleNum - 1], BoxWidthAndHeight);
	Constrains[ConstrainNum - 3].BuildConstrain(TestParticles[TestParticleNum - 1], TestParticles[TestParticleNum - 4], BoxWidthAndHeight);

	Constrains[ConstrainNum - 2].BuildConstrain(TestParticles[TestParticleNum - 4], TestParticles[TestParticleNum - 2], SqrtTwo * BoxWidthAndHeight);
	Constrains[ConstrainNum - 1].BuildConstrain(TestParticles[TestParticleNum - 3], TestParticles[TestParticleNum - 1], SqrtTwo * BoxWidthAndHeight);
}


Enjoy it!!!

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

cpongo11

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值