FPS weapon with gluLookAt - visual-c++

I'm developing a 3D maze-like game, just for learning(and of course for fun :) ). I have made the maze, I can move between the walls in First-Person mode. My only problem is, that I want some kind of weapon for my First-Person view( like an FPS game). To moving in the maze I'm using gluLookAt.
Code snippets:
void RenderScene(void)
{
glLoadIdentity();
gluLookAt(x, 1.0f, z,x + lx, 1.0f, z + lz,0.0f, 1.0f, 0.0f);
....
glBindTexture(GL_TEXTURE_2D, texture[0]); //texture binding
glScalef(7.0f, 8.0f, 7.0f);
glTranslatef(-(r * 2), 0.0f, -(c * 2)); //place the maze walls(cubes)
glCallList(mazeListId);//using the display list
}
void SpecialKeys(int key, int xx, int yy)
{
// ...
int state;
float fraction = 1.0f;
switch (key) {
case GLUT_KEY_LEFT:
angle -= 0.15f;
lx = sin(angle);
lz = -cos(angle);
break;
case GLUT_KEY_RIGHT:
angle += 0.15f;
lx = sin(angle);
lz = -cos(angle);
break;
case GLUT_KEY_UP:
x += lx * fraction;
z += lz * fraction;
break;
case GLUT_KEY_DOWN:
x -= lx * fraction;
z -= lz * fraction;
break;
}
I've tried to do this with my cube( the cube is now the "weapon").
glPushMatrix();
glTranslatef(0.0f, 0.0f, 5.0f);
glTranslatef(x + lx, -0.5f, z + lz);
glRotatef(angle, 0.0f, 0.0f, 1.0f);
drawCube(2);
glPopMatrix();
With this the cube moves forward és backward perfectly, but when I turn left or right, it stays at its position.
Can somebody help me with the turning?

Finally, I solved the problem! I didn't made the right order with the transformations. I share my code, if someone will need it in the future.
gluLookAt(x, 1.0f, z,
x + lx, 1.0f, z + lz,
0.0f, 1.0f, 0.0f);
glPushMatrix();
glTranslatef(x + lx, -0.5f, z + lz);
glRotatef(-angle* 57.2957795, 0.0f, 1.0f, 0.0f);
glTranslatef(0.0f, 0.0f, 5.0f); // offset
drawCube(2);
glPopMatrix();

Related

How to draw sample code from the Cairo documentation?

I'm a complete beginner and would really like to draw some of the shapes from https://www.cairographics.org/samples/ and tinker a bit with the placement of these shapes. But first I need to set everything up - just copy-pasting the code doesn't work.
/* a custom shape that could be wrapped in a function */
double x = 25.6, /* parameters like cairo_rectangle */
y = 25.6,
width = 204.8,
height = 204.8,
aspect = 1.0, /* aspect ratio */
corner_radius = height / 10.0; /* and corner curvature radius */
double radius = corner_radius / aspect;
double degrees = M_PI / 180.0;
cairo_new_sub_path (cr);
cairo_arc (cr, x + width - radius, y + radius, radius, -90 * degrees, 0 * degrees);
cairo_arc (cr, x + width - radius, y + height - radius, radius, 0 * degrees, 90 * degrees);
cairo_arc (cr, x + radius, y + height - radius, radius, 90 * degrees, 180 * degrees);
cairo_arc (cr, x + radius, y + radius, radius, 180 * degrees, 270 * degrees);
cairo_close_path (cr);
cairo_set_source_rgb (cr, 0.5, 0.5, 1);
cairo_fill_preserve (cr);
cairo_set_source_rgba (cr, 0.5, 0, 0, 0.5);
cairo_set_line_width (cr, 10.0);
cairo_stroke (cr);
This code should generate the following shape:
a rounded rectangle
But clearly more is needed. So I decided to run the following code, which creates a window:
#include <X11/Xlib.h>
#include <X11/Xatom.h>
#include <X11/Xutil.h>
#include <cairo.h>
#include <cairo-xlib.h>
#include <stdio.h>
#include <stdlib.h>
/*! Simple Cairo/Xlib example.
* #author Bernhard R. Fischer, 2048R/5C5FFD47 <bf#abenteuerland.at>.
* #version 2014110801
* Compile with
* gcc -Wall $(pkg-config --libs --cflags cairo x11) -o cairo_xlib_simple cairo_xlib_simple.c
*/
/*! Check for Xlib Mouse/Keypress events. All other events are discarded.
* #param sfc Pointer to Xlib surface.
* #param block If block is set to 0, this function always returns immediately
* and does not block. if set to a non-zero value, the function will block
* until the next event is received.
* #return The function returns 0 if no event occured (and block is set). A
* positive value indicates that a key was pressed and the X11 key symbol as
* defined in <X11/keysymdef.h> is returned. A negative value indicates a mouse
* button event. -1 is button 1 (left button), -2 is the middle button, and -3
* the right button.
*/
int cairo_check_event(cairo_surface_t *sfc, int block)
{
char keybuf[8];
KeySym key;
XEvent e;
for (;;)
{
if (block || XPending(cairo_xlib_surface_get_display(sfc)))
XNextEvent(cairo_xlib_surface_get_display(sfc), &e);
else
return 0;
switch (e.type)
{
case ButtonPress:
return -e.xbutton.button;
case KeyPress:
XLookupString(&e.xkey, keybuf, sizeof(keybuf), &key, NULL);
return key;
default:
fprintf(stderr, "Dropping unhandled XEevent.type = %d.\n", e.type);
}
}
}
/*! Open an X11 window and create a cairo surface base on that window.
* #param x Width of window.
* #param y Height of window.
* #return Returns a pointer to a valid Xlib cairo surface. The function does
* not return on error (exit(3)).
*/
cairo_surface_t *cairo_create_x11_surface0(int x, int y)
{
Display *dsp;
Drawable da;
int screen;
cairo_surface_t *sfc;
if ((dsp = XOpenDisplay(NULL)) == NULL)
exit(1);
screen = DefaultScreen(dsp);
da = XCreateSimpleWindow(dsp, DefaultRootWindow(dsp), 0, 0, x, y, 0, 0, 0);
XSelectInput(dsp, da, ButtonPressMask | KeyPressMask);
XMapWindow(dsp, da);
sfc = cairo_xlib_surface_create(dsp, da, DefaultVisual(dsp, screen), x, y);
cairo_xlib_surface_set_size(sfc, x, y);
return sfc;
}
/*! Destroy cairo Xlib surface and close X connection.
*/
void cairo_close_x11_surface(cairo_surface_t *sfc)
{
Display *dsp = cairo_xlib_surface_get_display(sfc);
cairo_surface_destroy(sfc);
XCloseDisplay(dsp);
}
int main(int argc, char **argv)
{
cairo_surface_t *sfc;
cairo_t *ctx;
sfc = cairo_create_x11_surface0(500, 500);
ctx = cairo_create(sfc);
cairo_set_source_rgb(ctx, 1, 1, 1);
cairo_paint(ctx);
cairo_move_to(ctx, 20, 20);
cairo_line_to(ctx, 200, 400);
cairo_line_to(ctx, 450, 100);
cairo_line_to(ctx, 20, 20);
cairo_set_source_rgb(ctx, 0, 0, 1);
cairo_fill_preserve(ctx);
cairo_set_line_width(ctx, 5);
cairo_set_source_rgb(ctx, 1, 1, 0);
cairo_stroke(ctx);
cairo_destroy(ctx);
cairo_check_event(sfc, 1);
cairo_close_x11_surface(sfc);
return 0;
}
The output can be accessed here: black window launches successfully
How do I now draw the shape and some text?
Kind regards,
'm a complete beginner and would really like to draw some of the shapes from https://www.cairographics.org/samples/ and tinker a bit with the placement of these shapes.
The simplest approach would not be to open an image, but instead to draw a PNG. Here is an example for the first example from that page.
#include <cairo.h>
#include <math.h> // For M_PI
int main() {
cairo_surface_t *surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, 300, 300);
cairo_t *cr = cairo_create (surface);
// Start of example
double xc = 128.0;
double yc = 128.0;
double radius = 100.0;
double angle1 = 45.0 * (M_PI/180.0); /* angles are specified */
double angle2 = 180.0 * (M_PI/180.0); /* in radians */
cairo_set_line_width (cr, 10.0);
cairo_arc (cr, xc, yc, radius, angle1, angle2);
cairo_stroke (cr);
/* draw helping lines */
cairo_set_source_rgba (cr, 1, 0.2, 0.2, 0.6);
cairo_set_line_width (cr, 6.0);
cairo_arc (cr, xc, yc, 10.0, 0, 2*M_PI);
cairo_fill (cr);
cairo_arc (cr, xc, yc, radius, angle1, angle1);
cairo_line_to (cr, xc, yc);
cairo_arc (cr, xc, yc, radius, angle2, angle2);
cairo_line_to (cr, xc, yc);
cairo_stroke (cr);
// End of example
cairo_surface_write_to_png (surface, "example.png");
cairo_destroy (cr);
cairo_surface_destroy (surface);
return 0;
}

Moving circles - like bouncing

Just another question! I'm trying to make the circle bounce around, but it's not working I even tried the most basic way, of just adding a value (from a 'step' int) to the circle x, but it's not working. What's the approach I should follow?
I know it's a basic question, but I'm knew to this :)
float time;
PFont font1;
/*float posX, posY, velX, velY, raio;
int dirX = 1;
int dirY = -1;*/
int passo = 2;
color c1 = color (253, 196, 80, 40);
color c2 = color(254, 127, 168, 40);
color c3 = color (53, 63, 114, 80);
color c4 = color (206, 186, 221, 80);
void setup() {
size(600, 800);
smooth();
background (#F6C4C7);
ellipseMode(RADIUS);
noStroke();
time = 17;
}
//make gradient
void desenhar_grad(float posX, float posY, int raio, color color1, color color2) {
pushStyle();
noStroke();
for (int r = raio; r > 0; r--) {
int tom = lerpColor(color1, color2, map(r, 0, raio, 0.0, 1.0)); // os últimos dois valores são as cores. o primeiro é o centro, o segundo é o exterior
fill(tom);
circle(posX, posY, r * 2);
}
popStyle();
}
/*void move() {
posY+=velY*dirY;
if (posY>height-raio || posY<raio)
dirY*=-1;
posX+=velX*dirX;
if (posX>width-raio || posX<raio)
dirX*=-1;
}*/
void draw () {
smooth();
for (int linha = 0; linha < 3; linha++) {
for (int coluna = 0; coluna < 3; coluna++) {
if (time <= 19) {
desenhar_grad(150 + coluna * 150, 200 + linha * 150, 30, c1, c2);
} else
desenhar_grad(150 + coluna * 150, 200 + linha * 150, 30, c4, c3);
}
}
}
} ```
Also, should I create a class for the circles in order to optimize the code?
Thank you!
I see your attempt with using the move() function (and related variables).
Again, close, but there are a few gotchas:
the values used in move() should be initialised: otherwise they'll default to 0 and any number multiplied by 0 is 0 which will result in no movement at all
once you have computed the correct posX, posY you could use those to translate() everything (i.e. the gradients): once everything is translated the 150, 200 offsets could be removed (and used as posX, posY initial values)
it's unclear with the "pivot" of the 3x3 gradient grid should be at the centre or the top left corner of the grid. Let's start with the simpler top left option. This can easily be changed later to centre simply by adding had the grid size to posX and posY
Here's a modified version of your sketch using the notes above:
float time;
// initialise movement variables
float posX = 150, posY = 200, velX = 1, velY = 1;
int raio = 30;
int dirX = 1;
int dirY = -1;
color c1 = color (253, 196, 80, 40);
color c2 = color(254, 127, 168, 40);
color c3 = color (53, 63, 114, 80);
color c4 = color (206, 186, 221, 80);
void setup() {
size(600, 800);
smooth();
ellipseMode(RADIUS);
smooth();
noStroke();
time = 17;
}
//make gradient
void desenhar_grad(float posX, float posY, int raio, color color1, color color2) {
pushStyle();
noStroke();
for (int r = raio; r > 0; r--) {
int tom = lerpColor(color1, color2, map(r, 0, raio, 0.0, 1.0)); // os últimos dois valores são as cores. o primeiro é o centro, o segundo é o exterior
fill(tom);
circle(posX, posY, r * 2);
}
popStyle();
}
void move() {
posY += velY * dirY;
if (posY > height - raio || posY < raio)
dirY *= -1;
posX += velX * dirX;
if (posX > width - raio || posX < raio)
dirX *= -1;
// for testing only:
println("posX",posX, "width", width, "posY", posY, "height", height);
}
void draw () {
if(!mousePressed) background (#F6C4C7);
// update posX, posY taking sketch borders into account
move();
// translate everything to the updated position
translate(posX, posY);
for (int linha = 0; linha < 3; linha++) {
for (int coluna = 0; coluna < 3; coluna++) {
if (time <= 19) {
desenhar_grad(coluna * 150, linha * 150, raio, c1, c2);
} else
desenhar_grad(coluna * 150, linha * 150, raio, c4, c3);
}
}
}
I've removed unused variables for clarity and added a few comments.
There are still a few confusing, perhaps unrelated items:
should the screen be cleared or should the grid leave trails ? (for now you can leave trails by holding the mouse pressed, but you can easily choose when to call background() based on the look you're going for)
how should the time variable be updated ? Currently it's set to 17 in setup() and doesn't change making the if/else condition inside the nested for loops redundant. Perhaps you meant to update in draw() based on some conditions ?
should the grid move as a whole or should each gradient move on its own ? my assumption is you're trying move the grid altogether however if you want to move each gradient on its own bare in mind you will need to use an array for each variable used in move() so it can be updated independently for each gradient (e.g. float[] posX, posY, velX, velY).)
Side note: If the movement is this simple you could get away with pos and
vel variables and not use dir variables:
void move() {
posY += velY;
if (posY > height - raio || posY < raio)
velY *= -1;
posX += velX;
if (posX > width - raio || posX < raio)
velY *= -1;
}
Manually updating each x,y variable is a great way to learn.
At a later date you might find PVector useful for movement.

PBR - Incorrect direct lighting

Based on many internet resources I wrote PBR implementation for directional lighting for my DirectX 11 game engine, but It works incorrectly.
Bellow, you can see a screenshot where I forced metalness to 0.0f and roughness to 1.0f. As you can see there are too many reflections. For example, the grass is reflective very, but roughness is set to 0, so it shouldn't look like that.
Bellow, I visualized ambientLigting and it looks correct.
Unfortunately, directLighting seems completely off and I don't know why. There are too many reflections. It might be because I applied PBR formulas incorrectly for the directional light source, but I don't know how to make it correct.
Here is my PBR source code. I hope you will help me solve this problem or at least give me a hint, where the problem may be because, to be honest, I have no idea at this moment how to fix it.
static const float PI = 3.14159265359f;
static const float3 DIELECTRIC_FACTOR = float3(0.04f, 0.04f, 0.04f);
static const float EPSILON = 0.00001f;
float DistributionGGX(float3 normal, float3 halfway, float roughness)
{
float alpha = roughness * roughness;
float alphaSquare = alpha * alpha;
float cosHalfway = max(dot(normal, halfway), 0.0f);
float cosHalfwaySquare = cosHalfway * cosHalfway;
float denominator = (cosHalfwaySquare * (alphaSquare - 1.0f)) + 1.0f;
denominator = PI * denominator * denominator;
return alphaSquare / denominator;
}
float GeometrySchlickGGX(float cosinus, float roughness)
{
float r = (roughness + 1.0);
float k = (r * r) / 8.0;
float denominator = cosinus * (1.0 - k) + k;
return cosinus / denominator;
}
float GeometrySmith(float3 normal, float roughness, float cosView, float cosLight)
{
return GeometrySchlickGGX(cosView, roughness) * GeometrySchlickGGX(cosLight, roughness);
}
float3 FresnelSchlick(float cosTheta, float3 F0)
{
return F0 + (1.0f - F0) * pow(1.0f - cosTheta, 5.0f);
}
float3 FresnelSchlickRoughness(float cosTheta, float3 F0, float roughness)
{
return F0 + (max(float(1.0f - roughness).xxx, F0) - F0) * pow(1.0f - cosTheta, 5.0f);
}
int GetTextureMipMapLevels(TextureCube input)
{
int width, heigth, levels;
input.GetDimensions(0, width, heigth, levels);
return levels;
}
float3 Pbr(float3 albedo, float3 normal, float metallic, float roughness, float occlusion,
TextureCube irradianceTexture, TextureCube radianceTexture, Texture2D brdfLut,
SamplerState defaultSampler, SamplerState brdfSampler, float3 lightDirection,
float3 lightColor, float3 cameraPosition, float3 pixelPosition, float shadowMultiplier)
{
lightDirection *= -1;
float3 viewDirection = normalize(cameraPosition - pixelPosition);
float3 halfwayDirection = normalize(viewDirection + lightDirection);
float3 reflectionDirection = reflect(-viewDirection, normal);
float3 F0 = lerp(DIELECTRIC_FACTOR, albedo, metallic);
float cosView = max(dot(normal, viewDirection), 0.0f);
float cosLight = max(dot(normal, lightDirection), 0.0f);
float NDF = DistributionGGX(normal, halfwayDirection, roughness);
float G = GeometrySmith(normal, roughness, cosView, cosLight);
float3 F = FresnelSchlick(max(dot(halfwayDirection, viewDirection), 0.0f), F0);
float3 nominator = NDF * G * F;
float denominator = 4 * cosView * cosLight + EPSILON;
float3 specular = nominator / denominator;
float3 kD = lerp(float3(1.0f, 1.0f, 1.0f) - F, float3(0.0f, 0.0f, 0.0f), metallic);
float3 directLighting = (kD * albedo / PI + specular) * lightColor * cosLight;
F = FresnelSchlickRoughness(cosView, F0, roughness);
kD = lerp(float3(1.0f, 1.0f, 1.0f) - F, float3(0.0f, 0.0f, 0.0f), metallic);
float3 irradiance = irradianceTexture.Sample(defaultSampler, normal).rgb;
float3 diffuse = irradiance * albedo;
int radianceLevels = GetTextureMipMapLevels(radianceTexture);
float3 radiance = radianceTexture.SampleLevel(defaultSampler, reflectionDirection, roughness * radianceLevels).rgb;
float2 brdf = brdfLut.Sample(brdfSampler, float2(cosView, roughness)).xy;
float3 specularColor = radiance * (F0 * brdf.x + brdf.y);
float3 ambientLighting = (kD * diffuse + specularColor) * occlusion;
return ambientLighting + (directLighting * shadowMultiplier);
}

How to center this grid of squares?

I am trying to simply produce a grid of 5 rotated rectangles. But the grid will not come out centered. Can anyone help me out?
int margin = 150; //padding to sides and top/bottom
int rectH = 60; // height of rectangle
int rectW = 20; // width of rectangle
int n_rectangles = 5; // 5 rectangles to draw
size(800,800);
for (int x = margin+rectW; x <= width - margin; x += (width-2*(margin+rectW))/n_rectangles) {
for (int y = margin+rectH; y <= height - margin; y += (height-2*(margin+rectH))/n_rectangles) {
fill(255);
//now rotate matrix 45 degrees
pushMatrix();
translate(x, y);
rotate(radians(45));
// draw rectangle at x,y point
rect(0, 0, rectW, rectH);
popMatrix();
}
}
I recommend to draw single "centered" rectangles, the origin of the rectangle is (-rectW/2, -rectH/2):
rect(-rectW/2, -rectH/2, rectW, rectH);
Calculate the distance of the first rectangle center tor the last rectangle center, for row and column:
int size_x = margin * (n_rectangles-1);
int size_y = margin * (n_rectangles-1);
Translate to the center of the screen (width/2, height/2),
to the position of the upper left rectangle (-size_x/2, -size_y/2)
and finally each rectangle to its position (i*margin, j*margin):
translate(width/2 - size_x/2 + i*margin, height/2 - size_y/2 + j*margin);
See the final code:
int margin = 150; //padding to sides and top/bottom
int rectH = 60; // height of rectangle
int rectW = 20; // width of rectangle
int n_rectangles = 5; // 5 rectangles to draw
size(800,800);
int size_x = margin * (n_rectangles-1);
int size_y = margin * (n_rectangles-1);
for (int i = 0; i < n_rectangles; ++i ) {
for (int j = 0; j < n_rectangles; ++j ) {
fill(255);
pushMatrix();
translate(width/2 - size_x/2 + i*margin, height/2 -size_y/2 + j*margin);
rotate(radians(45));
rect(-rectW/2, -rectH/2, rectW, rectH);
popMatrix();
}
}

HLSL projection shader

I am rendering a scene to a texture and then drawing a water plane with that texture using projection. Most of the samples I have seen on the web pass in a view/projection matrix to the vertex shader and transform the vertex, then in the pixel shader they do :
projection.x = input.projectionCoords.x / input.projectionCoords.w / 2.0 + 0.5;
projection.y = input.projectionCoords.y / input.projectionCoords.w / 2.0 + 0.5;
I have a shader that does the following and it works too but I don't know where I found this particular code or how it gives the same results with the above code. Here is the code I have
Vertex shader : (world is an identityMatrix, viewProj is my cameras combined viewProjection matrix):
output.position3D = mul(float4(vsin.position,1.0), world).xyz;
output.position = mul(float4(output.position3D,1.0), viewProj);
output.reflectionTexCoord.x = 0.5 * (output.position.w + output.position.x);
output.reflectionTexCoord.y = 0.5 * (output.position.w - output.position.y);
output.reflectionTexCoord.z = output.position.w;
Pixel shader :
float2 projectedTexCoord = (input.reflectionTexCoord.xy / input.reflectionTexCoord.z);
What confuses me is the usage of 0.5 * (output.position.w + output.position.x) and 0.5 * (output.position.w - output.position.y). How does this have the same effect and what does the w component mean here?
After a while I realized that it ends up being the same thing :
0.5 * (output.position.w + output.position.x);
0.5 * output.position.w + 0.5 * output.position.x
Then in the pixel shader :
(0.5 * output.position.w + 0.5 * output.position.x) / output.position.w
(0.5 * output.position.w)/output.position.w + (0.5 * output.position.x) / output.position.w
The first part becomes 0.5 :
0.5 + 0.5 * ( output.position.x / output.position.w)
This is equal to :
(output.position.x / output.position.w) / 2 + 0.5
I believe moving this calculation to the vertex shader is more efficient so I will just leave it there.
To completely move the calculation out of the shader the matrix can be calculated on the client side :
XMMATRIX v = XMLoadFloat4x4(&view);
XMMATRIX p = XMLoadFloat4x4(&projection);
XMMATRIX t(
0.5f, 0.0f, 0.0f, 0.0f,
0.0f, -0.5f, 0.0f, 0.0f,
0.0f, 0.0f, 1.0f, 0.0f,
0.5f, 0.5f, 0.0f, 1.0f);
XMMATRIX reflectionTransform = v * p * t;
XMStoreFloat4x4(&_reflectionTransform, XMMatrixTranspose(reflectionTransform));
Then all the vertex shader has to do is :
output.reflectionTexCoord = mul(float4(output.position3D,1.0), reflectionProjectionMatrix);

Resources