Weird eigen matrix multiplication behavior when using row-major matrices - c++

The following is working just fine for me:
using Mat4 = Eigen::Matrix4f;
using Vec3 = Eigen::Vector3f;
class Camera {
public:
Vec3 pos = { 0.0f, 0.0f, 0.0f };
Vec3 forward = { 0.0f, 0.0f, 1.0f };
Vec3 up = { 0.0f, 1.0f, 0.0f };
float vfov = degrees(45.0f);
float near_plane = 0.1f;
float far_plane = 100.0f;
Mat4 cameraToScreen(float aspect_ratio) const {
Mat4 result;
float tanHalfFovy = tan(vfov *0.5f);
float x_scale = 1.0f / (aspect_ratio * tanHalfFovy);
float y_scale = 1.0f / (tanHalfFovy);
result <<
x_scale, 0, 0, 0,
0, y_scale, 0, 0,
0, 0, -(far_plane + near_plane) / (far_plane - near_plane), -1.0f,
0, 0, -2.0f * near_plane * far_plane / (far_plane - near_plane), 0;
return result;
}
Mat4 worldToCamera() const {
Mat4 result;
Vec3 p = pos;
Vec3 f = forward.normalized();
Vec3 r = f.cross(up).normalized();
Vec3 u = r.cross(f).normalized();
result <<
r.x(), u.x(), -f.x(), 0.0f,
r.y(), u.y(), -f.y(), 0.0f,
r.z(), u.z(), -f.z(), 0.0f,
-r.dot(p), -u.dot(p), f.dot(p), 1.0f;
return result;
}
Mat4 worldToScreen(float aspect_ratio) const {
return cameraToScreen(aspect_ratio) * worldToCamera();
}
};
However, since this is going to OpenGL, and I don't like dealing with transpositions, I though I could simply switch to row-major matrices:
using Mat4 = Eigen::Matrix<float, 4, 4, Eigen::RowMajor>;
Unfortunately, everything broke. Interestingly enough, inverting the final matrix multiplication (which is wrong) fixes the issue:
Mat4 worldToScreen(float aspect_ratio) const {
return worldToCamera() * cameraToScreen(aspect_ratio);
}
It's almost as if eigen performed the matrix multiplication with the assumption that the storage was column-major, regardless of my template tag, but that can't be right.
I tested both matrices individually, and they are performing as I want in row-major mode when used in isolation, it's only the product of both matrices that's wrong.
What am I not understanding with the way Eigen handles row-major matrices?
Edit:
Here's effectively how I send the data to OpenGL. My code has a lot of additional boilerplate, but it boils down to this:
struct CameraData {
Mat4 world_to_screen ;
};
void draw(Camera const& cam) {
CameraData cam_data;
// I remove the transposed() call when using Eigen::RowMajor
cam_data.world_to_screen = cam.worldToScreen(16.0f/9.0f).transposed();
// Camera data has a permanent ubo binding point shared by all programs.
glBindBuffer(GL_UNIFORM_BUFFER, cam_data_ubo);
glBufferSubData(GL_UNIFORM_BUFFER, 0, sizeof(cam_data), &cam_data);
//.. perform drawing
}
and the glsl:
#version 420
in vec3 vertex;
layout (std140) uniform CameraData {
mat4 world_to_screen;
};
void main() {
gl_Position = world_to_screen * vec4(vertex, 1.0);
}

Related

Directional Light Shadow Mapping Issues

So I've been trying to re-implement shadow mapping in my engine using directional lights, but I have to throw shade on my progress so far (see what I did there?).
I had it working in a previous commit a while back but refactored my engine and I'm trying to redo some of the shadow mapping. Wouldn't say I'm the best in terms of drawing shadows so thought I'd try and get some help.
Basically my issue seems to stem from the calculation of the light space matrix (seems a lot of people have the same issue). Initially I had a hardcoded projection matrix and simple view matrix for the light like this
void ZLight::UpdateLightspaceMatrix()
{
// …
if (type == ZLightType::Directional) {
auto lightDir = glm::normalize(glm::eulerAngles(Orientation()));
glm::mat4 lightV = glm::lookAt(lightDir, glm::vec3(0.f), WORLD_UP);
glm::mat4 lightP = glm::ortho(-50.f, 50.f, -50.f, 50.f, -100.f, 100.f);
lightspaceMatrix_ = lightP * lightV;
}
// …
}
This then gets passed unmodified as a shader uniform, with which I multiply the vertex world space positions by. A few months ago this was working but with the recent refactor I did on the engine it no longer shows anything. The output to the shadow map looks like this
And my scene isn't showing any shadows, at least not where it matters
Aside from this, after hours of scouring posts and articles about how to implement a dynamic frustrum for the light that will encompass the scene's contents at any given time, I also implemented a simple solution based on transforming the camera's frustum into light space, using an NDC cube and transforming it with the inverse camera VP matrix, and computing a bounding box from the result, which gets passed in to glm::ortho to make the light's projection matrix
void ZLight::UpdateLightspaceMatrix()
{
static std::vector <glm::vec4> ndcCube = {
glm::vec4{ -1.0f, -1.0f, -1.0f, 1.0f },
glm::vec4{ 1.0f, -1.0f, -1.0f, 1.0f },
glm::vec4{ -1.0f, 1.0f, -1.0f, 1.0f },
glm::vec4{ 1.0f, 1.0f, -1.0f, 1.0f },
glm::vec4{ -1.0f, -1.0f, 1.0f, 1.0f },
glm::vec4{ 1.0f, -1.0f, 1.0f, 1.0f },
glm::vec4{ -1.0f, 1.0f, 1.0f, 1.0f },
glm::vec4{ 1.0f, 1.0f, 1.0f, 1.0f }
};
if (type == ZLightType::Directional) {
auto activeCamera = Scene()->ActiveCamera();
auto lightDir = normalize(glm::eulerAngles(Orientation()));
glm::mat4 lightV = glm::lookAt(lightDir, glm::vec3(0.f), WORLD_UP);
lightspaceRegion_ = ZAABBox();
for (const auto& corner : ndcCube) {
auto invVPMatrix = glm::inverse(activeCamera->ProjectionMatrix() * activeCamera->ViewMatrix());
auto transformedCorner = lightV * invVPMatrix * corner;
transformedCorner /= transformedCorner.w;
lightspaceRegion_.minimum.x = glm::min(lightspaceRegion_.minimum.x, transformedCorner.x);
lightspaceRegion_.minimum.y = glm::min(lightspaceRegion_.minimum.y, transformedCorner.y);
lightspaceRegion_.minimum.z = glm::min(lightspaceRegion_.minimum.z, transformedCorner.z);
lightspaceRegion_.maximum.x = glm::max(lightspaceRegion_.maximum.x, transformedCorner.x);
lightspaceRegion_.maximum.y = glm::max(lightspaceRegion_.maximum.y, transformedCorner.y);
lightspaceRegion_.maximum.z = glm::max(lightspaceRegion_.maximum.z, transformedCorner.z);
}
glm::mat4 lightP = glm::ortho(lightspaceRegion_.minimum.x, lightspaceRegion_.maximum.x,
lightspaceRegion_.minimum.y, lightspaceRegion_.maximum.y,
-lightspaceRegion_.maximum.z, -lightspaceRegion_.minimum.z);
lightspaceMatrix_ = lightP * lightV;
}
}
What results is the same output in my scene (no shadows anywhere) and the following shadow map
I've checked the light space matrix calculations over and over, and tried tweaking values dozens of times, including all manner of lightV matrices using the glm::lookAt function, but I never get the desired output.
For more reference, here's my shadow vertex shader
#version 450 core
#include "Shaders/common.glsl" //! #include "../common.glsl"
layout (location = 0) in vec3 position;
layout (location = 5) in ivec4 boneIDs;
layout (location = 6) in vec4 boneWeights;
layout (location = 7) in mat4 instanceM;
uniform mat4 P_lightSpace;
uniform mat4 M;
uniform mat4 Bones[MAX_BONES];
uniform bool rigged = false;
uniform bool instanced = false;
void main()
{
vec4 pos = vec4(position, 1.0);
if (rigged) {
mat4 boneTransform = Bones[boneIDs[0]] * boneWeights[0];
boneTransform += Bones[boneIDs[1]] * boneWeights[1];
boneTransform += Bones[boneIDs[2]] * boneWeights[2];
boneTransform += Bones[boneIDs[3]] * boneWeights[3];
pos = boneTransform * pos;
}
gl_Position = P_lightSpace * (instanced ? instanceM : M) * pos;
}
my soft shadow implementation
float PCFShadow(VertexOutput vout, sampler2D shadowMap) {
vec3 projCoords = vout.FragPosLightSpace.xyz / vout.FragPosLightSpace.w;
if (projCoords.z > 1.0)
return 0.0;
projCoords = projCoords * 0.5 + 0.5;
// PCF
float shadow = 0.0;
float bias = max(0.05 * (1.0 - dot(vout.FragNormal, vout.FragPosLightSpace.xyz - vout.FragPos.xzy)), 0.005);
for (int i = 0; i < 4; ++i) {
float z = texture(shadowMap, projCoords.xy + poissonDisk[i]).r;
shadow += z < (projCoords.z - bias) ? 1.0 : 0.0;
}
return shadow / 4;
}
...
...
float shadow = PCFShadow(vout, shadowSampler0);
vec3 color = (ambient + (1.0 - shadow) * (diffuse + specular)) + materials[materialIndex].emission;
FragColor = vec4(color, albd.a);
and my camera view and projection matrix getters
glm::mat4 ZCamera::ProjectionMatrix()
{
glm::mat4 projectionMatrix(1.f);
auto scene = Scene();
if (!scene) return projectionMatrix;
if (cameraType_ == ZCameraType::Orthographic)
{
float zoomInverse_ = 1.f / (2.f * zoom_);
glm::vec2 resolution = scene->Domain()->Resolution();
float left = -((float)resolution.x * zoomInverse_);
float right = -left;
float bottom = -((float)resolution.y * zoomInverse_);
float top = -bottom;
projectionMatrix = glm::ortho(left, right, bottom, top, -farClippingPlane_, farClippingPlane_);
}
else
{
projectionMatrix = glm::perspective(glm::radians(zoom_),
(float)scene->Domain()->Aspect(),
nearClippingPlane_, farClippingPlane_);
}
return projectionMatrix;
}
glm::mat4 ZCamera::ViewMatrix()
{
return glm::lookAt(Position(), Position() + Front(), Up());
}
Been trying all kinds of small changes but I still don't get correct shadows. Don't know what I'm doing wrong here. The closest I've gotten is by scaling lightspaceRegion_ bounds by a factor of 10 in the light space matrix calculations (only in X and Y) but the shadows are still no where near correct.
The camera near and far clipping planes are set at reasonable values (0.01 and 100.0, respectively), camera zoom is 45.0 degrees and scene→Domain()→Aspect() just returns the width/height aspect ratio of the framebuffer's resolution. My shadow map resolution is set to 2048x2048.
Any help here would be much appreciated. Let me know if I left out any important code or info.

OpenGL Projection Matrix showing Orthographic

I got an orthographic camera working however I wanted to try and implement a perspective camera so I can do some parallax effects later down the line. I am having some issues when trying to implement it. It seems like the depth is not working correctly. I am rotating a 2d image along the x-axis to simulate it laying somewhat down so I get see the projection matrix working. It is still showing as an orthographic perspective though.
Here is some of my code:
CameraPersp::CameraPersp() :
_camPos(0.0f,0.0f,0.0f), _modelMatrix(1.0f), _viewMatrix(1.0f), _projectionMatrix(1.0f)
Function called init to setup the matrix variables:
void CameraPersp::init(int screenWidth, int screenHeight)
{
_screenHeight = screenHeight;
_screenWidth = screenWidth;
_modelMatrix = glm::translate(_modelMatrix, glm::vec3(0.0f, 0.0f, 0.0f));
_modelMatrix = glm::rotate(_modelMatrix, glm::radians(-55.0f), glm::vec3(1.0f, 0.0f, 0.0f));
_viewMatrix = glm::translate(_viewMatrix, glm::vec3(0.0f, 0.0f, -3.0f));
_projectionMatrix = glm::perspective(glm::radians(45.0f), static_cast<float>(_screenWidth) / _screenHeight, 0.1f, 100.0f);
}
Initializing a texture to be loaded in with x,y,z,width,height,src
_sprites.back()->init(-0.5f, -0.5f, 0.0f, 1.0f, 1.0f, "src/content/sprites/DungeonCrawlStoneSoupFull/monster/deep_elf_death_mage.png");
Sending in the matrices to the vertexShader:
GLint mLocation = _colorProgram.getUniformLocation("M");
glm::mat4 mMatrix = _camera.getMMatrix();
//glUniformMatrix4fv(mLocation, 1, GL_FALSE, &(mMatrix[0][0]));
glUniformMatrix4fv(mLocation, 1, GL_FALSE, glm::value_ptr(mMatrix));
GLint vLocation = _colorProgram.getUniformLocation("V");
glm::mat4 vMatrix = _camera.getVMatrix();
//glUniformMatrix4fv(vLocation, 1, GL_FALSE, &(vMatrix[0][0]));
glUniformMatrix4fv(vLocation, 1, GL_FALSE, glm::value_ptr(vMatrix));
GLint pLocation = _colorProgram.getUniformLocation("P");
glm::mat4 pMatrix = _camera.getPMatrix();
//glUniformMatrix4fv(pLocation, 1, GL_FALSE, &(pMatrix[0][0]));
glUniformMatrix4fv(pLocation, 1, GL_FALSE, glm::value_ptr(pMatrix));
Here is my vertex shader:
#version 460
//The vertex shader operates on each vertex
//input data from VBO. Each vertex is 2 floats
in vec3 vertexPosition;
in vec4 vertexColor;
in vec2 vertexUV;
out vec3 fragPosition;
out vec4 fragColor;
out vec2 fragUV;
//uniform mat4 MVP;
uniform mat4 M;
uniform mat4 V;
uniform mat4 P;
void main() {
//Set the x,y position on the screen
//gl_Position.xy = vertexPosition;
gl_Position = M * V * P * vec4(vertexPosition, 1.0);
//the z position is zero since we are 2d
//gl_Position.z = 0.0;
//indicate that the coordinates are nomalized
gl_Position.w = 1.0;
fragPosition = vertexPosition;
fragColor = vertexColor;
// opengl needs to flip the coordinates
fragUV = vec2(vertexUV.x, 1.0 - vertexUV.y);
}
I can see the image "squish" a little because it is still rendering the perspective as orthographic. If I remove the rotation on the x-axis, it is not longer squished because it isn't laying down at all. Any thoughts on what I am doing wrong? I can supply more info upon request but I think I put in most of the meat of things.
Picture:
You shouldn't modify gl_Position.w
gl_Position = M * V * P * vec4(vertexPosition, 1.0); // gl_Position is good
//indicate that the coordinates are nomalized < not true
gl_Position.w = 1.0; // Now perspective divisor is lost, projection isn't correct

OpenGL - Getting camera to move

I'm having trouble with my OpenGL game where I can't get the camera to move.
I am unable to use GLFW, GLUT and glulookat(). Here is my code, what's wrong?
P.S everything works except the camera movement meaning the game plays and works perfectly, just cant move the camera.
My Camera Code:
#include "SpriteRenderer.h"
#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>
class Camera
{
private:
Shader shader;
GLfloat angle = -90.f;
glm::vec3 cameraFront = glm::vec3(0.0f, 0.0f, -1.0f),
cameraPosition = glm::vec3(0.0f, 0.0f, 0.1f),
cameraUp = glm::vec3(0.0f, 1.0f, 0.0f);
glm::mat4 viewMatrix;
// recompute the view matrix from the camera variables
void updateMatrix()
{
viewMatrix = glm::lookAt(cameraPosition, cameraPosition + cameraFront, cameraUp);
}
// default constructor
void defaultNew()
{
cameraPosition = glm::vec3(0.0f, 0.0f, 0.1f);
cameraFront = glm::vec3(0.0f, 0.0f, -1.0f);
cameraUp = glm::vec3(0.0f, 1.0f, 0.0f);
updateMatrix();
}
public:
Camera() { defaultNew(); }
Camera(Shader &shader) { this->shader = shader; defaultNew(); }
glm::mat4 GetViewMatrix() const
{
// if your view matrix is always up-to-date, just return it directly
return viewMatrix;
}
// get functions
glm::vec3 GetCameraPosition() const { return cameraPosition; }
// .. same for Front and Up
// set functions
// call updateMatrix every time you update a variable
void SetCameraPosition(glm::vec3 pos)
{
cameraPosition = pos;
updateMatrix();
}
// .. same for Front and Up
// no need to use this-> all the time
virtual void Draw()
{
this->shader.Use();
this->shader.SetMatrix4("view", viewMatrix);
}
};
My Shader Code:
Shader &Use(){ glUseProgram(this->ID); return *this; }
void SetMatrix4(const GLchar *name, const glm::mat4 &matrix, GLboolean useShader = false)
{ if (useShader)this->Use(); glUniformMatrix4fv(glGetUniformLocation(this->ID, name), 1, GL_FALSE, glm::value_ptr(matrix)); }
My Game Code:
Camera *View;
projection2 = glm::perspective(glm::radians(44.0f), (float)this->Width / (float)this->Width, 0.1f, 100.0f);
AssetController::LoadShader("../src/Shaders/Light.vert", "../src/Shaders/Light.frag", "light");
AssetController::GetShader("light").SetMatrix4("projection", projection2);
View = new Camera(AssetController::GetShader("light"));
(...)
GLfloat velocity = playerSpeed * deltaTime;
glm::vec3 camPosition;
// Update Players Position
if (movingLeft)
{
if (Player->Position.x >= 0)
{
Player->Position.x -= velocity;
if (Ball->Stuck)
Ball->Position.x -= velocity;
camPosition = View->GetCameraPosition();
camPosition.x -= velocity / 2;
View->SetCameraPosition(camPosition);
}
}
else if (movingRight)
{
if (Player->Position.x <= this->Width - Player->Size.x)
{
Player->Position.x += velocity;
if (Ball->Stuck)
Ball->Position.x += velocity;
camPosition = View->GetCameraPosition();
camPosition.x += velocity / 2;
View->SetCameraPosition(camPosition);
}
}
(...)
GameOver->Draw(*Renderer);
View->Draw();
My Shaders:
.vert:
#version 440 core
layout (location = 0) in vec3 aPos;
layout (location = 1) in vec2 aTexCoord;
out vec2 TexCoord;
uniform mat4 model;
uniform mat4 view;
uniform mat4 projection;
void main()
{
gl_Position = projection * view * model * vec4(aPos, 1.0f);
TexCoord = vec2(aTexCoord.x, aTexCoord.y);
}
.frag:
#version 440 core
out vec4 FragColor;
in vec2 TexCoord;
// texture samplers
uniform sampler2D texture1;
uniform sampler2D texture2;
void main()
{
// linearly interpolate between both textures (80% container, 20% awesomeface)
FragColor = mix(texture(texture1, TexCoord), texture(texture2, TexCoord), 0.2);
}
The problem is that you only update local position variable cameraPosition, and not the view matrix, which is passed to OpenGL during rendering.
It is also a bad habit to make the camera variables and matrix public, as they can potentially be modified incorrectly or out-of-sync (as you are doing). Instead, you could write a pair of get/set functions:
class Camera
{
private:
Shader shader;
GLfloat angle = -90.f;
glm::vec3 cameraFront = glm::vec3(0.0f, 0.0f, -1.0f),
cameraPosition = glm::vec3(0.0f, 0.0f, 0.1f),
cameraUp = glm::vec3(0.0f, 1.0f, 0.0f);
glm::mat4 viewMatrix;
// recompute the view matrix from the camera variables
void updateMatrix()
{
viewMatrix = glm::lookAt(cameraPosition, cameraPosition + cameraFront, cameraUp);
}
// default constructor
void defaultNew()
{
cameraPosition = glm::vec3(0.0f, 0.0f, 0.1f);
cameraFront = glm::vec3(0.0f, 0.0f, -1.0f);
cameraUp = glm::vec3(0.0f, 1.0f, 0.0f);
updateMatrix();
}
public:
Camera() {
defaultNew();
}
Camera(Shader &shader) {
this->shader = shader;
defaultNew();
}
glm::mat4 GetViewMatrix() const
{
// if your view matrix is always up-to-date, just return it directly
return viewMatrix;
}
// get functions
glm::vec3 GetCameraPosition() const { return cameraPosition; }
// .. same for Front and Up
// set functions
// call updateMatrix every time you update a variable
void SetCameraPosition(glm::vec3 p)
{
cameraPosition = p;
updateMatrix();
}
// .. same for Front and Up
// no need to use this-> all the time
virtual void Draw()
{
shader.Use();
shader.SetMatrix4("view", viewMatrix);
}
};
And then when you update the camera position, simply use these functions instead of the exposed variables:
view->SetCameraPosition(view->GetCameraPosition() + velocity / 2.0f);
This will make sure that the draw calls always use the updated view matrix instead of the initial one (which was the case before and the source of your troubles).

Problems with drawing billboards

I am currently trying to draw billboards and some geometry with "modern opengl approach". Problem is that I cannot force billboards to keep their positions in space.
I need to link text positions with positions of another objects. Coordinates of text position are (3,3,3) and same coordinates has end of black line. In some positions I have exactly what I need: text is drawn at the end of line, but in some - it is too far from the end of line.
My render code:
public void Draw()
{
//Set up matrices
projectionMatrix = Matrix4.CreateOrthographic(_width, _height, -10000, 10000);
modelMatrix = Matrix4.Identity;
viewMatrix = Matrix4.CreateRotationY((float)xrot) *
Matrix4.CreateRotationX((float)yrot) *
Matrix4.CreateScale((float)scale);
var viewPort = new Rectangle(-(_width / 2), -(_height / 2), _width, _height);
var viewportTransformationMatrix = ComputeViewportTransformationMatrix(viewPort, -100, 100);
var viewportOrthographicMatrix = ComputeViewportOrthographicMatrix(viewPort);
worldViewProj = modelMatrix * viewMatrix * projectionMatrix;
//DRAW AXISES
GL.UseProgram(axisesProgramID);
axisesProgram.Uniforms["worldViewProj"].SetValue(worldViewProj);
axisesVAO.Bind();
for (int i = 0; i < 4; i++)
{
GL.DrawArrays(PrimitiveType.Lines, i * 2, 2);
}
//DRAW TEXT WITH PRE-CREATED TEXTURE
GL.UseProgram(textProgramID);
GL.ActiveTexture(TextureUnit.Texture0);
GL.BindTexture(TextureTarget.Texture2D, textureID);
//set-up uniforms
textProgram.Uniforms["og_viewportOrthographicMatrix"].SetValue(viewportOrthographicMatrix);
textProgram.Uniforms["og_viewportTransformationMatrix"].SetValue(viewportTransformationMatrix);
textProgram.Uniforms["Position"].SetValue(new float[] { 3.0f, 3.0f, 3.0f });
textProgram.Uniforms["projectionMatrix"].SetValue(projectionMatrix);
textProgram.Uniforms["modelViewMatrix"].SetValue(modelViewMatrix);
textProgram.Uniforms["og_texture0"].SetValue(0);
GL.DrawArrays(PrimitiveType.Points, 0, 1);
GL.BindTexture(TextureTarget.Texture2D, 0);
}
public Matrix4 ComputeViewportTransformationMatrix(Rectangle viewport, float nearDepthRange, float farDepthRange)
{
double halfWidth = viewport.Width * 0.5;
double halfHeight = viewport.Height * 0.5;
double halfDepth = (farDepthRange - nearDepthRange) * 0.5;
//
// Bottom and top swapped: MS -> OpenGL
//
return new Matrix4(
(float)halfWidth, 0.0f, 0.0f, (float)viewport.Left + (float)halfWidth,
0.0f, (float)halfHeight, 0.0f, (float)viewport.Top + (float)halfHeight,
0.0f, 0.0f, (float)halfDepth, (float)nearDepthRange + (float)halfDepth,
0.0f, 0.0f, 0.0f, 1.0f);
}
public static Matrix4 ComputeViewportOrthographicMatrix(Rectangle viewport)
{
//
// Bottom and top swapped: MS -> OpenGL
//
return Matrix4.CreateOrthographicOffCenter(
(float)viewport.Left, (float)viewport.Right,
(float)viewport.Top, (float)viewport.Bottom,
0.0f, 1.0f);
}
My axises shaders are really simple path-through.
//VERTEX SHADER
#version 150 core
in vec3 in_Position;
in vec3 in_Color;
out vec4 color;
uniform mat4 worldViewProj;
void main(void) {
gl_Position = worldViewProj * vec4(in_Position, 1.0);
color = vec4(in_Color, 1.0f);
}
//FRAGMENT SHADER
#version 150 core
in vec4 color;
out vec4 out_Color;
void main(void)
{
out_Color = color;
}
Here are text (texture) shaders:
//VERTEX SHADER
#version 330
out float gsOrigin;
out vec2 gsPixelOffset;
uniform mat4 projectionMatrix;
uniform mat4 modelViewMatrix;
uniform mat4 og_viewportTransformationMatrix;
uniform float origin = 6; // TODO: Why does this not work when float is int?
uniform vec2 pixelOffset = vec2(0,0);
uniform vec3 Position;
vec4 ModelToWindowCoordinates(
vec4 v,
mat4 modelViewPerspectiveMatrix,
mat4 viewportTransformationMatrix)
{
v = modelViewPerspectiveMatrix * v; // clip coordinates
v.xyz /= v.w; // normalized device coordinates
v.xyz = (viewportTransformationMatrix * vec4(v.xyz, 1.0)).xyz; // window coordinates
return v;
}
void main()
{
gl_Position = ModelToWindowCoordinates ( vec4(Position, 1.0f) , modelViewMatrix * projectionMatrix , og_viewportTransformationMatrix ) ;
gsOrigin = origin;
gsPixelOffset = pixelOffset;
}
//GEOMETRY SHADER
#version 330
layout(points) in;
layout(triangle_strip, max_vertices = 4) out;
in float gsOrigin[];
in vec2 gsPixelOffset[];
out vec2 fsTextureCoordinates;
uniform sampler2D og_texture0;
uniform float og_highResolutionSnapScale;
uniform mat4 og_viewportOrthographicMatrix;
void main()
{
float originScales[3] = float[](0.0, 1.0, -1.0);
vec2 halfSize = vec2(textureSize(og_texture0, 0)) * 0.5 * og_highResolutionSnapScale;
vec4 center = gl_in[0].gl_Position;
int horizontalOrigin = int(gsOrigin[0]) & 3; // bits 0-1
int verticalOrigin = (int(gsOrigin[0]) & 12) >> 2; // bits 2-3
center.xy += (vec2(originScales[horizontalOrigin], originScales[verticalOrigin]) * halfSize);
center.xy += (gsPixelOffset[0] * og_highResolutionSnapScale);
vec4 v0 = vec4(center.xy - halfSize, 0, 1.0);
vec4 v1 = vec4(center.xy + vec2(halfSize.x, -halfSize.y), 0, 1.0);
vec4 v2 = vec4(center.xy + vec2(-halfSize.x, halfSize.y), 0, 1.0);
vec4 v3 = vec4(center.xy + halfSize, 0, 1.0);
gl_Position = og_viewportOrthographicMatrix * v0;
fsTextureCoordinates = vec2(0.0, 0.0);
EmitVertex();
gl_Position = og_viewportOrthographicMatrix * v1;
fsTextureCoordinates = vec2(1.0, 0.0);
EmitVertex();
gl_Position = og_viewportOrthographicMatrix * v2;
fsTextureCoordinates = vec2(0.0, 1.0);
EmitVertex();
gl_Position = og_viewportOrthographicMatrix * v3;
fsTextureCoordinates = vec2(1.0, 1.0);
EmitVertex();
}
//FRAGMENT SHADER
#version 330
in vec2 fsTextureCoordinates;
out vec4 fragmentColor;
uniform sampler2D og_texture0;
uniform vec3 u_color;
void main()
{
vec4 color = texture(og_texture0, fsTextureCoordinates);
if (color.a == 0.0)
{
discard;
}
fragmentColor = vec4(color.rgb * u_color.rgb, color.a);
}
To me it looks like there is some basic coordinate system confusion. I have not checked everything here, but to me,
worldViewProj = modelMatrix * viewMatrix * projectionMatrix;
looks like the wrong way round, as vertices should be multiplied from the right like
projection*view*model*vertex
The same issue is within your shaders.
Also, i am not entirely sure, but it seems you are computing pixel coordinates for gl_Position in the shader (as you are applying some viewporttransform in the function ModelToWindowCoordinates). Since pixel coordinates may e.g. range from 0,0 to 1920,1080 they are not correct for gl_Position, which should be in clip coordinates.
I think you should read up a good tutorial about 3d billboarding and the math, for example
this one looks quite interesting. Then modify the sample code to fit your needs step by step.

Setting highlight to an image in OpenGL shader language

I'm trying to set a highlight mask to an image currently covered by mouse. My problem is that instead of setting the mask to all corners of an image it sets it only to the left top corner.
Here are my shaders:
string vertexShaderSource = #"
#version 140
uniform mat4 modelview_matrix;
uniform mat4 projection_matrix;
// incoming
in vec3 vertex_position;
in vec2 i_texCoord;
in vec4 i_highlightColor;
//outgoing
out vec2 o_texCoord;
out vec4 o_highlightColor;
void main(void)
{
gl_Position = projection_matrix * modelview_matrix * vec4( vertex_position, 1 );
o_texCoord = i_texCoord;
o_highlightColor = i_highlightColor;
}";
string fragmentShaderSource = #"
#version 140
precision highp float;
in vec2 o_texCoord;
in vec4 o_highlightColor;
out vec4 out_frag_color;
uniform sampler2D s_texture;
void main(void)
{
out_frag_color = texture( s_texture, o_texCoord ) + o_highlightColor;
if(out_frag_color.a == 0.0)
discard;
}";
This is how I transfer the highlight color to the graphics card:
float[] highlightColor = new float[myList.Count * 4];
int count = 0;
float[] noHighlight = new float[4] { 0.0f, 0.0f, 0.0f, 0.0f };
float[] yesHighlight = new float[4] { 1.0f, 0.0f, 0.0f, 0.3f };
foreach (GameObject go in myList)
{
...
for (int i = 0; i < 4; i++)
{
if (go.currentlyHovered)
highlightColor[count * 4 + i] = yesHighlight[i];
else
highlightColor[count * 4 + i] = noHighlight[i];
}
...
count++;
}
...
GL.BindBuffer(BufferTarget.ArrayBuffer, highlightColorLocation);
GL.BufferData<float>(BufferTarget.ArrayBuffer,
new IntPtr(highlightColor.Length * sizeof(float)),
highlightColor, BufferUsageHint.StaticDraw);
GL.EnableVertexAttribArray(2);
GL.BindAttribLocation(shaderProgramHandle, 2, "i_highlightColor");
GL.VertexAttribPointer(2, 4, VertexAttribPointerType.Float, false, OpenTK.Vector4.SizeInBytes, 0);
...
It seems as if I'm sending the highlight color only to one vertex but why? I thought the "in" modifier in glsl causes that data is sent to every vertex... And interesting is fact that when I replace "+ o_highlightColor" in my fargment shader with " + vec4(1.0, 0.0, 0.0, 0.3)" then the lighting covers whole image!
It seems like I've overlooked the fact that in order to apply the highlight to whole quad I need to send the highlight data to all 4 vertices, not only one like above. In total it will be 16 floats per object in each render frame in order to apply consistent highlight on whole area of the object.
float[] highlightColor = new float[myList.Count * 16];
int count = 0;
float[] noHighlight = new float[4] { 0.0f, 0.0f, 0.0f, 0.0f };
float[] yesHighlight = new float[4] { 1.0f, 0.0f, 0.0f, 0.3f };
foreach (GameObject go in myList)
{
...
for (int i = 0; i < 16; i++)
{
if (go.currentlyHovered)
highlightColor[count * 16 + i] = yesHighlight[i % 4];
else
highlightColor[count * 16 + i] = noHighlight[i % 4];
}
...
count++;
}