Coloring with shaders - ios

I have created a project on top of the XCode OpenGL ES template.
Is there a way to customize the shader color for each object?
Shader.vsh:
attribute vec4 position;
attribute vec3 normal;
varying lowp vec4 colorVarying;
uniform mat4 modelViewProjectionMatrix;
uniform mat3 normalMatrix;
void main()
{
vec3 eyeNormal = normalize(normalMatrix * normal);
vec3 lightPosition = vec3(1.0, 1.0, 1.0);
vec4 diffuseColor = vec4(1, 0.4, 1.0, 1.0);
float nDotVP = max(0.0, dot(eyeNormal, normalize(lightPosition)));
colorVarying = diffuseColor * nDotVP;
gl_Position = modelViewProjectionMatrix * position;
}
Shader.fsh:
varying lowp vec4 colorVarying;
void main()
{
gl_FragColor = colorVarying;
}
Do i need to create an extra attribute in Shader.vsh which parses the color to replace diffuse variable or how is this done?

I suggest using uniform variables for colors
// put this in Shader.vsh, before the main()
uniform vec4 diffuseColor;
and in the code just set the value:
glUseProgram(progID);
// object 1 (R, G, B, A is a color)
glUniform4f(glGetUniformLocation(progID, "diffuseColor"), R, G, B, A);
draw_object_1();
// object 2 (R, G, B, A is a color)
glUniform4f(glGetUniformLocation(progID, "diffuseColor"), R, G, B, A);
draw_object_2();
the same can be done with light position as well.

Related

How blending image mask?

How can I apply such a mask
to get effect such as bokeh
need to blur edge in mask and apply on image texture. How do that?
Vertex shader:
attribute vec4 a_Position;
void main()
{
gl_Position = a_Position;
}
Fragment shader:
precision lowp float;
uniform sampler2D u_Sampler; // textureSampler
uniform sampler2D u_Mask; // maskSampler
uniform vec3 iResolution;
vec4 blur(sampler2D source, vec2 size, vec2 uv) {
vec4 C = vec4(0.0);
float width = 1.0 / size.x;
float height = 1.0 / size.y;
float divisor = 0.0;
for (float x = -25.0; x <= 25.0; x++)
{
C += texture2D(source, uv + vec2(x * width, 0.0));
C += texture2D(source, uv + vec2(0.0, x * height));
divisor++;
}
C*=0.5;
return vec4(C.r / divisor, C.g / divisor, C.b / divisor, 1.0);
}
void main()
{
vec2 uv = gl_FragCoord.xy / iResolution.xy;
vec4 videoColor = texture2D(u_Sampler, uv);
vec4 maskColor = texture2D(u_Mask, uv);
gl_FragColor = blur(u_Sampler, iResolution.xy, uv);
}
vec4 blurColor = blur(u_Sampler, iResolution.xy, uv);
gl_FragColor = mix(blurColor, videoColor, maskColor.r);
But FYI it's not common to blur in one pass like you have. It's more common to blur in one direction (horizontally), then blur the result of that vertically, then mix the results, blurredTexture, videoTexture, mask.

Phong Shader: Fixed light specular component rotates with camera

I wrote a Phong shader for WebGL. My Scene supports camera rotation using Euler Angles. The light should be fixed in the scene. As soon as I rotate the camera the specular effects on objects move as well. Translation also seems to have strange effects on the specular component. I
(hopefully) made sure that calculations are performed in eye space. I first want to find out if my shaders are correct.
Here is my code:
Vertex Shader
struct Light {
vec3 position;
/* ... */
};
uniform Light u_light;
uniform mat4 u_modelViewProjMat;
uniform mat4 u_modelViewMat;
uniform mat4 u_viewMat;
uniform mat3 u_normalMat;
in vec3 a_position;
in vec3 a_normal;
in vec2 a_texCoord;
out vec2 v_texCoord;
out vec3 v_normal;
out vec3 f_position;
out vec3 v_lightPos;
void main() {
v_normal = u_normalMat * a_normal;
v_texCoord = a_texCoord;
f_position = vec3(u_modelViewMat * vec4(a_position, 1.0));
v_lightPos = vec3(u_viewMat * vec4(u_light.position, 1.0));
gl_Position = u_modelViewProjMat * vec4(a_position, 1.0);
}
Fragment Shader
struct Material {
sampler2D diffuse;
vec3 specular;
float shininess;
};
struct Light {
/* ... */
vec3 ambient;
vec3 diffuse;
vec3 specular;
};
uniform Material u_material;
uniform Light u_light;
uniform vec3 u_eyePosition;
in vec2 v_texCoord;
in vec3 v_normal;
in vec3 f_position;
in vec3 v_lightPos;
out vec4 outColor;
void main() {
vec3 texture = vec3(texture(u_material.diffuse, v_texCoord));
// ambient
vec3 ambient = u_light.ambient * texture;
// diffuse
vec3 normal = normalize(v_normal);
vec3 lightDir = normalize(v_lightPos - f_position);
float diff = max(dot(normal, lightDir), 0.0);
vec3 diffuse = u_light.diffuse * diff * texture;
// specular
vec3 viewDir = normalize(u_eyePosition - f_position);
vec3 reflectDir = reflect(-lightDir, normal);
float spec = pow(max(dot(viewDir, reflectDir), 0.0), u_material.shininess);
vec3 specular = u_light.specular * (spec * u_material.specular);
outColor = vec4((ambient + diffuse + specular), 1.0);
}
f_position is a camera space position, so to get the viewDir vector for your specular component you should only perform vec3 viewDir = normalize(-f_position); or work with world space coordinates

WebGL attribute is always null

I'm trying to make a graphic engine in WebGL, but I'm having lots of trouble.
One of this problems is about attributes being null or -1 when I call them with "gl.getUniformLocation".
My main problem with this right now is "aVertexTextureCoords", which is always -1.
I leave here my shaders, just in case they're the problem.
<script id="shader-vs" type="x-shader/x-vertex">
attribute vec3 aVertexPosition;
attribute vec3 aVertexNormal;
attribute vec4 aVertexColor;
attribute vec2 aVertexTextureCoords;
uniform mat4 uMVMatrix;
uniform mat4 uPMatrix;
uniform mat4 uNMatrix;
uniform float uAlpha;
const int NUM_LIGHTS = 4;
uniform vec4 uMaterialDiffuse;
uniform vec3 uLightPosition[NUM_LIGHTS];
//varyings
varying vec4 vColor;
varying vec2 vTextureCoord;
varying vec3 vNormal;
varying vec3 vLightRay[NUM_LIGHTS];
void main(void) {
//Transformed vertex position
vec4 vertex = uMVMatrix * vec4(aVertexPosition, 1.0);
//Transformed normal position
vNormal = vec3(uNMatrix * vec4(aVertexNormal, 1.0));
//Calculate light ray per each light
for(int i=0; i < NUM_LIGHTS; i++){
vec4 lightPosition = uMVMatrix * vec4(uLightPosition[i], 1.0);
vLightRay[i] = vertex.xyz - lightPosition.xyz;
}
//Final vertex position
gl_Position = uPMatrix * uMVMatrix * vec4(aVertexPosition, 1.0);
vTextureCoord = aVertexTextureCoords;
}
</script>
<script id="shader-fs" type="x-shader/x-fragment">
#ifdef GL_ES
precision highp float;
#endif
//object uniforms
uniform bool uWireframe;
uniform vec4 uMaterialAmbient;
uniform vec4 uMaterialDiffuse;
//Incluimos un uniform que asociara la textura a un uniform
uniform sampler2D uSampler;
//light uniforms
const int NUM_LIGHTS = 4;
uniform bool uLightSource;
uniform vec4 uLightAmbient;
uniform vec4 uLightDiffuse[NUM_LIGHTS];
uniform float uCutOff;
//varyings
varying vec2 vTextureCoord;
varying vec3 vNormal;
varying vec3 vLightRay[NUM_LIGHTS];
void main(void)
{
if(uWireframe || uLightSource){
gl_FragColor = uMaterialDiffuse;
}
else{
vec4 Ia = uLightAmbient * uMaterialAmbient; //Ambient component: one for all
vec4 finalColor = vec4(0.0,0.0,0.0,1.0); //Color that will be assigned to gl_FragColor
vec3 N = normalize(vNormal);
vec3 L = vec3(0.0);
float lambertTerm = 0.0;
for(int i = 0; i < NUM_LIGHTS; i++){ //For each light
L = normalize(vLightRay[i]); //Calculate reflexion
lambertTerm = dot(N, -L);
if (lambertTerm > uCutOff){
finalColor += uLightDiffuse[i] * uMaterialDiffuse *lambertTerm; //Add diffuse component, one per light
}
}
//Final color
finalColor += Ia;
finalColor.a = 1.0; //Add ambient component: one for all
gl_FragColor = finalColor * texture2D(uSampler, vTextureCoord); //The alpha value in this example will be 1.0
}
}
</script>
Can somebody tell me what I'm doing wrong?
Calling gl.getUniformLocation for a vertex attribute is wrong because it's an attribute, not a uniform. Replace the call with gl.getAttribLocation.

Transparent objects with visible textures(set alpha channel)

I have to show transparent objects with texture that is set alpha channel.
Using OpenGL ES 2.0 and mtl2opengl.pl I could show object with texture on my iPhone but alpha channel didn't work.
This is almost same as mtl2opengl.pl sample. How should I change code?
in ViewController.m:
- (void)glkView:(GLKView *)view drawInRect:(CGRect)rect{
// Clear Buffers
glClearColor(1.0, 1.0, 1.0, 1.0);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
// Set View Matrices
[self updateViewMatrices];
glUniformMatrix4fv(_uniforms.uProjectionMatrix, 1, 0, _projectionMatrix.m);
glUniformMatrix4fv(_uniforms.uModelViewMatrix, 1, 0, _modelViewMatrix.m);
glUniformMatrix3fv(_uniforms.uNormalMatrix, 1, 0, _normalMatrix.m);
// Attach Texture
glUniform1i(_uniforms.uTexture, 0);
// Set View Mode
glUniform1i(_uniforms.uMode, self.viewMode.selectedSegmentIndex);
// Enable Attributes
glEnableVertexAttribArray(_attributes.aVertex);
glEnableVertexAttribArray(_attributes.aNormal);
glEnableVertexAttribArray(_attributes.aTexture);
// Load OBJ Data
glVertexAttribPointer(_attributes.aVertex, 3, GL_FLOAT, GL_FALSE, 0, buildOBJVerts);
glVertexAttribPointer(_attributes.aNormal, 3, GL_FLOAT, GL_FALSE, 0, buildOBJNormals);
glVertexAttribPointer(_attributes.aTexture, 2, GL_FLOAT, GL_FALSE, 0, buildOBJTexCoords);
// Load MTL Data
for(int i=0; i<buildMTLNumMaterials; i++)
{
glUniform3f(_uniforms.uAmbient, buildMTLAmbient[i][0], buildMTLAmbient[i][1], buildMTLAmbient[i][2]);
glUniform3f(_uniforms.uDiffuse, buildMTLDiffuse[i][0], buildMTLDiffuse[i][1], buildMTLDiffuse[i][2]);
glUniform3f(_uniforms.uSpecular, buildMTLSpecular[i][0], buildMTLSpecular[i][1], buildMTLSpecular[i][2]);
glUniform1f(_uniforms.uExponent, buildMTLExponent[i]);
// Draw scene by material group
glDrawArrays(GL_TRIANGLES, buildMTLFirst[i], buildMTLCount[i]);
}
// Disable Attributes
glDisableVertexAttribArray(_attributes.aVertex);
glDisableVertexAttribArray(_attributes.aNormal);
glDisableVertexAttribArray(_attributes.aTexture);
}
Shader.fsh:
// FRAGMENT SHADER
static const char* ShaderF = STRINGIFY
(
// Input from Vertex Shader
varying mediump vec3 vNormal;
varying mediump vec2 vTexture;
// MTL Data
uniform lowp vec3 uAmbient;
uniform lowp vec3 uDiffuse;
uniform lowp vec3 uSpecular;
uniform highp float uExponent;
uniform lowp int uMode;
uniform lowp vec3 uColor;
uniform sampler2D uTexture;
lowp vec3 materialDefault(highp float df, highp float sf)
{
lowp vec3 diffuse = vec3(0.0,1.0,0.0);
highp float exponent = 1.0;
sf = pow(sf, exponent);
return (df * diffuse);
}
lowp vec3 materialMTL(highp float df, highp float sf)
{
sf = pow(sf, uExponent);
return (df * uDiffuse);
}
lowp vec3 modelColor(void)
{
highp vec3 N = normalize(vNormal);
highp vec3 L = vec3(1.0, 1.0, 0.5);
highp vec3 E = vec3(0.0, 0.0, 1.0);
highp vec3 H = normalize(L + E);
highp float df = max(0.0, dot(N, L));
highp float sf = max(0.0, dot(N, H));
// Default
if(uMode == 0)
return materialDefault(df, sf);
// Texture
else if(uMode == 1)
return (materialDefault(df, sf) * vec3(texture2D(uTexture, vTexture)));
// Material
else if(uMode == 2)
return materialMTL(df, sf);
}
void main(void)
{
lowp vec3 color = modelColor();
gl_FragColor = vec4(color, 1.0);
}
);
It's obvious, learn the language from a book, use vec4 everywhere (materialDefault, materialMTL, modelColor) and activate alpha blending.
example:
lowp vec4 materialMTL(highp float df, highp float sf)
{
sf = pow(sf, uExponent);
return vec4(df * uDiffuse, 1.0);
}
In lowp vec4 modelColor(void):
return (materialDefault(df, sf) * texture2D(uTexture, vTexture));
activate alpha blending:
glEnable (GL_BLEND);
glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
What's the real problem ?
Add
glEnable (GL_BLEND);
glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
Before rendering transparent objects.

basic arithmetic in iOS GLSL fragment shader

Here is my fragment shader program which runs on iOS 5.1.1 on iPhone 3g.
#ifdef GL_ES
precision lowp float;
#endif
varying vec2 v_texCoord;
void main()
{
float offset = sin(v_texCoord.x * 10.0);
// offset = offset * 1.0; // (!!!)
gl_FragColor = vec4(offset, 0.0, 0.0, 1.0);
}
Which produces nice sin:
Note the line marked by (!!!). I suppose, multiplying float value by 1.0 must change nothing. (The same shader being run under Windows OS works exactly as expected.) So, I uncomment the line and receive this:
WTF?!
How to reproduce:
Create iOS Game project from standard template in xcode. If you run the project then you will see two floating cubes. One red and one blue.
Change contents of Shader.vsh to the following. (I've just added one varying parameter v_pos).
attribute vec4 position;
attribute vec3 normal;
varying lowp vec4 colorVarying;
varying lowp vec4 v_pos;
uniform mat4 modelViewProjectionMatrix;
uniform mat3 normalMatrix;
void main()
{
vec3 eyeNormal = normalize(normalMatrix * normal);
vec3 lightPosition = vec3(0.0, 0.0, 1.0);
vec4 diffuseColor = vec4(0.4, 0.4, 1.0, 1.0);
float nDotVP = max(0.0, dot(eyeNormal, normalize(lightPosition)));
colorVarying = diffuseColor * nDotVP;
gl_Position = modelViewProjectionMatrix * position;
v_pos = gl_Position;
}
Chnge Shader.fsh to the following.
varying lowp vec4 colorVarying;
varying lowp vec4 v_pos;
void main()
{
gl_FragColor = colorVarying;
lowp float a = sin(v_pos.x * 10.0);
// a = a * 1.0; // (!!!)
gl_FragColor = vec4(a, 0.0, 0.0, 1.0);
}
Run program on a device and see cool bars on blue cube:
Uncomment the line (a = a * 1.0;) marked by (!!!) and run again:
Well, let me answer my own question.
The problem is in lowp precision qualifier used in shader.
After changing it to mediump shader started to work as expected.

Resources