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
Related
I'm trying to use the shader from this post https://stackoverflow.com/a/27764539/6736544 with a ThreeJS geometry, so far without success.
This is the original shader code from #gman:
<script src="https://webglfundamentals.org/webgl/resources/webgl-utils.js"></script>
<script id="vs" type="foo">
attribute vec4 a_position;
attribute float a_v;
varying float v_v;
void main() {
// PS: In a real WebGL app you'd probably need to multiply a_position by
// a matrix at a minimum
gl_Position = a_position;
v_v = a_v;
}
</script>
<script id="fs" type="foo">
precision mediump float;
varying float v_v;
uniform float u_borderSize;
uniform vec4 u_baseColor;
uniform vec4 u_borderColor;
void main() {
float mixAmount = step(u_borderSize, v_v);
gl_FragColor = mix(u_baseColor,
u_borderColor,
mixAmount);
}
</script>
<canvas id="c" width="256" height="256"></canvas>
This is my attempt:
<script>
var vertexShader = `
varying vec2 vUv;
attribute float alpha;
varying float vAlpha;
attribute vec3 center;
varying vec3 vCenter;
void main() {
vUv = uv;
vAlpha = alpha;
vCenter = center;
gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
}
`;
var fragmentShader = `
//precision mediump float;
uniform vec3 color1;
uniform float color1Alpha;
uniform vec3 borderColor;
uniform float borderThickness;
varying vec2 vUv;
varying float vAlpha;
varying vec3 vCenter;
void main() {
float u_borderSize = borderThickness;
vec4 u_baseColor = vec4(color1, color1Alpha);
vec4 u_borderColor = vec4(borderColor, 1.0);
// This is where I get stuck. No idea how to get a correct 'v_v' value.
float v_v = vUv.y;
float mixAmount = step(u_borderSize, v_v);
gl_FragColor = mix(u_baseColor,
u_borderColor,
mixAmount);
}
`;
</script>
See the jsfiddle here: https://jsfiddle.net/vuqarejz/
This is what I'm trying to achieve:
Questions:
Not sure what I'm missing, nor where the 'v_a' attribute is coming from.
Maybe it is the way UVs are unwrapped?
Maybe this is not the correct shader to use for my purpose?
Solved by tfoller in ThreeJS forum:
https://discourse.threejs.org/t/unwrapping-a-custom-shapebuffergeometry/39565/4
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
I have this vert/frag shader, which is using vertex data and two textures.
I am trying to apply post blur effect, but having only rectangles after it.
vert:
attribute float type;
attribute float size;
attribute float phase;
attribute float increment;
uniform float time;
uniform vec2 resolution;
uniform sampler2D textureA;
uniform sampler2D textureB;
varying float t;
void main() {
t = type;
vec4 mvPosition = modelViewMatrix * vec4(position, 1.0 );
if(t == 0.) {
gl_PointSize = size * 0.8;
} else {
gl_PointSize = size * sin(phase + time * increment) * 12.;
}
gl_Position = projectionMatrix * mvPosition;
}
frag:
uniform float time;
uniform vec2 resolution;
uniform sampler2D textureA;
uniform sampler2D textureB;
varying float t;
uniform sampler2D texture;
vec4 blur2D(sampler2D image, vec2 uv, vec2 resolution, vec2 direction) {
vec4 color = vec4(0.0);
vec2 off1 = vec2(1.3846153846) * direction;
vec2 off2 = vec2(3.2307692308) * direction;
color += texture2D(image, uv) * 0.2270270270;
color += texture2D(image, uv + (off1 / resolution)) * 0.3162162162;
color += texture2D(image, uv - (off1 / resolution)) * 0.3162162162;
color += texture2D(image, uv + (off2 / resolution)) * 0.0702702703;
color += texture2D(image, uv - (off2 / resolution)) * 0.0702702703;
return color;
}
void main() {
vec2 direction = vec2(1., 0.);
vec2 uv = vec2(gl_FragCoord.xy / resolution.xy);
gl_FragColor = vec4(vec3(1.0, 1.0, 1.0), 1.);
if(t == 0.){
gl_FragColor = gl_FragColor * texture2D(textureA, gl_PointCoord);
} else {
gl_FragColor = gl_FragColor * texture2D(textureB, gl_PointCoord);
}
gl_FragColor = blur2D(texture, uv, resolution.xy, direction);
}
How could I 'bake' everything before applying blurring to texture2D/sampler2D?
Maybe I need to create another blur shader and pass texture2D to it?
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?
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?