Sign in to follow this  
photo

ObjectWaterMesh scale rendering

Recommended Posts

Добрый день, сотрудники компании Unigine.

Разрабатываю компонент анимации заполнения резервуара нефтью. Основная идея состоит в том, чтобы от mesh-а узла на который навешано свойство (компонент) динамически создать objectMeshStatic, с увеличенным Scale на 0.008f по осям X и Z, а на основе mesh-а созданного objectMeshStatic динамически создать ObjectWaterMesh, так-же с увеличенным Scale на 0.008f по осям X и Z, т.е. на 0.016f увеличен масштаб относительно базового узла на который навешан компонент. В этой схеме промежуточный ObjectMeshStatic создаю для того, чтобы не изменять "Transperency preset" у материала узла. Анимация налива подразумевает постепенное наращивание области заполнения нефтью части поверхности резервуара, но при этом видимая часть поверхности резервуара не должна менять свой первоначальный вид. Проблемой стало то, что если у материала поверхности резервуара задан какой-то "Transparency preset", например "Alpha Test" то созданный поверх ObjectWaterMesh выглядит прозрачным. Поэтому приходится поверх mesh-а резервуара создать на его основе ObjectMeshStatic, масштабировать его по осям X и Z на 0.008f, задать ему  настройки render-а материала на:

setBlendFunc(RenderState::BLEND_NONE, RenderState::BLEND_ZERO)

и после этого поверх него создать ObjectWaterMesh, также с увеличением масштаба по осям X и Z на 0.008f, после чего созданный ObjectWaterMesh уже не выглядит прозрачным. Анимация заполнения основывается на постепенном увеличении Scale у ObjectMeshStatic и ObjectWaterMesh по оси Y.

Например, если анимация заполнения нефтью будет составлять 50% резервуара, то графически общая схема выглядит так:

680870735_meshesscheme.thumb.png.7cea694c7a1110fa7a6dfeed433f44a7.png

Код компонента:

FillingAnimation.h

#pragma once
#include "../source/ComponentSystem/ComponentSystem.h"
#include <UnigineObjects.h>

using namespace Unigine;
using namespace Math;

class FillingAnimation : public ComponentBase
{
public:
	COMPONENT(FillingAnimation, ComponentBase);
	COMPONENT_INIT(init);
	COMPONENT_UPDATE(update);

	PROP_NAME("filling_animation");
	PROP_AUTOSAVE(1);
	PROP_PARAM(Float, filling_coefficient);
	PROP_PARAM(Float, filling_augment, 0.01f);
private:
	void init();
	void update();
	void coefficientCorrection();

private:
	bool filling = false;
	Vec3 position;
	Vec3 worldPosition;
	quat rotation;
	quat worldRotation;
	vec3 scale;
	vec3 worldScale;
	Mat4 transform;
	Mat4 worldTransform;

	ObjectWaterMeshPtr waterMesh;
	ObjectMeshStaticPtr substrateMesh;
	MeshPtr mesh;
	MeshPtr mesh2;
	float fillingCoefficient;
};

FillingAnimation.cpp

#include "FillingAnimation.h"
#include <UnigineMaterials.h>
#include <UnigineRender.h>
#include <UnigineGame.h>

using namespace Unigine;

REGISTER_COMPONENT(FillingAnimation)

void FillingAnimation::init()
{
	fillingCoefficient = filling_coefficient;

	position = node->getPosition();
	worldPosition = node->getWorldPosition();
	rotation = node->getRotation();
	worldRotation = node->getWorldRotation();
	scale = node->getScale();
	worldScale = node->getWorldScale();
	transform = node->getTransform();
	worldTransform = node->getWorldTransform();

	mesh = Mesh::create();
	mesh2 = Mesh::create();
	ObjectMeshStaticPtr nodeMesh = ObjectMeshStatic::cast(node);

	if (nodeMesh) {
		if (nodeMesh->getMesh(mesh)) {
			substrateMesh = ObjectMeshStatic::create(mesh);

			substrateMesh->setPosition(position);
			substrateMesh->setWorldPosition(worldPosition);
			substrateMesh->setRotation(rotation);
			substrateMesh->setWorldRotation(worldRotation);

			substrateMesh->setScale(vec3(nodeMesh->getScale().x + 0.008f, fillingCoefficient, nodeMesh->getScale().z + 0.008f));

			MaterialPtr nodeMaterial = nodeMesh->getMaterial(0);
			MaterialPtr newMaterial = nodeMaterial->inherit("rvs_000");
			newMaterial->setBlendFunc(RenderState::BLEND_NONE, RenderState::BLEND_ZERO);
			substrateMesh->setMaterial(newMaterial, "*");
			substrateMesh->getMesh(mesh2);

			waterMesh = ObjectWaterMesh::create(mesh2);
			waterMesh->setPosition(position);
			waterMesh->setWorldPosition(worldPosition);
			waterMesh->setRotation(rotation);
			waterMesh->setWorldRotation(worldRotation);
			waterMesh->setScale(vec3(substrateMesh->getScale().x + 0.008f, substrateMesh->getScale().y, substrateMesh->getScale().z + 0.008f));

			waterMesh->setWave(0, vec4(0.0f, 1.0f, 6.28319f, 0.0f));
			waterMesh->setWave(1, vec4(0.0f, 1.0f, 6.28319f, 0.0f));
			waterMesh->setWave(2, vec4(0.0f, 1.0f, 6.28319f, 0.0f));
			waterMesh->setWave(3, vec4(0.0f, 1.0f, 6.28319f, 0.0f));

			Materials *materials = Materials::get();
			MaterialPtr mat = materials->findMaterial("water_mesh_base_0");
			waterMesh->setMaterial(mat, "*");
			waterMesh->getMaterial(0)->setParameterFloat("underwater_fog_transparency", -1.0f);
		}
	}
}

void FillingAnimation::update()
{
	float delta = Game::get()->getIFps();
	fillingCoefficient += filling_augment * Game::get()->getIFps();
	substrateMesh->setScale(vec3(substrateMesh->getScale().x, fillingCoefficient, substrateMesh->getScale().z));
	waterMesh->setScale(vec3(substrateMesh->getScale().x, fillingCoefficient, substrateMesh->getScale().z));
}

В итоге я получаю проблемы с rendering-ом волн, т.к. в методе update я каждый кадр меняю Scale, то получаю рябь от наложений анимации волн:

1285147021_fillinganimation(bad).gif.c47fd0c23865b9fd2965173bd3af7083.gif

 

Вопросы:

  1. Скажите пожалуйста как мне сделать Rendering анимации заполнения корректным, подобным обычной анимации, статичного ObjectWaterMesh:
    2129612903_ObjectWaterMeshanimation.gif.c7bbafb45961a69935e0d7530b6810db.gif
  2. Может моя реализованная идея кардинально не верная и мою задачу нужно решать другим, более рациональным способом или может даже какими-то стандартными инструментами для реализации анимации имеющимися в движке Unigine?
    Задача в рамках которой реализую этот компонент - возможность анимации процесса слива/налива нефти в резервуаре при открытии/закрытии системы задвижек (других компонентов).

Share this post


Link to post

Николай, здравствуйте!

Мы не рекомендуем скейлить объекты типа WaterMesh. Из-за особенностей реализации они могут при скейле вести себя не совсем корректно.

Сходу пришла в голову другая мысль - сделать весь цилиндр (на 100% заполненности) и просто менять ему позицию по Z (часть цилиндра будет под террейном когда бак пустой). Такой вариант подойдет?

Спасибо!

Share this post


Link to post

I am just curious, thats y I ask: Why do u use the water mesh, not a regular mesh_base material?

Animated textures could probably do the same job (or better) than water material.?

;)

Best.w.

Share this post


Link to post
Posted (edited)
On 6/25/2020 at 11:42 AM, silent said:

Николай, здравствуйте!

Мы не рекомендуем скейлить объекты типа WaterMesh. Из-за особенностей реализации они могут при скейле вести себя не совсем корректно.

Сходу пришла в голову другая мысль - сделать весь цилиндр (на 100% заполненности) и просто менять ему позицию по Z (часть цилиндра будет под террейном когда бак пустой). Такой вариант подойдет?

Спасибо!

Жаль. Спасибо за совет - этот костыль, конечно подойдёт под текущую задачу и сцену, но задумывалось сделать универсальный компонент, а этот вариант не предусматривает его применение на многоуровневых сценах (какие-то установки с баками, сепараторы и т.д.)  или объекты над поверхностью.земли. Может всё-таки имеется-ли более профессиональное решение данной задачи?

Edited by nikolaj.kormushkin

Share this post


Link to post
1 hour ago, werner.poetzelberger said:

I am just curious, thats y I ask: Why do u use the water mesh, not a regular mesh_base material?

Animated textures could probably do the same job (or better) than water material.?

;)

Best.w.

Спасибо, werner.poetzelberger, я попробую реализовать Ваше предложение! Может у Вас есть уже готовые примеры реализованные на Unigine?

Share this post


Link to post

Uhm. Its the question, what you want to achive I assume.

Maybe a simple solution would be (this as well should solve the z fighting and you dont need extra meshes), to use the Detail Material Option of a base_mesh material.

Your base material is the tank. The detail material is the oil. You could animate the texcoordinates with an alpha channel to dragit across the tank.
Of course you need to set UV coord. correctly.

Or Just duplicate the tank and use the inflation (balloon) option to scale it. Then you hav a seperate mesh you can use for your effect.

Or use a decal, which you project onto the surface of the tank.

Or you write your own shader with a discard function.

So u see there are many options.

 

I think its easier, if you dont use the water material. So you will discover plenty of possibilities ;)

 

All the best.

Werner

 

 

 

Share this post


Link to post
Sign in to follow this