/r/opengl

Photograph via snooOG

News, information and discussion about OpenGL development.

/r/opengl

28,897 Subscribers

1

OpenGL shaders problem

Hi guys i have 2 vertex shaders and two frgament shader files that are linked into 2 programs one for cube (reporresents object)one for second cube(represents light) everything is good except in side 1st shader program variables are not passed from VS to FS in second program everything works fine. Botoh of shader programs have same code VS and FS just in difretn files and both programs are wroking(when i run without passing variables from object cube VS to FS it draws with local shader variables) however when i try tu use code like this:

#version 
330
 core
out vec4 FragColor;
in vec3 color;
void
 main() {
        FragColor = vec4(color,
1.0
f);
}
#version 330 core
layout (location = 0) in vec3 aPosLight;

out vec3 color;

uniform mat4 modelMatrix;
uniform mat4 viewMatrix;
uniform mat4 projectionMatrix;

void main()
{
    gl_Position = projectionMatrix * viewMatrix * modelMatrix * vec4(aPosLight, 1.0);
    color = aPosLight;
}

first cube draws but second not -- i guess vec3 color is not being passed to FS but i dont understand why in second shader it works

*for both objects there are diffrerent VAOS

0 Comments
2024/12/20
18:57 UTC

4

Indirect rendering & textures

Hi,

How do you guys throw a lot of different objects' textures to a fragment shader using indirect rendering?

I got some issues with bindless textures (only first texture is active), and, RenderDoc doesn't support this extension. I will be unable to debug my application.

12 Comments
2024/12/19
11:08 UTC

0

How does GL draw? / Custom input depthbuffer

I'm aware this might sound wack and/or stupid. But at the risk of having a bunch of internet strangers calling me an idiot:

So, for a project I'm working on I received a c++ engine that relies on openGL to draw frames. (Writing my own 3D rendering from scratch. It doesn't use the by now standard way of 3d rendering)

Now, to continue that project, I need some form of a depthbuffer. In order to draw the correct objects on top. I know openGL has one, but i don't think I can make it work with the way I'm rendering my 3d as what I'm actually drawing to the screen are polygons. (So, glbegin(gl_polygo); {vertecies2f} glend();)

(The 3f vertecies only draw on depth 1, which is interesting, but I don't immediately see a way to use this)

Every tutorial on how to make the build in depthbuffer work seems to relies on the standard way to render 3d. (I don't use matrixes) Though I'll be honest I have no idea how the depth buffer practically works (I know the theory, but I don't know how it does it's thing within gl)

So I was wondering if there was a way to write to the depthbuffer myself. (And thus also read from it)

Or preferably: to know how GL actually draws/where I can find how it actually draws, so I can manipulate that function to adapt to what would essentially be a custom depthbuffer that I'd write from scratch.

19 Comments
2024/12/19
00:33 UTC

4

Question regarding std430 layout

Google told me std430 packs data in a much more tight way . If the largest type in block is vec3 , then it will pad a single float with 2*4 bytes to make it float3 .

layout(std140, binding=0 ) readonly buffer vertexpos{
    vec3 pos;
};

I have a SSBO storing vertex positions . These positions are originally vec3 . That is to say , if I stay it std140, I will have them expanded to vec4 with w being blank . If I change it to std430, then they're just aligned to vec3 , without extra padding ? Am I correct ?

My question is that should I directly use vec4 instead of using vec3 and letting Opengl to do padding for it ? People often talk about 'avoiding usage of vec3' . But I do have them being vec3 originally in CPU. I'd assume there would be problem if I change it to vec4 e.g. the former vector takes the x component of the next vector to it as its own w value

8 Comments
2024/12/18
07:36 UTC

12

Voxel greedy meshing without caring about texture ID

Hello! I have been playing around with voxels and for greedy meshing I've been trying to mesh without needing to care about texture. I got the idea by watching this video https://youtu.be/4xs66m1Of4A?t=917

Here is an example of what I'm trying to do.

https://preview.redd.it/0sjt8wf53j7e1.png?width=1194&format=png&auto=webp&s=3145b0f95490212ccac0a48231adb0bf4c6dfb72

The issue I have right now is how do I tell which texture I need to use at x,y of the quad. I thought about using a 2D array with the ids of the textures to use, so I made a 2D texture specifically to tell the fragment shader that (later will be 3D texture instead). I manged to mostly succeed, however I found a problem, edges of the original texture blend terribly and it ruins the texture I want to use. I've attached a video of the result:

https://reddit.com/link/1hgt3ax/video/s3do0khp3j7e1/player

On one side you can see the checker board texture with either 0 or 1 as the ID for the texture to use on the other side.
I am using `GL_NEAREST` I have tried a few other things but could not get it to look good.

If anyone has a suggestion on how to fix it or even a better way of solving this problem let me know!

10 Comments
2024/12/18
03:51 UTC

3

Playing around with adding lighting support to my abstraction.

In fixed function OpenGL, We have access to lights 0 - 7. But of course. That's not enough lights for a whole game level.

I came up with a solution where, The user can provide required lights, Like the sun or a flashlight. If there is any slots left, The rest of the lights in your scene would be optional lights Where, We solve for the attenuation that light would provide on the closest point to the light on the bounding box of the object we're currently drawing and teleport the 8 GL lights we have around as we draw.

The box looks weird because I don't have materials or Vertex Normals yet so they're almost definitely wrong. But I'm loving it.

https://reddit.com/link/1hgsdwq/video/a1porhlsxi7e1/player

1 Comment
2024/12/18
03:12 UTC

0

OpenGL setup script update !!!

On my previous post I talked about the script which set up a basic project structure with glfw and glad . In the updated version the script links both Sokol and cglm to get you started with whatever you want in c/c++ whether it’s is graphics or game programming . There is a lot of confusion especially for Mac users so I hope this helps . I’m planning on adding Linux support soon . Check it out in my GitHub and consider leaving a star if it helps : https://github.com/GeorgeKiritsis/Apple-Silicon-Opengl-Setup-Script

2 Comments
2024/12/17
13:57 UTC

0

What is wrong here?

import java.awt.*;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.awt.image.BufferedImage;
import java.io.*;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;

import java.nio.FloatBuffer;
import java.nio.IntBuffer;
import java.util.*;
import java.util.Timer;
import javax.imageio.ImageIO;
import javax.swing.*;

import com.jogamp.common.nio.Buffers;
import com.jogamp.opengl.*;
import com.jogamp.opengl.awt.GLCanvas;
import com.jogamp.opengl.glu.GLU;
import com.jogamp.opengl.util.FPSAnimator;

public class PongVBO {
    public static void main(String[] args) {
        SwingUtilities.
invokeLater
(new Runnable() {
            public void run() {
                MyGui myGUI = new MyGui();
                myGUI.createGUI();
            }
        });
    }
}

class MyGui extends JFrame implements GLEventListener {
    private Game game;
    private final GLU glu = new GLU();

    public void createGUI() {
        setTitle("PongVBO");
        setDefaultCloseOperation(JFrame.
EXIT_ON_CLOSE
);

        GLProfile glp = GLProfile.
getDefault
();
        GLCapabilities caps = new GLCapabilities(glp);
        GLCanvas canvas = new GLCanvas(caps);
        final FPSAnimator ani = new FPSAnimator(canvas, 120, true);
        canvas.addGLEventListener(this);
        game = new Game();
        canvas.addKeyListener(game);
        ani.start();

        getContentPane().setPreferredSize(new Dimension(800, 450));
        getContentPane().add(canvas);
        pack();
        setVisible(true);
        canvas.requestFocus();
    }

    @Override
    public void init(GLAutoDrawable d) {
        GL2 gl = d.getGL().getGL2(); // get the OpenGL 2 graphics context
        // enable depth test
        gl.glEnable(gl.
GL_DEPTH_TEST
);

        game.init(d);
    }

    @Override
    public void reshape(GLAutoDrawable d, int x, int y, int width, int height) {
        GL2 gl = d.getGL().getGL2(); // get the OpenGL 2 graphics context
        gl.glViewport(0, 0, width, height);
    }

    @Override
    public void display(GLAutoDrawable d) {
        game.update();
        game.display(d);
    }

    @Override
    public void dispose(GLAutoDrawable d) {
    }
}

class Game extends KeyAdapter {
    boolean pauseGame = true;
    VBOLoader vboLoader = new VBOLoader();

    Player playerOne;
    Score scoreOne;
    Player playerTwo;
    Score scoreTwo;
    Ball ball;
    PowerUp powerUp;
    Court court;

    ArrayList<GameObject> gameObjects = new ArrayList<>();

    private int progID = 0;
    private int vertID = 0;
    private int fragID = 0;

    private float[] projection = new float[16];
    private float[] view = new float[16];

    public Game() {

        ball = new Ball();
        playerOne = new Player(-1.8f, 0f, 0, -90);
        scoreOne = new Score(-0.15f, 0.85f);
        playerTwo = new Player(1.8f, 0f, 0, 90);
        scoreTwo = new Score(0.15f, 0.85f);
        court = new Court();

        //gameObjects.add(court);
        gameObjects.add(ball);
        //gameObjects.add(playerOne);
        //gameObjects.add(playerTwo);
        //gameObjects.add(scoreOne);
        //gameObjects.add(scoreTwo);
    }

    public void init(GLAutoDrawable d) {
        setupShaders(d);

        // load vbos
        vboLoader.initVBO(d);
        ball.vertBufID = vboLoader.vertBufIDs[0];
        ball.vertNo = vboLoader.vertNos[0];
        playerOne.vertBufID = vboLoader.vertBufIDs[1];
        playerOne.vertNo = vboLoader.vertNos[1];
        playerTwo.vertBufID = vboLoader.vertBufIDs[1];
        playerTwo.vertNo = vboLoader.vertNos[1];

        // setup textures
        court.texID = Util.
loadTexture
(d, "./interstellar.png");
        PowerUp.
texIDs
[0] = Util.
loadTexture
(d, "./powerup_icons_grow.png");
        PowerUp.
texIDs
[1] = Util.
loadTexture
(d, "./powerup_icons_shrink.png");
        PowerUp.
texIDs
[2] = Util.
loadTexture
(d, "./powerup_icons_star.png");
    }

    public void  setupShaders(GLAutoDrawable d) {

        GL3 gl = d.getGL().getGL3(); // get the OpenGL 3 graphics context
        vertID = gl.glCreateShader(GL3.
GL_VERTEX_SHADER
);
        fragID = gl.glCreateShader(GL3.
GL_FRAGMENT_SHADER
);

        String[] vs = loadVertShader();
        String[] fs = loadFragShader();

        gl.glShaderSource(vertID, 1, vs, null, 0);
        gl.glShaderSource(fragID, 1, fs, null, 0);

        gl.glCompileShader(vertID);
        gl.glCompileShader(fragID);


        printShaderInfoLog(d, vertID);
        printShaderInfoLog(d, fragID);


        progID = gl.glCreateProgram();

        gl.glAttachShader(progID, vertID);
        gl.glAttachShader(progID, fragID);

        gl.glBindFragDataLocation(progID, 0, "outputColor");

        gl.glLinkProgram(progID);
        printProgramInfoLog(d, progID);

        GameObject.
shaderProgramID 
= progID;
    }

    private void printShaderInfoLog(GLAutoDrawable d, int obj) {
        GL3 gl = d.getGL().getGL3(); // get the OpenGL 3 graphics context
        IntBuffer infoLogLengthBuf = IntBuffer.
allocate
(1);
        int infoLogLength;
        gl.glGetShaderiv(obj, GL3.
GL_INFO_LOG_LENGTH
, infoLogLengthBuf);
        infoLogLength = infoLogLengthBuf.get(0);
        if (infoLogLength > 0) {
            ByteBuffer byteBuffer = ByteBuffer.
allocate
(infoLogLength);
            gl.glGetShaderInfoLog(obj, infoLogLength, infoLogLengthBuf, byteBuffer);
            for (byte b:byteBuffer.array()){
                System.
err
.print((char)b);
            }
        }
    }


    private void printProgramInfoLog(GLAutoDrawable d, int obj) {
        GL3 gl = d.getGL().getGL3(); // get the OpenGL 3 graphics context
        IntBuffer infoLogLengthBuf = IntBuffer.
allocate
(1);
        int infoLogLength;
        gl.glGetProgramiv(obj, GL3.
GL_INFO_LOG_LENGTH
, infoLogLengthBuf);
        infoLogLength = infoLogLengthBuf.get(0);
        if (infoLogLength > 0) {
            ByteBuffer byteBuffer = ByteBuffer.
allocate
(infoLogLength);
            gl.glGetProgramInfoLog(obj, infoLogLength, infoLogLengthBuf, byteBuffer);
            for (byte b:byteBuffer.array()){
                System.
err
.print((char)b);
            }
        }
    }

    private String[] loadFragShader() {
        return ("#version 140 \n" +
                "in vec3 forFragColor;\n" +
                "in vec2 forFragTexCoord;\n" +
                "out vec4 outputColor;\n" +
                //"uniform in int isTextured;"+
                //"uniform sampler2D myTexture;\n" +
                "\n" +
                "void main() {\n" +
                //"if(isTexturedFrag == 1){" +
               // "    vec3 textureColor = vec3( texture(myTexture, forFragTexCoord) );\n" +
               // "    outputColor = vec4(forFragColor*textureColor,1.0);\n" +
                //"} else { \n" +
                "    outputColor = vec4(1.0,0.0,0.0,1.0);\n" +
                //"}" +
                "}").split("\n");
    }

    private String[] loadVertShader() {
        return ("#version 140 \n" +
                "in vec3 position;\n" +
                "in vec4 color;\n" +
                "in vec2 texCoord;\n" +
                "in vec3 normal;\n" +
                "uniform mat4 projection,modelview, view;\n" +
                "out vec3 forFragColor;\n" +
                "out vec2 forFragTexCoord;\n" +
                "void main(){\n" +
                "    forFragColor = inputColor.rgb;\n" +
                "    forFragTexCoord = inputTexCoord;\n" +
                "    gl_Position =  projection * view * modelview * vec4(position, 1.0);\n" +
                "}").split("\n");
    }

    public void display(GLAutoDrawable d) {
        GL3 gl = d.getGL().getGL3(); // get the OpenGL 2 graphics context
        // clear the screen
        gl.glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
        gl.glClear(GL.
GL_COLOR_BUFFER_BIT 
| GL.
GL_DEPTH_BUFFER_BIT
);

        gl.glUseProgram(progID);

        int projectionLoc = gl.glGetUniformLocation(progID, "projection");
        int viewLoc = gl.glGetUniformLocation(progID, "view");

        Util.
mat4Perspective
(projection,60f,16f/9f,1f,10f);
        Util.
mat4Identity
(view);

        gl.glUniformMatrix4fv(projectionLoc, 1, false, projection, 0);
        gl.glUniformMatrix4fv(viewLoc, 1, false, view, 0);

        for (GameObject gameObject : gameObjects) {
            gameObject.display(gl);
        }

        gl.glFlush();
        printShaderInfoLog(d,progID);
    }

    public void update() {
        for (GameObject gameObject : gameObjects) {
            gameObject.update();
        }
        checkCollisionBallPlayer();
        checkCollisionBallBorder();
        checkCollisionBallPowerUp();

        // spawn power up
        if (Util.
rand
.nextInt(10000) > 9975 && (ball.posY > 0.2f || ball.posY < -0.02f)) {
            spawnPowerUp();
        }
    }

    public void startGame() {
        if (scoreOne.getScore() > 2 || scoreTwo.getScore() > 2) {
            scoreOne.setScore(0);
            scoreTwo.setScore(0);
        }
        ball.velocityX = 0.03f;
        ball.velocityY = 0.015f;
        pauseGame = false;
    }

    public void score(Score score) {
        removePowerUp();

        score.setScore(score.getScore() + 1);
        ball.reset();
        pauseGame = true;
    }

    public void spawnPowerUp() {
        if (!PowerUp.
spawned 
&& !PowerUp.
taken
) {
            powerUp = new PowerUp();
            gameObjects.add(powerUp);
            PowerUp.
spawned 
= true;
        }
    }

    public void removePowerUp() {
        for (int i = 0; i < gameObjects.size(); i++) {
            if (gameObjects.get(i) instanceof PowerUp) {
                gameObjects.remove(i);
                break;
            }
        }
        PowerUp.
spawned 
= false;
    }

    public void checkCollisionBallPlayer() {
        // collision player one
        if (ball.borderLeft < playerOne.borderRight && ball.borderLeft > playerOne.borderLeft) {
            if (ball.borderDown < playerOne.borderUp && ball.borderUp > playerOne.borderDown) {
                // calc hit positions distance to center
                float distanceToCenter = Math.
abs
(Math.
abs
(ball.posY) - Math.
abs
(playerOne.posY));
                if (ball.borderLeft < playerOne.borderRight - distanceToCenter * 0.125f) {
                    ball.posX = (playerOne.borderRight - distanceToCenter * 0.125f) + ball.scaleX;
                    // rotate ball
                    ball.rotationZ = playerOne.velocity * 273;
                    // reflect ball
                    ball.velocityX = -(ball.velocityX + (ball.rotationZ * .0005f));
                    ball.velocityY += (ball.rotationZ * .0015f);
                }
            }
        }

        // collision player two
        if (ball.borderRight > playerTwo.borderLeft && ball.borderRight < playerTwo.borderRight) {
            if (ball.borderDown < playerTwo.borderUp && ball.borderUp > playerTwo.borderDown) {
                float distanceToCenter = Math.
abs
(Math.
abs
(ball.posY) - Math.
abs
(playerTwo.posY));
                if (ball.borderRight > playerTwo.borderLeft + distanceToCenter * 0.125f) {
                    ball.posX = (playerTwo.borderLeft + distanceToCenter * 0.125f) - ball.scaleX;
                    // rotate ball
                    ball.rotationZ = playerTwo.velocity * 273;
                    // reflect ball
                    ball.velocityX = -ball.velocityX + (ball.rotationZ * .0005f);
                    ball.velocityY += (ball.rotationZ * .0015f);
                }
            }
        }
    }

    public void checkCollisionBallBorder() {
        // let and right border
        if (ball.posX > 1.9f) {
            score(scoreOne);
        }
        if (ball.posX < -1.9f) {
            score(scoreTwo);
        }

        // ceiling and ground
        if (ball.posY > 1f) {
            ball.velocityY = -ball.velocityY;
        }
        if (ball.posY < -1f) {
            ball.velocityY = -ball.velocityY;
        }
    }

    public void checkCollisionBallPowerUp() {
        if (PowerUp.
spawned
) {
            if (Math.
abs
(powerUp.posX - ball.posX) < powerUp.sizeX + ball.sizeX
                    && Math.
abs
(powerUp.posY - ball.posY) < powerUp.sizeY + ball.sizeY) {
                if (ball.velocityX < 0) {
                    powerUp.applyPowerUp(playerTwo, playerOne);
                } else {
                    powerUp.applyPowerUp(playerOne, playerTwo);
                }
                removePowerUp();
                PowerUp.
taken 
= true;
            }
        }
    }

    public void keyPressed(KeyEvent e) {
        switch (e.getKeyCode()) {
            case KeyEvent.
VK_W
:
                playerOne.moveUp = true;
                break;
            case KeyEvent.
VK_S
:
                playerOne.moveDown = true;
                break;
            case KeyEvent.
VK_P
:
                playerTwo.moveUp = true;
                break;
            case KeyEvent.
VK_L
:
                playerTwo.moveDown = true;
                break;
            case KeyEvent.
VK_SPACE
:
                if (pauseGame) {
                    startGame();
                }
                break;
        }
    }

    public void keyReleased(KeyEvent e) {
        switch (e.getKeyCode()) {
            case KeyEvent.
VK_W
:
                playerOne.moveUp = false;
                break;
            case KeyEvent.
VK_S
:
                playerOne.moveDown = false;
                break;
            case KeyEvent.
VK_P
:
                playerTwo.moveUp = false;
                break;
            case KeyEvent.
VK_L
:
                playerTwo.moveDown = false;
                break;
        }
    }
}

abstract class GameObject {
    static int 
shaderProgramID
;

    float[] vertices = Cube.
geom
;
    public int vertBufID;
    public int vertNo;

    float angleY, angleZ;
    float rotationY, rotationZ;
    float posX, posY;
    float sizeX, sizeY, sizeZ;

    public void display(GL3 gl) {

        // Rotate the object
        angleY += rotationY;
        angleZ += rotationZ;

        // Calculate the model matrix for transformations
        float[] modelview = new float[16];

        // Assuming a utility function exists for creating a model matrix:
        Util.
mat4ModelView
(modelview, posX, posY,2f, sizeX, sizeY, sizeZ,0f, angleY, angleZ);

        //int modelMatrixLocation = gl.glGetUniformLocation(shaderProgramID, "modelview");
        //gl.glUniformMatrix4fv(modelMatrixLocation, 1, false, modelview, 0);
        gl.glBindBuffer(GL.
GL_ARRAY_BUFFER
, vertBufID);

        int stride = (3 + 4 + 2 + 3) * Buffers.
SIZEOF_FLOAT
;
        int offset = 0;

        int positionAttribute = gl.glGetAttribLocation(
shaderProgramID
, "position");
        gl.glVertexAttribPointer(positionAttribute, 3, GL.
GL_FLOAT
, false, stride, offset);
        gl.glEnableVertexAttribArray(positionAttribute);

        offset += 3 * Buffers.
SIZEOF_FLOAT
;

        int colorAttribute = gl.glGetAttribLocation(
shaderProgramID
, "color");
        gl.glVertexAttribPointer(colorAttribute, 4, GL.
GL_FLOAT
, false, stride, offset);
        gl.glEnableVertexAttribArray(colorAttribute);

        offset += 4 * Buffers.
SIZEOF_FLOAT
;

        int texCoordAttribute = gl.glGetAttribLocation(
shaderProgramID
, "texCoord");
        gl.glVertexAttribPointer(texCoordAttribute, 2, GL.
GL_FLOAT
, false, stride, offset);
        gl.glEnableVertexAttribArray(texCoordAttribute);

        offset += 2 * Buffers.
SIZEOF_FLOAT
;

        int normalAttribute = gl.glGetAttribLocation(
shaderProgramID
, "normal");
        gl.glVertexAttribPointer(normalAttribute, 3, GL.
GL_FLOAT
, false, stride, offset);
        gl.glEnableVertexAttribArray(normalAttribute);

        // Draw the object
        gl.glDrawArrays(GL.
GL_TRIANGLES
, 0, vertNo);

        // Disable vertex attributes
        gl.glDisableVertexAttribArray(positionAttribute);
        gl.glDisableVertexAttribArray(colorAttribute);
        gl.glDisableVertexAttribArray(texCoordAttribute);
        gl.glDisableVertexAttribArray(normalAttribute);
    }

     abstract void update();
}

class Player extends GameObject {
    boolean moveUp, moveDown = false;
    float ACCELERATION_VALUE = 0.012f;
    float acceleration;
    float velocity;
    float borderLeft, borderRight, borderUp, borderDown;
    float scaleX, scaleY, scaleZ;

    public Player(float posX, float posY, float angleY, float angleZ) {
        this.scaleX = 0.35f;
        this.scaleY = 0.35f;
        this.scaleZ = 0.05f;
        this.sizeX = this.scaleX * 2;
        this.sizeY = this.scaleY * 2;
        this.sizeZ = this.scaleZ * 2;
        this.posX = posX;
        this.posY = posY;
        this.angleY = angleY;
        this.angleZ = angleZ;
    }

    public void setScaleY(float scaleY) {
        this.scaleY = scaleY;
        this.sizeY = this.scaleY * 2;
    }

    public void update() {
        acceleration = 0.0f;
        if (moveUp) {
            acceleration += ACCELERATION_VALUE;
        }
        if (moveDown) {
            acceleration += -ACCELERATION_VALUE;
        }

        velocity += acceleration;
        velocity *= 0.75;
        this.posY += velocity;

        if (this.posY >= 0.8f) {
            this.posY = 0.8f;
        }
        if (this.posY <= -0.8f) {
            this.posY = -0.8f;
        }

        // update collision border
        this.borderLeft = this.posX - this.scaleX / 4f;
        this.borderRight = this.posX + this.scaleX / 4f;

        this.borderUp = this.posY + this.scaleY;
        this.borderDown = this.posY - this.scaleY;
    }
}

class Ball extends GameObject {
    float velocityX, velocityY;
    float borderLeft, borderRight, borderUp, borderDown;
    float scaleX, scaleY, scaleZ;

    public Ball() {
        this.scaleX = this.scaleY = this.scaleZ = 0.075f;
        this.sizeX = this.sizeY = this.sizeZ = this.scaleX * 2;
    }

    public void update() {
        this.posX += velocityX;
        this.posY += velocityY;

        // update collision border
        this.borderLeft = this.posX - this.scaleX;
        this.borderRight = this.posX + this.scaleX;
        this.borderUp = this.posY + this.scaleY;
        this.borderDown = this.posY - this.scaleY;
    }

    public void reset() {
        this.velocityX = 0;
        this.velocityY = 0;
        this.posX = 0;
        this.posY = 0;
        this.angleZ = 0;
        this.rotationZ = 0;
    }
}

class PowerUp extends GameObject {
    Timer timer;
    static boolean 
taken 
= false;
    static boolean 
spawned 
= false;
    float velocity;
    int type;
    static int[] 
texIDs 
= new int[3];

    public PowerUp() {
        this.angleZ = -90f;
        this.sizeX = this.sizeY = this.sizeZ = 0.1f;

        // set random velocity
        velocity = Util.
rand
.nextInt(1000) / 1000f * 0.05f;
        // set random type
        type = Util.
rand
.nextInt(2);
    }

    public void update() {
        if (posY > 1f) {
            posY = 1f;
            velocity = -velocity;
        }
        if (posY < -1f) {
            posY = -1f;
            velocity = -velocity;
        }
        posY += velocity;
    }

    public void applyPowerUp(Player consumer, Player other) {
        switch (type) {
            case 0:
                consumer.setScaleY(consumer.scaleY * 2);
                break;
            case 1:
                other.setScaleY(other.scaleY / 2);
                break;
            case 2:
                consumer.ACCELERATION_VALUE *= 2;
                break;
        }
        timer = new Timer(true);
        timer.schedule(new TimerTask() {
            @Override
            public void run() {
                removePowerUp(consumer, other);
                PowerUp.
taken 
= false;
                timer.cancel();
            }
        }, 4000);
    }

    public void removePowerUp(Player consumer, Player other) {
        switch (type) {
            case 0:
                consumer.setScaleY(consumer.scaleY / 2);
                break;
            case 1:
                other.setScaleY(other.scaleY * 2);
                break;
            case 2:
                consumer.ACCELERATION_VALUE /= 2;
                break;
        }
    }

    public void display(GL3 gl) {
        // bind texture
        gl.glEnable(GL2.
GL_TEXTURE_2D
);
        gl.glBindTexture(GL2.
GL_TEXTURE_2D
, PowerUp.
texIDs
[type]);

        gl.glDisable(GL2.
GL_TEXTURE_2D
);
    }
}

class Court extends GameObject {
    int texID;

    public Court() {
        this.rotationY = -0.005f;
    }

    public void update() {
        this.angleY += rotationY;
    }

    public void display(GL3 gl) {
        // bind texture
        gl.glEnable(GL2.
GL_TEXTURE_2D
);
        gl.glBindTexture(GL2.
GL_TEXTURE_2D
, texID);

        gl.glDisable(GL2.
GL_TEXTURE_2D
);
    }
}

class Score extends GameObject {
    private int score = 0;

    float[] score0Data = {0.06f, 0.1f, 0.04f, 0.1f, 0.04f, -0.1f, 0.06f, -0.1f, -0.04f, 0.1f, -0.06f, 0.1f, -0.06f,
            -0.1f, -0.04f, -0.1f, 0.05f, 0.1f, 0.05f, 0.08f, -0.05f, 0.08f, -0.05f, 0.1f, 0.05f, -0.08f, 0.05f, -0.1f,
            -0.05f, -0.1f, -0.05f, -0.08f};

    float[] score1Data = {0.01f, 0.1f, -0.01f, 0.1f, -0.01f, -0.1f, 0.01f, -0.1f};

    float[] score2Data = {0.06f, 0.1f, 0.04f, 0.1f, 0.04f, 0.0f, 0.06f, 0.0f, -0.04f, 0.0f, -0.06f, 0.0f, -0.06f,
            -0.1f, -0.04f, -0.1f, 0.05f, 0.1f, 0.05f, 0.08f, -0.05f, 0.08f, -0.05f, 0.1f, 0.05f, -0.08f, 0.05f, -0.1f,
            -0.05f, -0.1f, -0.05f, -0.08f, 0.05f, 0.01f, 0.05f, -0.01f, -0.05f, -0.01f, -0.05f, 0.01f};

    float[] score3Data = {0.06f, 0.1f, 0.04f, 0.1f, 0.04f, -0.1f, 0.06f, -0.1f, 0.05f, 0.1f, 0.05f, 0.08f, -0.05f,
            0.08f, -0.05f, 0.1f, 0.05f, -0.08f, 0.05f, -0.1f, -0.05f, -0.1f, -0.05f, -0.08f, 0.05f, 0.01f, 0.05f,
            -0.01f, -0.05f, -0.01f, -0.05f, 0.01f};

    public Score(float posX, float posY) {
        this.setScore(this.score);
        this.posX = posX;
        this.posY = posY;
    }

    public void setScore(int score) {
        if (score > 3) {
            return;
        }
        this.score = score;
        switch (score) {
            case 0:
                this.vertices = score0Data;
                break;
            case 1:
                this.vertices = score1Data;
                break;
            case 2:
                this.vertices = score2Data;
                break;
            case 3:
                this.vertices = score3Data;
                break;
        }
    }

    public int getScore() {
        return this.score;
    }

    @Override
    public void display(GL3 gl) {

    }
    public void update(){

    }
}

class Cube {
    static float[] 
geom 
= {
            // front
            1.0f, 1.0f, 1.0f, -1.0f, 1.0f, 1.0f, -1.0f, -1.0f, 1.0f, 1.0f, -1.0f, 1.0f,

            // back
            1.0f, 1.0f, -1.0f, -1.0f, 1.0f, -1.0f, -1.0f, -1.0f, -1.0f, 1.0f, -1.0f, -1.0f,

            // top
            1.0f, 1.0f, 1.0f, -1.0f, 1.0f, 1.0f, -1.0f, 1.0f, -1.0f, 1.0f, 1.0f, -1.0f,

            // bottom
            1.0f, -1.0f, 1.0f, -1.0f, -1.0f, 1.0f, -1.0f, -1.0f, -1.0f, 1.0f, -1.0f, -1.0f,

            // left
            -1.0f, 1.0f, 1.0f, -1.0f, -1.0f, 1.0f, -1.0f, -1.0f, -1.0f, -1.0f, 1.0f, -1.0f,

            // right
            1.0f, 1.0f, 1.0f, 1.0f, -1.0f, 1.0f, 1.0f, -1.0f, -1.0f, 1.0f, 1.0f, -1.0f};

    static float[] 
texCoord 
= {

            // front
            0.75f, 0.5f, 1f, 0.5f, 1f, 0.25f, 0.75f, 0.25f,

            // back
            0.5f, 0.5f, 0.25f, 0.5f, 0.25f, 0.25f, 0.5f, 0.25f,

            // top
            0.5f, 0.75f, 0.25f, 0.75f, 0.25f, 0.5f, 0.5f, 0.5f,

            // bottom
            0.5f, 0f, 0.25f, 0f, 0.25f, 0.25f, 0.5f, 0.25f,

            // left
            0f, 0.5f, 0f, 0.25f, 0.25f, 0.25f, 0.25f, 0.5f,

            // right
            0.75f, 0.5f, 0.75f, 0.25f, 0.5f, 0.25f, 0.5f, 0.5f};

    static float[] 
texCoordsPowerUp 
= {0f, 1f, 0f, 0f, 0f, 0f, 1f, 0f, 0f, 1f, 1f, 0f, 0f, 1f, 0f, 0f, 0f, 0f, 1f, 0f,
            0f, 1f, 1f, 0f, 0f, 1f, 0f, 0f, 0f, 0f, 1f, 0f, 0f, 1f, 1f, 0f, 0f, 1f, 0f, 0f, 0f, 0f, 1f, 0f, 0f, 1f, 1f,
            0f, 0f, 1f, 0f, 0f, 0f, 0f, 1f, 0f, 0f, 1f, 1f, 0f, 0f, 1f, 0f, 0f, 0f, 0f, 1f, 0f, 0f, 1f, 1f, 0f};
}

class Util {
    static Random 
rand 
= new Random();

    // returns a valid textureID on success, otherwise 0
    static int loadTexture(GLAutoDrawable d, String filename) {
        GL2 gl = d.getGL().getGL2(); // get the OpenGL 2 graphics context
        int width;
        int height;
        int level = 0;
        int border = 0;

        try {
            // open file
            FileInputStream fileInputStream = new FileInputStream(filename);
            // read image
            BufferedImage bufferedImage = ImageIO.
read
(fileInputStream);
            fileInputStream.close();

            width = bufferedImage.getWidth();
            height = bufferedImage.getHeight();
            int[] pixelIntData = new int[width * height];
            // convert image to ByteBuffer
            bufferedImage.getRGB(0, 0, width, height, pixelIntData, 0, width);
            ByteBuffer buffer = ByteBuffer.
allocateDirect
(pixelIntData.length * 4);
            buffer.order(ByteOrder.
nativeOrder
());

            // Unpack the data, each integer into 4 bytes of the ByteBuffer.
            // Also we need to vertically flip the image because the image origin
            // in OpenGL is the lower-left corner.
            for (int y = 0; y < height; y++) {
                int k = (height - 1 - y) * width;
                for (int x = 0; x < width; x++) {
                    buffer.put((byte) (pixelIntData[k] >>> 16));
                    buffer.put((byte) (pixelIntData[k] >>> 8));
                    buffer.put((byte) (pixelIntData[k]));
                    buffer.put((byte) (pixelIntData[k] >>> 24));
                    k++;
                }
            }
            buffer.rewind();

            // data is aligned in byte order
            gl.glPixelStorei(GL2.
GL_UNPACK_ALIGNMENT
, 1);

            // request textureID
            final int[] textureID = new int[1];
            gl.glGenTextures(1, textureID, 0);

            // bind texture
            gl.glBindTexture(GL2.
GL_TEXTURE_2D
, textureID[0]);

            // define how to filter the texture
            gl.glTexParameteri(GL2.
GL_TEXTURE_2D
, GL2.
GL_TEXTURE_MAG_FILTER
, GL2.
GL_NEAREST
);
            gl.glTexParameteri(GL2.
GL_TEXTURE_2D
, GL2.
GL_TEXTURE_MIN_FILTER
, GL2.
GL_NEAREST
);

            // texture colors should replace the original color values
            gl.glTexEnvf(GL2.
GL_TEXTURE_ENV
, GL2.
GL_TEXTURE_ENV_MODE
, GL2.
GL_REPLACE
); // GL_MODULATE
            // specify the 2D texture map
            gl.glTexImage2D(GL2.
GL_TEXTURE_2D
, level, GL2.
GL_RGB
, width, height, border, GL2.
GL_RGBA
,
                    GL2.
GL_UNSIGNED_BYTE
, buffer);

            return textureID[0];
        } catch (FileNotFoundException e) {
            System.
out
.println("Can not find texture data file " + filename);
        } catch (IOException e) {
            e.printStackTrace();
        }

        return 0;
    }



    public static float vec3Dot(float[] a, float[] b) {
        return a[0]*b[0] + a[1]*b[1] + a[2]*b[2];
    }

    public static void vec3Cross(float[] a, float[] b, float[] res) {
        res[0] = a[1] * b[2]  -  b[1] * a[2];
        res[1] = a[2] * b[0]  -  b[2] * a[0];
        res[2] = a[0] * b[1]  -  b[0] * a[1];
    }

    public static void vec3Normalize(float[] a) {
        float mag = (float) Math.
sqrt
(a[0] * a[0]  +  a[1] * a[1]  +  a[2] * a[2]);
        a[0] /= mag; a[1] /= mag; a[2] /= mag;
    }

    public static void mat4Identity(float[] a) {
        for (int i = 0; i < 16; ++i) a[i] = 0.0f;
        for (int i = 0; i < 4; ++i) a[i + i * 4] = 1.0f;
    }

    public static void mat4Multiply(float[] a, float[] b, float[] res) {
        for (int i = 0; i < 4; ++i) {
            for (int j = 0; j < 4; ++j) {
                res[j*4 + i] = 0.0f;
                for (int k = 0; k < 4; ++k) {
                    res[j*4 + i] += a[k*4 + i] * b[j*4 + k];
                }
            }
        }
    }

    public static void mat4Perspective(float[] a, float fov, float aspect, float zNear, float zFar) {
        float f = 1.0f / (float) (Math.
tan 
(fov/2.0f * (Math.
PI 
/ 180.0f)));
        
mat4Identity
(a);
        a[0] = f / aspect;
        a[1 * 4 + 1] = f;
        a[2 * 4 + 2] = (zFar + zNear)  / (zNear - zFar);
        a[3 * 4 + 2] = (2.0f * zFar * zNear) / (zNear - zFar);
        a[2 * 4 + 3] = -1.0f;
        a[3 * 4 + 3] = 0.0f;
    }

    public static void mat4ModelView(float[] a, float posX, float posY,float posZ, float sizeX, float sizeY, float sizeZ,float angleX, float angleY, float angleZ){
        float[] transform = new float[16];
        float[] scale = new float[16];
        float[] rotationX = new float[16];
        float[] rotationY = new float[16];
        float[] rotationZ = new float[16];

        
mat4Identity
(transform);
        transform[11] = posX;
        transform[12] = posY;
        transform[13] = posZ;

        
mat4Identity
(scale);
        scale[0] = sizeX;
        scale[5] = sizeY;
        scale[10] = sizeZ;

        
mat4Identity
(rotationX);
        
mat4Identity
(rotationY);
        
mat4Identity
(rotationZ);

        float[] identity = new float[16];
        
mat4Identity
(identity);
        float[] scaled = new float[16];
        
mat4Multiply
(scale,identity,scaled);
        float[] rotatedX = new float[16];
        
mat4Multiply
(rotationX,scaled,rotatedX);
        float[] rotatedY = new float[16];
        
mat4Multiply
(rotationY,rotatedX,rotatedY);
        float[] rotatedZ = new float[16];
        
mat4Multiply
(rotationZ,rotatedY,rotatedZ);

        
mat4Multiply
(transform,rotatedZ,a);
    }


    public static void mat4LookAt(float[] viewMatrix,
                            float eyeX, float eyeY, float eyeZ,
                            float centerX, float centerY, float centerZ,
                            float upX, float upY, float upZ) {

        float dir[] = new float[3];
        float right[] = new float[3];
        float up[] = new float[3];
        float eye[] = new float[3];

        up[0]=upX; up[1]=upY; up[2]=upZ;
        eye[0]=eyeX; eye[1]=eyeY; eye[2]=eyeZ;

        dir[0]=centerX-eyeX; dir[1]=centerY-eyeY; dir[2]=centerZ-eyeZ;
        
vec3Normalize
(dir);
        
vec3Cross
(dir,up,right);
        
vec3Normalize
(right);
        
vec3Cross
(right,dir,up);
        
vec3Normalize
(up);
        // first row
        viewMatrix[0]  = right[0];
        viewMatrix[4]  = right[1];
        viewMatrix[8]  = right[2];
        viewMatrix[12] = -
vec3Dot
(right, eye);
        // second row
        viewMatrix[1]  = up[0];
        viewMatrix[5]  = up[1];
        viewMatrix[9]  = up[2];
        viewMatrix[13] = -
vec3Dot
(up, eye);
        // third row
        viewMatrix[2]  = -dir[0];
        viewMatrix[6]  = -dir[1];
        viewMatrix[10] = -dir[2];
        viewMatrix[14] =  
vec3Dot
(dir, eye);
        // forth row
        viewMatrix[3]  = 0.0f;
        viewMatrix[7]  = 0.0f;
        viewMatrix[11] = 0.0f;
        viewMatrix[15] = 1.0f;
    }

    public static void mat4Print(float[] a) {
        // opengl uses column major order
        for (int i = 0; i < 4; ++i) {
            for (int j = 0; j < 4; ++j) {
                System.
out
.print( a[j * 4 + i] + " ");
            }
            System.
out
.println(" ");
        }
    }
}


5 Comments
2024/12/16
22:29 UTC

42

Hi, I wanted to share my 1 DRAW CALL open-gl engine (passion project)

Hey y'all,
I wanted to introduce a passion project of mine

https://github.com/micro-gl/nitro-gl

What sets this open-gl engine apart from other engines:

- ability to merge shaders as samplers and execute them as ONE draw call.

think about a shader as a sampler, that can reference other samplers and everything gets

merged through demangling and source code poetry at runtime and then cached.

- A very cool and fast LRU Pool to manage instances of Recently Used Shaders.

- It is a passion project

- it supports OpenGL ES as well

Hope it will interest you. i am here for Q&A

Thanks

15 Comments
2024/12/16
16:52 UTC

10

OpenGL (glad + glfw) configuration script for macOS

I usually see a lot of beginners who want to get into graphics programming / game dev in C having problems to link and configure glfw and glad especially in macOS . The YouTube tutorials available as well as the references online seem overwhelming for beginners and some may be even outdated . So I created this script to get someone up and running easily with a an empty glfw window. The “Hello world” of graphics programming . It provides a makefile and basic folder structure as well as a .c (or .cpp) file if you select it . I want to hear your feedback ! You can find it here : https://github.com/GeorgeKiritsis/Apple-Silicon-Opengl-Setup-Script

4 Comments
2024/12/16
13:50 UTC

25

OpenGL - GIobal Illumination using Voxel Cone Tracing - Bistro test scene

5 Comments
2024/12/16
08:38 UTC

10

how are you dealing with face culling?

I was following learnopengl guide and face culling chapter was pretty easy.

The question is, how do i integrate this with model loading? As i know, there is no way to set winding order(CW / CCW) using assimp. And there is no promise, that all triangles in the mesh will use same winding order.

The solution i ended up with was having winding field in each mesh and call glFrontFace based on it. Does someone know better solution?

7 Comments
2024/12/15
15:13 UTC

1

Rendering lines to show where their overlaps/intersections are?

I'm rendering a bunch of vector geometry with GL_LINE_STRIP and had an idea that requires that pixels where the lines overlap be drawn with a different color or some kind of pattern/effect on them to indicate that there's not just one line occupying those pixels.

The number of vertices in these polylines can easily get into the hundreds of thousands, and they can change on a frame-to-frame basis, so they're not just a static VBO being drawn that I can do any kind of precompute on.

I'm wondering if anyone has any ideas that could be pretty cheap/simple to implement to show where more than one line occupies the framebuffer. I'm already using GL_SMOOTH in combination with alpha-blending (GL_SRC_ALPHA/GL_ONE_MINUS_SRC_ALPHA) to antialias the lines and doing anything else with blending means they'd not look right against the background that they're already being drawn against.

I did think that maybe I could draw the lines so that they increment the stencil buffer and then draw a fullscreen quad specifically to highlight wherever the stencil buffer is greater than one? Is that probably the best way to go? Is that a workable solution?

Thanks! :]

3 Comments
2024/12/15
06:05 UTC

5

Image3D only has 8 bindings

I want to have about 500 image3Ds on the GPU which are each 255x255x255 in size. Each image3D is a chunk of terrain. I cant store this number of image3Ds on the GPU because there are only 8 bindings for this.

Does anybody know of a work around for this?

Would I need to move the data to be stored on the CPU and then move back onto the GPU each time it needs processing?

12 Comments
2024/12/14
17:40 UTC

4

Incorrectly Rendered OBJ Model

Hello everyone !

I've been exploring OpenGL in my spare time whiile following the LearnOpenGL page.

Earlier this year I decided to create my own OBJ file parser and got to a point where I could load a simple cube and a Cessna after some tweaking. However, I cannot render the entire model correctly; the engines are rendered, but the wings and tail aren't and it has holes in the fuselage. The model has been triangulated in Blender and looks fine when I open it with the 3D model viewer that comes with Windows.

I also tried rendering the model in different polygon modes (Triangle, Triangle strips, Points...), but that didn't seem to be the issue. I separated each part of the plane into it's own group, but still no luck.

Is there a step in the parsing that I'm misssing ? Or am I not submitting my vertices correctly?

Any help would be greatly appreciated!

project github page: https://github.com/JoseAFRibeiro/vertigal/blob/obj/src/models/objmodel.c

https://preview.redd.it/j3odlv0r1u6e1.png?width=1919&format=png&auto=webp&s=e8e9f869ab39c0d2b415f869c6f0deb4847c6b96

https://preview.redd.it/464x33112u6e1.png?width=2560&format=png&auto=webp&s=fd083bc28e6503ade49832f7b9cf987cdd662f0f

8 Comments
2024/12/14
15:43 UTC

2

Multiple image3D with different bindings using same compute shader

I am making an isometric 3D cellular automata. I have multiple chunks for a game world which are stored in an image3D. My problem is that I need all the image3D stored in the GPU with different bindings. They all need to access the same compute shader functions and fragment shader functions and I want to draw them with different draw calls. They are all being processed independently. Is there a way to have an image3D in a compute shader be bound dynamically depending on which image3D I need at that time?

What I am getting at the moment is the same chunk being repeated depending on the compute shader binding and the binding before the draw call is being ignored.

How I am calling the compute shader to generate the chunk:

glUseProgram(openglControl.getTerrainGenerationProgram().getShaderProgram());

glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, openglControl.getTypesSBO());
glBindBuffer(GL_SHADER_STORAGE_BUFFER, openglControl.getTypesSBO());

glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 3, openglControl.getRandomSBO());
glBindBuffer(GL_SHADER_STORAGE_BUFFER, openglControl.getRandomSBO());

//chunk data
int64_t chunkData[] = { this->pos.x,this->pos.y, this->pos.z };
glBindBuffer(GL_UNIFORM_BUFFER, openglControl.getChunkUBO());
glBufferSubData(GL_UNIFORM_BUFFER, 0, sizeof(chunkData), chunkData);
glBindBuffer(GL_UNIFORM_BUFFER, 1);

//world data
uint64_t worldData[] = { seed };
glBindBuffer(GL_UNIFORM_BUFFER, openglControl.getWorldUBO());
glBufferSubData(GL_UNIFORM_BUFFER, 0, sizeof(worldData), worldData);
glBindBuffer(GL_UNIFORM_BUFFER, 3);

//3d texture
glGenTextures(1, &this->texture);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_3D, this->texture);
glBindImageTexture(0, this->texture, 0, GL_TRUE, 0, GL_WRITE_ONLY, GL_RGBA32F);
glTexStorage3D(GL_TEXTURE_3D, 1, GL_RGBA32F, 200, 200, 200);
glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
unsigned int chunkLoc = glGetUniformLocation(openglControl.getTerrainGenerationProgram().getShaderProgram(), "chunkTexture");
glUniform1i(chunkLoc, 0);

glDispatchCompute(100,1,1);
glMemoryBarrier(GL_ALL_BARRIER_BITS);

this->generated = true;

How I am calling the draw calls:

for (unsigned int c = 0; c < world.getChunks().size(); c++) {
    //texture
    glActiveTexture(GL_TEXTURE0);
    glBindTexture(GL_TEXTURE_3D, world.getChunks()[c].getTexture());
    glBindImageTexture(0, world.getChunks()[c].getTexture(), 0, GL_TRUE, 0, GL_READ_ONLY, GL_RGBA32F);
    unsigned int chunkLoc = glGetUniformLocation(openglControl.getSpriteProgram().getShaderProgram(), "chunkTexture");
    glUniform1i(chunkLoc, 0);

    //chunk data
    int64_t chunkData[] = { world.getChunks()[c].getPos().x,world.getChunks()[c].getPos().y, world.getChunks()[c].getPos().z };
    glBindBuffer(GL_UNIFORM_BUFFER, openglControl.getChunkUBO());
    glBufferSubData(GL_UNIFORM_BUFFER, 0, sizeof(chunkData), chunkData);
    glBindBuffer(GL_UNIFORM_BUFFER, 1);

    glDrawArrays(GL_TRIANGLES, 0, 6);
}

How I am defining the image3D in the compute shader:

layout(binding = 0, rgba32f) uniform writeonly image3D chunkTexture;
3 Comments
2024/12/14
15:07 UTC

3

CubeMap coordinates to texture 2D conversion

SOLVED:

I've taken a look at OpenGL 4.6 spec and in the section "8.13. CUBE MAPTEXTURESELECTION" there is a table showing exactly how to select the face and UV for it. In my case the signs in multiple faces where wrong.

For anyone interested I've updated to code below (it should work fine now):

vec3 textureCubeTo2DArray(vec3 dir, int offset)
{
    vec2 uv;
    int  sliceIndex = -1;

    vec3 absDir = abs(dir);

    if (absDir.x > absDir.y && absDir.x > absDir.z)
    {
        if (dir.x > 0.0) {
            // +X face
            sliceIndex = 0;
            uv = vec2(-dir.z, -dir.y) / absDir.x;
        } else {
            // -X face
            sliceIndex = 1;
            uv = vec2(dir.z, -dir.y) / absDir.x;
        }
    }
    else if (absDir.y > absDir.x && absDir.y > absDir.z)
    {
        if (dir.y > 0.0) {
            // +Y face
            sliceIndex = 2;
            uv = vec2(dir.x, dir.z) / absDir.y;
        } else {
            // -Y face
            sliceIndex = 3;
            uv = vec2(dir.x, -dir.z) / absDir.y;
        }
    }
    else if (absDir.z > absDir.x && absDir.z > absDir.y)
    {
        if (dir.z > 0.0) {
            // +Z face
            sliceIndex = 4;
            uv = vec2(dir.x, -dir.y) / absDir.z;
        } else {
            // -Z face
            sliceIndex = 5;
            uv = vec2(-dir.x, -dir.y) / absDir.z;
        }
    }

    return vec3( uv * 0.5 + 0.5, sliceIndex + offset );
}
4 Comments
2024/12/14
00:58 UTC

20

Why I use opengl 1.x

  • it's easy to learn
  • backwards compatibility is insane (if I compile for 32bit)
  • ain't reading allat glew and glad stuff
  • ain't reading allat glsl stuff
45 Comments
2024/12/13
19:05 UTC

38

OpenGL - GIobal Illumination using Voxel Cone Tracing - Bistro test scene

12 Comments
2024/12/13
15:36 UTC

0

Can a call the glcolor3ub function before the glbegin function to make the entire shape the color specified in said glcolor3ub?

something like this:

  glColor3ub(200, 0, 0);
  glBegin(GL_POLYGON);
  glVertex3i(-4, -4, 0);
  glVertex3i(4, -4, 0);
  glVertex3i(0, 4, 0);
  glEnd();   glColor3ub(200, 0, 0);
  glBegin(GL_POLYGON);
  glVertex3i(-4, -4, 0);
  glVertex3i(4, -4, 0);
  glVertex3i(0, 4, 0);
  glEnd();

from here

10 Comments
2024/12/13
05:03 UTC

0

bind image3D for use in fragment shader

I have multiple 3d images which I want to bind for reading in a fragment shader. I want to bind to "chunkTexture" then draw then bind and draw the next. For some reason it is not re-binding each time and is just using the binding of the last one I generated in a compute shader.

compute shader dispatch:

void Chunk::generate(uint64_t seed, OpenGLControl& openglControl) {
glUseProgram(openglControl.getTerrainGenerationProgram().getShaderProgram());

//3d texture
glGenTextures(1, &this->texture);
glActiveTexture(GL_TEXTURE0 + 0);
glBindTexture(GL_TEXTURE_3D, this->texture);
glBindImageTexture(0, this->texture, 0, GL_TRUE, 0, GL_WRITE_ONLY, GL_RGBA32F);
glTexStorage3D(GL_TEXTURE_3D, 1, GL_RGBA32F, 200, 200, 200);
glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);

unsigned int chunkLoc = glGetUniformLocation(openglControl.getTerrainGenerationProgram().getShaderProgram(), "chunkTexture");
glUniform1i(chunkLoc, 0);

glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, openglControl.getTypesSBO());
glBindBuffer(GL_SHADER_STORAGE_BUFFER, openglControl.getTypesSBO());

glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 3, openglControl.getRandomSBO());
glBindBuffer(GL_SHADER_STORAGE_BUFFER, openglControl.getRandomSBO());

//chunk data
int64_t chunkData[] = { this->pos.x,this->pos.y, this->pos.z };
glBindBuffer(GL_UNIFORM_BUFFER, openglControl.getChunkUBO());
glBufferSubData(GL_UNIFORM_BUFFER, 0, sizeof(chunkData), chunkData);
glBindBuffer(GL_UNIFORM_BUFFER, 1);

//world data
uint64_t worldData[] = { seed };
glBindBuffer(GL_UNIFORM_BUFFER, openglControl.getWorldUBO());
glBufferSubData(GL_UNIFORM_BUFFER, 0, sizeof(worldData), worldData);
glBindBuffer(GL_UNIFORM_BUFFER, 3);

glDispatchCompute(100,1,1);
glMemoryBarrier(GL_ALL_BARRIER_BITS);

glBindImageTexture(10, this->texture, 0, GL_TRUE, 0, GL_WRITE_ONLY, GL_RGBA32F);

this->generated = true;
}

draw calls:

for (unsigned int c = 0; c < world.getChunks().size(); c++) {
    //texture
    glActiveTexture(GL_TEXTURE0);
    glBindTexture(GL_TEXTURE_3D, world.getChunks()[c].getTexture());
    glBindImageTexture(0, world.getChunks()[c].getTexture(), 0, GL_TRUE, 0, GL_READ_ONLY, GL_RGBA32F);
    unsigned int chunkLoc = glGetUniformLocation(openglControl.getSpriteProgram().getShaderProgram(), "chunkTexture");
    glUniform1i(chunkLoc, 0);

    //chunk data
    int64_t chunkData[] = { world.getChunks()[c].getPos().x,world.getChunks()[c].getPos().y, world.getChunks()[c].getPos().z };
    glBindBuffer(GL_UNIFORM_BUFFER, openglControl.getChunkUBO());
    glBufferSubData(GL_UNIFORM_BUFFER, 0, sizeof(chunkData), chunkData);
    glBindBuffer(GL_UNIFORM_BUFFER, 1);

    glDrawArraysInstanced(GL_TRIANGLES, 0, 6, 1);
}
0 Comments
2024/12/12
19:22 UTC

84

Ultra Engine 0.9.8 Released

Hi, I just wanted to let you know the OpenGL 4.6-powered Ultra Engine 0.9.8 is out. This update adds a new material painting system, really good tessellation, and a first-person shooter game template.

Material Painting

With and without material painting

The new material painting system lets you add unique detail all across your game level. It really makes a big improvement over plain tiled textures. Here's a quick tutorial showing how it works:

How to use material painting

Tessellation Made Practical

I put quite a lot of work into solving the problems of cracks at the seams of tessellation meshes, and came up with a set of tools that turns tessellation into a practical feature you can use every day. When combined with the material painting system, you can use materials with displacement maps to add unique geometric detail all throughout your game level, or apply mesh optimization tools to seal the cracks of single models.

Sealing the cracks of a tessellated mesh

First-person Shooter Template

This demo makes a nice basis for games and shows off what the engine can do. Warning: there may be some jump scares. :D

First-person shooter example game

Website is here if you want to check it out: https://www.ultraengine.com/

This engine was created to solve the rendering performance problems I saw while working on VR simulations at NASA. Ultra Engine provides up to 10x faster rendering performance than both Leadwerks and Unity:
https://github.com/UltraEngine/Benchmarks

All of this was done with OpenGL 4.6 and a lot of GLSL code. Let me know if you have got any questions and I will try to reply to everyone.

17 Comments
2024/12/12
17:32 UTC

0

Why won't my text render?

So I'm busy making a game engine (using OpenGL of course) in C#. I've come to the point where I want to add text to my engine (text on UI level), I have decided to use FontStashSharp, but for some reason it won't render the glyphs. I think it is because the texture atlas isn't correctly updated or something, but it could be something different.

Thanks in advance.

edit: it works now

solution:
when creating the texture atlas, set all the texture data stuff to be empty (so basically instantiate the texture)
and set the tex parameters.

here's a link to the github repo if anyone's curious:
Game engine: (please excuse my poor coding)
https://github.com/fancypants-goat/OpenGL-Lib

Project using the game engine (for testing text rendering):
https://github.com/fancypants-goat/OpenGL/tree/main/TextTest

7 Comments
2024/12/12
16:39 UTC

1

why is my metal or roughness texture not getting in 0 to 1 range at max even if i clamp it

iam using gltf damaged helmet file with metal and roughness as b and g channel even when i clamp the value to 0 to 1 i get the same effect as roughness is not set to max at one same with metalness. The max range lies somewhere between 0 to 5-6 range shouldnt the range when using clamp be set to 1 max and zero min. what am i doing wrong here.

this is load texture

//load texture fomat is in GL_RGB8 ie Channel 3
void OpenGLTexture2D::InvalidateImpl(std::string_view path, uint32_t width, uint32_t height, const void* data, uint32_t channels)
{
mPath = path;
 
if (mRendererID)
glDeleteTextures(1, &mRendererID);
 
mWidth = width;
mHeight = height;
 
GLenum internalFormat = 0, dataFormat = 0;
switch (channels)
{
case 1:
internalFormat = GL_R8;
dataFormat = GL_RED;
break;
case 2:
internalFormat = GL_RG8;
dataFormat = GL_RG;
break;
case 3:
internalFormat = GL_RGB8;
dataFormat = GL_RGB;
break;
case 4:
internalFormat = GL_RGBA8;
dataFormat = GL_RGBA;
break;
default:
GLSL_CORE_ERROR("Texture channel count is not within (1-4) range. Channel count: {}", channels);
break;
}
 
mInternalFormat = internalFormat;
mDataFormat = dataFormat;
 
GLSL_CORE_ASSERT(internalFormat & dataFormat, "Format not supported!");
 
glGenTextures(1, &mRendererID);
glBindTexture(GL_TEXTURE_2D, mRendererID);
 
glTextureParameteri(mRendererID, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
glTextureParameteri(mRendererID, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
 
glTextureParameteri(mRendererID, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTextureParameteri(mRendererID, GL_TEXTURE_WRAP_T, GL_REPEAT);
 
glTexImage2D(GL_TEXTURE_2D, 0, static_cast<int>(internalFormat), static_cast<int>(mWidth), static_cast<int>(mHeight), 0, dataFormat, GL_UNSIGNED_BYTE, data);
glGenerateMipmap(GL_TEXTURE_2D);
}


// Set Metallic Map Mesh.cpp
if (metallicMaps.size() > 0 &&
(name.find("metal") != std::string::npos || name.find("Metal") != std::string::npos ||
name.find("metallic") != std::string::npos || name.find("Metallic") != std::string::npos))
{
submesh.Mat->SetTexture(slot, metallicMaps[0]);  // Set Metallic Map
}
 
// Set Roughness Map
if (roughnessMaps.size() > 0 &&
(name.find("rough") != std::string::npos || name.find("Rough") != std::string::npos ||
name.find("roughness") != std::string::npos || name.find("Roughness") != std::string::npos))
{
submesh.Mat->SetTexture(slot, roughnessMaps[0]);  // Set Roughness Map
}

//Material class
void Material::Bind() const
{
const auto& materialProperties = mShader->GetMaterialProperties();
 
mShader->Bind();
for (const auto& [name, property] : materialProperties)
{
char* bufferStart = mBuffer + property.OffsetInBytes;
uint32_t slot = *reinterpret_cast<uint32_t*>(bufferStart);
switch (property.Type)
{
case MaterialPropertyType::None: break;
case MaterialPropertyType::Sampler2D:
{
mShader->SetInt(name, static_cast<int>(slot));
if (mTextures.at(slot))
mTextures.at(slot)->Bind(slot);
else
sWhiteTexture->Bind(slot);
break;
}
void Material::SetTexture(uint32_t slot, const Ref<Texture2D>& texture)
{
mTextures[slot] = texture;

}




//shader frag
struct Properties
{
vec4 AlbedoColor;
float Roughness;
float Metalness;
float EmissiveIntensity;
bool UseNormalMap;
vec4 EmissiveColor;
//bool UseRoughnessMap;

 
sampler2D AlbedoMap;
sampler2D NormalMap;
sampler2D MetallicMap;
sampler2D RoughnessMap;
sampler2D AmbientOcclusionMap;
sampler2D EmissiveMap;
 
};
 
uniform Properties uMaterial;
 void main()
float outMetalness = clamp(texture(uMaterial.MetallicMap, Input.TexCoord).b, 0.0, 1.0); 
float outRoughness = clamp(texture(uMaterial.RoughnessMap, Input.TexCoord).g, 0.05, 1.0);
outMetalness *= uMaterial.Metalness;
outRoughness *= uMaterial.Roughness;
oMR = vec4(outMetalness, outRoughness, outAO, outEmmisIntensity/255);
0 Comments
2024/12/12
06:13 UTC

Back To Top