I'm learning OpenGL with the openTK librairy in c#.
I've managed to successefuly renderer triangles on my window,
and things are running properly.
However, the performance is terrible (running at half a fps with only 100k triangles).
My question is, is there anything that I am doing badly ?
how could I improve performances ?
for the most part, I've followed this tutorial translated from c++.
Here is the render method, called each frame :
public static void Render()
{
//render the mesh render queue to the screen and clear it
GL.UseProgram(shaderProgram.id);
//meshRenderQueue is a List<Mesh>
foreach(Mesh mesh in meshRenderQueue)
{
mesh.Draw();
}
meshRenderQueue.Clear();
}
Here is my Mesh class :
public class Mesh
{
private Vertex[] vertices;
private uint[] triangles;
private int VAO;
private int VBO;
private int EBO;
public Mesh()
{
//create lots of unoptimized triangles to test performances
int triCount = 100000;
vertices = new Vertex[3 * triCount];
for(int i = 0; i < triCount; i++)
{
vertices[3 * i + 0] = new Vertex(new Vector3(-0.5f, -0.5f, 0f));
vertices[3 * i + 1] = new Vertex(new Vector3(0.5f, -0.5f, 0f));
vertices[3 * i + 2] = new Vertex(new Vector3(0, 0.5f, 0f));
};
triangles = new uint[3 * triCount];
for (int i = 0; i < triCount; i++)
{
triangles[3 * i + 0] = 0;
triangles[3 * i + 1] = 1;
triangles[3 * i + 2] = 2;
};
SetUpMesh();
}
private void SetUpMesh()
{
//initialize the openGL buffers
VAO = GL.GenVertexArray();
VBO = GL.GenBuffer();
EBO = GL.GenBuffer();
GL.BindVertexArray(VAO);
GL.BindBuffer(BufferTarget.ArrayBuffer, VBO);
GL.BufferData(BufferTarget.ArrayBuffer, vertices.Length * 8 * 4, vertices, BufferUsageHint.StaticDraw);
GL.BindBuffer(BufferTarget.ElementArrayBuffer, EBO);
GL.BufferData(BufferTarget.ElementArrayBuffer, triangles.Length * sizeof(int), triangles, BufferUsageHint.StaticDraw);
//vertex positions
GL.EnableVertexAttribArray(0);
GL.VertexAttribPointer(0, 3, VertexAttribPointerType.Float, false, 8 * 4, 0);
//vertex normals
GL.EnableVertexAttribArray(1);
GL.VertexAttribPointer(1, 3, VertexAttribPointerType.Float, false, 8 * 4, 3 * 4);
//vertex texture coords
GL.EnableVertexAttribArray(2);
GL.VertexAttribPointer(2, 2, VertexAttribPointerType.Float, false, 8 * 4, 6 * 4);
//unbind vertex array (what for ?)
GL.BindVertexArray(0);
}
public void Draw()
{
//render the mesh with the given shader
GL.BindVertexArray(VAO);
GL.DrawElements(BeginMode.Triangles, triangles.Length, DrawElementsType.UnsignedInt, 0);
GL.BindVertexArray(0);
}
}
And finally the Vertex struct, if usefull :
public struct Vertex
{
public Vector3 position;
public Vector3 normal;
public Vector2 textureCoords;
public Vertex(Vector3 pos, Vector3 norm, Vector2 textCoords)
{
position = pos;
normal = norm;
textureCoords = textCoords;
}
public Vertex(Vector3 pos)
{
position = pos;
normal = Vector3.zero;
textureCoords = new Vector2(0, 0);
}
}
Thanks in advance for any help. cheers !
Related
I have generated a 2D Hectogon in my scene view, however I am now confused as to how to make the shape three dimensional. Any help in the maths or method that is used to calculate this would be greatly appreciated. I have only just started with C# and I feel this is a tall order considering the lack of new relevant content on OpenTk in terms of most of the calls used in most tutorials are now obsolete.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Drawing;
using System.IO;
using OpenTK;
using OpenTK.Input;
using OpenTK.Graphics.OpenGL;
using OpenTK.Graphics;
namespace SimpleGame
{
class Game : GameWindow
{
public Game() : base(1280, 720, new GraphicsMode(32, 24, 0, 4)) // screen resilotion
{
}
int pgmID;
int vsID;
int fsID;
int attribute_vcol;
int attribute_vpos;
int uniform_mview;
int vbo_position;
int vbo_color;
int vbo_mview;
int ibo_elements;
Vector3[] vertdata;
Vector3[] coldata;
Matrix4[] mviewdata;
int[] indicedata;
float time = 0.0f;
void initProgram()
{
pgmID = GL.CreateProgram();
loadShader("F:/Year 1/Semester 2/Simulation In Games/SimpleGame/SimpleGame/vs.glsl", ShaderType.VertexShader, pgmID, out vsID);
loadShader("F:/Year 1/Semester 2/Simulation In Games/SimpleGame/SimpleGame/fs.glsl", ShaderType.FragmentShader, pgmID, out fsID);
GL.LinkProgram(pgmID);
Console.WriteLine(GL.GetProgramInfoLog(pgmID));
attribute_vpos = GL.GetAttribLocation(pgmID, "vPosition");
attribute_vcol = GL.GetAttribLocation(pgmID, "vColor");
uniform_mview = GL.GetUniformLocation(pgmID, "modelview");
GL.GenBuffers(1, out vbo_position);
GL.GenBuffers(1, out vbo_color);
GL.GenBuffers(1, out vbo_mview);
GL.GenBuffers(1, out ibo_elements);
}
protected override void OnLoad(EventArgs e)
{
base.OnLoad(e);
initProgram();
vertdata = new Vector3[] {
//new Vector3(0.0f,0.0f,0.0f), // center
//new Vector3(2.0f, 0f,0f), // right hand side
//new Vector3(0f,2f,0f), // up
new Vector3(0.0f,0.0f,-0.8f), // center point
new Vector3(2.0f,0.0f,-0.8f), // right hand side
new Vector3(1.0f,1.7f,-0.8f), // right hand top
new Vector3(-1.0f,1.7f,-0.8f), // right hand top
new Vector3(-2.0f,0.0f,-0.8f), // left hand top
new Vector3(-1.0f,-1.7f,-0.8f),
new Vector3(1.0f,-1.7f,-0.8f), // right hand top
};
indicedata = new int[]{
//front
0, 1, 2,
0, 2, 3,
//back
0, 3, 4,
0, 4, 5,
//left
0, 5, 6,
0, 6, 1,
};
coldata = new Vector3[] { new Vector3(1f, 0f, 0f),
new Vector3( 0f, 0f, 1f),
new Vector3( 0f, 1f, 0f),new Vector3(1f, 0f, 0f),
new Vector3( 0f, 0f, 1f),
new Vector3( 0f, 1f, 0f),new Vector3(1f, 0f, 0f),
new Vector3( 0f, 0f, 1f)};
mviewdata = new Matrix4[]{
Matrix4.Identity
};
Title = "Hello OpenTK!";
GL.ClearColor(Color.DarkTurquoise);
GL.PointSize(5f);
}
void loadShader(String filename, ShaderType type, int program, out int address)
{
address = GL.CreateShader(type);
using (StreamReader sr = new StreamReader(filename))
{
GL.ShaderSource(address, sr.ReadToEnd());
}
GL.CompileShader(address);
GL.AttachShader(program, address);
Console.WriteLine(GL.GetShaderInfoLog(address));
}
protected override void OnRenderFrame(FrameEventArgs e)
{
base.OnRenderFrame(e);
GL.Viewport(0, 0, Width, Height);
GL.Clear(ClearBufferMask.ColorBufferBit | ClearBufferMask.DepthBufferBit);
GL.Enable(EnableCap.DepthTest);
GL.EnableVertexAttribArray(attribute_vpos);
GL.EnableVertexAttribArray(attribute_vcol);
GL.DrawElements(BeginMode.Triangles, indicedata.Length, DrawElementsType.UnsignedInt, 0);
GL.DisableVertexAttribArray(attribute_vpos);
GL.DisableVertexAttribArray(attribute_vcol);
GL.Flush();
SwapBuffers();
}
protected override void OnUpdateFrame(FrameEventArgs e)
{
base.OnUpdateFrame(e);
GL.BindBuffer(BufferTarget.ArrayBuffer, vbo_position);
GL.BufferData<Vector3>(BufferTarget.ArrayBuffer, (IntPtr)(vertdata.Length * Vector3.SizeInBytes), vertdata, BufferUsageHint.StaticDraw);
GL.VertexAttribPointer(attribute_vpos, 3, VertexAttribPointerType.Float, false, 0, 0);
GL.BindBuffer(BufferTarget.ArrayBuffer, vbo_color);
GL.BufferData<Vector3>(BufferTarget.ArrayBuffer, (IntPtr)(coldata.Length * Vector3.SizeInBytes), coldata, BufferUsageHint.StaticDraw);
GL.VertexAttribPointer(attribute_vcol, 3, VertexAttribPointerType.Float, true, 0, 0);
time += (float)e.Time;
mviewdata[0] = Matrix4.CreateRotationY(0.2f time) Matrix4.CreateRotationX(0.0f time) Matrix4.CreateTranslation(0.0f, -1.0f, -4.0f) *
Matrix4.CreatePerspectiveFieldOfView(1.3f, ClientSize.Width / (float)ClientSize.Height, 1.0f, 40.0f); // rotation
GL.UniformMatrix4(uniform_mview, false, ref mviewdata[0]);
GL.UseProgram(pgmID);
GL.BindBuffer(BufferTarget.ArrayBuffer, 0);
GL.BindBuffer(BufferTarget.ElementArrayBuffer, ibo_elements);
GL.BufferData(BufferTarget.ElementArrayBuffer, (IntPtr)(indicedata.Length * sizeof(int)), indicedata, BufferUsageHint.StaticDraw);
}
}
}
I don't think there is a built in method for creating prisms. A prism based on a heptagon (7-sided polygon) is made up from two heptagons (one on the bottom, one on the top) plus 7 vertical 4-sided polygons. So the algorithm for extruding a prism from a horizontal polygon would be (in pseudo code)
create_prism(bottom : polygon, height : float) : body
var top : polygon
top = bottom.Clone()
for all vertices v of top
v.z = v.z + height
end
var b = new body
b.Add(bottom)
b.Add(top)
for i : integer = 0 to bottom.Count - 1
var j : integer
j = (i + 1) modulo bottom.Count
var side = new polygon[4]
side[0] = bottom[i]
side[1] = bottom[j]
side[2] = top[j]
side[3] = top[i]
b.Add(side)
end
return b
end
I'm running a C# project with the Pencil.Gaming library, which is the C# binding of GLFW which uses OpenTK to wrap OpenGL functions. I am trying to draw an array of Vertices in a vbo, and once I get to GL.DrawArrays, it gives me a System.AccessViolationException and an Invalid Operation error when I call GL.GetError(). Below is my code for the Mesh class and a screencap of the error is Visual Studio. The object I am trying to draw and a copy of my Vertex class is also below.
static Mesh mesh;
mesh = new Mesh();
Vertex[] data = new Vertex[] {new Vertex(new Vector3(-1,-1,0)),
new Vertex(new Vector3(0,1,0)),
new Vertex(new Vector3(1,-1,0))};
mesh.addVertices(data);
mesh.draw();
The Vertex Class:
struct Vertex
{
public static readonly int SIZE = 3;
private Vector3 position;
public Vertex(Vector3 position)
{
this.position = position;
}
}
The Mesh class:
using System;
using Pencil.Gaming.Graphics;
using Pencil.Gaming.MathUtils;
namespace Practicalis.Rendering
{
class Mesh
{
private int size;
private int vbo;
public Mesh()
{
size = 0;
GL.GenBuffers(size, out vbo);
}
public void addVertices(Vertex[] vertices)
{
size = vertices.Length * sizeof(float);
GL.BindBuffer(BufferTarget.ArrayBuffer, vbo);
GL.BufferData(BufferTarget.ArrayBuffer, (IntPtr)size, (IntPtr)vbo, BufferUsageHint.StaticDraw);
}
public void draw()
{
GL.EnableVertexAttribArray(0);
GL.BindBuffer(BufferTarget.ArrayBuffer, vbo);
GL.VertexAttribPointer(0, 3, VertexAttribPointerType.Float, false, Vertex.SIZE * 4, 0);
Console.WriteLine(GL.GetError());
GL.DrawArrays(BeginMode.Triangles, 0, size);
GL.DisableVertexAttribArray(0);
}
}
}
GL.GenBuffers(size, out vbo);
Before this line you have size 0. It should be at least one since thats the number of buffers to be generated.
In the add vertice function, I wasn't passing in my actual Vertex array, just the pointer to vbo. The proper function is below.
public void addVertices(Vertex[] vertices)
{
size = vertices.Length * Vector3.SizeInBytes;
Vector3[] vertsData = new Vector3[vertices.Length];
GL.BindBuffer(BufferTarget.ArrayBuffer, vbo);
for (int i = 0; i < vertices.Length; i++)
vertsData[i] = vertices[i].Position;
GL.BufferData(BufferTarget.ArrayBuffer, (IntPtr)size, vertsData, BufferUsageHint.StaticDraw);
}
I need to know how to draw transparent circle/ellipse using OpenTK in Xamarin.Forms.
I have tried with creating Vertex and Fragment shaders with reference of following link : How to draw circle on OpenGL ES 2.0 cross platform? But did not get anything on screen it is showing blank on screen.
Below is the Sample Code used to draw circle with OpenTK in Xamarin.Forms.
GL.ClearColor(0.0f, 0.0f, 0.0f, 1.0f);
GL.Clear(ClearBufferMask.ColorBufferBit | ClearBufferMask.DepthBufferBit);
GL.Enable(EnableCap.DepthTest);
GL.UseProgram(programID);
// The locations where we pass in our color and vertex data
positionInput = GL.GetAttribLocation(programID, "Position");
colorInput = GL.GetAttribLocation(programID, "SourceColor");
// The locations where we pass in unchanging data
projectionInput = GL.GetUniformLocation(programID, "Projection");
modelviewInput = GL.GetUniformLocation(programID, "Modelview");
Matrix4 modelview = Matrix4.CreateRotationX(rotation) * Matrix4.CreateRotationY(rotation) * Matrix4.CreateRotationZ(rotation) * Matrix4.CreateTranslation(xTranslation, yTranslation, -7f);
GL.UniformMatrix4(modelviewInput, false, ref modelview);
float h = 4.0f * (height / width);
Matrix4 projection = Matrix4.CreatePerspectiveOffCenter(-2, 2, -h / 2f, h / 2f, 4, 10);
GL.Viewport(0, 0, (int)width, (int)height);
GL.UniformMatrix4(projectionInput, false, ref projection);
GL.BindBuffer(BufferTarget.ArrayBuffer, colorDataBuffer);
GL.EnableVertexAttribArray(colorInput);
GL.VertexAttribPointer(colorInput, 4, VertexAttribPointerType.Float, false, 0, 0);
float DEGREE_TO_RAD = (float)( 3.14 / 180);
int M_IN_DEGREE = 370;
int N_IN_DEGREE = 100;
int nCount = 1;
int index = 0;
int size = 2;
float[] stVertexArray = new float[2*360];
stVertexArray[0] = 0;
stVertexArray[1] = 0;
for( int nR =N_IN_DEGREE; nR < M_IN_DEGREE; nR++ )
{
float fX = (float) System.Math.Sin((float)nR * DEGREE_TO_RAD ) ;
float fY = (float) System.Math.Cos((float)nR * DEGREE_TO_RAD );
stVertexArray[nCount*2] = fX;
stVertexArray[nCount*2 + 1] = fY;
nCount++;
}
GL.BindBuffer(BufferTarget.ArrayBuffer, stVertexArray.Length);
GL.EnableVertexAttribArray(0);
GL.VertexAttribPointer (index,size, VertexAttribPointerType.Float, false, stVertexArray.Length, IntPtr.Zero);
GL.DrawElements(BeginMode.LineLoop, stVertexArray.Length, DrawElementsType.UnsignedByte,stVertexArray);
GL.Finish();
I am pretty new to the 3D side of XNA and am converting a 2D game.
Its basically designed as a grid and I am drawing with the code below. This works but is a bit laggy, am I doing this completely wrong? Presumably there shouldn't be much lag at this point when we are only talking about a few small models.
protected override void Draw(GameTime gameTime)
{
fpsTimer += gameTime.ElapsedGameTime;
fpsCount++;
if (fpsTimer >= TimeSpan.FromSeconds(1))
{ fpsTimer = TimeSpan.FromSeconds(0); fps = fpsCount; fpsCount = 0; }
GraphicsDevice.Clear(Color.CornflowerBlue);
projection = Matrix.CreatePerspectiveFieldOfView(MathHelper.PiOver4, device.Viewport.AspectRatio, 1.0f, 1000.0f);
world = Matrix.CreateTranslation(new Vector3(0, 0, 0));
view = Matrix.CreateLookAt(new Vector3(xPos, yPos, zHeight), new Vector3(xPos, yPos + zRotation, 0), new Vector3(0, 5, 0));
// DRAW OBJECTS ON MAP
drawMap(view, world, projection);
spriteBatch.Begin(SpriteSortMode.Immediate, BlendState.AlphaBlend);
spriteBatch.DrawString(font, "" + fps, new Vector2(100, 100), Color.Black);
spriteBatch.End();
base.Draw(gameTime);
}
private void drawMap(Matrix view, Matrix world, Matrix projection)
{
GraphicsDevice.BlendState = BlendState.Opaque;
GraphicsDevice.DepthStencilState = DepthStencilState.Default;
GraphicsDevice.SamplerStates[0] = SamplerState.LinearWrap;
int scale = Globals.scale;
int screenWidthScale = Globals.screenwidth / scale;
int screenHeightScale = Globals.screenheight / scale;
int mapXtile = Convert.ToInt32(xPos/2);
int mapYtile = Convert.ToInt32(yPos/2);
for (int i = Convert.ToInt32(xPos/2) - 30; i < Convert.ToInt32(xPos/2) + 30; i++)
{
for (int a = Convert.ToInt32(yPos/2); a < Convert.ToInt32(yPos/2) + 50; a++)
{
if (mapXtile > 0 && mapYtile > 0 && mapXtile < Globals.mapsizex && mapYtile < Globals.mapsizey)
{
int currentTile = Globals.levelArray[mapXtile, mapYtile].TyleType;
// DRAW TREES
if (currentTile == tyleType.tree)
{
if (Globals.levelArray[mapXtile, mapYtile].typeModifier == 1)
{
Matrix worldMatrix = Matrix.CreateScale(0.8f, 0.8f, 0.8f) * Matrix.CreateRotationX(1.5f) * Matrix.CreateTranslation(new Vector3(i * 2 + 0.2f, a * 2 - 0.4f, -0.1f));
tree.Draw(worldMatrix, view, projection);
}
if (Globals.levelArray[mapXtile, mapYtile].typeModifier == 2)
{
Matrix worldMatrix = Matrix.CreateScale(0.8f, 0.8f, 0.8f) * Matrix.CreateRotationX(1.5f) * Matrix.CreateTranslation(new Vector3(i * 2+0.2f, a * 2-0.4f, -0.1f));
tree2.Draw(worldMatrix, view, projection);
}
}
}
mapYtile = mapYtile + 1;
//mapYtile++;
}
mapXtile = mapXtile + 1;
mapYtile = Convert.ToInt32(yPos / 2);
}
}
So i have been finding that for Box2D your physics information should not be your rendering information
so you can't do things like
spriteBatch.Draw(mazeBox, mazeBody.Position / 0.01f, Color.White)
instead you should create transforms of the physics info and use that as your rendering.
So what does that exactly mean? I have been trying to find info on how to use transforms and render but i am getting blanks.
That means that physics could be rendered just as you wish: bigger, smaller, rotated, translated and so on. You just need to find out which proportions your renderer (in our case it's XNA) will draw your physic bodies. Just do the next: draw a line at ground position and a 1x1 box in the ball / box position using "hello box2d" application (this one doesn't exists at all, but you can simply create a new box2d application, which does nothing but simulating ball / box falling on the floor. And do not forget about stepping your physics!).
If you're interested, here's my SFML application with box2d and some character controller basics:
#include <stdio.h>
#include <Box2D/Box2D.h>
#include <SFML/Window.hpp>
#include <SFML/Graphics.hpp>
#include "Animation.h"
#pragma comment(lib, "Box2D.lib")
#pragma comment(lib, "sfml-system.lib")
#pragma comment(lib, "sfml-window-s.lib")
#pragma comment(lib, "sfml-graphics.lib")
#define M_PI 3.14f
#define PIXELS_PER_METER 64.f
#define METERS_PER_PIXEL (1.f / PIXELS_PER_METER)
#define PPM PIXELS_PER_METER
#define MPP METERS_PER_PIXEL
#define x_cor 2.f * METERS_PER_PIXEL
#define y_cor METERS_PER_PIXEL
// Thanks to bobasaurus =)
class DebugDraw : public b2DebugDraw
{
public:
DebugDraw(sf::RenderWindow *renderWindow)
{
window = renderWindow;
}
void DrawPolygon(const b2Vec2 *vertices, int32 vertexCount, const b2Color &color)
{
sf::Shape polygon;
for (int32 i = 0; i < vertexCount; i++)
{
b2Vec2 vertex = vertices[i];
polygon.AddPoint(vertex.x * PIXELS_PER_METER, window->GetHeight() - (vertex.y * PIXELS_PER_METER), sf::Color(0, 0, 0, 0), B2SFColor(color));
}
window->Draw(polygon);
}
void DrawSolidPolygon(const b2Vec2 *vertices, int32 vertexCount, const b2Color &color)
{
sf::Shape polygon;
for (int32 i = 0; i < vertexCount; i++)
{
b2Vec2 vertex = vertices[i];
polygon.AddPoint(vertex.x * PIXELS_PER_METER, window->GetHeight() - (vertex.y * PIXELS_PER_METER), B2SFColor(color)); //need transparant outline?
}
window->Draw(polygon);
}
void DrawCircle(const b2Vec2& center, float32 radius, const b2Color& color)
{
sf::Shape circle = sf::Shape::Circle(center.x * PPM, window->GetHeight() - (center.y * PPM), radius * PPM, sf::Color(0, 0, 0, 0), 1.0f, B2SFColor(color));
window->Draw(circle);
}
void DrawSolidCircle(const b2Vec2& center, float32 radius, const b2Vec2& axis, const b2Color& color)
{
sf::Shape circle = sf::Shape::Circle(center.x * PPM, window->GetHeight() - (center.y * PPM), radius * PPM, B2SFColor(color));
window->Draw(circle);
}
void DrawSegment(const b2Vec2& p1, const b2Vec2& p2, const b2Color& color) {}
void DrawTransform(const b2Transform& xf) {}
private:
sf::RenderWindow *window;
sf::Color B2SFColor(const b2Color &color)
{
sf::Color result((sf::Uint8) (color.r * 255), (sf::Uint8) (color.g * 255), (sf::Uint8) (color.b * 255));
return result;
}
};
int main()
{
sf::RenderWindow *App = new sf::RenderWindow(sf::VideoMode(800, 600, 32), "SFML + Box2D Test");
App->UseVerticalSync(true);
// ================= Init Physics ====================
b2World *world = new b2World(b2Vec2(0.0f, -10.0f), true);
DebugDraw *debugDraw = new DebugDraw(App);
debugDraw->SetFlags(b2DebugDraw::e_shapeBit);
world->SetDebugDraw(debugDraw);
// Define the ground body.
b2BodyDef groundBodyDef;
groundBodyDef.position.Set(0.0f * x_cor, 0.0f * y_cor);
b2Body* groundBody = world->CreateBody(&groundBodyDef);
b2PolygonShape groundBox;
groundBox.SetAsBox(500.f * x_cor, 10.0f * y_cor);
groundBody->CreateFixture(&groundBox, 0.0f);
// ====================================================
// ====================================
/*b2PolygonShape shape;
shape.SetAsBox(5.f * x_cor, 5.f * x_cor);
b2FixtureDef fd;
fd.shape = &shape;
fd.density = 1.0f;
fd.friction = 0.3f;
fd.restitution = 0.7f;
b2BodyDef bd;
bd.type = b2_dynamicBody;
bd.angle = M_PI / 4.f;
bd.position.Set(10.f * x_cor, 80.f * x_cor);
b2Body* body = world->CreateBody(&bd);
body->CreateFixture(&fd);*/
b2BodyDef bd;
bd.position.Set(3.0f, 5.0f);
bd.type = b2_dynamicBody;
bd.fixedRotation = true;
bd.allowSleep = false;
b2Body* body = world->CreateBody(&bd);
b2PolygonShape shape;
shape.SetAsBox(0.25f, 0.25f);
b2FixtureDef fd;
fd.shape = &shape;
fd.friction = 20.0f;
fd.density = 20.0f;
body->CreateFixture(&fd);
// ====================================
sf::Image Image;
if (!Image.LoadFromFile("moo.jpg"))
return 1;
//Image.Copy(Image, 0, 0, sf::IntRect(0, 0, 67 * 5, 68));
sf::Animation Sprite(Image, 45, 50, 5);
Sprite.SetLoopSpeed(20);
Sprite.Play(0, 4);
Sprite.SetBlendMode(sf::Blend::Alpha);
Sprite.SetCenter(Sprite.GetSize().x / 2, Sprite.GetSize().y / 2);
while (App->IsOpened())
{
sf::Event Event;
static std::vector<sf::Vector2f> points;
static sf::Color cl;
bool nonConvex = false;
while (App->GetEvent(Event))
{
if (Event.Type == sf::Event::Closed)
App->Close();
if (Event.Type == sf::Event::KeyPressed)
{
if (Event.Key.Code == sf::Key::Escape)
App->Close();
if (Event.Key.Code == sf::Key::W && abs(body->GetLinearVelocity().y) < 1.0f)
body->ApplyLinearImpulse(b2Vec2(0, 5 * body->GetMass()), body->GetWorldCenter());
}
}
{
if (App->GetInput().IsKeyDown(sf::Key::A) && abs(body->GetLinearVelocity().x) < 5.0f)
{
body->ApplyForce(b2Vec2(-30 * body->GetMass(), 0), body->GetPosition());
}
if (App->GetInput().IsKeyDown(sf::Key::D) && abs(body->GetLinearVelocity().x) < 5.0f)
{
body->ApplyForce(b2Vec2(30 * body->GetMass(), 0), body->GetPosition());
}
if (App->GetInput().IsKeyDown(sf::Key::D))
{
//if (Sprite.IsStopped())
{
Sprite.FlipX(false);
Sprite.Play(0, 5);
}
} else
if (App->GetInput().IsKeyDown(sf::Key::A))
{
//if (Sprite.IsStopped())
{
Sprite.FlipX(true);
Sprite.Play(0, 5);
}
} else
//if (!Sprite.IsStopped())
{
Sprite.Play(12, 22);
}
}
world->Step(App->GetFrameTime(), 1024, 1024);
world->ClearForces();
App->Clear();
// And draw all the stuff
world->DrawDebugData();
Sprite.Update();
Sprite.SetPosition(body->GetPosition().x * PPM, App->GetHeight() - (body->GetPosition().y * PPM));
App->Draw(Sprite);
App->Display();
}
return 0;
}
Given a Body that represents a rectangle, the following c# code will render a texture according to the Body's physics:
spritebatch.Begin();
spritebatch.Draw(texture,
Body.Position * Scale,
textureSourceRectangle,
Color.White,
Body.Rotation,
new Vector2(textureWidth / 2f, textureHeight / 2f),
1f,
SpriteEffects.None,
0);
spritebatch.End();
Scale is defined for me as 100.0f, meaning that a Body with Height set to 0.1f is equal to 0.1f * 100.0f = 10 pixels.
The same goes for Body.Position. (0.1f, 0.1f) in box2D is equal to (10,10) in screen coordinates.
It's also important to set the Origin to the center of the rectangle when drawing. This way the rotation happens around the center of your texture.