I'm interested in learning how to write toon shaders in OpenGL Shading Language. I found a demo, but haven't been able to get the demo running on my computer. The trouble I'm having is with writing an application which will use this shader. Could somebody please show me how to write a simple application which would use this shader? I'm using GLSL 1.2 (OpenGL 2.1) on Linux.
Here is the main sketch:
/*
* Use keys 1 - 8 to play with different GLUT Solids
* mouse affects light position
* Toon Shader by Philip Rideout:
* http://www.lighthouse3d.com/opengl/glsl/index.php?toon2
*/
import processing.opengl.*;
import javax.media.opengl.*;
import javax.media.opengl.glu.*;
import com.sun.opengl.util.*;
PGraphicsOpenGL pgl;
GL gl;
GLSL toon;
GLU glu;
GLUT glut;
boolean glInit;
int glutSolidIndex = 7;
void setup()
{
size(600, 500, OPENGL);
glu = new GLU();
glut = new GLUT();
pgl = (PGraphicsOpenGL) g;
gl = pgl.gl;
}
void draw()
{
background(0);
PGraphicsOpenGL pgl = (PGraphicsOpenGL) g;
GL gl = pgl.beginGL();
if(!glInit){
toon=new GLSL();
toon.loadVertexShader("toon.vs");
toon.loadFragmentShader("toon.fs");
toon.useShaders();
glInit = true;
}
gl.glClear(gl.GL_COLOR_BUFFER_BIT | gl.GL_DEPTH_BUFFER_BIT);
//TRS
gl.glTranslatef(width * .5, height * .5,0.0f);
gl.glRotatef(160,1,0,0);
gl.glRotatef(frameCount * .5,0,1,0);
gl.glRotatef(frameCount * .5,0,0,1);
gl.glScalef(80,80,80);
// draw
toon.startShader();
toon.uniform3f(toon.getUniformLocation("LightPosition"), mouseX-width*.5, -(mouseY-height*.5), 20.0f);
gl.glColor3f(1.0f, 0.5f, 0.0f);
glutSolid();
toon.endShader();
pgl.endGL();
}
void glutSolid(){
switch(glutSolidIndex){
case 0:
glut.glutSolidCube(1);
break;
case 1:
glut.glutSolidTetrahedron();
break;
case 2:
glut.glutSolidOctahedron();
break;
case 3:
glut.glutSolidDodecahedron();
break;
case 4:
glut.glutSolidIcosahedron();
break;
case 5:
glut.glutSolidSphere(1,16,8);
break;
case 6:
glut.glutSolidTorus(.5,1,32,24);
break;
case 7:
glut.glutSolidTeapot(1);
break;
}
}
void keyPressed(){
if((int)key >= 49 && (int)key <= 56) glutSolidIndex = (int)(key) - 49;
}
Here is the GLSL class used:
/*
* Class posted by JohnG on the Processing forums:
* http://processing.org/discourse/yabb2/YaBB.pl?board=OpenGL;action=display;num=1159494801
* check it out for more details
*/
import processing.opengl.*;
import javax.media.opengl.*;
import java.nio.IntBuffer;
import java.nio.ByteBuffer;
import com.sun.opengl.util.BufferUtil;
class GLSL
{
int programObject;
GL gl;
boolean vertexShaderEnabled;
boolean vertexShaderSupported;
int vs;
int fs;
GLSL()
{
PGraphicsOpenGL pgl = (PGraphicsOpenGL) g;
gl = pgl.gl;
//gl=((PGraphicsGL)g).gl;
String extensions = gl.glGetString(GL.GL_EXTENSIONS);
vertexShaderSupported = extensions.indexOf("GL_ARB_vertex_shader") != -1;
vertexShaderEnabled = true;
programObject = gl.glCreateProgramObjectARB();
vs=-1;
fs=-1;
}
void loadVertexShader(String file)
{
String shaderSource=join(loadStrings(file),"\n");
vs = gl.glCreateShaderObjectARB(GL.GL_VERTEX_SHADER_ARB);
gl.glShaderSourceARB(vs, 1, new String[]{
shaderSource }
,(int[]) null, 0);
gl.glCompileShaderARB(vs);
checkLogInfo(gl, vs);
gl.glAttachObjectARB(programObject, vs);
}
void loadFragmentShader(String file)
{
String shaderSource=join(loadStrings(file),"\n");
fs = gl.glCreateShaderObjectARB(GL.GL_FRAGMENT_SHADER_ARB);
gl.glShaderSourceARB(fs, 1, new String[]{
shaderSource }
,(int[]) null, 0);
gl.glCompileShaderARB(fs);
checkLogInfo(gl, fs);
gl.glAttachObjectARB(programObject, fs);
}
int getAttribLocation(String name)
{
return(gl.glGetAttribLocationARB(programObject,name));
}
int getUniformLocation(String name)
{
return(gl.glGetUniformLocationARB(programObject,name));
}
void useShaders()
{
gl.glLinkProgramARB(programObject);
gl.glValidateProgramARB(programObject);
checkLogInfo(gl, programObject);
}
void startShader()
{
gl.glUseProgramObjectARB(programObject);
}
void endShader()
{
gl.glUseProgramObjectARB(0);
}
void checkLogInfo(GL gl, int obj)
{
IntBuffer iVal = BufferUtil.newIntBuffer(1);
gl.glGetObjectParameterivARB(obj, GL.GL_OBJECT_INFO_LOG_LENGTH_ARB, iVal);
int length = iVal.get();
if (length <= 1)
{
return;
}
ByteBuffer infoLog = BufferUtil.newByteBuffer(length);
iVal.flip();
gl.glGetInfoLogARB(obj, length, iVal, infoLog);
byte[] infoBytes = new byte[length];
infoLog.get(infoBytes);
println("GLSL Validation >> " + new String(infoBytes));
}
void uniform3f(int location, float v0, float v1, float v2)
{
gl.glUniform3fARB(location, v0, v1, v2);
}
void uniform1i(int location, int v0)
{
gl.glUniform1iARB(location, v0);
}
}
And the GLSL code,
the vertex shader: toon.vs
//
// Vertex shader for cartoon-style shading
//
// Author: Philip Rideout
//
// Copyright (c) 2005-2006 3Dlabs Inc. Ltd.
//
// See 3Dlabs-License.txt for license information
//
varying vec3 Normal;
void main(void)
{
Normal = normalize(gl_NormalMatrix * gl_Normal);
#ifdef __GLSL_CG_DATA_TYPES // Fix clipping for Nvidia and ATI
gl_ClipVertex = gl_ModelViewMatrix * gl_Vertex;
#endif
gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;
}
And the fragment shader: toon.fs
/* http://www.lighthouse3d.com/opengl/glsl/index.php?toon2 */
varying vec3 Normal;
uniform vec3 LightPosition;// = vec3(10.0, 10.0, 20.0);
void main()
{
vec4 color1 = gl_FrontMaterial.diffuse;
vec4 color2;
float intensity = dot(normalize(LightPosition),Normal);
if (intensity > 0.95) color2 = vec4(1.0, 1.0, 1.0, 1.0);
else if (intensity > 0.75) color2 = vec4(0.8, 0.8, 0.8, 1.0);
else if (intensity > 0.50) color2 = vec4(0.6, 0.6, 0.6, 1.0);
else if (intensity > 0.25) color2 = vec4(0.4, 0.4, 0.4, 1.0);
else color2 = vec4(0.2, 0.2, 0.2, 1.0);
gl_FragColor = color1 * color2;
}
If it helps, here is the zipped Processing project. Once you've installed Processing, unzip the file into the default Processing folder(~/Documents/Processing) and run Processing > it should show under File > Sketchbook
And here's a screenshot:
HTH
Update
Processing now provides a nice PShader class and comprehensive tutorial.
It incluses a Toon shader:
PShader toon;
void setup() {
size(640, 360, P3D);
noStroke();
fill(204);
toon = loadShader("ToonFrag.glsl", "ToonVert.glsl");
toon.set("fraction", 1.0);
}
void draw() {
shader(toon);
background(0);
float dirY = (mouseY / float(height) - 0.5) * 2;
float dirX = (mouseX / float(width) - 0.5) * 2;
directionalLight(204, 204, 204, -dirX, -dirY, -1);
translate(width/2, height/2);
sphere(120);
}
ToonVert.glsl:
uniform mat4 transform;
uniform mat3 normalMatrix;
uniform vec3 lightNormal;
attribute vec4 vertex;
attribute vec4 color;
attribute vec3 normal;
varying vec4 vertColor;
varying vec3 vertNormal;
varying vec3 vertLightDir;
void main() {
gl_Position = transform * vertex;
vertColor = color;
vertNormal = normalize(normalMatrix * normal);
vertLightDir = -lightNormal;
}
ToonFrag.glsl:
#ifdef GL_ES
precision mediump float;
precision mediump int;
#endif
#define PROCESSING_LIGHT_SHADER
uniform float fraction;
varying vec4 vertColor;
varying vec3 vertNormal;
varying vec3 vertLightDir;
void main() {
float intensity;
vec4 color;
intensity = max(0.0, dot(vertLightDir, vertNormal));
if (intensity > pow(0.95, fraction)) {
color = vec4(vec3(1.0), 1.0);
} else if (intensity > pow(0.5, fraction)) {
color = vec4(vec3(0.6), 1.0);
} else if (intensity > pow(0.25, fraction)) {
color = vec4(vec3(0.4), 1.0);
} else {
color = vec4(vec3(0.2), 1.0);
}
gl_FragColor = color * vertColor;
}
Related
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 am writing a basic Sphere-Tracer in a fragment shader, everything is doing fine if I just color points according to their surface normals, but as soon as I try to implement the reflecting algorithm, it takes a bit longer to compile, and just blackscreens. The fps starts out at 1 but quickly goes up to 1000, which is the code limit I put, telling me the shader is actually not doing anything and just ignores my code, which should be much slower than that. I initially thought I was hitting the instruction limit of my GPU, but I don't think that's the problem, as using the normal-shading code, I can set MAX_MARCH to high values, like 1000, but using reflections, even with MAX_REFLECTIONS and MAX_AA to one, which should be similar to the amount of instructions of normal-shading(maybe ~50 more, not significant I don't think). But I need to set MAX_MARCH to 1 for it to render, even setting it to two causes the bug.
Vertex shader:
//Draw a quad on the whole display and calculates sky color
#version 400 core
in vec3 position;
out vec2 uvPos;
out vec4 backColor;
void main(void){
gl_Position = vec4(position, 1.0);
uvPos = position.xy*0.5+0.5;
backColor = mix(vec4(1, 1, 1, 1), vec4(0.5, 0.7, 1, 1), uvPos.y);
}
Fragment shader:
#version 400 core
#define FLT_MAX 3.402823466e+38
#define FLT_MIN 1.175494351e-38
#define DBL_MAX 1.7976931348623158e+308
#define DBL_MIN 2.2250738585072014e-308
#define PI 3.141592653589793115997963468544185161590576171875
#define MAX_AA 1
#define MAX_MARCH 1000
#define MAX_REFLECTIONS 10
#define MAX_DIST 10
in vec2 uvPos;
in vec4 backColor;
out vec4 outColor;
int randomIterator = 0;
//############################################################ Structure definitions #########################################################################
struct Material{
int type;
vec3 albedo;
};
struct Object{
int type; //1:Sphere, 2:Box
vec3 center;
float radius;
vec3 size;
Material material;
};
struct Scene{
Object objects[3];
};
struct Ray{
vec3 origin;
vec3 dir;
};
struct HitRecord{
vec3 p;
vec3 n;
Object o;
Material mat;
float closest;
};
struct Camera{
vec3 origin;
vec3 lowerLeftCorner;
vec3 horizontal;
vec3 vertical;
};
//############################################################ Uniforms ####################################################################################
uniform float random[2048];
uniform vec2 resolution;
uniform Camera cam;
uniform Scene scene;
uniform int objectAmount;
//############################################################ Tools
float randf(){
return random[randomIterator++];
}
Ray getRay(Camera cam, vec2 v){
return Ray(cam.origin, normalize(cam.lowerLeftCorner+cam.horizontal*v.s+cam.vertical*v.t-cam.origin));
}
vec3 randOnBall(){
vec3 p;
do{
p = vec3(randf(), randf(), randf())*2-1;
}while(p.length() >= 1);
return p;
}
//############################################################ Signed Distance Functions
float sphereSDF(vec3 p, Object o){
return length(p-o.center)-o.radius;
}
float boxSDF(vec3 p, Object o){
vec3 q = abs(p-o.center) - o.size;
return (length(max(q, 0.0)) + min(max(q.x, max(q.y, q.z)), 0.0));
}
float sceneSDF(vec3 p, Scene s){
float dist = FLT_MAX;
for(int i = 0; i < objectAmount; i++){
switch(s.objects[i].type){
case 1:
dist = min(dist, sphereSDF(p, s.objects[i]));
break;
case 2:
dist = min(dist, boxSDF(p, s.objects[i]));
break;
default:
break;
}
}
return dist;
}
float sceneSDF(vec3 p, Scene s, inout HitRecord rec){
float dist = FLT_MAX;
for(int i = 0; i < objectAmount; i++){
float tmpDist=FLT_MAX;
switch(s.objects[i].type){
case 1:
tmpDist = sphereSDF(p, s.objects[i]);
break;
case 2:
tmpDist = boxSDF(p, s.objects[i]);
break;
default:
break;
}
if(tmpDist<dist){
dist = tmpDist;
rec.o = s.objects[i];
rec.mat = s.objects[i].material;
}
}
return dist;
}
//############################################################ Material Scatter Function
bool scatterDiffuse(Ray r, HitRecord rec, inout vec3 tmpAtt, inout Ray scattered){
tmpAtt = vec3(rec.mat.albedo);
scattered = Ray(rec.p, rec.n+randOnBall());
return true;
}
bool scatter(Ray r, HitRecord rec, inout vec3 tmpAtt, inout Ray scattered){
return scatterDiffuse(r, rec, tmpAtt, scattered); //Starting out with diffuse materials, planned to
add switch-case for different materials
}
//############################################################ Main
vec3 findSceneNormal(Scene s, vec3 p){
const float h = 0.0001; // replace by an appropriate value
const vec2 k = vec2(1,-1);
return normalize( k.xyy*sceneSDF( p + k.xyy*h, s ) +
k.yyx*sceneSDF( p + k.yyx*h, s ) +
k.yxy*sceneSDF( p + k.yxy*h, s ) +
k.xxx*sceneSDF( p + k.xxx*h, s ) );
}
float findSceneIntersect(Ray r, Scene scene, inout HitRecord rec){
float t = 0.005;
vec3 p;
for(int i = 0; i < MAX_MARCH; i++){
p = r.origin+t*r.dir;
float dist = abs(sceneSDF(p, scene, rec));
if(dist < 0.001){
rec.n = findSceneNormal(scene, p);
rec.p = p;
return t;
}else{
t += dist;
if(t >= MAX_DIST){
rec.p = r.origin+t*r.dir;
rec.n = vec3(0, 0, 0);
return -1;
}
}
}
return -1;
}
vec3 calcColor(Ray r){
vec3 color;
Material emptyMat = Material(0, vec3(0));
Object emptyO = Object(0, vec3(0), 0, vec3(0), emptyMat);
HitRecord rec = HitRecord(vec3(0), vec3(0), emptyO, emptyMat, 0);
float t = findSceneIntersect(r, scene, rec);
int reflections = 0;
vec3 att = vec3(1, 1, 1);
for(int ref = 0; ref < MAX_REFLECTIONS; ref++){
if(t != -1){
vec3 tmpAtt = vec3(0);
if(scatter(r, rec, tmpAtt, r)){
att *= tmpAtt;
t = findSceneIntersect(r, scene, rec);
reflections++;
}else {
att *= tmpAtt;
t = -1;
}
}else {
color = backColor.xyz*att;
break;
}
}
return color;
}
void main(void){
HitRecord rec = HitRecord(vec3(0), vec3(0), Object(-1, vec3(0), 0, vec3(0), Material(-1, vec3(0))), Material(-1, vec3(1, 1, 1)), 0);
#if 1 //Reflection rendering
vec3 color = vec3(0);
for(int s = 0; s < MAX_AA; s++){
vec2 uv = uvPos+(vec2(randf(), randf())*2-1)/resolution;
color += calcColor(getRay(cam, uv));
}
outColor = vec4(color/MAX_AA, 1);
#else //Coloring based on normals
Ray r = getRay(cam, uvPos);
float t = findSceneIntersect(r, scene, rec);
if(t == -1){
outColor = backColor;
}else {
outColor = vec4(rec.n*0.5+0.5, 1);
}
#endif
}
Java code where I load and compile the shader (Using LWJGL):
private static int loadShader(String file, int type) {
System.out.println("Loading shader at path: " + file);
StringBuilder shaderSource = new StringBuilder();
try{
BufferedReader reader = new BufferedReader(new FileReader(file));
String line;
while((line = reader.readLine())!=null){
shaderSource.append(line).append("//\n");
}
reader.close();
}catch(IOException e){
e.printStackTrace();
System.exit(-1);
}
int shaderID = glCreateShader(type);
glShaderSource(shaderID, shaderSource);
glCompileShader(shaderID);
if(glGetShaderi(shaderID, GL_COMPILE_STATUS )== GL_FALSE){
System.out.println(glGetShaderInfoLog(shaderID, 500));
System.err.println("Could not compile shader!");
System.exit(-1);
}
return shaderID;
}
The function loadShader in my code does not give me any error as it does with syntax errors and doesn't exit the program, thus GL_COMPILE_STATUS is not false.
I am fully aware nested for loops and my use of conditionals is far from efficient performance-wise, but I would expect it to be slow, not completely broken. I am running this on an Intel UHD 630, which according to https://www.intel.ca/content/www/ca/en/support/products/98909/graphics/graphics-for-7th-generation-intel-processors/intel-hd-graphics-630.html supports openGL 4.4. Therefore, according to GLSL maximum number of instructions, I should have access to 65536 instructions in my frag shader and fully dynamic branching. For these reasons, I don't think instruction limit is the problem and any help would be greatly appreciated. If you need any more information, I'll add it as soon as possible. If the CPU code is necessary, I can add it too, but I don't think it's the issue, as changing only the shader can trigger this bug.
Edit 1:
Both glGetShaderInfoLog and glGetProgramInfoLog return nothing when called after the program has been validated and linked.
I’m try to porting the shadertoy chromakey example to p5 with webcam as video source. After many time reading documentations of shaders, my code seems not working. I need some help.
I followed this guide to port the code for the p5
Fragment shader code:
#ifdef GL_ES
precision mediump float;
#endif
uniform sampler2D tex0;
uniform sampler2D tex1;
mat4 RGBtoYUV = mat4(0.257, 0.439, -0.148, 0.0,
0.504, -0.368, -0.291, 0.0,
0.098, -0.071, 0.439, 0.0,
0.0625, 0.500, 0.500, 1.0 );
vec4 chromaKey = vec4(0.05, 0.63, 0.14, 1);
vec2 maskRange = vec2(0.005, 0.26);
float colorclose(vec3 yuv, vec3 keyYuv, vec2 tol)
{
float tmp = sqrt(pow(keyYuv.g - yuv.g, 2.0) + pow(keyYuv.b - yuv.b, 2.0));
if (tmp < tol.x)
return 0.0;
else if (tmp < tol.y)
return (tmp - tol.x)/(tol.y - tol.x);
else
return 1.0;
}
void main()
{
vec2 fragPos = gl_FragCoord.xy / iResolution.xy;
vec4 texColor0 = texture(text0, fragPos);
vec4 texColor1 = texture(text1, fragPos);
vec4 keyYUV = RGBtoYUV * chromaKey;
vec4 yuv = RGBtoYUV * texColor0;
float mask = 1.0 - colorclose(yuv.rgb, keyYUV.rgb, maskRange);
gl_FragColor = max(texColor0 - mask * chromaKey, 0.0) + texColor1 * mask;
}
P5 sketch code:
let theShader;
let cam;
let img;
function preload(){
theShader = loadShader('webcam.vert', 'webcam.frag');
img = loadImage('http://www.quadrochave.com/wp-content/uploads/elementor/thumbs/nodulo_bannersite_ptodu%C3%A7%C3%A3o2-mpe2nvmu8s8o2uqcd7b2oh3mnuv9up05ubby33shz4.png');
}
function setup() {
pixelDensity(1);
createCanvas(windowWidth, windowHeight, WEBGL);
noStroke();
cam = createCapture(VIDEO);
cam.size(windowWidth, windowHeight);
cam.hide();
}
function draw() {
// shader() sets the active shader with our shader
shader(theShader);
// passing cam as a texture
theShader.setUniform('tex0', cam);
theShader.setUniform('tex1', img);
// rect gives us some geometry on the screen
theShader.rect(0,0,width,height);
}
Test on Glitch
Shadertoy chromakey original fragment shader
The mayor issue is, that you didn't specify and set the uniform variable iResolution. But there are some more issues in the shader code (tex0 and tex1 rather than text0 and text1).
Fragment shader:
precision mediump float;
uniform sampler2D tex0;
uniform sampler2D tex1;
uniform vec2 iResolution;
mat4 RGBtoYUV = mat4(0.257, 0.439, -0.148, 0.0,
0.504, -0.368, -0.291, 0.0,
0.098, -0.071, 0.439, 0.0,
0.0625, 0.500, 0.500, 1.0 );
vec4 chromaKey = vec4(0.05, 0.63, 0.14, 1);
vec2 maskRange = vec2(0.005, 0.26);
float colorclose(vec3 yuv, vec3 keyYuv, vec2 tol)
{
float tmp = sqrt(pow(keyYuv.g - yuv.g, 2.0) + pow(keyYuv.b - yuv.b, 2.0));
if (tmp < tol.x)
return 0.0;
else if (tmp < tol.y)
return (tmp - tol.x)/(tol.y - tol.x);
else
return 1.0;
}
void main()
{
vec2 fragPos = gl_FragCoord.xy / iResolution.xy;
vec4 texColor0 = texture2D(tex0, fragPos);
vec4 texColor1 = texture2D(tex1, fragPos);
vec4 keyYUV = RGBtoYUV * chromaKey;
vec4 yuv = RGBtoYUV * texColor0;
float mask = 1.0 - colorclose(yuv.rgb, keyYUV.rgb, maskRange);
gl_FragColor = max(texColor0 - mask * chromaKey, 0.0) + texColor1 * mask;
}
Script:
let theShader;
let cam;
let img;
function setup() {
createCanvas(windowWidth, windowHeight, WEBGL);
theShader = loadShader('webcam.vert', 'webcam.frag');
img = loadImage('http://www.quadrochave.com/wp-content/uploads/elementor/thumbs/nodulo_bannersite_ptodu%C3%A7%C3%A3o2-mpe2nvmu8s8o2uqcd7b2oh3mnuv9up05ubby33shz4.png');
pixelDensity(1);
noStroke();
cam = createCapture(VIDEO);
cam.size(windowWidth, windowHeight);
cam.hide();
}
function draw() {
// shader() sets the active shader with our shader
shader(theShader);
// passing cam as a texture
theShader.setUniform('tex0', cam);
theShader.setUniform('tex1', img);
theShader.setUniform('iResolution', [width, height]);
// rect gives us some geometry on the screen
rect(0,0,width,height);
}
If the vertex shader provides the texture the coordinate:
// our vertex data
attribute vec3 aPosition;
attribute vec2 aTexCoord;
// lets get texcoords just for fun!
varying vec2 vTexCoord;
void main() {
// copy the texcoords
vTexCoord = aTexCoord;
// copy the position data into a vec4, using 1.0 as the w component
vec4 positionVec4 = vec4(aPosition, 1.0);
positionVec4.xy = positionVec4.xy * 2.0 - 1.0;
// send the vertex information on to the fragment shader
gl_Position = positionVec4;
}
then you can use this coordinate instead of gl_FragCoord.xy / iResolution.xy:
varying vec2 vTexCoord;
// [...]
void main() {
vec2 fragPos = vTexCoord.xy;
// [...]
}
I need to flip my textures upside-down in shaders before applying perspective transformations. I modified vertTexCoord in vert.glsl, but I don't know where to use it in swap.glsl. The way to do it like
gl_FragColor = texture2D(texture, vertTexCoord );
does not work, because I also need the texture to be modified in perspective.
vert.glsl:
#define PROCESSING_COLOR_SHADER
uniform mat4 transform;
uniform mat4 texMatrix;
attribute vec4 vertex;
attribute vec4 color;
attribute vec2 texCoord;
varying vec4 vertColor;
varying vec4 vertTexCoord;
void main() {
gl_Position = transform * vertex;
vertColor = color;
vertTexCoord = texMatrix * vec4(texCoord, 1.0, 1.0);
}
swap.glsl:
#ifdef GL_ES
precision highp float;
#endif
// General parameters
uniform sampler2D from;
uniform sampler2D to;
uniform float progress;
uniform vec2 resolution;
uniform float reflection;
uniform float perspective;
uniform float depth;
varying vec4 vertColor;
varying vec4 vertTexCoord;
const vec4 black = vec4(0.0, 0.0, 0.0, 1.0);
const vec2 boundMin = vec2(0.0, 0.0);
const vec2 boundMax = vec2(1.0, 1.0);
bool inBounds (vec2 p) {
return all(lessThan(boundMin, p)) && all(lessThan(p, boundMax));
}
vec2 project (vec2 p) {
return p * vec2(1.0, -1.2) + vec2(0.0, -0.02);
}
vec4 bgColor (vec2 p, vec2 pfr, vec2 pto) {
vec4 c = black;
pfr = project(pfr);
if (inBounds(pfr)) {
c += mix(black, texture2D(from, pfr), reflection * mix(1.0, 0.0, pfr.y));
}
pto = project(pto);
if (inBounds(pto)) {
c += mix(black, texture2D(to, pto), reflection * mix(1.0, 0.0, pto.y));
}
return c;
}
void main() {
vec2 p = gl_FragCoord.xy / resolution.xy;
vec2 pfr, pto = vec2(-1.);
float size = mix(1.0, depth, progress);
float persp = perspective * progress;
pfr = (p + vec2(-0.0, -0.5)) * vec2(size/(1.0-perspective*progress), size/(1.0-size*persp*p.x)) + vec2(0.0, 0.5);
size = mix(1.0, depth, 1.-progress);
persp = perspective * (1.-progress);
pto = (p + vec2(-1.0, -0.5)) * vec2(size/(1.0-perspective*(1.0-progress)), size/(1.0-size*persp*(0.5-p.x))) + vec2(1.0, 0.5);
bool fromOver = progress < 0.5;
if (fromOver) {
if (inBounds(pfr)) {
gl_FragColor = texture2D(from, pfr);
}
else if (inBounds(pto)) {
gl_FragColor = texture2D(to, pto);
}
else {
gl_FragColor = bgColor(p, pfr, pto);
}
}
else {
if (inBounds(pto)) {
gl_FragColor = texture2D(to, pto);
}
else if (inBounds(pfr)) {
gl_FragColor = texture2D(from, pfr);
}
else {
gl_FragColor = bgColor(p, pfr, pto);
}
}
}
You sample the texture at
(u,v)
If you want to flip the Y-axis, just sample at
(u, 1.0f -v)
So your updated main will look like:
void main() {
gl_Position = transform * vertex;
vertColor = color;
newTCoord = texCoord;
newTCoord.y = 1.0 - newTCoord.y;
vertTexCoord = vec4(newTCoord, 1.0, 1.0);
}
I've been having problems sending the shininess factor to my bump mapping shader.
The result always looks like this: http://i.imgur.com/unzdx.jpg
But if I hard code the value inside the shader to 0.0 it's working just fine.
When I send 0.0 to the shader it's turning out like in the picture above.
Any ideas?
Here's my shader
#version 110
uniform sampler2D tex;
uniform sampler2D bmap;
uniform bool boolBump;
uniform vec4 vecColor;
uniform bool onlyColor;
uniform float fTransparencyThresh;
uniform float fShininess;
uniform float alpha;
varying vec3 vecLight;
varying vec3 vecEye;
varying vec3 vecNormal;
vec4 getLighting()
{
//Ambient part
vec4 color = (gl_FrontLightModelProduct.sceneColor * gl_FrontMaterial.ambient) + (gl_LightSource[0].ambient * gl_FrontMaterial.ambient);
//For bump mapping, the normal comes from the bump map texture lookup
vec3 n = normalize(vecNormal);
if(boolBump)
{
n = normalize(texture2D(bmap, gl_TexCoord[0].st).xyz * 2.0 - 1.0);
}
vec3 l = normalize(vecLight);
//Lambert term
float NdotL = dot(n, l);
if(NdotL > 0.0)
{
//Diffuse part
color += gl_LightSource[0].diffuse * gl_FrontMaterial.diffuse * max(0.0, NdotL);
//Specular part
vec3 e = normalize(vecEye);
vec3 r = normalize(-reflect(l,n));
float spec = pow(max(0.0, dot(r, e)), fShininess);
color += gl_LightSource[0].specular * gl_FrontMaterial.specular * spec;
}
return color;
}
void main(void)
{
vec4 texel = texture2D(tex, gl_TexCoord[0].st);
if(texel.a < fTransparencyThresh)
discard;
//Get shading
vec4 color = getLighting();
//Color only mode?
if(onlyColor)
{
color *= vecColor;
}
else
{
color *= texel;
}
//Set fragment color, alpha comes from MTL file
gl_FragColor = vec4(color.xyz, alpha);
}
Edit, OpenGL code:
void MyClass::sendToShader(const OBJ::StelModel* pStelModel, Effect cur, bool& tangEnabled, int& tangLocation)
{
int location;
tangEnabled = false;
if(cur != No)
{
location = curShader->uniformLocation("fTransparencyThresh");
curShader->setUniform(location, fTransparencyThresh);
location = curShader->uniformLocation("alpha");
curShader->setUniform(location, pStelModel->pMaterial->alpha);
location = curShader->uniformLocation("fShininess");
curShader->setUniform(location, 0.0f);
...
Edit: Even this wont work:
GLint loc = glGetUniformLocation(curShader->program, "fShininess");
glUniform1f(loc, 0.0f);
Note that pow(0, 0) is undefined. This means spec is undefined if dot(r, e) == 0 and fShininess == 0.
Do you make sure the program is actively bound when you call glUniform? Do you check glGetError anywhere?