Hello !
I'm trying to apply a custom shader on a textured plane.
I want to add custom attributes that represent the position (XYZ) , the rotation (XYZ) and the scale (XYZ) and apply the transformation inside the vertexShader.
I maybe wrong but I suppose that pushMatrix method create a new Matrix3D instance , so it means one Matrix by DisplayObject and a very complex calcul for each (easy to use but deeply complex inside). It's actually possible to do not use matrix operation at all, and replace it by a few simple operations , and that's exactly what I want to do , but it doesn't work in my processing code (it works well in other languages)
My code is strongly inspired from this very old Flash-5 code that you can find here
The interesting function is here
- var sx = Math.sin(axisRotations.x);
- var cx = Math.cos(axisRotations.x);
- var sy = Math.sin(axisRotations.y);
- var cy = Math.cos(axisRotations.y);
- var sz = Math.sin(axisRotations.z);
- var cz = Math.cos(axisRotations.z);
- // rotation around x
- xy = cx*y - sx*z;
- xz = sx*y + cx*z;
- // rotation around y
- yz = cy*xz - sy*x;
- yx = sy*xz + cy*x;
- // rotation around z
- zx = cz*yx - sz*xy;
- zy = sz*yx + cz*xy;
- scaleFactor = focalLength/(focalLength + yz);
- x = zx*scaleFactor;
- y = zy*scaleFactor;
- z = yz;
This code apply a rotationX,rotationY,rotationZ on a point.
Scale operation are only multiplications, translation are additions ; so it's all we need to create the transformation without a matrix object.
Scale and translation can be applyed after this calculation
- projmodelviewMatrix * inVertex
and it works without problem.
But the rotations must be applyed on the vertex before using the projection, and the results are very weird.
If all rotations are set to zero, there is no problem ; if not, it work a little bit but it's like other calculations were applyed before and the transformations are wrong.
Here is the whole code (sorry for the very long post, I know it's not a pleasure to read it...)
- import java.nio.*;
- PImage img;
- PShader testShader;
- PGL pgl;
- float[] scaleXYZ;
- float[] positionXYZ;
- float[] rotationXYZ;
- float[] colors;
- FloatBuffer scaleData;
- FloatBuffer positionData;
- FloatBuffer rotationData;
- FloatBuffer colorData;
- int scaleLoc;
- int positionLoc;
- int rotationLoc;
- int colorLoc;
- void setup() {
- size(640, 640, P3D);
- img = loadImage("Desert.jpg");
- testShader = loadShader("fragment.glsl","vertex.glsl");
- int i;
- scaleXYZ = new float[12];
- scaleXYZ[0] = scaleXYZ[3] = scaleXYZ[6] = scaleXYZ[9] = 200;
- scaleXYZ[1] = scaleXYZ[4] = scaleXYZ[7] = scaleXYZ[10] = 200;
- scaleXYZ[2] = scaleXYZ[5] = scaleXYZ[8] = scaleXYZ[11] = 1;
- positionXYZ = new float[12];
- positionXYZ[0] = positionXYZ[3] = positionXYZ[6] = positionXYZ[9] = 0;
- positionXYZ[1] = positionXYZ[4] = positionXYZ[7] = positionXYZ[10] = 0;
- positionXYZ[2] = positionXYZ[5] = positionXYZ[8] = positionXYZ[11] = 0;
- rotationXYZ = new float[12];
- rotationXYZ[0] = rotationXYZ[3] = rotationXYZ[6] = rotationXYZ[9] = 0;
- rotationXYZ[1] = rotationXYZ[4] = rotationXYZ[7] = rotationXYZ[10] = 0;
- rotationXYZ[2] = rotationXYZ[5] = rotationXYZ[8] = rotationXYZ[11] = 0;
- colors = new float[16];
- colors[0] = colors[4] = colors[8] = colors[12] = 1;
- colors[1] = colors[5] = colors[9] = colors[13] = 0;
- colors[2] = colors[6] = colors[10] = colors[14] = 0;
- colors[3] = colors[7] = colors[11] = colors[15] = 1;
- scaleData = allocateDirectFloatBuffer(12);
- scaleData.put(scaleXYZ);
- scaleData.position(0);
- positionData = allocateDirectFloatBuffer(12);
- positionData.put(positionXYZ);
- positionData.position(0);
- rotationData = allocateDirectFloatBuffer(12);
- rotationData.put(rotationXYZ);
- rotationData.position(0);
- colorData = allocateDirectFloatBuffer(16);
- colorData.put(colors);
- colorData.position(0);
- noStroke();
- }
- void draw() {
- background(0);
- translate(width / 2, height / 2);
- rotateY(map(mouseX, 0, width, -PI, PI));
- //rotateZ(PI/6);
- pgl = beginPGL();
- scaleLoc = pgl.getAttribLocation(testShader.glProgram, "inScale");
- pgl.enableVertexAttribArray(scaleLoc);
- pgl.vertexAttribPointer(scaleLoc, 3, PGL.FLOAT, false, 0, scaleData);
- positionLoc = pgl.getAttribLocation(testShader.glProgram, "inPosition");
- pgl.enableVertexAttribArray(positionLoc);
- pgl.vertexAttribPointer(positionLoc, 3, PGL.FLOAT, false, 0, positionData);
- rotationLoc = pgl.getAttribLocation(testShader.glProgram, "inRotation");
- pgl.enableVertexAttribArray(rotationLoc);
- pgl.vertexAttribPointer(rotationLoc, 3, PGL.FLOAT, false, 0, rotationData);
- colorLoc = pgl.getAttribLocation(testShader.glProgram, "inColour");
- pgl.enableVertexAttribArray(colorLoc);
- pgl.vertexAttribPointer(colorLoc, 4, PGL.FLOAT, false, 0, colorData);
- endPGL();
- shader(testShader);
- beginShape();
- texture(img);
- vertex(-0.5, -0.5, 0, 0, 0);
- vertex(0.5, -0.5, 0, img.width, 0);
- vertex(0.5, 0.5, 0, img.width, img.height);
- vertex(-0.5, 0.5, 0, 0, img.height);
- endShape();
- resetShader();
- }
- FloatBuffer allocateDirectFloatBuffer(int n) {
- return ByteBuffer.allocateDirect(n * Float.SIZE/8).order(ByteOrder.nativeOrder()).asFloatBuffer();
- }
Here is the VertexShader
- uniform mat4 projmodelviewMatrix;
- //custom attributes
- attribute vec3 inScale;
- attribute vec3 inPosition;
- attribute vec3 inRotation;
- attribute vec4 inColour; //inColor cannot be overrided (it always a white color)
- //so I renamed it 'colour' for the test.
- attribute vec4 inVertex;
- attribute vec2 inTexcoord;
- varying vec2 vertTexcoord;
- varying vec4 vertColor;
- void main() {
- vec4 pos = projmodelviewMatrix * inVertex;
- float cx = cos(inRotation.x);
- float cy = cos(inRotation.y);
- float cz = cos(inRotation.z);
- float sx = sin(inRotation.x);
- float sy = sin(inRotation.y);
- float sz = sin(inRotation.z);
- pos = inVertex;
- float xy = cx*pos.y - sx*pos.z;
- float xz = sx*pos.y + cx*pos.z;
- float yz = cy*xz - sy*pos.x;
- float yx = sy*xz + cy*pos.x;
- float zx = cz*yx - sz*xy;
- float zy = sz*yx + cz*xy;
- vec4 position = vec4(zx,zy,yz,1);
- // Vertex in clip coordinates
- pos = projmodelviewMatrix * position;
- pos.xyz *= inScale.xyz;
- pos.xyz += inPosition.xyz;
- gl_Position = pos;
- vertTexcoord = inTexcoord;
- vertColor = inColour;
- }
And the FragmentShader
- #ifdef GL_ES
- precision mediump float;
- precision mediump int;
- #endif
- uniform sampler2D textureSampler;
- varying vec2 vertTexcoord;
- varying vec4 vertColor;
- void main() {
- vec4 texture = texture2D(textureSampler, vertTexcoord);
- texture.xyz *= vertColor.xyz;
- gl_FragColor = texture;
- }
Thanks you for your help !