Really new for Unreal Engine 4.
My main point is draw transparent 3d object with sprecific border made by lines.
For these i have array of points which make lines.
so i have a procedural mesh for creating in c++ object, but it can only draw polygons.
After searching information about line drawing in UE4, have tried to use "draw
debug lines", but it is only for debug and only for 2 points (i need draw array of points)
so - my problem is : drawing lines in c++ code of UE4.
how can i draw not debug lines?
If you have an array with all your linked point, why not iterate throught this array and create a DebugLine for each "linked points" ?
TArray<FVector> myArray = .... ;
for (size_t i = 0; i < myArray.Num() - 1; ++i)
{
FVector LinkStart = myArray[i];
FVector LinkEnd = myArray[i+1];
DrawDebugLine(GetWorld(), LinkStart, LinkEnd,
FColor(255,0,0), false, -1, 0, 10 );
}
If you really do not want debug line, there is another method to Drawline in the SceneManagement from the FPrimitiveDrawInterface classes.(I've never used it, not sure it's the better solution for your issue)
In a harder way, you can use the procedural generation of mesh in C++, where you create mesh and populate vertices and edges. Take a look at the doc, and you may be able to adapt the code for your case
For those who are struggling (like myself, once):
ULineBatchComponent::DrawLine - if you are looking to draw in world-space (https://docs.unrealengine.com/4.27/en-US/API/Runtime/Engine/Components/ULineBatchComponent/DrawLine/)
AHUD::DrawLine - if you need to draw on screen-space (https://docs.unrealengine.com/4.27/en-US/API/Runtime/Engine/GameFramework/AHUD/DrawLine/)
Related
I have two graphs of drawing signals on a gtkmm application.
The problem comes when I have to paint a graph with many points (around 300-350k) and lines to the following points since it slows down a lot to paint all the points each iteration.
bool DrawArea::on_draw(const Cairo::RefPtr<Cairo::Context>& c)
{
cairo_t* cr = c->cobj();
//xSignal.size() = ySignal.size() = 350000
for (int j = 0; j < xSignal.size() - 1; ++j)
{
cairo_move_to(cr, xSignal[j], ySignal[j]);
cairo_line_to(cr, xSignal[j + 1], ySignal[j + 1]);
}
cairo_stroke(cr);
return true;
}
I know that exist a cairo_stroke_preserve but i think is not valid for me because when I switch between graphs, it disappears.
I've been researching about save the path and restore it on the Cairo documentation but i don´t see anything. In 2007, a user from Cairo suggested in the documentation 'to do' the same thing but apparently it has not been done.
Any suggestion?
It's not necessary that you draw everything in on_draw. What I understand from your post is that you have a real-time waveform drawing application where samples are available at fixed periods (every few milliseconds I presume). There are three approaches you can follow.
Approach 1
This is good particularly when you have limited memory and do not care about retaining the plot if window is resized or uncovered. Following could be the function that receives samples (one by one).
NOTE: Variables prefixed with m_ are class members.
void DrawingArea::PlotSample(int nSample)
{
Cairo::RefPtr <Cairo::Context> refCairoContext;
double dNewY;
//Get window's cairo context
refCairoContext = get_window()->create_cairo_context();
//TODO Scale and transform sample to new Y coordinate
dNewY = nSample;
//Clear area for new waveform segment
{
refCairoContext->rectangle(m_dPreviousX
+ 1,
m_dPreviousY,
ERASER_WIDTH,
get_allocated_height()); //See note below on m_dPreviousX + 1
refCairoContext->set_source_rgb(0,
0,
0);
refCairoContext->fill();
}
//Setup Cairo context for the trace
{
refCairoContext->set_source_rgb(1,
1,
1);
refCairoContext->set_antialias(Cairo::ANTIALIAS_SUBPIXEL); //This is up to you
refCairoContext->set_line_width(1); //It's 2 by default and better that way with anti-aliasing
}
//Add sub-path and stroke
refCairoContext->move_to(m_dPreviousX,
m_dPreviousY);
m_dPreviousX += m_dXStep;
refCairoContext->line_to(m_dPreviousX,
dNewY);
refCairoContext->stroke();
//Update coordinates
if (m_dPreviousX
>= get_allocated_width())
{
m_dPreviousX = 0;
}
m_dPreviousY = dNewY;
}
While clearing area the X coordinate has to be offset by 1 because otherwise the 'eraser' will clear of the anti-aliasing on the last coulmn and your trace will have jagged edges. It may need to be more than 1 depending on your line thickness.
Like I said before, with this method your trace will get cleared if the widget is resized or 'revealed'.
Approach 2
Even here the sample are plotted the same way as before. Only difference is that each sample received is pushed directly into a buffer. When the window is resized or 'reveled' the widget's on_draw is called and there you can plot all the samples one time. Of course you'll need some memory (quite a lot if you have 350K samples in queue) but the trace stays on screen no matter what.
Approach 3
This one also takes up a little bit of memory (probably much more depending on the size of you widget), and uses an off-screen buffer. Here instead of storing samples we store the rendered result. Override the widgets on_map method and on_size_allocate to create an offsceen buffer.
void DrawingArea::CreateOffscreenBuffer(void)
{
Glib::RefPtr <Gdk::Window> refWindow = get_window();
Gtk::Allocation oAllocation = get_allocation();
if (refWindow)
{
Cairo::RefPtr <Cairo::Context> refCairoContext;
m_refOffscreenSurface =
refWindow->create_similar_surface(Cairo::CONTENT_COLOR,
oAllocation.get_width(),
oAllocation.get_height());
refCairoContext = Cairo::Context::create(m_refOffscreenSurface);
//TODO paint the background (grids may be?)
}
}
Now when you receive samples, instead of drawing into the window directly draw into the off-screen surface. Then block copy the off screen surface by setting this surface as your window's cairo context's source and then draw a rectangle to draw the newly plotted sample. Also in your widget's on_draw just set this surface as the source of widget's cairo context and do a Cairo::Context::paint(). This approach is particularly useful if your widget probably doesn't get resized and the advantage is that the blitting (where you transfer contents of one surface to the other) is way faster than plotting individual line segments.
To answer your question:
There is cairo_copy_path() and cairo_append_path() (there is also cairo_copy_path_flat() and cairo_path_destroy()).
Thus, you can save a path with cairo_copy_path() and later append it to the current path with cairo_append_path().
To answer your not-question:
I doubt that this will speed up your drawing. Appending these lines to the current path is unlikely to be slow. Rather, I would expect the actual drawing of these lines to be slow.
You write "it slows down a lot to paint all the points each iteration.". I am not sure what "each iteration" refers to, but why are you drawing all these points all the time? Wouldn't it make more sense to only draw them once and then to re-use the drawn result?
While my problem lies strictly in the opacity of the tristrip, I'd like to give some context first.
Recently I started developing a game through LibGdx which involves 2D circles which bounce around the screen. So as to provide a neat graphical effect, I created a small system that would provide a "tail" to the actors, which would fade over time. Visually, it looks like this:
Nice Trail Example
Now that ended up looking satisfactory. My problem, however, lies in situation where parts of the "trail" effect overlap, creating an ugly artifact which I would guess is the sum of the opacities of the points.
Ugly Trail Example
I believe this problem lies in the way with which the tristrip is drawn, specifically with the blending methods used.
The code used to generate the trail is as follows:
Array<Vector2> tristrip = new Array<Vector2>(); //Contains the vector information for OpenGL to build the strip.
Array<Vector2> texcoord = new Array<Vector2>(); //Contains the opacity information for the corresponding tristrip point.
// ... Code Here.... //
gl20.begin(camera.combined, GL20.GL_TRIANGLE_STRIP);
for (int i = 0; i < tristrip.size; i++) {
if (i == batchSize) {
gl20.end();
gl20.begin(camera.combined, GL20.GL_TRIANGLE_STRIP);
}
Vector2 point = tristrip.get(i);
Vector2 textcoord = texcoord.get(i);
gl20.color(color.r, color.g, color.b, color.a); // Color.WHITE
gl20.texCoord(textcoord.x, 0f);
gl20.vertex(point.x, point.y, 0);
}
gl20.end();
It is also important to note that the draw function for the strip is called within another class, in this fashion:
private void renderFX() {
Gdx.gl.glEnable(GL20.GL_BLEND);
Gdx.gl.glBlendFunc(GL20.GL_SRC_ALPHA, GL20.GL_ONE_MINUS_SRC_ALPHA);
Array<Ball> balls = mainstage.getBalls();
for (int i = 0; i < balls.size; i++) { //Draws the trails for each actor
balls.get(i).drawFX();
}
}
Is this problem a rookie mistake on my part, or was my implementation of the drawing of the vector array tristrip flawed from the start? How can I fix the blending issue in order to create smoother trails even in the presence of sharp curves?
Thanks in advance...
Edit: Since originally asking this question, I've experimented with some possible solutions, also implementing Deniz Yılmaz's suggestion of using a FBO to facilitate blending. Given that, my render function currently looks like this:
private void renderFX() {
frameBuffer.begin();
Gdx.gl20.glDisable(GL20.GL_BLEND);
Gdx.gl20.glClearColor(0f, 0f, 0f, 0);
Gdx.gl20.glClear(GL20.GL_COLOR_BUFFER_BIT);
Gdx.gl20.glEnable(GL20.GL_STENCIL_TEST);
Gdx.gl20.glStencilOp(GL20.GL_KEEP, GL20.GL_INCR, GL20.GL_INCR);
Gdx.gl20.glStencilMask(0xFF);
Gdx.gl20.glClear(GL20.GL_STENCIL_BUFFER_BIT);
Array<Ball> balls = mainstage.getBalls();
for (int i = 0; i < balls.size; i++) {
Gdx.gl20.glStencilFunc(GL20.GL_EQUAL, 0, 0xFF);
balls.get(i).drawFX(1f, Color.RED);
}
frameBuffer.end();
}
As shown, I've also experimented with stencils so as to try and mask the overlapping portion of the trail. This approach, however, results in the following visuals:
Stenciled Version
Again, this is not ideal, and has made me realize that approaching this problem by masking is not a good idea, as the opacity gradient will never be smooth in the corners as there will always be a sharp line between the two overlapping opacity values, even if somehow the logic prevents blending.
Given that, how else could I approach this problem? Should I scrap this method entirely if I plan to achieve a smooth gradient for this trail effect?
Thanks again.
glBlendFunc() is useless in this case because by default the values calculated based on the blend function are added.
So something like glBlendEquation(GL_MAX) needed
BUT
blending alone won't work, since it can't tell the difference between what is the background and what is the overlapping shapes.
Instead use FrameBuffer to draw trail with a glBlendEquation.
https://github.com/mattdesl/lwjgl-basics/wiki/FrameBufferObjects
Dear stackoverflowers,
I am trying to use a static (solid) body in ofxBox2d in openFrameworks. Because it's a concave object I am breaking it up in little triangles with the triangulation function of ofxBox2d. The triangulation is working fine as long as I don't create the body as static (ie density of zero).
So in my code I have:
//create shape here//
//triangulate shape here//
// now loop through all the triangles and make a box2d triangle
for (int i=0; i<tris.size(); i++)
{
ofPtr<ofxBox2dPolygon> triangle = ofPtr<ofxBox2dPolygon>(new ofxBox2dPolygon);
triangle.get()->addTriangle(tris[i].a, tris[i].b, tris[i].c);
triangle.get()->setPhysics(1, 0, 0); //density, bounce, friction
//triangle.get()->body->SetType(b2_staticBody);
triangle.get()->create(box2d.getWorld());
polyShapes.push_back(triangle);
}
Please see this link for 2 pictures showing the problem.
In the top picture : The object is dynamic (density > 0), it is triangulated properly but it is moved by the forces of the falling balls because it is dynamic. In red: what the original shape looks like.
In the bottom picture: If I set the density to 0 (or explicitly set it to static by uncomment the "SetType" line in the code above then my object is not drawn correctly (notice lines in top left corner of image) but behaves just like before (ie. balls pass through it, but they bump into "ghost" triangles); In red: the original (input) shape - or the solid object I expect.
I have written this small program the code of which I am attaching (openFrameworks).
I have tried my best to make a simple case to prove the point. Any help much appreciated :).
Thank you.
When my programm start, it must display a circle on a background. Also i must controll all displaying circles. I use class VertexController and class Vertex for that purpose. In Vertex i have constructor:
Vertex::Vertex(const ci::Vec2f & CurrentLoc){
vColor = Color(Rand::randFloat(123.0f),Rand::randFloat(123.0f),Rand::randFloat(123.0f));
vRadius = Rand::randFloat(23.0f);
vLoc = CurrentLoc;
}
and in VertexController i have
VertexController::VertexController()
{
Vertex CenterVertex = Vertex(getWindowCenter());
CenterVertex.draw(); // function-member draw solid circle with random color
}
and in setup{} method i wrote
void TutorialApp::setup(){
gl::clear(Color(255,204,0));
mVertexController=VertexController();
}
Unfrtunatelly, my way didnt work.I see only background.
So the main question - in CINDER_APP_BASIC drawing possible only in draw{},update{},setup{} directly? If yes, advise a solution, else say where is my fail.
this line of code does not make any sense to me:
mVertexController=VertexController();
Anyways, you should use draw() function just for drawing circles to window. This it why by default there is gl::clear(Color(0,0,0)); to clear background and start drawing new frame from scratch (this is the way drawing in OpenGL, used by default in Cinder, works).
I suggest to use Vector container for storing all circles (this way you can add and remove circles on the fly with some effort), add the first one in VertexController constructor, and make separate function VertexController::draw() to draw all circles using for loop.
I have a 2D list of vectors (say 20x20 / 400 points) and I am drawing these points on a screen like so:
for row in grid:
for point in row:
pygame.draw.circle(window, white, (particle.x, particle.y), 2, 0)
pygame.display.flip() #redraw the screen
This works perfectly, however it's much slower then I expected.
I want to rewrite this in C++ and hopefully learn some stuff (I am doing a unit on C++ atm, so it'll help) on the way. What's the easiest way to approach this? I have looked at Direct X, and have so far followed a bunch of tutorials and have drawn some rudimentary triangles. However I can't find a simple (draw point).
DirectX doesn't have functions for drawing just one point. It operates on vertex and index buffers only. If you want simpler way to make just one point, you'll need to write a wrapper.
For drawing lists of points you'll need to use DrawPrimitive(D3DPT_POINTLIST, ...). however, there will be no easy way to just plot a point. You'll have to prepare buffer, lock it, fill with data, then draw the buffer. Or you could use dynamic vertex buffers - to optimize performance. There is a DrawPrimitiveUP call that is supposed to be able to render primitives stored in system memory (instead of using buffers), but as far as I know, it doesn't work (may silently discard primitives) with pure devices, so you'll have to use software vertex processing.
In OpenGL you have glVertex2f and glVertex3f. Your call would look like this (there might be a typo or syntax error - I didn't compiler/run it) :
glBegin(GL_POINTS);
glColor3f(1.0, 1.0, 1.0);//white
for (int y = 0; y < height; y++)
for (int x = 0; x < width; x++)
glVertex2f(points[y][x].x, points[y][x].y);//plot point
glEnd();
OpenGL is MUCH easier for playing around and experimenting than DirectX. I'd recommend to take a look at SDL, and use it in conjuction with OpenGL. Or you could use GLUT instead of SDL.
Or you could try using Qt 4. It has a very good 2D rendering routines.
When I first dabbled with game/graphics programming I became fond of Allegro. It's got a huge range of features and a pretty easy learning curve.