Rotating, moving and Scaling a mask in shader - opengl-es

I want to move (or other action) a mask in shader.But I have no clue to how perform these action in shader.
My code:
#Override
public void create() {
batch = new SpriteBatch();
background = new Texture(Gdx.files.internal("images/background.png"));
spritebackgournd = new Sprite(background,Gdx.graphics.getWidth(),Gdx.graphics.getHeight());
foreground = new Texture(Gdx.files.internal("images/foreground.png"));
mask = new Texture(Gdx.files.internal("images/mask.png"));
spriteforegournd = new Sprite(foreground,Gdx.graphics.getWidth(),Gdx.graphics.getHeight());
shader = new ShaderProgram(Gdx.files.internal("shaders/shader1.vert"), Gdx.files.internal("shaders/shader1.frag"));
}
#Override
public void render() {
batch.begin();
spritebackgournd.draw(batch);
batch.setShader(shader);
Gdx.graphics.getGL20().glActiveTexture(GL20.GL_TEXTURE0);
spriteforegournd.getTexture().bind(0);
//texture.bind(0);
shader.setUniformi("u_texture", 0);
Gdx.graphics.getGL20().glActiveTexture(GL20.GL_TEXTURE1);
//spritemask.getTexture().bind(1);
mask.bind(1);
shader.setUniformi("u_mask", 1);
Gdx.graphics.getGL20().glActiveTexture(GL20.GL_TEXTURE0);
spriteforegournd.draw(batch);
batch.end();
batch.setShader(null);
}
The vertex shader:
attribute vec4 a_position;
attribute vec4 a_color;
attribute vec2 a_texCoord0;
uniform mat4 u_projTrans;
varying vec2 v_texCoords;
void main() {
v_texCoords = a_texCoord0;
gl_Position = u_projTrans * a_position;
}
The fragment shader:
varying vec2 v_texCoords;
uniform sampler2D u_texture;
uniform sampler2D u_mask;
uniform mat4 u_projTrans;
void main() {
vec4 texColor = texture2D(u_texture, v_texCoords);
vec4 maskColor = texture2D(u_mask, v_texCoords);
gl_FragColor = texColor * maskColor.a;
}
What I would like to be able to scale, rotate and move the mask in shader.How can i do this?

Related

Incorrect lighting of a bone-animated object on OpenGL ES 2.0

I imported a simple animated object from Blender on three bones. I have a problem with lighting of skinning object. I set a light position above the object:
const vec3 lightPosition = vec3(0.0, 15.0, 0.0);
You can see that lighting is affected under object too:
precision mediump float;
attribute vec3 aPosition;
attribute vec4 aNormal;
attribute vec2 aTexCoord;
attribute vec3 aJoints;
attribute vec3 aWeights;
uniform mat4 uMvpMatrix;
uniform mat4 uModelMatrix;
uniform mat4 uNormalMatrix;
uniform mat4 uTransforms[3];
varying vec3 vPosition;
varying vec3 vNormal;
varying vec2 vTexCoord;
void main()
{
vec4 totalLocalPos = vec4(0.0);
vec4 totalNormal = vec4(0.0);
for (int i = 0; i < 3; i++)
{
int jointIndex = int(aJoints[i]);
mat4 jointTransform = uTransforms[jointIndex];
vec4 posePosition = jointTransform * vec4(aPosition, 1.0);
totalLocalPos += posePosition * aWeights[i];
vec4 worldNormal = jointTransform * aNormal;
totalNormal += worldNormal * aWeights[i];
}
gl_Position = uMvpMatrix * totalLocalPos;
vPosition = vec3(uModelMatrix * vec4(aPosition, 1.0));
vNormal = totalNormal.xyz;
vTexCoord = aTexCoord;
}
precision mediump float;
const vec3 lightColor = vec3(0.8, 0.8, 0.8);
const vec3 lightPosition = vec3(0.0, 15.0, 0.0);
const vec3 ambientLight = vec3(0.3, 0.3, 0.3);
uniform sampler2D uSampler;
varying vec3 vPosition;
varying vec3 vNormal;
varying vec2 vTexCoord;
void main()
{
vec4 color = texture2D(uSampler, vTexCoord);
vec3 normal = normalize(vNormal);
vec3 lightDirection = normalize(lightPosition - vPosition);
float nDotL = max(dot(lightDirection, normal), 0.0);
vec3 diffuse = lightColor * color.rgb * nDotL;
vec3 ambient = ambientLight * color.rgb;
gl_FragColor = vec4(diffuse + ambient, color.a);
}
Aroch helped me on Russian forum here:
the normal only needs to be rotated.
Now it works as it should. I took shaders (except lighting model) from source for a video tutorial series from ThinMatrix. It works fine for ThinMatrix. This means that for some reason its lighting model is not affected by the translation of the normal vector. It will be necessary to figure out later why he does not have this problem. I made the transfer of the array of rotation matrices a separate uniform:
uniform mat4 uTransforms[3];
uniform mat4 uRotations[3];
...
for (int i = 0; i < 3; i++)
{
int jointIndex = int(aJoints[i]);
mat4 jointTransform = uTransforms[jointIndex];
vec4 posePosition = jointTransform * vec4(aPosition, 1.0);
totalLocalPos += posePosition * aWeights[i];
mat4 rotation = uRotations[jointIndex];
vec4 worldNormal = rotation * aNormal;
totalNormal += worldNormal * aWeights[i];
}
Gif Animation: https://gamedev.ru/files/images/solution-with-lighting.gif

Geometry instancing with one shader but multiple textures

I'd like to add a second crate texture to the shader using the shader/technique provided with this example:
https://threejs.org/examples/#webgl_buffergeometry_instancing_dynamic
I figured I could pass in another uniform to add a second map.
crateMaterial = new THREE.RawShaderMaterial( {
uniforms: {
map: { value: new THREE.TextureLoader().load( './img/textures/crate/crate.gif' ),
map2: { value: new THREE.TextureLoader().load( './img/textures/crate2/crate2.gif' ) }
};
However I'm struggling to figure out how to "tag" specific crates and then use the shader to draw vertices with the correct texture, as my experience and skill with GLSL are quite limited.
Could I just pass in another uniform consisting of (vertex) indices to specify where the shader should apply the second texture? ie:
crateMaterial.uniforms.cratesTexturemap = [];
for(i=0;i<cratesToRender;i++) {
/* set position */
...
this._instancePositions.push( position.x, position.y, position.z );
if (drawCrate2) {
crateMaterial.uniforms.cratesTexturemap.push(i); /* correlates to (vertex) position index */
crateMaterial.uniforms.cratesTexturemap.push(i+1);
crateMaterial.uniforms.cratesTexturemap.push(i+2);
}
...
}
Also performance/memory-wise, is it better to have a (dynamic) array of textures passed to the shader or is passing them one by one (a uniform value for every texture as above) more advantageous?
Example shader code for reference:
<script id="vertexShader" type="x-shader/x-vertex">
precision highp float;
uniform mat4 modelViewMatrix;
uniform mat4 projectionMatrix;
attribute vec3 position;
attribute vec3 offset;
attribute vec2 uv;
attribute vec4 orientation;
varying vec2 vUv;
// http://www.geeks3d.com/20141201/how-to-rotate-a-vertex-by-a-quaternion-in-glsl/
vec3 applyQuaternionToVector( vec4 q, vec3 v ){
return v + 2.0 * cross( q.xyz, cross( q.xyz, v ) + q.w * v );
}
void main() {
vec3 vPosition = applyQuaternionToVector( orientation, position );
vUv = uv;
gl_Position = projectionMatrix * modelViewMatrix * vec4( offset + vPosition, 1.0 );
}
</script>
<script id="fragmentShader" type="x-shader/x-fragment">
precision highp float;
uniform sampler2D map;
varying vec2 vUv;
void main() {
gl_FragColor = texture2D( map, vUv );
}
</script>
Can't you just pass an array of textures and choose which to apply using an index passed by a int uniform?
So for every crate you could do
crate.material.uniforms.index = 2
to choose the 3rd texture in the array

Pass additional N textures to a custom shader in cocos2d

I want to pass N number of texture to a custom shader. As I surfed thru net, the best option I've got is to override the Sprite::draw() function and add a CustomCommand object to the draw pool.
CPP file:
void SpriteSub::draw(Renderer *renderer, const Mat4 &transform, uint32_t flags) {
m_cmdCustom.init(_globalZOrder, transform, flags);
m_cmdCustom.func = CC_CALLBACK_0(SpriteSub::onDraw, this, transform, flags);
renderer->addCommand(&m_cmdCustom);
Sprite::draw(renderer, transform, flags);
}
void SpriteSub::onDraw(const Mat4 &transform, uint32_t /*flags*/) {
this->getGLProgram()->use();
auto wwProgram = m_shader->getProgram();
auto texBall0 = Director::getInstance()->getTextureCache()->addImage("ball.png")->getName();
GLuint locTexIcon0 = glGetUniformLocation(wwProgram, "texBall0");
glUniform1i(locTexIcon0, 0);
//glActiveTexture(GL_TEXTURE0 + 0); glBindTexture(GL_TEXTURE_2D, texBall0);
//glActiveTexture(GL_TEXTURE0 + 0);
GL::bindTexture2D(texBall0);
}
frament shader:
#ifdef GL_ES
precision lowp float;
#endif
varying vec4 v_fragmentColor;
varying vec2 v_texCoord;
uniform sampler2D texBall0;
uniform sampler2D texBall1;
//uniform sampler2D texBall2;
//uniform sampler2D texBall3;
//uniform sampler2D texBall4;
//uniform sampler2D texBall5;
void main()
{
float t = 0.7f;
//gl_FragColor = texture2D(CC_Texture0, v_texCoord);
//this is just a sample code
gl_FragColor = texture2D(texBall0, v_texCoord) * t;
gl_FragColor += texture2D(texBall1, v_texCoord) * (t-1);
//some code that uses the other textures...
}
The shader above is just a sample and not the actual code I'm using. For now, I just need to successfully pass multiple textures in a single shader to process their pixels.
Currently, I can't display the passed texture. What should be done to achieve this? Does Sprite::draw() in SpriteSub::draw() cancel-out the gl commands from onDraw()?
'Solved it!
You don't even need to override the draw or add a CustomCommand to render queue.
Steps:
1.) Create a GLProgramState with the GLProgram object you created with your custom shaders.
2.) Use GLProgramState::setUniformTexture("uniformVarName", tex2D) to locate uniform variable and pass texture name.
3.) Call sprite->setGLProgramState(programState) instead of sprite->setGLProgram(program);
CCP File:
m_shader = GLProgram::createWithByteArrays(ccPositionTextureColor_noMVP_vert, shader_frag);
m_shader->retain();
auto shaderState = GLProgramState::getOrCreateWithGLProgram(m_shader);
auto textureCache = Director::getInstance()->getTextureCache();
auto img0 = textureCache->addImage("icon_tex0.png")->getName();
auto img1 = textureCache->addImage("icon_tex1.png")->getName();
auto img2 = textureCache->addImage("icon_tex2.png")->getName();
auto img3 = textureCache->addImage("icon_tex3.png")->getName();
auto img4 = textureCache->addImage("icon_tex4.png")->getName();
auto img5 = textureCache->addImage("icon_tex5.png")->getName();
shaderState->setUniformTexture("texIcon0", img0);
shaderState->setUniformTexture("texIcon1", img1);
shaderState->setUniformTexture("texIcon2", img2);
shaderState->setUniformTexture("texIcon3", img3);
shaderState->setUniformTexture("texIcon4", img4);
shaderState->setUniformTexture("texIcon5", img5);
//this->setGLProgram(m_shader);
this->setGLProgramState(shaderState);
fragment shader:
#ifdef GL_ES
precision lowp float;
#endif
varying vec4 v_fragmentColor;
varying vec2 v_texCoord;
uniform sampler2D texIcon0;
uniform sampler2D texIcon1;
uniform sampler2D texIcon2;
uniform sampler2D texIcon3;
uniform sampler2D texIcon4;
uniform sampler2D texIcon5;
void main()
{
int numTex = 6;
float fWeight = 1.0f/float(length);
//gl_FragColor = texture2D(CC_Texture0, v_texCoord);
gl_FragColor += texture2D(texIcon0, v_texCoord) * fWeight;
gl_FragColor += texture2D(texIcon1, v_texCoord) * fWeight;
gl_FragColor += texture2D(texIcon2, v_texCoord) * fWeight;
gl_FragColor += texture2D(texIcon3, v_texCoord) * fWeight;
gl_FragColor += texture2D(texIcon4, v_texCoord) * fWeight;
gl_FragColor += texture2D(texIcon5, v_texCoord) * fWeight;
}
sources:
http://discuss.cocos2d-x.org/t/solved-passing-a-variable-to-a-shader/27141/3
http://cocos2d-x.org/docs/programmers-guide/advanced_topics/index.html#customizing-shaders

Shadow artifacts in opengl

I am trying to render an object and two lights, one of the lights cast shadows. Everything works ok but I noticed that there are some obvious artifacts, as shown in the below image, some shadows seem to overflow to bright areas.
Below is the shaders to render depth information into a framebuffer
<script id="shadow-shader-vertex" type="x-shader/x-vertex">
attribute vec4 aVertexPosition;
uniform mat4 uObjMVP;
void main() {
gl_Position = uObjMVP * aVertexPosition;
}
</script>
<script id="shadow-shader-fragment" type="x-shader/x-vertex">
precision mediump float;
void main() {
//pack gl_FragCoord.z
const vec4 bitShift = vec4(1.0, 256.0, 256.0 * 256.0, 256.0 * 256.0 * 256.0);
const vec4 bitMask = vec4(1.0/256.0, 1.0/256.0, 1.0/256.0, 0.0);
vec4 rgbaDepth = fract(gl_FragCoord.z * bitShift);
rgbaDepth -= rgbaDepth.gbaa * bitMask;
gl_FragColor = rgbaDepth;
}
</script>
In the above shaders, uObjMVP is the MVP matrix used when looking from the position of the light that cast shadow (the warm light, the cold light does not cast shadow)
And here are the shaders to draw everything:
<script id="shader-vertex" type="x-shader/x-vertex">
//position of a vertex.
attribute vec4 aVertexPosition;
//vertex normal.
attribute vec3 aNormal;
//mvp matrix
uniform mat4 uObjMVP;
uniform mat3 uNormalMV;
//shadow mvp matrix
uniform mat4 uShadowMVP;
//interplate normals
varying vec3 vNormal;
//for shadow calculation
varying vec4 vShadowPositionFromLight;
void main() {
gl_Position = uObjMVP * aVertexPosition;
//convert normal direction from object space to view space
vNormal = uNormalMV * aNormal;
vShadowPositionFromLight = uShadowMVP * aVertexPosition;
}
</script>
<script id="shader-fragment" type="x-shader/x-fragment">
precision mediump float;
uniform sampler2D uShadowMap;
varying vec3 vNormal;
varying vec4 vShadowPositionFromLight;
struct baseColor {
vec3 ambient;
vec3 diffuse;
};
struct directLight {
vec3 direction;
vec3 color;
};
baseColor mysObjBaseColor = baseColor(
vec3(1.0, 1.0, 1.0),
vec3(1.0, 1.0, 1.0)
);
directLight warmLight = directLight(
normalize(vec3(-83.064, -1.99, -173.467)),
vec3(0.831, 0.976, 0.243)
);
directLight coldLight = directLight(
normalize(vec3(37.889, 47.864, -207.187)),
vec3(0.196, 0.361, 0.608)
);
vec3 ambientLightColor = vec3(0.3, 0.3, 0.3);
float unpackDepth(const in vec4 rgbaDepth) {
const vec4 bitShift = vec4(1.0, 1.0/256.0, 1.0/(256.0*256.0), 1.0/(256.0*256.0*256.0));
float depth = dot(rgbaDepth, bitShift);
return depth;
}
float calVisibility() {
vec3 shadowCoord = (vShadowPositionFromLight.xyz/vShadowPositionFromLight.w)/2.0 + 0.5;
float depth = unpackDepth(texture2D(uShadowMap, shadowCoord.xy));
return (shadowCoord.z > depth + 0.005) ? 0.4 : 1.0;
}
vec3 calAmbientLight(){
return ambientLightColor * mysObjBaseColor.ambient;
}
vec3 calDiffuseLight(const in directLight light, const in float visibility){
vec3 inverseLightDir = light.direction * -1.0;
float dot = max(dot(inverseLightDir, normalize(vNormal)), 0.0);
return light.color * mysObjBaseColor.diffuse * dot * visibility;
}
void main() {
vec3 ambientLight = calAmbientLight();
float visibility = calVisibility();
vec3 warmDiffuseLight = calDiffuseLight(warmLight, visibility);
// cold light does not cast shadow and hence visilibility is always 1.0
vec3 coldDiffuseLight = calDiffuseLight(coldLight, 1.0);
gl_FragColor = vec4(coldDiffuseLight + warmDiffuseLight + ambientLight, 1.0);
}
</script>
If I simply draw the depth information out on to the canvas,
void main() {
// vec3 ambientLight = calAmbientLight();
// float visibility = calVisibility();
// vec3 warmDiffuseLight = calDiffuseLight(warmLight, visibility);
// // cold light does not cast shadow and hence visilibility is always 1.0
// vec3 coldDiffuseLight = calDiffuseLight(coldLight, 1.0);
// gl_FragColor = vec4(coldDiffuseLight + warmDiffuseLight + ambientLight, 1.0);
vec3 shadowCoord = (vShadowPositionFromLight.xyz/vShadowPositionFromLight.w)/2.0 + 0.5;
gl_FragColor = vec4(unpackDepth(texture2D(uShadowMap, shadowCoord.xy)), 0.0, 0.0, 1.0);
}
I would get this image
Thanks in advance.

opengles 2.0 per-vertex lighting

VertexShader:
varying vec4 diffuseColor;
uniform mat4 modelViewProj;
uniform mat4 modelViewTranspose;
attribute vec3 streamNormal;
attribute vec3 streamPosition;
void main() {
gl_Position = modelViewProj * streamPosition;
diffuseColor = max(0, dot(normalize(modelViewTranspose * streamNormal), vec3(0,0,1)) * vec4(1,0,0,1);
}
PixelShader:
varying vec4 diffuseColor;
void main() {
gl_FragColor = diffuseColor;
}
the matrix is by left-hand (row major), modelViewProj calculated by C++, it is the world * view * projection, modelViewTranspose = transpose(inverse(world * view)).
The render result is not right, I cannot see any thing, but if I set gl_FragColor always to vec4(1,1,1,1), the model render is no problem. Does my code have errors? or other problems?

Resources