Opengl ES 2.0 - Problem with color opacity by glDrawElements(GL_TRIANGLES) - c++

I created simple c++ class for drawing square in opengl es 2.0. It puts square on specific place with specific color and opacity. All is fine, except opacity. I set color and opacity with function "setColor". I expect 0.0f full transparent and 1.0 full visible. Looks like, for black color it works, but white color is still full visible, does not matter what I set to opacity. For other colors is opacity weird too.
At beginning I set
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glEnable(GL_BLEND);
My class :
GLSquare::GLSquare() {
vecs = new std::vector<GLfloat>();
indices = new std::vector<GLshort>();
colors = new std::vector<GLfloat>();
indicesCount = 6;
for (int i = 0; i < 12; i++) {
vecs->push_back(0.0f);
}
for (int i=0; i<16; i+=4) {
colors->push_back(0.0f);
colors->push_back(0.0f);
colors->push_back(0.0f);
colors->push_back(1.0f);
}
GLshort ind[] = { 0, 1, 2, 0, 2, 3 };
for (int i = 0; i < indicesCount; i++) {
indices->push_back(ind[i]);
}
}
GLSquare::~GLSquare() {
delete vecs;
delete colors;
delete indices;
}
void GLSquare::draw(Matrix *matrix) {
glUseProgram(program->id);
glEnableVertexAttribArray(program->positionHandle);
glVertexAttribPointer(program->positionHandle, 3, GL_FLOAT, false, 12, &vecs->front());
glEnableVertexAttribArray(program->colorHandle);
// Prepare the background coordinate data
glVertexAttribPointer(program->colorHandle, 4, GL_FLOAT, false, 0, &colors->front());
glUniformMatrix4fv(program->matrixHandle, 1, false, matrix->projectionAndView);
glDrawElements(GL_TRIANGLES, indicesCount, GL_UNSIGNED_SHORT, &indices->front());
glDisableVertexAttribArray(program->positionHandle);
glDisableVertexAttribArray(program->colorHandle);
}
void GLSquare::set(float left, float top, float width, float height) {
position[0] = left;
position[1] = top;
size[0] = width;
size[1] = height;
vecs->at(0) = left;
vecs->at(1) = top;
vecs->at(3) = left;
vecs->at(4) = top + height;
vecs->at(6) = left + width;
vecs->at(7) = top + height;
vecs->at(9) = left + width;
vecs->at(10) = top;
}
void GLSquare::setColor(Color color, GLfloat opacity) {
for (int i=0; i<16; i+=4) {
colors->at(i) = color.r;
colors->at(i + 1) = color.g;
colors->at(i + 2) = color.b;
colors->at(i + 3) = opacity;
}
}
my fragment shader is simple :
precision mediump float;
varying vec4 v_Color;
void main()
{
gl_FragColor = v_Color;
}
My vertex shader :
uniform mat4 uMVPMatrix;
attribute vec4 vPosition;
attribute vec4 a_Color;
varying vec4 v_Color;
void main()
{
gl_Position = uMVPMatrix * vPosition;
v_Color = a_Color;
}
Gettings colorHandle from shader:
program->colorHandle = glGetAttribLocation(programID, "a_Color");
Here is how it looks with :
square->setColor(Color(1.0f,1.0f,1.0f), 0.1f);
white rectangle in left top corner
and here is with black color, opacity 0.1

I found the problem. Code works correctly, other 3rd party library overrides glBlendFunc. Fixing it solved the issue

Related

LWJGL3 Visual artifacts caused by different projections

I have a very simple glsl vertex shader, which is the following:
#version 430
in vec2 vertices;
in vec2 textures;
out vec2 tex_coords;
uniform mat4 projection;
uniform mat4 texModifier;
void main() {
tex_coords = (texModifier * vec4(textures,0,1)).xy;
gl_Position = projection * vec4(vertices, 0, 1);
}
This shader is used to render text. The text is just a font sheet where I change the texModifier so that the mat4 coordinates are over the specific letter I want to draw. This works fine, but I noticed that different projection matrixes cause different visual artifacts.
Here is the an example:
This is the text using its original position.
And this is the the same text only the projection matrix is translated 0.1f / 1920 to the left. The visual artifacts change from being around commas and r to being around the u, S and more. These artifacts appear even when using linear interpolation.
This is the function used to draw text:
public void drawText(Shader shader, CharSequence text, float x, float y, int letters) {
if(letters == -1)
letters = text.length();
Model model;
Matrix4f projection = new Matrix4f();
Texture fontSheet = texture;
int textHeight = getTextHeight(text);
projection.setOrtho(-1, 1, -1, 1, -1, 1);
float drawX = x;
float drawY = y;
if (textHeight > fontHeight) {
drawY += textHeight - fontHeight;
}
shader.bind();
shader.setUniform("sampler", 0);
fontSheet.bind(0);
for (int i = 0; i < text.length() && i < letters; i++) {
char ch = text.charAt(i);
if (ch == '\n') {
/* Line feed, set x and y to draw at the next line */
drawY -= fontHeight;
drawX = x;
continue;
}
if (ch == '\r') {
/* Carriage return, just skip it */
continue;
}
Glyph g = glyphs.get(ch);
model = Model.createQuad((float) g.width / 2, (float) g.height / 2);
projection.setTranslation(((float) g.width / 2 + drawX) / Main.WINDOW_WIDTH, drawY / Main.WINDOW_HEIGHT, 0);
Matrix4f texModifier =
new Matrix4f()
.translate((float) g.x / fontSheet.getWidth(), 0, 0)
.scale((float) g.width / fontSheet.getWidth(), -(float) g.height / fontSheet.getHeight(), 1);
shader.setUniform("projection", projection);
shader.setUniform("texModifier", texModifier);
model.render();
drawX += g.width;
}
}
Why is the projection causing theses artifacts?

Object not moving according to mouse position when using shaders in raylib

I'm creating a few glowing particles in raylib using shaders and the particles are supposed to move along with the mouse but when compiling it gets stuck to the bottom left corner and the particles dont move.
How it Looks
The c++ code
#include <raylib.h>
#include <vector>
const int W = 400;
const int H = 400;
std::vector<Vector2> particle;
float remap(float value, float low1, float high1, float low2, float high2) {
return low2 + (value - low1) * (high2 - low2) / (high1 - low1);
}
int main() {
SetConfigFlags( FLAG_WINDOW_RESIZABLE );
InitWindow(W, H, "FireWorks");
Shader shader = LoadShader("../assets/vert.glsl", "../assets/frag.glsl");
Texture2D texture = LoadTextureFromImage(GenImageColor(W, H, BLUE));
int resolLoc = GetShaderLocation(shader, "resolution");
int particleLoc = GetShaderLocation(shader, "particle");
int particleCountLoc = GetShaderLocation(shader, "particleCount");
float res[2] = {(float)W, (float)H};
SetShaderValue(shader, resolLoc, res, SHADER_UNIFORM_VEC2);
SetTargetFPS(60);
while (!WindowShouldClose()) {
BeginDrawing();
ClearBackground(BLACK);
particle.push_back(Vector2{(float)GetMouseX(), (float)GetMouseY()});
int removeCount = 1;
for (int i = 0; i < removeCount; i++) {
if (particle.size() == 0) break;
if (particle.size() > 30) {
particle.erase(particle.begin() + i);
}
}
BeginShaderMode(shader);
float particles[30][2];
for ( int i = 0; i < particle.size(); i++) {
particles[i][0] = remap(particle[i].x, 0, W, 0.0, 1.0);
particles[i][1] = remap(particle[i].y, 0, H, 1.0, 0.0);
}
int pSize = particle.size();
SetShaderValue(shader, particleCountLoc, &pSize, SHADER_UNIFORM_INT);
SetShaderValue(shader, particleLoc, particles, SHADER_UNIFORM_VEC2);
DrawTextureRec(texture, (Rectangle) { 0, 0, (float)texture.width, (float) -texture.height }, (Vector2) { 0, 0}, RAYWHITE);
DrawRectangle(0, 0, W, H, BLACK);
EndShaderMode();
EndDrawing();
}
UnloadTexture(texture);
UnloadShader(shader);
CloseWindow();
return 0;
}
The Vertex Shader
#version 330
// Input vertex attributes
in vec3 vertexPosition;
in vec2 vertexTexCoord;
in vec3 vertexNormal;
in vec4 vertexColor;
// Input uniform values
uniform mat4 mvp;
// Output vertex attributes (to fragment shader)
out vec2 fragTexCoord;
out vec4 fragColor;
// NOTE: Add here your custom variables
void main()
{
// Send vertex attributes to fragment shader
fragTexCoord = vertexTexCoord;
fragColor = vertexColor;
// Calculate final vertex position
gl_Position = mvp * vec4(vertexPosition, 1.0);
}
The Fragment Shader
#version 330
// Input vertex attributes (from vertex shader)
in vec2 fragTexCoord;
in vec4 fragColor;
// Input uniform values
uniform sampler2D texture0;
uniform vec4 colDiffuse;
// Output fragment color
out vec4 finalColor;
// NOTE: Add here your custom variables
uniform vec2 resolution;
uniform int particleCount;
uniform vec2 particle[30];
void main() {
// Texel color fetching from texture sampler
vec4 texelColor = texture(texture0, fragTexCoord);
vec2 st = gl_FragCoord.xy / resolution.xy;
float r = 0.0;
float g = 0.0;
float b = 0.0;
for (int i = 0; i < 30; i++) {
if (i < particleCount) {
vec2 particlePos = particle[i];
float value = float(i) / distance(st, particlePos.xy) * 0.00015;
g += value * 0.5;
b += value;
}
}
finalColor = vec4(r, g, b, 1.0) * texelColor * colDiffuse;
}
The JS version of the code (which works) is here.
If you could point me in the right direction it'd be great.
The uniform particle is of type vec2[30]. An uniform array can needs to be set with SetShaderValueV instead of SetShaderValue:
SetShaderValue(shader, particleLoc, particles, SHADER_UNIFORM_VEC2);
SetShaderValueV(shader, particleLoc, particles[0], SHADER_UNIFORM_VEC2, 30);

OpenGL ES - texturing sphere

I have a sphere. I can map texture on it. But now my texture is outside sphere. And I need inside. My user sit like inside sphere, so he can view inside it (rotate and zoom). So simply like a sky dome, but sphere. Maybe I need fix uv texture coordinates or enable something?
Here code for generating sphere:
class Sphere : public ParametricSurface {
public:
Sphere(float radius) : m_radius(radius)
{
ParametricInterval interval = { ivec2(20, 20), vec2(Pi, TwoPi), vec2(8, 14) };
SetInterval(interval);
}
vec3 Evaluate(const vec2& domain) const
{
float u = domain.x, v = domain.y;
float x = m_radius * sin(u) * cos(v);
float y = m_radius * cos(u);
float z = m_radius * -sin(u) * sin(v);
return vec3(x, y, z);
}
private:
float m_radius;
};
vec2 ParametricSurface::ComputeDomain(float x, float y) const
{
return vec2(x * m_upperBound.x / m_slices.x, y * m_upperBound.y / m_slices.y);
}
void ParametricSurface::GenerateVertices(float * vertices) const
{
float* attribute = vertices;
for (int j = 0; j < m_divisions.y; j++) {
for (int i = 0; i < m_divisions.x; i++) {
// Compute Position
vec2 domain = ComputeDomain(i, j);
vec3 range = Evaluate(domain);
attribute = range.Write(attribute);
// Compute Normal
if (m_vertexFlags & VertexFlagsNormals) {
float s = i, t = j;
// Nudge the point if the normal is indeterminate.
if (i == 0) s += 0.01f;
if (i == m_divisions.x - 1) s -= 0.01f;
if (j == 0) t += 0.01f;
if (j == m_divisions.y - 1) t -= 0.01f;
// Compute the tangents and their cross product.
vec3 p = Evaluate(ComputeDomain(s, t));
vec3 u = Evaluate(ComputeDomain(s + 0.01f, t)) - p;
vec3 v = Evaluate(ComputeDomain(s, t + 0.01f)) - p;
vec3 normal = u.Cross(v).Normalized();
if (InvertNormal(domain))
normal = -normal;
attribute = normal.Write(attribute);
}
// Compute Texture Coordinates
if (m_vertexFlags & VertexFlagsTexCoords) {
float s = m_textureCount.x * i / m_slices.x;
float t = m_textureCount.y * j / m_slices.y;
attribute = vec2(s, t).Write(attribute);
}
}
}
}
void ParametricSurface::GenerateLineIndices(unsigned short * indices) const
{
unsigned short * index = indices;
for (int j = 0, vertex = 0; j < m_slices.y; j++) {
for (int i = 0; i < m_slices.x; i++) {
int next = (i + 1) % m_divisions.x;
*index++ = vertex + i;
*index++ = vertex + next;
*index++ = vertex + i;
*index++ = vertex + i + m_divisions.x;
}
vertex += m_divisions.x;
}
}
void ParametricSurface::GenerateTriangleIndices(unsigned short * indices) const
{
unsigned short * index = indices;
for (int j = 0, vertex = 0; j < m_slices.y; j++) {
for (int i = 0; i < m_slices.x; i++) {
int next = (i + 1) % m_divisions.x;
*index++ = vertex + i;
*index++ = vertex + next;
*index++ = vertex + i + m_divisions.x;
*index++ = vertex + next;
*index++ = vertex + next + m_divisions.x;
*index++ = vertex + i + m_divisions.x;
}
vertex += m_divisions.x;
}
}
And here is VBO creation:
+ (DrawableVBO *)createVBO:(SurfaceType)surfaceType
{
ISurface * surface = [self createSurface:surfaceType]; // just Sphere type
surface->SetVertexFlags(VertexFlagsNormals | VertexFlagsTexCoords); // which vertexes I need
// Get vertice from surface.
//
int vertexSize = surface->GetVertexSize();
int vBufSize = surface->GetVertexCount() * vertexSize;
GLfloat * vbuf = new GLfloat[vBufSize];
surface->GenerateVertices(vbuf);
// Get triangle indice from surface
//
int triangleIndexCount = surface->GetTriangleIndexCount();
unsigned short * triangleBuf = new unsigned short[triangleIndexCount];
surface->GenerateTriangleIndices(triangleBuf);
// Create the VBO for the vertice.
//
GLuint vertexBuffer;
glGenBuffers(1, &vertexBuffer);
glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer);
glBufferData(GL_ARRAY_BUFFER, vBufSize * sizeof(GLfloat), vbuf, GL_STATIC_DRAW);
// Create the VBO for the triangle indice
//
GLuint triangleIndexBuffer;
glGenBuffers(1, &triangleIndexBuffer);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, triangleIndexBuffer);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, triangleIndexCount * sizeof(GLushort), triangleBuf, GL_STATIC_DRAW);
delete [] vbuf;
delete [] triangleBuf;
delete surface;
DrawableVBO * vbo = [[DrawableVBO alloc] init];
vbo.vertexBuffer = vertexBuffer;
vbo.triangleIndexBuffer = triangleIndexBuffer;
vbo.vertexSize = vertexSize;
vbo.triangleIndexCount = triangleIndexCount;
return vbo;
}
Here is my light setup:
- (void)setupLights
{
// Set up some default material parameters.
//
glUniform3f(_ambientSlot, 0.04f, 0.04f, 0.04f);
glUniform3f(_specularSlot, 0.5, 0.5, 0.5);
glUniform1f(_shininessSlot, 50);
// Initialize various state.
//
glEnableVertexAttribArray(_positionSlot);
glEnableVertexAttribArray(_normalSlot);
glUniform3f(_lightPositionSlot, 1.0, 1.0, 5.0);
glVertexAttrib3f(_diffuseSlot, 0.8, 0.8, 0.8);
}
And finally shaders:
fragment:
precision mediump float;
varying vec4 vDestinationColor;
varying vec2 vTextureCoordOut;
uniform sampler2D Sampler;
void main()
{
gl_FragColor = texture2D(Sampler, vTextureCoordOut) * vDestinationColor;
}
vertex:
uniform mat4 projection;
uniform mat4 modelView;
attribute vec4 vPosition;
attribute vec2 vTextureCoord;
uniform mat3 normalMatrix;
uniform vec3 vLightPosition;
uniform vec3 vAmbientMaterial;
uniform vec3 vSpecularMaterial;
uniform float shininess;
attribute vec3 vNormal;
attribute vec3 vDiffuseMaterial;
varying vec4 vDestinationColor;
varying vec2 vTextureCoordOut;
void main(void)
{
gl_Position = projection * modelView * vPosition;
vec3 N = normalMatrix * vNormal;
vec3 L = normalize(vLightPosition);
vec3 E = vec3(0, 0, 1);
vec3 H = normalize(L + E);
float df = max(0.0, dot(N, L));
float sf = max(0.0, dot(N, H));
sf = pow(sf, shininess);
vec3 color = vAmbientMaterial + df * vDiffuseMaterial + sf * vSpecularMaterial;
vDestinationColor = vec4(color, 1);
vTextureCoordOut = vTextureCoord;
}
Some monkey code but I fix his. Firstly we enable culling and disable front side rendering:
glEnable(GL_CULL_FACE);
glCullFace(GL_FRONT);
Then I change position of the light source:
glUniform3f(_lightPositionSlot, 1.0, 1.0, -2.5);
(I even don't need the light, so next step - I must disable it at all). But finally I have a sphere, user is inside it, can rotate it, zoom in and out and see the texture!

How to smooth the painting of a custom QML element?

I try now to create custom QML element, derived from QQuickItem. So I overrided QQuickItem::updatePaintNode and want now do draw a line. My code:
QSGNode *StrikeLine::updatePaintNode(QSGNode *oldNode, QQuickItem::UpdatePaintNodeData *)
{
QSGGeometryNode *node = 0;
QSGGeometry *geometry;
QSGFlatColorMaterial *material;
node = static_cast<QSGGeometryNode *>(oldNode);
if(!node) {
node = new QSGGeometryNode;
geometry = new QSGGeometry(QSGGeometry::defaultAttributes_Point2D(), 2);
geometry->setDrawingMode(GL_LINES);
geometry->setLineWidth(3);
material = new QSGFlatColorMaterial;
material->setColor(QColor(255, 0, 0));
node->setGeometry(geometry);
node->setFlag(QSGNode::OwnsGeometry);
node->setMaterial(material);
node->setFlag(QSGNode::OwnsMaterial);
getColor();
} else {
geometry = node->geometry();
material = static_cast<QSGFlatColorMaterial *>(node->material());
}
geometry->vertexDataAsPoint2D()[0].set(p_startPoint.x(), p_startPoint.y());
geometry->vertexDataAsPoint2D()[1].set(p_endPoint.x(), p_endPoint.y());
material->setColor(getColor());
node->markDirty(QSGNode::DirtyGeometry);
return node;
}
But my line looks so ugly. The edges are rough and it looks like DOS graphics at all. So my question - how can I apply smooth painting? I now it may be some shader or something but I cannot find any documentation.
The scene graph supports two types of antialiasing. Primitives such as rectangles and images will be antialiased by adding more vertices along the edge of the primitives so that the edges fade to transparent. This method called vertex antialiasing. If you requests a multisampled OpenGL context, the scene graph will prefer multisample based antialiasing (MSAA).
Vertex antialiasing can produce seams between edges of adjacent primitives, even when the two edges are mathmatically the same. Multisample antialiasing does not.
Multisample Antialiasing
Multisample antialiasing is a hardware feature where the hardware calculates a coverage value per pixel in the primitive. Some hardware can multisample at a very low cost, while other hardware may need both more memory and more GPU cycles to render a frame.
To enable multisample antialiasing you should set QSurfaceFormat with samples greater than 0 using QQuickWindow::setFormat()
QQuickView view;
QSurfaceFormat format = view.format();
format.setSamples(16);
view.setFormat(format);
view.show();
Vertex Antialiasing
Vertex antialiasing can be enabled and disabled on a per-item basis using the Item::antialiasing property. It will work regardless of what the underlying hardware supports and produces higher quality antialiasing, both for normally rendered primitives and also for primitives captured into framebuffer objects.
The downside to using vertex antialiasing is that each primitive with antialiasing enabled will have to be blended. In terms of batching, this means that the renderer needs to do more work to figure out if the primitive can be batched or not and due to overlaps with other elements in the scene, it may also result in less batching, which could impact performance.
To apply vertex antialiasing to custom QML element, derived from QQuickItem, follow next steps:
1) Create custom material and OpenGL shader program.
smoothcolormaterial.h
#include <QSGMaterial>
#include <QSGMaterialShader>
//----------------------------------------------------------------------
class QSGSmoothColorMaterial : public QSGMaterial
{
public:
QSGSmoothColorMaterial();
int compare(const QSGMaterial *other) const;
protected:
virtual QSGMaterialType *type() const;
virtual QSGMaterialShader *createShader() const;
};
//----------------------------------------------------------------------
class QSGSmoothColorMaterialShader : public QSGMaterialShader
{
public:
QSGSmoothColorMaterialShader();
virtual void updateState(const RenderState &state, QSGMaterial *newEffect, QSGMaterial *oldEffect);
virtual char const *const *attributeNames() const;
private:
void initialize();
int m_matrixLoc;
int m_opacityLoc;
int m_pixelSizeLoc;
};
smoothcolormaterial.cpp
QSGSmoothColorMaterial::QSGSmoothColorMaterial()
{
setFlag(RequiresFullMatrixExceptTranslate, true);
setFlag(Blending, true);
}
int QSGSmoothColorMaterial::compare(const QSGMaterial *other) const
{
Q_UNUSED(other)
return 0;
}
QSGMaterialType *QSGSmoothColorMaterial::type() const
{
static QSGMaterialType type;
return &type;
}
QSGMaterialShader *QSGSmoothColorMaterial::createShader() const
{
return new QSGSmoothColorMaterialShader();
}
//----------------------------------------------------------------------
QSGSmoothColorMaterialShader::QSGSmoothColorMaterialShader()
: QSGMaterialShader()
{
setShaderSourceFile(QOpenGLShader::Vertex, QStringLiteral(":/shaders/smoothcolor.vert"));
setShaderSourceFile(QOpenGLShader::Fragment, QStringLiteral(":/shaders/smoothcolor.frag"));
}
void QSGSmoothColorMaterialShader::updateState(const QSGMaterialShader::RenderState &state, QSGMaterial *newEffect, QSGMaterial *oldEffect)
{
Q_UNUSED(newEffect)
if (state.isOpacityDirty())
program()->setUniformValue(m_opacityLoc, state.opacity());
if (state.isMatrixDirty())
program()->setUniformValue(m_matrixLoc, state.combinedMatrix());
if (oldEffect == 0) {
// The viewport is constant, so set the pixel size uniform only once.
QRect r = state.viewportRect();
program()->setUniformValue(m_pixelSizeLoc, 2.0f / r.width(), 2.0f / r.height());
}
}
const char * const *QSGSmoothColorMaterialShader::attributeNames() const
{
static char const *const attributes[] = {
"vertex",
"vertexColor",
"vertexOffset",
0
};
return attributes;
}
void QSGSmoothColorMaterialShader::initialize()
{
m_matrixLoc = program()->uniformLocation("matrix");
m_opacityLoc = program()->uniformLocation("opacity");
m_pixelSizeLoc = program()->uniformLocation("pixelSize");
}
Fragment Shader
varying lowp vec4 color;
void main()
{
gl_FragColor = color;
}
Vertex Shader
uniform highp vec2 pixelSize;
uniform highp mat4 matrix;
uniform lowp float opacity;
attribute highp vec4 vertex;
attribute lowp vec4 vertexColor;
attribute highp vec2 vertexOffset;
varying lowp vec4 color;
void main()
{
highp vec4 pos = matrix * vertex;
gl_Position = pos;
if (vertexOffset.x != 0.) {
highp vec4 delta = matrix[0] * vertexOffset.x;
highp vec2 dir = delta.xy * pos.w - pos.xy * delta.w;
highp vec2 ndir = .5 * pixelSize * normalize(dir / pixelSize);
dir -= ndir * delta.w * pos.w;
highp float numerator = dot(dir, ndir * pos.w * pos.w);
highp float scale = 0.0;
if (numerator < 0.0)
scale = 1.0;
else
scale = min(1.0, numerator / dot(dir, dir));
gl_Position += scale * delta;
}
if (vertexOffset.y != 0.) {
highp vec4 delta = matrix[1] * vertexOffset.y;
highp vec2 dir = delta.xy * pos.w - pos.xy * delta.w;
highp vec2 ndir = .5 * pixelSize * normalize(dir / pixelSize);
dir -= ndir * delta.w * pos.w;
highp float numerator = dot(dir, ndir * pos.w * pos.w);
highp float scale = 0.0;
if (numerator < 0.0)
scale = 1.0;
else
scale = min(1.0, numerator / dot(dir, dir));
gl_Position += scale * delta;
}
color = vertexColor * opacity;
}
2) Create custom AttributeSet for QSGGeometry.
myquickitem.cpp
namespace
{
struct Color4ub
{
unsigned char r, g, b, a;
};
inline Color4ub colorToColor4ub(const QColor &c)
{
Color4ub color = { uchar(c.redF() * c.alphaF() * 255),
uchar(c.greenF() * c.alphaF() * 255),
uchar(c.blueF() * c.alphaF() * 255),
uchar(c.alphaF() * 255)
};
return color;
}
struct SmoothVertex
{
float x, y;
Color4ub color;
float dx, dy;
void set(float nx, float ny, Color4ub ncolor, float ndx, float ndy)
{
x = nx; y = ny; color = ncolor;
dx = ndx; dy = ndy;
}
};
const QSGGeometry::AttributeSet &smoothAttributeSet()
{
static QSGGeometry::Attribute data[] = {
QSGGeometry::Attribute::create(0, 2, GL_FLOAT, true),
QSGGeometry::Attribute::create(1, 4, GL_UNSIGNED_BYTE, false),
QSGGeometry::Attribute::create(2, 2, GL_FLOAT, false)
};
static QSGGeometry::AttributeSet attrs = { 3, sizeof(SmoothVertex), data };
return attrs;
}
}
3) Apply custom material and custom geometry to QSGGeometryNode.
myquickitem.cpp
QSGNode *MyQuickItem::updatePaintNode(QSGNode *oldNode, QQuickItem::UpdatePaintNodeData *data)
{
QSGGeometryNode *node = 0;
QSGGeometry *geometry;
QSGSmoothColorMaterial *material;
node = static_cast<QSGGeometryNode *>(oldNode);
if(!node) {
node = new QSGGeometryNode;
geometry = new QSGGeometry(smoothAttributeSet(), 0);
geometry->setDrawingMode(GL_TRIANGLE_STRIP);
material = new QSGSmoothColorMaterial();
node->setGeometry(geometry);
node->setFlag(QSGNode::OwnsGeometry);
node->setMaterial(material);
node->setFlag(QSGNode::OwnsMaterial);
} else {
geometry = node->geometry();
material = static_cast<QSGSmoothColorMaterial *>(node->material());
}
4) Get pointer to vertex data.
int vertexStride = geometry->sizeOfVertex();
int vertexCount = 8;
geometry->allocate(vertexCount, 0);
SmoothVertex *smoothVertices = reinterpret_cast<SmoothVertex *>(geometry->vertexData());
memset(smoothVertices, 0, vertexCount * vertexStride);
5) Set vertex data.
You need 4 points.
float lineWidth = 4;
float tlX = 0; float tlY = 0; //top-left
float blX = 0; float blY = 0 + lineWidth; //bottom-left
float trX = 500; float trY = 100; //top-right
float brX = 500; float brY = 100 + lineWidth; //bottom-right
float delta = lineWidth * 0.5f;
Color4ub fillColor = colorToColor4ub(QColor(255,0,0,255));
Color4ub transparent = { 0, 0, 0, 0 };
To draw antialiased line you should set 8 vertices to draw 6 triangles(2 for line, 4 for antialiasing). Vertices 0 and 2, 1 and 3, 4 and 6, 5 and 7 have the same coordinates, but different color and opposite vertex offset.
smoothVertices[0].set(trX, trY, transparent, delta, -delta);
smoothVertices[1].set(tlX, tlY, transparent, -delta, -delta);
smoothVertices[2].set(trX, trY, fillColor, -delta, delta);
smoothVertices[3].set(tlX, tlY, fillColor, delta, delta);
smoothVertices[4].set(brX, brY, fillColor, -delta, -delta);
smoothVertices[5].set(blX, blY, fillColor, delta, -delta);
smoothVertices[6].set(brX, brY, transparent, delta, delta);
smoothVertices[7].set(blX, blY, transparent, -delta, delta);
node->markDirty(QSGNode::DirtyGeometry);
return node;
}

OpenGL 3.x Assimp trouble implementing phong shading (normals?)

I'm having trouble getting phong shading to look right. I'm pretty sure there's something wrong with either my OpenGL calls, or the way I'm loading my normals, but I guess it could be something else since 3D graphics and Assimp are both still very new to me. When trying to load .obj/.mtl files, the problems I'm seeing are:
The models seem to be lit too intensely (less phong-style and more completely washed out, too bright).
Faces that are lit seem to be lit equally all over (with the exception of a specular highlight showing only when the light source position is moved to be practically right on top of the model)
Because of problems 1 and 2, spheres look very wrong:
picture of sphere
And things with larger faces look (less-noticeably) wrong too:
picture of cube
I could be wrong, but to me this doesn't look like proper phong shading.
Here's the code that I think might be relevant (I can post more if necessary):
file: assimpRenderer.cpp
#include "assimpRenderer.hpp"
namespace def
{
assimpRenderer::assimpRenderer(std::string modelFilename, float modelScale)
{
initSFML();
initOpenGL();
if (assImport(modelFilename)) // if modelFile loaded successfully
{
initScene();
mainLoop(modelScale);
shutdownScene();
}
shutdownOpenGL();
shutdownSFML();
}
assimpRenderer::~assimpRenderer()
{
}
void assimpRenderer::initSFML()
{
windowWidth = 800;
windowHeight = 600;
settings.majorVersion = 3;
settings.minorVersion = 3;
app = NULL;
shader = NULL;
app = new sf::Window(sf::VideoMode(windowWidth,windowHeight,32), "OpenGL 3.x Window", sf::Style::Default, settings);
app->setFramerateLimit(240);
app->setActive();
return;
}
void assimpRenderer::shutdownSFML()
{
delete app;
return;
}
void assimpRenderer::initOpenGL()
{
GLenum err = glewInit();
if (GLEW_OK != err)
{
/* Problem: glewInit failed, something is seriously wrong. */
std::cerr << "Error: " << glewGetErrorString(err) << std::endl;
}
// check the OpenGL context version that's currently in use
int glVersion[2] = {-1, -1};
glGetIntegerv(GL_MAJOR_VERSION, &glVersion[0]); // get the OpenGL Major version
glGetIntegerv(GL_MINOR_VERSION, &glVersion[1]); // get the OpenGL Minor version
std::cout << "Using OpenGL Version: " << glVersion[0] << "." << glVersion[1] << std::endl;
return;
}
void assimpRenderer::shutdownOpenGL()
{
return;
}
void assimpRenderer::initScene()
{
// allocate heap space for VAOs, VBOs, and IBOs
vaoID = new GLuint[scene->mNumMeshes];
vboID = new GLuint[scene->mNumMeshes*2];
iboID = new GLuint[scene->mNumMeshes];
glClearColor(0.4f, 0.6f, 0.9f, 0.0f);
glEnable(GL_DEPTH_TEST);
glDepthFunc(GL_LEQUAL);
glEnable(GL_CULL_FACE);
shader = new Shader("shader.vert", "shader.frag");
projectionMatrix = glm::perspective(60.0f, (float)windowWidth / (float)windowHeight, 0.1f, 100.0f);
rot = 0.0f;
rotSpeed = 50.0f;
faceIndex = 0;
colorArrayA = NULL;
colorArrayD = NULL;
colorArrayS = NULL;
normalArray = NULL;
genVAOs();
return;
}
void assimpRenderer::shutdownScene()
{
delete [] iboID;
delete [] vboID;
delete [] vaoID;
delete shader;
}
void assimpRenderer::renderScene(float modelScale)
{
sf::Time elapsedTime = clock.getElapsedTime();
clock.restart();
if (rot > 360.0f)
rot = 0.0f;
rot += rotSpeed * elapsedTime.asSeconds();
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
viewMatrix = glm::translate(glm::mat4(1.0f), glm::vec3(0.0f, -3.0f, -10.0f)); // move back a bit
modelMatrix = glm::scale(glm::mat4(1.0f), glm::vec3(modelScale)); // scale model
modelMatrix = glm::rotate(modelMatrix, rot, glm::vec3(0, 1, 0));
//modelMatrix = glm::rotate(modelMatrix, 25.0f, glm::vec3(0, 1, 0));
glm::vec3 lightPosition( 0.0f, -100.0f, 0.0f );
float lightPositionArray[3];
lightPositionArray[0] = lightPosition[0];
lightPositionArray[1] = lightPosition[1];
lightPositionArray[2] = lightPosition[2];
shader->bind();
int projectionMatrixLocation = glGetUniformLocation(shader->id(), "projectionMatrix");
int viewMatrixLocation = glGetUniformLocation(shader->id(), "viewMatrix");
int modelMatrixLocation = glGetUniformLocation(shader->id(), "modelMatrix");
int ambientLocation = glGetUniformLocation(shader->id(), "ambientColor");
int diffuseLocation = glGetUniformLocation(shader->id(), "diffuseColor");
int specularLocation = glGetUniformLocation(shader->id(), "specularColor");
int lightPositionLocation = glGetUniformLocation(shader->id(), "lightPosition");
int normalMatrixLocation = glGetUniformLocation(shader->id(), "normalMatrix");
glUniformMatrix4fv(projectionMatrixLocation, 1, GL_FALSE, &projectionMatrix[0][0]);
glUniformMatrix4fv(viewMatrixLocation, 1, GL_FALSE, &viewMatrix[0][0]);
glUniformMatrix4fv(modelMatrixLocation, 1, GL_FALSE, &modelMatrix[0][0]);
glUniform3fv(lightPositionLocation, 1, lightPositionArray);
for (unsigned int i = 0; i < scene->mNumMeshes; i++)
{
colorArrayA = new float[3];
colorArrayD = new float[3];
colorArrayS = new float[3];
material = scene->mMaterials[scene->mNumMaterials-1];
normalArray = new float[scene->mMeshes[i]->mNumVertices * 3];
unsigned int normalIndex = 0;
for (unsigned int j = 0; j < scene->mMeshes[i]->mNumVertices * 3; j+=3, normalIndex++)
{
normalArray[j] = scene->mMeshes[i]->mNormals[normalIndex].x; // x
normalArray[j+1] = scene->mMeshes[i]->mNormals[normalIndex].y; // y
normalArray[j+2] = scene->mMeshes[i]->mNormals[normalIndex].z; // z
}
normalIndex = 0;
glUniformMatrix3fv(normalMatrixLocation, 1, GL_FALSE, normalArray);
aiColor3D ambient(0.0f, 0.0f, 0.0f);
material->Get(AI_MATKEY_COLOR_AMBIENT, ambient);
aiColor3D diffuse(0.0f, 0.0f, 0.0f);
material->Get(AI_MATKEY_COLOR_DIFFUSE, diffuse);
aiColor3D specular(0.0f, 0.0f, 0.0f);
material->Get(AI_MATKEY_COLOR_SPECULAR, specular);
colorArrayA[0] = ambient.r; colorArrayA[1] = ambient.g; colorArrayA[2] = ambient.b;
colorArrayD[0] = diffuse.r; colorArrayD[1] = diffuse.g; colorArrayD[2] = diffuse.b;
colorArrayS[0] = specular.r; colorArrayS[1] = specular.g; colorArrayS[2] = specular.b;
// bind color for each mesh
glUniform3fv(ambientLocation, 1, colorArrayA);
glUniform3fv(diffuseLocation, 1, colorArrayD);
glUniform3fv(specularLocation, 1, colorArrayS);
// render all meshes
glBindVertexArray(vaoID[i]); // bind our VAO
glDrawElements(GL_TRIANGLES, scene->mMeshes[i]->mNumFaces*3, GL_UNSIGNED_INT, 0);
glBindVertexArray(0); // unbind our VAO
delete [] normalArray;
delete [] colorArrayA;
delete [] colorArrayD;
delete [] colorArrayS;
}
shader->unbind();
app->display();
return;
}
void assimpRenderer::handleEvents()
{
sf::Event event;
while (app->pollEvent(event))
{
if (event.type == sf::Event::Closed)
{
app->close();
}
if ((event.type == sf::Event::KeyPressed) && (event.key.code == sf::Keyboard::Escape))
{
app->close();
}
if (event.type == sf::Event::Resized)
{
glViewport(0, 0, event.size.width, event.size.height);
}
}
return;
}
void assimpRenderer::mainLoop(float modelScale)
{
while (app->isOpen())
{
renderScene(modelScale);
handleEvents();
}
}
bool assimpRenderer::assImport(const std::string& pFile)
{
// read the file with some example postprocessing
scene = importer.ReadFile(pFile,
aiProcess_CalcTangentSpace |
aiProcess_Triangulate |
aiProcess_JoinIdenticalVertices |
aiProcess_SortByPType);
// if the import failed, report it
if (!scene)
{
std::cerr << "Error: " << importer.GetErrorString() << std::endl;
return false;
}
return true;
}
void assimpRenderer::genVAOs()
{
int vboIndex = 0;
for (unsigned int i = 0; i < scene->mNumMeshes; i++, vboIndex+=2)
{
mesh = scene->mMeshes[i];
indexArray = new unsigned int[mesh->mNumFaces * sizeof(unsigned int) * 3];
// convert assimp faces format to array
faceIndex = 0;
for (unsigned int t = 0; t < mesh->mNumFaces; ++t)
{
const struct aiFace* face = &mesh->mFaces[t];
std::memcpy(&indexArray[faceIndex], face->mIndices, sizeof(float) * 3);
faceIndex += 3;
}
// generate VAO
glGenVertexArrays(1, &vaoID[i]);
glBindVertexArray(vaoID[i]);
// generate IBO for faces
glGenBuffers(1, &iboID[i]);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, iboID[i]);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(GLuint) * mesh->mNumFaces * 3, indexArray, GL_STATIC_DRAW);
// generate VBO for vertices
if (mesh->HasPositions())
{
glGenBuffers(1, &vboID[vboIndex]);
glBindBuffer(GL_ARRAY_BUFFER, vboID[vboIndex]);
glBufferData(GL_ARRAY_BUFFER, mesh->mNumVertices * sizeof(GLfloat) * 3, mesh->mVertices, GL_STATIC_DRAW);
glEnableVertexAttribArray((GLuint)0);
glVertexAttribPointer((GLuint)0, 3, GL_FLOAT, GL_FALSE, 0, 0);
}
// generate VBO for normals
if (mesh->HasNormals())
{
normalArray = new float[scene->mMeshes[i]->mNumVertices * 3];
unsigned int normalIndex = 0;
for (unsigned int j = 0; j < scene->mMeshes[i]->mNumVertices * 3; j+=3, normalIndex++)
{
normalArray[j] = scene->mMeshes[i]->mNormals[normalIndex].x; // x
normalArray[j+1] = scene->mMeshes[i]->mNormals[normalIndex].y; // y
normalArray[j+2] = scene->mMeshes[i]->mNormals[normalIndex].z; // z
}
normalIndex = 0;
glGenBuffers(1, &vboID[vboIndex+1]);
glBindBuffer(GL_ARRAY_BUFFER, vboID[vboIndex+1]);
glBufferData(GL_ARRAY_BUFFER, mesh->mNumVertices * sizeof(GLfloat) * 3, normalArray, GL_STATIC_DRAW);
glEnableVertexAttribArray((GLuint)1);
glVertexAttribPointer((GLuint)1, 3, GL_FLOAT, GL_FALSE, 0, 0);
delete [] normalArray;
}
// tex coord stuff goes here
// unbind buffers
glBindVertexArray(0);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
delete [] indexArray;
}
vboIndex = 0;
return;
}
}
file: shader.vert
#version 150 core
in vec3 in_Position;
in vec3 in_Normal;
uniform mat4 projectionMatrix;
uniform mat4 viewMatrix;
uniform mat4 modelMatrix;
uniform vec3 lightPosition;
uniform mat3 normalMatrix;
smooth out vec3 vVaryingNormal;
smooth out vec3 vVaryingLightDir;
void main()
{
// derive MVP and MV matrices
mat4 modelViewProjectionMatrix = projectionMatrix * viewMatrix * modelMatrix;
mat4 modelViewMatrix = viewMatrix * modelMatrix;
// get surface normal in eye coordinates
vVaryingNormal = normalMatrix * in_Normal;
// get vertex position in eye coordinates
vec4 vPosition4 = modelViewMatrix * vec4(in_Position, 1.0);
vec3 vPosition3 = vPosition4.xyz / vPosition4.w;
// get vector to light source
vVaryingLightDir = normalize(lightPosition - vPosition3);
// Set the position of the current vertex
gl_Position = modelViewProjectionMatrix * vec4(in_Position, 1.0);
}
file: shader.frag
#version 150 core
out vec4 out_Color;
uniform vec3 ambientColor;
uniform vec3 diffuseColor;
uniform vec3 specularColor;
smooth in vec3 vVaryingNormal;
smooth in vec3 vVaryingLightDir;
void main()
{
// dot product gives us diffuse intensity
float diff = max(0.0, dot(normalize(vVaryingNormal), normalize(vVaryingLightDir)));
// multiply intensity by diffuse color, force alpha to 1.0
out_Color = vec4(diff * diffuseColor, 1.0);
// add in ambient light
out_Color += vec4(ambientColor, 1.0);
// specular light
vec3 vReflection = normalize(reflect(-normalize(vVaryingLightDir), normalize(vVaryingNormal)));
float spec = max(0.0, dot(normalize(vVaryingNormal), vReflection));
if (diff != 0)
{
float fSpec = pow(spec, 128.0);
// Set the output color of our current pixel
out_Color.rgb += vec3(fSpec, fSpec, fSpec);
}
}
I know it's a lot to look through, but I'm putting most of the code up so as not to assume where the problem is.
Are you doing the right thing for the normal matrix? This looks quite bizarre to me.
for (unsigned int j = 0; j < scene->mMeshes[i]->mNumVertices * 3; j+=3, normalIndex++)
{
normalArray[j] = scene->mMeshes[i]->mNormals[normalIndex].x; // x
normalArray[j+1] = scene->mMeshes[i]->mNormals[normalIndex].y; // y
normalArray[j+2] = scene->mMeshes[i]->mNormals[normalIndex].z; // z
}
glUniformMatrix3fv(normalMatrixLocation, 1, GL_FALSE, normalArray);
Why does the normalMatrix have anything to do with the vertices of the mesh? It should be identical to your modelMatrix (provided that you're not doing any non-uniform scaling).