/r/opengl
News, information and discussion about OpenGL development.
News and discussion about OpenGL on all platforms.
Tutorials
Reference
Related subreddits
Programming Subreddits
/r/opengl
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
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.
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.
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
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.
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!
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.
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
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(" ");
}
}
}
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
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
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?
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! :]
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?
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
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;
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 );
}
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
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);
}
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:
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.
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
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);