I'm trying to rotate an image in webgl. If the texture has the same width as height there is no problem, but if width is for example 256px and height only 32px the image gets skewed.
It seems as if only the texture is rotating and not the vertices. However usually when only the texture is rotating it's corners gets clipped as they move outside the vertices. That doesn't happen here so I'm a bit confused.
Here is my vertex shader code:
precision lowp float;
attribute vec3 vertPosition;
attribute vec3 vertColor;
attribute vec2 aTextureCoord;
varying vec3 fragColor;
varying lowp vec2 vTextureCoord;
varying lowp vec2 vTextureCoordBg;
uniform vec2 uvOffsetBg;
uniform vec2 uvScaleBg;
uniform mat4 uPMatrix;
uniform vec2 uvOffset;
uniform vec2 uvScale;
uniform vec3 translation;
uniform vec3 scale;
uniform float rotateZ;
uniform vec2 vertPosFixAfterRotate;
void main()
{
fragColor = vertColor;
vTextureCoord = (vec4(aTextureCoord.x, aTextureCoord.y, 0, 1)).xy * uvScale + uvOffset;
vTextureCoordBg = (vec4(aTextureCoord, 0, 1)).xy * uvScaleBg + uvOffsetBg;
mat4 worldPosTrans = mat4(
vec4(scale.x*cos(rotateZ), scale.y*-sin(rotateZ), 0, 0),
vec4(scale.x*sin(rotateZ), scale.y*cos(rotateZ), 0, 0),
vec4(0, 0, scale.z, 0),
vec4(translation.x, translation.y, translation.z, 1));
gl_Position = (uPMatrix * worldPosTrans) * vec4(vertPosition.x + vertPosFixAfterRotate.x, vertPosition.y + vertPosFixAfterRotate.y, vertPosition.z, 1.0);
}
The rotation is sent from javascript to the shader through the rotateZ uniform.
You have to do the scaling before the rotation:
Scale matrix:
mat4 sm = mat4(
vec4(scale.x, 0.0, 0.0, 0.0),
vec4(0.0, scale.y, 0.0, 0.0),
vec4(0.0, 0.0, scale.z, 0.0),
vec4(0.0, 0.0, 0.0, 1.0));
Rotation matrix:
mat4 rm = mat4(
vec4(cos(rotateZ), -sin(rotateZ), 0.0, 0.0),
vec4(sin(rotateZ), cos(rotateZ), 0.0, 0.0),
vec4(0.0, 0.0, 1.0, 0.0),
vec4(0.0, 0.0, 0.0, 1.0));
Translation matrix:
mat4 tm = mat4(
vec4(1.0, 0.0, 0.0, 0.0),
vec4(0.0, 1.0, 0.0, 0.0),
vec4(0.0, 0.0, 0.0, 0.0),
vec4(translation.x, translation.y, translation.z, 1.0));
Model transformtion:
mat4 worldPosTrans = tm * rm * sm;
See the result and focus on scale.x and scale.y, in compare to the code snippet in your question:
mat4 worldPosTrans = mat4(
vec4(scale.x * cos(rotateZ), scale.x * -sin(rotateZ), 0.0, 0.0),
vec4(scale.y * sin(rotateZ), scale.y * cos(rotateZ), 0.0, 0.0),
vec4(0.0, 0.0, scale.z, 0.0),
vec4(translation.x, translation.y, translation.z, 1.0));
Related
When i use TbloomEffect and TgloomEffect (Delphi component) under android/iOS (so with openGL) then it's produce only black & white output :( under windows (DX11) then it's work ok. I guess it's a bug in the delphi source code but i can't find what wrong in the original GLSL code below I extracted from the original delphi source:
TgloomEffect use :
varying vec4 TEX0;
vec4 _ret_0;
vec3 _TMP4;
float _TMP3;
vec3 _x0014;
vec3 _TMP15;
float _grey0022;
float _grey0028;
vec3 _TMP35;
uniform float _GloomIntensity;
uniform float _BaseIntensity;
uniform float _GloomSaturation;
uniform float _BaseSaturation;
uniform sampler2D _Input;
void main()
{
vec4 _color1;
vec3 _base;
vec3 _gloom;
vec3 _TMP10;
_color1 = texture2D(_Input, TEX0.xy);
_base = 1.0 - _color1.xyz/_color1.w;
_x0014 = (_base - 2.50000000E-001)/7.50000000E-001;
_TMP4 = min(vec3( 1.0, 1.0, 1.0), _x0014);
_TMP15 = max(vec3( 0.0, 0.0, 0.0), _TMP4);
_grey0022 = dot(_TMP15, vec3( 3.00000012E-001, 5.89999974E-001, 1.09999999E-001));
_TMP3 = _grey0022 + _GloomSaturation*(_TMP15.x - _grey0022);
_gloom = vec3(_TMP3, _TMP3, _TMP3)*_GloomIntensity;
_grey0028 = dot(_base, vec3( 3.00000012E-001, 5.89999974E-001, 1.09999999E-001));
_TMP3 = _grey0028 + _BaseSaturation*(_base.x - _grey0028);
_base = vec3(_TMP3, _TMP3, _TMP3)*_BaseIntensity;
_TMP4 = min(vec3( 1.0, 1.0, 1.0), _gloom);
_TMP35 = max(vec3( 0.0, 0.0, 0.0), _TMP4);
_base = _base*(1.0 - _TMP35);
_TMP10 = (1.0 - (_base + _gloom))*_color1.w;
_ret_0 = vec4(_TMP10.x, _TMP10.y, _TMP10.z, _color1.w);
gl_FragColor = _ret_0;
return;
}
and TBloomEffect use :
varying vec4 TEX0;
vec4 _ret_0;
vec3 _TMP5;
float _TMP4;
vec3 _TMP3;
vec3 _TMP14;
vec3 _x0015;
float _grey0021;
float _grey0027;
vec3 _TMP34;
uniform float _BloomIntensity;
uniform float _BaseIntensity;
uniform float _BloomSaturation;
uniform float _BaseSaturation;
uniform sampler2D _Input;
void main()
{
vec4 _color1;
vec3 _base;
vec3 _bloom;
vec3 _TMP11;
_color1 = texture2D(_Input, TEX0.xy);
_base = _color1.xyz/_color1.w;
_x0015 = (_base - 2.50000000E-001)/7.50000000E-001;
_TMP3 = min(vec3( 1.0, 1.0, 1.0), _x0015);
_TMP14 = max(vec3( 0.0, 0.0, 0.0), _TMP3);
_grey0021 = dot(_TMP14, vec3( 3.00000012E-001, 5.89999974E-001, 1.09999999E-001));
_TMP4 = _grey0021 + _BloomSaturation*(_TMP14.x - _grey0021);
_bloom = vec3(_TMP4, _TMP4, _TMP4)*_BloomIntensity;
_grey0027 = dot(_base, vec3( 3.00000012E-001, 5.89999974E-001, 1.09999999E-001));
_TMP4 = _grey0027 + _BaseSaturation*(_base.x - _grey0027);
_base = vec3(_TMP4, _TMP4, _TMP4)*_BaseIntensity;
_TMP5 = min(vec3( 1.0, 1.0, 1.0), _bloom);
_TMP34 = max(vec3( 0.0, 0.0, 0.0), _TMP5);
_base = _base*(1.0 - _TMP34);
_TMP11 = (_base + _bloom)*_color1.w;
_ret_0 = vec4(_TMP11.x, _TMP11.y, _TMP11.z, _color1.w);
gl_FragColor = _ret_0;
return;
}
What wrong in those 2 GLSL codes that make output only in black & white ?
because of a bug in delphi ...
good code is :
varying vec4 TEX0;
vec4 _ret_0;
vec3 _TMP4;
vec3 _TMP3;
vec3 _x0014;
vec3 _TMP15;
float _grey0022;
float _grey0028;
vec3 _TMP35;
uniform float _GloomIntensity;
uniform float _BaseIntensity;
uniform float _GloomSaturation;
uniform float _BaseSaturation;
uniform sampler2D _Input;
void main()
{
vec4 _color1;
vec3 _base;
vec3 _gloom;
vec3 _TMP10;
_color1 = texture2D(_Input, TEX0.xy);
_base = 1.0 - _color1.xyz/_color1.w;
_x0014 = (_base - 0.25)/0.75;
_TMP4 = min(vec3( 1.0, 1.0, 1.0), _x0014);
_TMP15 = max(vec3( 0.0, 0.0, 0.0), _TMP4);
_grey0022 = dot(_TMP15, vec3( 0.3, 0.59, 0.11));
_TMP3 = vec3(_grey0022, _grey0022, _grey0022) + _GloomSaturation*(_TMP15 - vec3(_grey0022, _grey0022, _grey0022));
_gloom = _TMP3*_GloomIntensity;
_grey0028 = dot(_base, vec3( 0.3, 0.59, 0.11));
_TMP3 = vec3(_grey0028, _grey0028, _grey0028) + _BaseSaturation*(_base - vec3(_grey0028, _grey0028, _grey0028));
_base = _TMP3*_BaseIntensity;
_TMP4 = min(vec3( 1.0, 1.0, 1.0), _gloom);
_TMP35 = max(vec3( 0.0, 0.0, 0.0), _TMP4);
_base = _base*(1.0 - _TMP35);
_TMP10 = (1.0 - (_base + _gloom))*_color1.w;
_ret_0 = vec4(_TMP10.x, _TMP10.y, _TMP10.z, _color1.w);
gl_FragColor = _ret_0;
return;
}
I am trying to create billboard using three.js. I tried using THREE.Sprite however size of sprite changes with distance as I am using perspective projection. I tried to create a plane using custom shaderMaterial with custom shader.
Shader code for scaling billboard
vec4 gl_Position = projectionMatrix * (modelViewMatrix * vec4(0.0, 0.0, 0.0, 1.0) + vec4(position.x, position.y, 0.0, 0.0));'
same for non scaling billboard, which I am trying implement
float distance = length(modelViewMatrix * vec4(0.0, 0.0, 0.0, 1.0));
vec4 newPosition = projectionMatrix * (modelViewMatrix * vec4(0.0, 0.0, 0.0, 1.0) + vec4(position.x, position.y, 0.0, 0.0));
gl_Position= newPosition*distance;
Unfortunately there is no changes in the output. Its still scaled billboard. Any suggestion that might fix the problem?
This problem is cocos2d-x related since I am using cocos2d-x as game engine but I can think it can be solved use basic opengl shader knowledge.
Part 1:
. I have a canvas size of 800 * 600
. I try to draw a simple colored square in size of 96 * 96 which is placed in the middle of the canvas
It is quite simple, the draw part code :
var boundingBox = this.getBoundingBox();
var squareVertexPositionBuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, squareVertexPositionBuffer);
var vertices = [
boundingBox.width, boundingBox.height,
0, boundingBox.height,
boundingBox.width, 0,
0, 0
];
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertices), gl.STATIC_DRAW);
gl.bindBuffer(gl.ARRAY_BUFFER, null);
gl.enableVertexAttribArray(cc.VERTEX_ATTRIB_POSITION);
gl.bindBuffer(gl.ARRAY_BUFFER, squareVertexPositionBuffer);
gl.vertexAttribPointer(cc.VERTEX_ATTRIB_POSITION, 2, gl.FLOAT, false, 0, 0);
gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4);
gl.bindBuffer(gl.ARRAY_BUFFER, null);
And the vert shader:
attribute vec4 a_position;
void main()
{
gl_Position = CC_PMatrix * CC_MVMatrix * a_position;
}
And the frag shader:
#ifdef GL_ES
precision highp float;
#endif
uniform vec2 center;
uniform vec2 resolution;
uniform float rotation;
void main()
{
vec4 RED = vec4(1.0, 0.0, 0.0, 1.0);
vec4 GREEN = vec4(0.0, 1.0, 0.0, 1.0);
gl_FragColor = GREEN;
}
And everything works fine :
The grid line is size of 32 * 32, and the black dot indicates the center of the canvas.
Part 2:
. I try to separate the square into half (vertically)
. The left part is green and the right part is red
I changed the frag shader to get it done :
void main()
{
vec4 RED = vec4(1.0, 0.0, 0.0, 1.0);
vec4 GREEN = vec4(0.0, 1.0, 0.0, 1.0);
/*
x => [0, 1]
y => [0, 1]
*/
vec2 UV = (rotatedFragCoord.xy - center.xy + resolution.xy / 2.0) / resolution.xy;
/*
x => [-1, 1]
y => [-1, 1]
*/
vec2 POS = -1.0 + 2.0 * UV;
if (POS.x <= 0.0) {
gl_FragColor = GREEN;
}
else {
gl_FragColor = RED;
}
}
The uniform 'center' is the position of the square so it is 400, 300 in this case.
The uniform 'resolution' is the content size of the square so the value is 96, 96.
The result is fine :
Part 3:
. I try to change the rotation in cocos2dx style
myShaderNode.setRotation(45);
And the square is rotated but the content is not :
So I tried to rotate the content according to the rotation angle of the node.
I changed the frag shader again:
void main()
{
vec4 RED = vec4(1.0, 0.0, 0.0, 1.0);
vec4 GREEN = vec4(0.0, 1.0, 0.0, 1.0);
vec2 rotatedFragCoord = gl_FragCoord.xy - center.xy;
float cosa = cos(rotation);
float sina = sin(rotation);
float t = rotatedFragCoord.x;
rotatedFragCoord.x = t * cosa - rotatedFragCoord.y * sina + center.x;
rotatedFragCoord.y = t * sina + rotatedFragCoord.y * cosa + center.y;
/*
x => [0, 1]
y => [0, 1]
*/
vec2 UV = (rotatedFragCoord.xy - center.xy + resolution.xy / 2.0) / resolution.xy;
/*
x => [-1, 1]
y => [-1, 1]
*/
vec2 POS = -1.0 + 2.0 * UV;
if (POS.x <= 0.0) {
gl_FragColor = GREEN;
}
else {
gl_FragColor = RED;
}
}
The uniform rotation is the angle the node rotated so in this case it is 45.
The result is close to what I want but still not right:
I tried hard but just can not figure out what is wrong in my code and what's more if there is anyway easier to get things done.
I am quite new to shader programming and any advice will be appreciated, thanks :)
Can we have vert shader without attributes?
#version 300 es
out mediump vec4 basecolor;
uniform ivec2 x1;
void main(void)
{
if(x1 == ivec2(10,20))
basecolor = vec4(0.0, 1.0, 0.0, 1.0);
else
basecolor = vec4(1.0, 0.0, 1.0, 1.0);
gl_PointSize = 64.0;
gl_Position = vec4(0.0, 0.0, 0.0, 1.0);
}
#version 300 es
in mediump vec4 basecolor;
out vec4 FragColor;
void main(void)
{
FragColor = basecolor;
}
Technically there is nothing in the specification that actually requires you to have vertex attributes. But by the same token, in OpenGL ES 3.0 you have two intrinsically defined in attributes whether you want them or not:
The built-in vertex shader variables for communicating with fixed functionality are intrinsically declared as follows in the vertex language:
in highp int gl_VertexID;
in highp int gl_InstanceID;
This is really the only time it actually makes sense not to have any attributes. You can dynamically compute the position based on gl_VertexID, gl_InstanceID or some combination of both, which is a major change from OpenGL ES 2.0.
I want to write a shader that creates a reflection of an image similiar to the ones used for coverflows.
// Vertex Shader
uniform highp mat4 u_modelViewMatrix;
uniform highp mat4 u_projectionMatrix;
attribute highp vec4 a_position;
attribute lowp vec4 a_color;
attribute highp vec2 a_texcoord;
varying lowp vec4 v_color;
varying highp vec2 v_texCoord;
mat4 rot = mat4( -1.0, 0.0, 0.0, 0.0,
0.0, -1.0, 0.0, 0.0,
0.0, 0.0, 1.0, 0.0,
0.0, 0.0, 0.0, 1.0 );
void main()
{
gl_Position = (u_projectionMatrix * u_modelViewMatrix) * a_position * rot;
v_color = a_color;
v_texCoord = a_texcoord;
}
// Fragment Shader
varying highp vec2 v_texCoord;
uniform sampler2D u_texture0;
uniform int slices;
void main()
{
lowp vec3 w = vec3(1.0,1.0,1.0);
lowp vec3 b = vec3(0.0,0.0,0.0);
lowp vec3 mix = mix(b, w, (v_texCoord.y-(float(slices)/10.0)));
gl_FragColor = texture2D(u_texture0,v_texCoord) * vec4(mix, 1.0);
}
But this shader is creating the following:
current result
And I dont know how to "flip" the image horizontally and I tried so many different parameters in the rotation matrix (I even tried to use a so called "mirror matrix") but I dont know how to reflect the image on the bottom of original image.
If you're talking about what images.google.com returns for "coverflow" result, then you don't need rotation matrix at all.
void main()
{
gl_Position = (u_projectionMatrix * u_modelViewMatrix) * a_position;
v_color = a_color;
v_texCoord = vec2(a_texcoord.x, 1.0 - a_texcoord.y);
}
Simply flip it vertically.
If you insist on using matrix and want to make a "mirror" shader (the one that takes it object, and puts it under "floor" to make reflection) then you need mirror matrix (don't forget to adjust frontface/backface culling):
mat4(1.0, 0.0, 0.0, 0.0,
0.0, -1.0, 0.0, 0.0,
0.0, 0.0, 1.0, 0.0,
0.0, 0.0, 0.0, 1.0 );
AND you must know where the floor is.
gl_Position = (u_projectionMatrix * u_modelViewMatrix) * (a_position * mirrorMatrix - floor);
Alternatively you could put floor translation into same matrix. Basically, to mirror against arbitrary height, you need to combine three transforms (pseudocode).
translate(0, -floorHeight, 0) * scale(1, -1, 1) * translate(0, floorHeight, 0).
and put them into your matrix.
Also it might make sense to split modelView matrix into "model"(object/world) and "view" matrices. This way it'll be easier to perform transformations like these.