Jump to content

Paint Material in Play Mode


subabrain

Recommended Posts

Hi there,


sorry for my Question ... i try to exec the following function in play mode:


ETerrainEditor.autoMaterialLayer(-10000, 10000, 0, 90, 100);


now i execute this function in the console window.

it doenst work - but if i try in editor mode it works.


Maybe u can help me with that - Thanks a lot!


Greetz

Robert

Link to comment
Share on other sites

@subabrain


Sure it's possible to paint the terrain. In T3D, there really is no difference between "play mode" and "edit mode". It's the same mode, just different UI.


However, I would have to question whether it is the best solution to whatever you are trying to achieve.

As Duion mentioned, it's really resource intensive and the terrain is not designed to be repainted during play. If you are doing a singleplayer-only game it is definetly not too big of a task to implement however.


You should consider whether decals is the better solution to your problem however, as it is networked, more efficient and allows for a higher level of detail.

Link to comment
Share on other sites

Alright so that code is meant to be used with the terrain painter, which has a big brush which is the "Selection".


A guess for an implementation is, based on the above code is:

https://hastebin.com/afuxekalay.php

(I did NOT test this, and it is likely riddled with issues and syntactical errors.)


I ripped out all the logic for selection, brushes and slopes and just made the logic for a single point.

I'm not sure whether having a reference to a TerrainEditor is the best way to go, I think it would be better to avoid that and get the terrain directly. But the TerrainEditor already has most of the logic.

Link to comment
Share on other sites

Hello Again,


this is now my status:

 

void TerrainEditor::mow()
{
	GameConnection* connection = GameConnection::getConnectionToServer();
 
	Player* playerObject = dynamic_cast< Player* >(connection->getControlObject());
 
	Point3F pos = playerObject->getPosition();
 
	// Fetch the terrain with a ray-trace.
	TerrainBlock *terrain = TerrainEditor::getTerrainUnderWorldPoint(Point3F(pos));
	F32 squareSize = terrain->getSquareSize();
 
	Point2F p;
 
	GridPoint gp;
 
	gp.terrainBlock = terrain;
	// Z-coordinate is not used
	gp.gridPos = gp.terrainBlock->getGridPos(Point3F(pos));
 
	GridInfo inf;
	GridInfo gi;
 
	TerrainEditor::getGridInfo(gp, gi);
 
	// If grid is already set to our material, or it is an
	// empty grid spot, then skip painting.
	S32 mat = 1;
 
	inf.mMaterialChanged = true;
 
	// Painting is really simple now... set the one mat index.
	inf.mMaterial = mat;
	TerrainEditor::setGridInfo(inf, true);
 
	TerrainEditor::scheduleMaterialUpdate();
 
}

 

it should work but i cannot run the Method mow - i have done this already after the method:

 

DefineEngineMethod(TerrainEditor, mow, void, (), ,"")
{
	object->mow();
}

 

i try to run the following command in TorqueScript:

 

ETerrainEditor.mow();

 

and already added the method in the terrainEditor.h:

 

void mow();

 

so it seems that the function "mow" couldnt run of course there is NOT an Syntax error because it runs without any errors ... but i dont know fruther :roll:


Would be nice if you could help - thx!


Greetings

Robert

Link to comment
Share on other sites

Hello Guys,


okay - i get now made some changes with the above code:


first the "mow.cpp":

 

#include "mow.h"
#include "T3D/player.h"
#include "T3D/gameBase/gameConnection.h"
#include "gui/worldEditor/terrainEditor.h"
#include "gui/worldEditor/terrainActions.h"
#include "console/simBase.h"
#include "console/console.h"
#include "terrain/terrData.h"
 
IMPLEMENT_CONOBJECT(mow);
 
void mow::setTerrainMaterial()
{
 
	Point2F pos = Point2F(10.0f, 10.0f);
 
	Con::printf("durchlauf");
 
	U32 mat = 1;
 
	TerrainEditor *mTerrainEditor = new TerrainEditor();
 
	// Fetch the terrain with a ray-trace.
	TerrainBlock *terrain = mTerrainEditor->getTerrainUnderWorldPoint(Point3F(pos.x, pos.y, 1000.0f));
	F32 squareSize = 2.0;
 
	Point2F p;
 
	GridPoint gp;
 
	gp.terrainBlock = terrain;
	// Z-coordinate is not used
	gp.gridPos = gp.terrainBlock->getGridPos(Point3F(pos.x, pos.y, 0));
 
	GridInfo inf;
	GridInfo gi;
 
	mTerrainEditor->getGridInfo(gp, gi);
 
	// If grid is already set to our material, or it is an
	// empty grid spot, then skip painting.
	if (inf.mMaterial == mat || inf.mMaterial == U8_MAX)
 
	inf.mMaterialChanged = true;
 
	// Painting is really simple now... set the one mat index.
	inf.mMaterial = mat;
	mTerrainEditor->setGridInfo(inf, true);
 
	mTerrainEditor->scheduleMaterialUpdate();
 
}
 
DefineEngineMethod(mow, setTerrainMaterial, void, (), , "")
{
	object->setTerrainMaterial();
}

 

then the "mow.h":

 

#include "console/simBase.h"
 
class mow : public SimObject {
 
private:
 
	typedef SimObject Parent;
 
public:
 
	mow() { }
 
	void setTerrainMaterial();
 
	DECLARE_CONOBJECT(mow);
 
};

 

and now i run it with the following code in mow.cs: (first i add it to the scriptExec.cs):

 

function mowit() {
 
   %obj = new mow();  
   %obj.setTerrainMaterial();
 
}

 

okay - now i call the function "mowit" via console in T3D - but it crashes :/


please help!



Thank you very much!


Greetz

Robert

Link to comment
Share on other sites

Hi there,


okay - i think the sorucecode is right now:

 

#include "mow.h"
#include "T3D/player.h"
#include "T3D/gameBase/gameConnection.h"
#include "gui/worldEditor/terrainEditor.h"
#include "gui/worldEditor/terrainActions.h"
#include "console/simBase.h"
#include "console/console.h"
#include "terrain/terrData.h"
 
IMPLEMENT_CONOBJECT(mow);
 
 
void mow::setTerrainMaterial() {
 
	//Point3F pos = Point3F(100.0f, 100.0f, 0);
 
	Point2F pos = Point2F(100.0f, 100.0f);
 
	TerrainEditor *mTerrainEditor = new TerrainEditor();
 
	GameConnection* connection = GameConnection::getConnectionToServer();
 
	Player* playerObject = dynamic_cast< Player* >(connection->getControlObject());
 
	//Point3F pos = playerObject->getPosition();
 
	// Fetch the terrain with a ray-trace.
	TerrainBlock *terrain = mTerrainEditor->getTerrainUnderWorldPoint(Point3F(pos.x, pos.y, 0));
 
	//Point2F p;
 
	GridInfo gi;
	GridPoint gp;
 
	gp.terrainBlock = terrain;
	// Z-coordinate is not used
	gp.gridPos = gp.terrainBlock->getGridPos(Point3F(pos.x, pos.y, 0));
 
	GridInfo inf;
 
	U32 mat = 1;
 
	mTerrainEditor->getGridInfo(gp, gi);
 
	inf.mMaterialChanged = true;
 
	inf.mMaterial = mat;
	mTerrainEditor->setGridInfo(inf, true);
 
	mTerrainEditor->scheduleMaterialUpdate();
 
}
 
DefineEngineMethod(mow, setTerrainMaterial, void, (), , "")
{
	object->setTerrainMaterial();
}

 

But i always get an exception with the following code:

 

"**m**" was "0x1CC".

 

okay - maybe you could help.


Thanks a lot for all Answers!



Greetings

Robert

Link to comment
Share on other sites

Alright so the issue is that the Terrain Editor isn't properly initialized, and it doesn't have a terrain. You have to either re-implement its getTerrainUnderWorldPoint method, or do something similar. I opted for a simple ray-trace.


Furthermore there were two GridInfo variables, and the scheduleMaterialUpdate doesn't work the way we use it.


Here is a working example:

 

DefineEngineFunction(paintTerrainUnderPlayer, void, (U32 mat), (1), "")
{
	// Create a new instance of the TerrainEditor so we can use its functionality.
	TerrainEditor *mTerrainEditor = new TerrainEditor();
 
	// Get the connection to the player.
	GameConnection* connection = GameConnection::getConnectionToServer();
 
	// Fetch the player.
	Player* playerObject = dynamic_cast< Player* >(connection->getControlObject());
 
	// Get the player's position.
	Point3F pos = playerObject->getPosition();
	// Grab a point above the player.
	pos.z + 5;
 
	// Fetch the terrain with a ray-trace. There are probably more efficient ways to get this.
	TerrainBlock *terrain;
	RayInfo r;
	bool hit = gClientContainer.castRay(pos, Point3F(pos.x, pos.y, pos.z - 1000), TerrainObjectType, &r);
	if (hit) {
		terrain = dynamic_cast(r.object);
	}
 
	// Initialize the GridInfo and GridPoint that our player's position maps to.
	GridInfo gi;
	GridPoint gp;
 
	// Specify the terrain this GridPoint belongs to.
	gp.terrainBlock = terrain;
 
	// Map the player position to a point on the grid.
	gp.gridPos = gp.terrainBlock->getGridPos(pos);
 
	// Get the Terrain information at that point on the grid (such as texture, height etc.)
	mTerrainEditor->getGridInfo(gp, gi);
 
	// Map the material as dirty.
	gi.mMaterialChanged = true;
 
	// Change the material (to a layer which can be between 0 and 31).
	gi.mMaterial = mat;
 
	// Update the grid.
	mTerrainEditor->setGridInfo(gi, true);
 
	// Repaint the terrain.
	terrain->updateGridMaterials(gp.gridPos, gp.gridPos);
}

 

Tested it on newest Development branch and it works. Notice that the "mat" parameter, is the index of the desired texture layer as they are ordered in the TerrainPainter.

Furthermore this code is designed to run client-side in a single-player scenario. You would have to do some extra tricks to make it work in multiplayer.

Link to comment
Share on other sites

  • 1 month later...

What kind of flickering you mean? You probably mean that the grass gets updated everytime you click paint or constantly if you hold mouse button.

So either make the paint a one time action and not constantly as long as you hold it or reduce the update frequency or only update when the material was changed for real.

No idea how to do that, but that are just my thoughts.

Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...