When I create a checkerboard texture on a sphere using UV mapping, I get a seam. I know there are a couple question about this, but I haven't found an answer involving a .frag file.
Here is the UV transformation in my main.cpp file:
void Update_Uv_Using_Spherical_Coordinates(const std::vector<Vector3>& vertices,std::vector<Vector2>& uv)
{
uv.clear();
/*Your implementation starts*/
Vector3 center = Vector3(0., 0., 0.);
for (int i = 0; i < vertices.size(); i++) {
float x = vertices[i][0];
float y = vertices[i][1];
float z = vertices[i][2];
float lon = atan2(y, x);
float lat = atan2(z, sqrt(x*x+y*y));
float u = (lon + M_PI)/(2*M_PI);
float v = (log(tan(lat/2 + M_PI/4)) + M_PI)/(2*M_PI);
uv.push_back(Vector2(u,v));
}
}
Here is my .frag file:
layout (std140) uniform camera
{
mat4 projection; /*camera's projection matrix*/
mat4 view; /*camera's view matrix*/
mat4 pvm; /*camera's projection*view*model matrix*/
mat4 ortho; /*camera's ortho projection matrix*/
vec4 position; /*camera's position in world space*/
};
in vec3 vtx_pos;
in vec4 vtx_color;
in vec3 vtx_nml;
in vec2 vtx_uv;
/*output variables*/
out vec4 frag_color;
void main()
{
vec3 col = vec3(1.0);
int numCheckers = 8;
int checkerNumber = int(floor(vtx_uv.x * numCheckers));
checkerNumber += int(floor(vtx_uv.y * numCheckers));
if (mod(checkerNumber,2) == 0) col = col * 0;
frag_color = vec4(col, 1.0);
}
I think there is something wrong with when I wrap around between UV being 0 and 1, but I'm not sure how I could assign 2 uvs in my .frag or .cpp file.
Related
I'm rendering a sphere with instanced drawing, while rotating the model-view-matrix around the Y axis.
It looks ok at the beginning:
But at another angle, things get worse:
It looks to me like a problem with normals. Currently, I'm calculating the normal-matrix from my model-view-matrix and then pass it to the shader, which is doing phong-like lighting:
attribute vec4 a_position;
attribute vec3 a_normal;
attribute vec4 a_color;
attribute vec2 a_coord;
attribute mat4 a_matrix;
uniform mat4 u_mv_matrix;
uniform mat4 u_projection_matrix;
uniform mat3 u_normal_matrix;
varying vec4 v_position;
varying vec3 v_normal;
varying vec4 v_color;
varying vec2 v_coord;
void main() {
vec4 transformedPosition = u_mv_matrix * a_matrix * a_position;
v_position = transformedPosition;
v_normal = u_normal_matrix * a_normal;
v_color = a_color;
v_coord = a_coord;
gl_Position = u_projection_matrix * transformedPosition;
}
uniform sampler2D u_sampler;
varying vec4 v_position;
varying vec3 v_normal;
varying vec4 v_color;
varying vec2 v_coord;
void main() {
vec3 lightPosition = vec3(0.0); // XXX
// set diffuse and specular colors
vec3 cDiffuse = (v_color * texture2D(u_sampler, v_coord)).rgb;
vec3 cSpecular = vec3(0.3);
// lighting calculations
vec3 N = normalize(v_normal);
vec3 L = normalize(lightPosition - v_position.xyz);
vec3 E = normalize(-v_position.xyz);
vec3 H = normalize(L + E);
// Calculate coefficients.
float phong = max(dot(N, L), 0.0);
const float kMaterialShininess = 20.0;
const float kNormalization = (kMaterialShininess + 8.0) / (3.14159265 * 8.0);
float blinn = pow(max(dot(N, H), 0.0), kMaterialShininess) * kNormalization;
// diffuse coefficient
vec3 diffuse = phong * cDiffuse;
// specular coefficient
vec3 specular = blinn * cSpecular;
gl_FragColor = vec4(diffuse + specular, 1);
}
Final note: I'm working on desktop OpenGL 2.1 as well as WebGL on the browser.
Edit: Per request, I'm adding some information.
The mesh is built as follows, by passing an identity matrix:
void Sphere::append(IndexedVertexBatch<XYZ.N.UV> &batch, const Matrix &matrix) const {
float sectorStep = TWO_PI / sectorCount;
float stackStep = PI / stackCount;
for(int i = 0; i <= stackCount; ++i) {
float stackAngle = HALF_PI - i * stackStep;
float xy = radius * cosf(stackAngle);
float z = radius * sinf(stackAngle);
for(int j = 0; j <= sectorCount; ++j) {
float sectorAngle = j * sectorStep;
float x = xy * cosf(sectorAngle);
float y = xy * sinf(sectorAngle);
float nx = x / radius;
float ny = y / radius;
float nz = z / radius;
float s = (float)j / sectorCount;
float t = (float)i / stackCount;
batch.addVertex(matrix.transformPoint(x, y, z), matrix.transformNormal(nx, ny, nz), glm::vec2(s, t));
}
}
for(int i = 0; i < stackCount; ++i) {
float k1 = i * (sectorCount + 1);
float k2 = k1 + sectorCount + 1;
for(int j = 0; j < sectorCount; ++j, ++k1, ++k2) {
if (i != 0) {
if (frontFace == CCW) {
batch.addIndices(k1, k1 + 1, k2);
} else {
batch.addIndices(k1, k2, k1 + 1);
}
}
if (i != (stackCount - 1)) {
if (frontFace == CCW) {
batch.addIndices(k1 + 1, k2 + 1, k2);
} else {
batch.addIndices(k1 + 1, k2, k2 + 1);
}
}
}
}
}
Regarding the transformation matrices, it works as follow:
camera.getMVMatrix()
.setIdentity()
.translate(0, -150, -600)
.rotateY(clock()->getTime() * 0.5f);
State()
.setShader(shader)
.setShaderMatrix<MV>(camera.getMVMatrix())
.setShaderMatrix<PROJECTION>(camera.getProjectionMatrix())
.setShaderMatrix<NORMAL>(camera.getNormalMatrix())
.apply();
Finally, the light position is defined as vec3(0) in the fragment shader.
Note: As you can see, I'm using my own framework which provides among other things high level methods for building meshes and handling transformations. It's all straightforward stuff, proven to work as intended, but let me know if you need pointers to the source-code.
Update: The lighting part of the shader I used ended up being wrong, so I switched to another method.
But in essence, the solution I proposed in my answer is still valid (or at least it does the job of solving the "normal problem" when instancing is used, and non-uniform scaling is avoided.)
Here is a gist with the source-code. There is also an online WebGL demo.
The solution was relatively simple: there is no point in passing a normal-matrix to the shader.
Instead, the normal needs to be computed in the vertex shader:
v_normal = vec3(u_mv_matrix * a_matrix * vec4(a_normal, 0.0));
Credits
Most of the shader codes are follow the instruction of LearnOpenGL. I could make sure that the g-buffer and noise data pass into the shader are correct. It seems like some kind of dislocation, but But I really can't figure out why this happened.
misplace ssao
#version 450 core
out float OUT_FragColor;
in vec2 TexCoords;
uniform sampler2D g_position;
uniform sampler2D g_normal;
uniform sampler2D noise_texture;
struct CameraInfo
{
vec4 position;
mat4 view;
mat4 projection;
};
layout(std140, binding = 0) uniform Camera
{
CameraInfo camera;
};
float radius = 0.5;
float bias = 0.025;
uniform int noise_tex_size;
void main()
{
const vec2 noise_scale = vec2(1280.0/noise_tex_size, 720.0/noise_tex_size);
vec3 frag_pos = texture(g_position, TexCoords).xyz;
vec3 normal = normalize(texture(g_normal, TexCoords).xyz);
vec3 random_vec = normalize(texture(noise_texture, TexCoords * noise_scale).xyz);
vec3 tangent = normalize(random_vec - normal * dot(random_vec, normal));
vec3 bitangent = cross(normal, tangent);
mat3 TBN = mat3(tangent, bitangent, normal);
float occlusion = 0.f;
for(int i = 0; i < sample_array.length(); ++i)
{
vec3 sample_pos = TBN * sample_array[i].xyz;
sample_pos = frag_pos + sample_pos * radius;
vec4 offset = vec4(sample_pos, 1.0);
offset = camera.projection * offset; // from view to clip-space
offset.xyz /= offset.w; // perspective divide ?????
offset.xyz = offset.xyz * 0.5 + 0.5; // transform to range 0.0 - 1.0
float sample_depth = texture(g_position, offset.xy).z;
float range_check = smoothstep(0.f, 1.f, radius / abs(frag_pos.z - sample_depth));
occlusion += (sample_depth >= sample_pos.z + bias ? 1.0 : 0.0) * range_check; //ignore sample points that too near the origin point
}
occlusion = 1.f - (occlusion / sample_array.length());
OUT_FragColor = occlusion;
}
transform the g_postion and g_normal into model space
FragPos = (camera.view * vec4(WorldPos, 1.0)).xyz;
mat4 normal_matrix = camera.view * mat4(transpose(inverse(mat3(model))));
FragNormal = mat3(normal_matrix) * normal;
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);
I decided to follow the classic guide for writing a basic GLSL water shaders using the sum of sines method. I attempted to implement it inside of Processing 5, where I made a field of vertices in a PShape to make a mesh to mess with. I then overwrote the default shaders with my own vertex and fragment shaders, and I dropped in a directional light so I can actually see the normals. I made sure the directional light was movable as well so I could see if the normals work from all angles.
I got the waves to form height correctly and I had some form of normals workings, but the normals are interacting really strange. When my light passes across the center axis of my water plane, the normals seem to morph between the different waves and change based on the light angle. The gif I captured was too large to post in line, so I'm sure seeing it would explain better than my words:
https://imgur.com/PCznL7U
You should maximize the link to see the whole picture. Note how as the light pans from left to right, the normals of the waves seem to morph between two sets? This is especially apparent as it crosses center. It's like the normals are inconsistent based on the direction the object is being lit from.
The sphere in the middle is a normal sphere using the standard Processing shader. I left it there as reference to see the waves as well as confirm where my lighting was and that it was working fine.
Any ideas what I did wrong? I know I did some math incorrectly somewhere.
EDIT: Was recommended I added the (lengthy) source code [which I should have done from the start].
Vertex Shader:
#define PROCESSING_LIGHT_SHADER
#define MAXWAVES 6
const float pi = 3.14159;
uniform mat4 transform;
uniform mat4 modelview;
uniform mat3 normalMatrix;
uniform float time; //Time since shader started
attribute vec4 position; //Position the vertex from Processing
attribute vec4 color; //Color of the vertex from Processing
attribute vec3 normal; //Normal of the vertex from Processing
attribute vec4 ambient;
attribute vec4 specular;
attribute vec4 emissive;
attribute float shininess;
varying vec4 vertColor; //Color passed on to fragment shader
varying vec4 backVertColor; //Color passed on to fragment shader
uniform float waveLength[MAXWAVES]; //Length of wave
uniform float speed[MAXWAVES]; //Cycle speed of wave
uniform float amplitude[MAXWAVES]; //Wave cycle height
uniform float xDirection[MAXWAVES];
uniform float yDirection[MAXWAVES]; //Flow vector of wave
uniform int lightCount;
uniform vec4 lightPosition[8];
uniform vec3 lightNormal[8];
uniform vec3 lightAmbient[8];
uniform vec3 lightDiffuse[8];
uniform vec3 lightSpecular[8];
uniform vec3 lightFalloff[8];
uniform vec2 lightSpot[8];
varying vec3 Normal;
varying vec3 FragPos;
varying vec3 Vec;
varying vec3 lightDir;
//Some constants that the processing shader used
const float zero_float = 0.0;
const float one_float = 1.0;
const vec3 zero_vec3 = vec3(0);
float falloffFactor(vec3 lightPos, vec3 vertPos, vec3 coeff) {
vec3 lpv = lightPos - vertPos;
vec3 dist = vec3(one_float);
dist.z = dot(lpv, lpv);
dist.y = sqrt(dist.z);
return one_float / dot(dist, coeff);
}
float spotFactor(vec3 lightPos, vec3 vertPos, vec3 lightNorm, float minCos, float spotExp) {
vec3 lpv = normalize(lightPos - vertPos);
vec3 nln = -one_float * lightNorm;
float spotCos = dot(nln, lpv);
return spotCos <= minCos ? zero_float : pow(spotCos, spotExp);
}
float lambertFactor(vec3 lightDir, vec3 vecNormal) {
return max(zero_float, dot(lightDir, vecNormal));
}
float blinnPhongFactor(vec3 lightDir, vec3 vertPos, vec3 vecNormal, float shine) {
vec3 np = normalize(vertPos);
vec3 ldp = normalize(lightDir - np);
return pow(max(zero_float, dot(ldp, vecNormal)), shine);
}
//Returns the height of a vertex given a single wave param
float WaveHeight(int waveNumber, float x, float y) {
vec2 direction = (vec2(xDirection[waveNumber], yDirection[waveNumber]));
float frequency = 2.0*pi/waveLength[waveNumber];
float phase = speed[waveNumber] * frequency;
float theta = dot(direction, vec2(x, y));
return amplitude[waveNumber] * sin(theta * frequency + time * phase);
}
//Returns height of a vertex given all the active waves
// and its current x/y value
float WaveSum(float x, float y)
{
float height = 0.0;
for(int i = 0; i < MAXWAVES; i++)
{
height += WaveHeight(i, x, y);
}
return height;
}
float getDy(int waveNumber, float x, float y) {
vec2 direction = (vec2(xDirection[waveNumber], yDirection[waveNumber]));
float frequency = 2.0*pi/waveLength[waveNumber];
float phase = speed[waveNumber] * frequency;
float theta = dot(direction, vec2(x, y));
float A = amplitude[waveNumber] * direction.y * frequency;
return A * cos(theta * frequency + time * phase);
}
float getDx(int waveNumber, float x, float y) {
vec2 direction = (vec2(xDirection[waveNumber], yDirection[waveNumber]));
float frequency = 2.0*pi/waveLength[waveNumber];
float phase = speed[waveNumber] * frequency;
float theta = dot(direction, vec2(x, y));
float A = amplitude[waveNumber] * direction.x * frequency;
return A * cos(theta * frequency + time * phase);
}
//Returns the normal vector for each vertex
vec3 getNormal(float x, float y) {
float dx = 0.0;
float dy = 0.0;
//Sum for each wave
for (int i = 0; i < MAXWAVES; i++) {
dx += getDx(i, x, y);
dy += getDy(i, x, y);
}
vec3 n = vec3(-dx, -dy, 1.0);
return normalize(n);
}
void main() {
vec4 pos = position; //Grab the position from Processing bc it's read only
pos.z = WaveSum(pos.x, pos.y);
gl_Position = transform * pos; //Get clipping matrix for view
vec3 ecVertex = vec3(modelview * pos);
// Normal vector in eye coordinates
vec3 Normal = getNormal(pos.x, pos.y);
vec3 ecNormal = normalize(normalMatrix * Normal);
vec3 ecNormalInv = ecNormal * -one_float;
// Light calculations
vec3 totalAmbient = vec3(0, 0, 0);
vec3 totalFrontDiffuse = vec3(0, 0, 0);
vec3 totalFrontSpecular = vec3(0, 0, 0);
vec3 totalBackDiffuse = vec3(0, 0, 0);
vec3 totalBackSpecular = vec3(0, 0, 0);
for (int i = 0; i < 8; i++) {
if (lightCount == i) break;
vec3 lightPos = lightPosition[i].xyz;
bool isDir = lightPosition[i].w < one_float;
float spotCos = lightSpot[i].x;
float spotExp = lightSpot[i].y;
vec3 lightDir;
float falloff;
float spotf;
if (isDir) {
falloff = one_float;
lightDir = -one_float * lightNormal[i];
} else {
falloff = falloffFactor(lightPos, ecVertex, lightFalloff[i]);
lightDir = normalize(lightPos - ecVertex);
}
spotf = spotExp > zero_float ? spotFactor(lightPos, ecVertex, lightNormal[i],
spotCos, spotExp)
: one_float;
if (any(greaterThan(lightAmbient[i], zero_vec3))) {
totalAmbient += lightAmbient[i] * falloff;
}
if (any(greaterThan(lightDiffuse[i], zero_vec3))) {
totalFrontDiffuse += lightDiffuse[i] * falloff * spotf *
lambertFactor(lightDir, ecNormal);
totalBackDiffuse += lightDiffuse[i] * falloff * spotf *
lambertFactor(lightDir, ecNormalInv);
}
if (any(greaterThan(lightSpecular[i], zero_vec3))) {
totalFrontSpecular += lightSpecular[i] * falloff * spotf *
blinnPhongFactor(lightDir, ecVertex, ecNormal, shininess);
totalBackSpecular += lightSpecular[i] * falloff * spotf *
blinnPhongFactor(lightDir, ecVertex, ecNormalInv, shininess);
}
}
// Calculating final color as result of all lights (plus emissive term).
// Transparency is determined exclusively by the diffuse component.
vertColor =
vec4(totalFrontDiffuse, 1) * color;
backVertColor =
vec4(totalBackDiffuse, 1) * color;
}
Fragment Shader:
#ifdef GL_ES
precision mediump float;
precision mediump int;
#endif
varying vec4 vertColor; //Color from vertshader
varying vec4 backVertColor; //Color from vertshader
void main() {
gl_FragColor = gl_FrontFacing ? vertColor : backVertColor;
}
My code for creating my grid is:
// Per-vertex position vectors
static float planeVertices[16] =
{
0,1,0,1,
0,0,0,1,
1,1,0,1,
1,0,0,1
};
// 12 faces each with 3 vertices (each face forms a triangle) (36 indices total)
static unsigned short planeVertexIndices[4] =
{
0,1,2,3
};
drawPlane:
void drawPlane(float x, float y, float z){
glUseProgram(planeShader);
glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
// Setup simple translation (model) matrix and pass to shader
GUMatrix4 planeModelTransform = GUMatrix4::translationMatrix(x, y, z);
static GLint planeShader_modelMatrixLocation = glGetUniformLocation(planeShader, "modelMatrix");
glUniformMatrix4fv(planeShader_modelMatrixLocation, 1, GL_FALSE, (const GLfloat*)&planeModelTransform);
glBindVertexArray(planeVAO);
glDrawElements(GL_TRIANGLE_STRIP, 4, GL_UNSIGNED_SHORT, (const GLvoid*)1);
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
//glBindVertexArray(0);
}
How its drawn in update:
int gridSize = 100;
float x = 0.0f;
float y = 0.0f;
float z = 0.0f;
for (float x = -gridSize/2; x < gridSize/2; x++){
for (float y = -gridSize/2; y < gridSize/2; y++){
drawPlane(x, y, z);
}
}
The grid draws fine, but none of its connected as I want the grid to wave, when I make it wave you can see the triangles are all separate.
My vertex shader:
#version 330
uniform float waveTime;
uniform float waveWidth;
uniform float waveHeight;
// UBO to store the camera projection and view matrices
uniform CameraMatrixBlock {
mat4 viewMatrix;
mat4 projectionMatrix;
} cam;
uniform mat4 modelMatrix;
layout (location=0) in vec4 vertexPos;
layout (location=1) in vec4 vertexColour;
out vec4 vp;
out vec4 colour;
void main(void) {
colour = vertexColour;
vec4 vp = vertexPos;
mat4 P = cam.projectionMatrix;
mat4 V = cam.viewMatrix;
mat4 mvpMatrix = P * V * modelMatrix;
vp.z = sin(waveWidth * vp.x + waveTime) * cos(waveWidth * vp.y + waveTime) * waveHeight;
gl_Position = mvpMatrix * vp;
}
What the result I get from all this:
The results