Skip to content

Instantly share code, notes, and snippets.

@arielm
Last active November 25, 2021 12:54
Show Gist options
  • Save arielm/64c6987deae758c267c522761b177c5e to your computer and use it in GitHub Desktop.
Save arielm/64c6987deae758c267c522761b177c5e to your computer and use it in GitHub Desktop.
Testing OpenGL 2.1 / WebGL1 instancing with lighting
#ifdef GL_ES
precision highp float;
#endif
uniform sampler2D u_sampler;
uniform float u_shininess;
varying vec3 v_normal;
varying vec4 v_color;
varying vec2 v_coord;
varying vec3 v_surface_to_light;
varying vec3 v_surface_to_view;
void main() {
vec3 normal = normalize(v_normal);
vec3 surfaceToLightDirection = normalize(v_surface_to_light);
vec3 surfaceToViewDirection = normalize(v_surface_to_view);
vec3 halfVector = normalize(surfaceToLightDirection + surfaceToViewDirection);
float specular = 0.0;
float light = dot(normal, surfaceToLightDirection);
if (light > 0.0) {
specular = pow(dot(normal, halfVector), u_shininess);
}
vec4 color = v_color * texture2D(u_sampler, v_coord);
gl_FragColor = vec4(color.rgb * light + specular, 1.0);
}
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 vec3 u_eye_position;
uniform vec3 u_light_position;
varying vec3 v_normal;
varying vec4 v_color;
varying vec2 v_coord;
varying vec3 v_surface_to_light;
varying vec3 v_surface_to_view;
void main() {
mat4 matrix = u_mv_matrix * a_matrix;
v_normal = vec3(matrix * vec4(a_normal, 0.0)); // XXX
v_color = a_color;
v_coord = a_coord;
v_surface_to_light = (u_mv_matrix * (vec4(u_light_position, 1.0) - a_position)).xyz;
v_surface_to_view = (u_mv_matrix * (vec4(u_eye_position, 1.0) - a_position)).xyz;
gl_Position = u_projection_matrix * matrix * a_position;
}
#include "Sketch.h"
#include "chr/gl/draw/Sphere.h"
using namespace std;
using namespace chr;
using namespace gl;
using namespace draw;
static constexpr float R1 = 250;
static constexpr float R2 = 150;
static constexpr float TURNS = 6;
static constexpr float H = 350;
Sketch::Sketch()
:
shader(InputSource::resource("Shader.vert"), InputSource::resource("Shader.frag"))
{}
void Sketch::setup()
{
texture = createCheckerTexture();
batch
.setShader(shader)
.setShaderColor(0.25f, 1.0f, 0.0f, 1)
.setTexture(texture);
Sphere()
.setFrontFace(CW)
.setSectorCount(40)
.setStackCount(20)
.setRadius(25)
.append(batch, Matrix());
instanceBuffer = InstanceBuffer(GL_STATIC_DRAW, GL_STATIC_DRAW);
threadHelix(instanceBuffer, R1, R2, TURNS, H, 0, 50);
// ---
lightBatch
.setShader(colorShader)
.setShaderColor(1, 1, 1, 1);
// ---
glEnable(GL_CULL_FACE);
glEnable(GL_DEPTH_TEST);
glDepthMask(GL_TRUE);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
}
void Sketch::resize()
{
camera
.setFov(60)
.setClip(0.1f, 1000.0f)
.setWindowSize(windowInfo.size);
}
void Sketch::draw()
{
glClearColor(0.5f, 0.5f, 0.5f, 1);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
// ---
camera.getMVMatrix()
.setIdentity()
.translate(0, -150, -600)
.rotateY(clock()->getTime() * 0.125f);
//
float t = clock()->getTime() * 1;
float radius = 300;
float x = cosf(t) * radius;
float y = 150;
float z = sinf(t) * radius;
glm::vec3 lightPosition(x, y, z);
//
State()
.setShaderMatrix<MVP>(camera.getModelViewProjectionMatrix())
.apply();
lightBatch.clear();
Sphere()
.setFrontFace(CW)
.setSectorCount(16)
.setStackCount(8)
.setRadius(4)
.append(lightBatch, Matrix().setTranslate(lightPosition));
lightBatch.flush();
//
State()
.setShaderMatrix<MV>(camera.getMVMatrix())
.setShaderMatrix<PROJECTION>(camera.getProjectionMatrix())
.setShaderUniform("u_eye_position", camera.getEyePosition())
.setShaderUniform("u_light_position", lightPosition)
.setShaderUniform("u_shininess", 50.0f)
.apply();
batch.flush(instanceBuffer);
}
void Sketch::threadHelix(InstanceBuffer &instanceBuffer, float r1, float r2, float turns, float h, float D, float spacing)
{
float l = TWO_PI * turns;
float L = PI * turns * (r1 + r2);
float dz = h / l;
float ay = -atan2f(h, L);
float r;
float dr;
bool conical = (fabsf(r1 - r2) > 0.00001f); // AVOIDS INFINITY AND DIVISIONS-BY-ZERO WITH CYLINDRICAL HELICES (r1 = r2)
if (conical)
{
dr = (r2 - r1) / l;
}
else
{
r = r1;
}
float d;
float half = spacing * 0.5f;
Matrix matrix;
do
{
D += half;
if (conical)
{
r = sqrtf(r1 * r1 + 2 * dr * D);
d = (r - r1) / dr;
}
else
{
d = D / r;
}
matrix
.setTranslate(-cosf(-d) * r, d * dz, +sinf(-d) * r)
.rotateY(HALF_PI - d)
.rotateZ(ay);
instanceBuffer.addMatrix(matrix);
D += half;
}
while (D < L);
}
Texture Sketch::createCheckerTexture()
{
vector<uint8_t> checker = {
0xFF, 0xCC, 0xFF, 0xCC, 0xFF, 0xCC, 0xFF, 0xCC,
0xCC, 0xFF, 0xCC, 0xFF, 0xCC, 0xFF, 0xCC, 0xFF,
0xFF, 0xCC, 0xFF, 0xCC, 0xFF, 0xCC, 0xFF, 0xCC,
0xCC, 0xFF, 0xCC, 0xFF, 0xCC, 0xFF, 0xCC, 0xFF,
0xFF, 0xCC, 0xFF, 0xCC, 0xFF, 0xCC, 0xFF, 0xCC,
0xCC, 0xFF, 0xCC, 0xFF, 0xCC, 0xFF, 0xCC, 0xFF,
0xFF, 0xCC, 0xFF, 0xCC, 0xFF, 0xCC, 0xFF, 0xCC,
0xCC, 0xFF, 0xCC, 0xFF, 0xCC, 0xFF, 0xCC, 0xFF,
};
GLuint textureId;
glGenTextures(1, &textureId);
glBindTexture(GL_TEXTURE_2D, textureId);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, 8, 8, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, checker.data());
return Texture(textureId, 8, 8, GL_LUMINANCE);
}
#pragma once
#include "chr/cross/Context.h"
#include "chr/gl/Batch.h"
#include "chr/gl/ShaderProgram.h"
#include "chr/gl/shaders/ColorShader.h"
#include "chr/gl/Camera.h"
class Sketch : public chr::CrossSketch
{
public:
Sketch();
virtual ~Sketch() {}
void setup() final;
void resize() final;
void draw() final;
protected:
chr::gl::Camera camera;
chr::gl::ShaderProgram shader;
chr::gl::IndexedVertexBatch<chr::gl::XYZ.N.UV> batch;
chr::gl::InstanceBuffer instanceBuffer;
chr::gl::Texture texture;
chr::gl::shaders::ColorShader colorShader;
chr::gl::IndexedVertexBatch<chr::gl::XYZ.N> lightBatch;
static void threadHelix(chr::gl::InstanceBuffer &instanceBuffer, float r1, float r2, float turns, float h, float D, float spacing);
static chr::gl::Texture createCheckerTexture();
};
@arielm
Copy link
Author

arielm commented Nov 24, 2021

Some context:

  1. Online demo (WebGL)
  2. Made with the chronotext-cross framework
  3. Stack Overflow question

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment