I have a really simple pixel shader:
float4 PixelShaderFunction(float2 uv : TEXCOORD0) : COLOR0
{
return float4(0, 1, 0, 1);
}
technique Technique1
{
pass Pass1
{
PixelShader = compile ps_3_0 PixelShaderFunction();
}
}
I have a texture:
Vector4[] textureData = new Vector4[width * height];
for (int y = 0; y < height; y++)
{
for (int x = 0; x < width; x++)
{
textureData[y * width + x] = new Vector4(1, 0, 0, 1);
}
}
myTexture = new Texture2D(GraphicsDevice, width, height, false, SurfaceFormat.Vector4);
myTexture.SetData(textureData);
and I draw it with this code:
spriteBatch.Begin(SpriteSortMode.Texture,
BlendState.Additive,
SamplerState.PointWrap,
DepthStencilState.DepthRead,
RasterizerState.CullNone);
myEffect.CurrentTechnique.Passes[0].Apply();
spriteBatch.Draw(myTexture, new Rectangle(0, 0, width, height), Color.White);
spriteBatch.End();
I would have figured that by calling .Apply() on the pixel shader that the subsequent spriteBatch.Draw() call would have sent myTexure through my pixel shader. Since the pixel shader function always returns float4(0, 1, 0, 1) I expected the result to have been a green square, but instead it renders a red one, as if the pixel shader is not touching it.
What am I missing?
You're never actually calling Begin() on your shader, so it will still be using the default shader.
Also, there is a cleaner way of doing it now. You can pass your effect as a parameter to the SpriteBatch begin call, as detailed here.
Looks like I just needed to change SpriteSortMode to Immediate and change the pixel shader version from 3 to 2
Related
Some time ago, I coded a little fidgetable logo based on CSS transforms alone.
You can fiddle with it over https://document.paris/
The result feels nice, it feels natural to click/touch and drag to rotate the logo.
I remember banging my head against the walls until I found out that I could chain CSS transforms quite easily just by chaining them.
transform: matrix3d(currentMatrix) rotate3d(x, y, z, angle);
And most importantly to get the currentMatrix I would simply do m = $('#logobackground').css('transform'); with jQuery, the browser would magically return the computed matrix instead of the raw "css" which actually avoided me to deal with matrices or to infinitely stack rotate3D() properties.
So the hardest part was then to calculate the rotate3D arguments (x, y, z, angle) based on mouse inputs. In theory shouldn't have problems transposing this part to java so i'll just skip over it.
Now
I'm trying to do the exact same thing with Processing and there is two problems :
There is no rotate3D() in processing.
There is no browser to apply/chain transformations and return me the current matrix state automatically.
Here's the plan/implementation I'm working on :
I need a "currentMatrix" to apply every frame to the scene
PMatrix3D currentMatrix = new PMatrix3D();
In the setup() I set it to the "identity matrix" which from what I understand is equivalent to "no transformation".
// set currentMatrix to identity Matrix
currentMatrix.set(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1);
Every frame I would calculate a transformation matrix and apply it to the currentMatrix.
Then I would apply this matrix to the scene.
// Apply Matrix to the currentMatrix
void mouseRotate() {
float diag = sqrt(pow(width,2)+pow(height,2));
float x = deltaX()/ diag * 10; // deltaX = difference between previous prevous MouseX and current mouseX)
float y = deltaY()/ diag * 10; // deltaY = same with Y axis
float angle = sqrt( pow(x, 2) + pow(y, 2) );
currentMatrix.apply( rotate3D(y,x,0,angle) );
}
// Apply Matrix to the scene
applyMatrix(currentMatrix);
PMatrix3D reference : https://processing.github.io/processing-javadocs/core/processing/core/PMatrix3D.html
ApplyMatrix() reference : https://processing.org/reference/applyMatrix_.html
All I need to do then is to implement the rotate3D css transform as a function which returns a transformation matrix.
Based on what I found on this page https://developer.mozilla.org/en-US/docs/Web/CSS/transform-function/rotate3d()
I implemented this first function :
PMatrix3D rotate3D(float x, float y, float z, float a) {
PMatrix3D rotationMatrix = new PMatrix3D();
rotationMatrix.set(
1+(1-cos(a))*(pow(x,2)-1), z*sin(a)+x*y*(1-cos(a)), -y*sin(a)+x*z*(1-cos(a)), 0,
-z*sin(a)+x*y*(1-cos(a)), 1+(1-cos(a))*(pow(y,2)-1), x*sin(a)+y*z*(1-cos(a)), 0,
y*sin(a)+x*z*(1-cos(a)), -x*sin(a)+y*z*(1-cos(a)), 1+(1-cos(a))*(pow(z,2)-1), 0,
0,0,0,1
);
return rotationMatrix;
}
and based on what I found on this page https://drafts.csswg.org/css-transforms-2/#Rotate3dDefined
I implemented this other function :
PMatrix3D rotate3Dbis(float getX, float getY, float getZ, float getA) {
float sc = sin(getA/2)*cos(getA/2);
float sq = pow(sin(getA/2),2);
float normalizer = sqrt( pow(getX,2) + pow(getY,2) + pow(getZ,2) );
float x = getX/normalizer;
float y = getY/normalizer;
float z = getZ/normalizer;
PMatrix3D rotationMatrix = new PMatrix3D();
rotationMatrix.set(
1-2*(pow(y,2)+pow(z,2))*sq, 2*(x*y*sq-z*sc), 2*(x*z*sq+y*sc), 0,
2*(x*y*sq+z*sc), 1-2*(pow(x,2)+pow(z,2))*sq, 2*(y*z*sq-x*sc), 0,
2*(x*z*sq-y*sc), 2*(y*z*sq+x*sc), 1-2*(pow(x,2)+pow(y,2)*sq), 0,
0, 0, 0, 1
);
return rotationMatrix;
}
When testing, they don't produce exactly the same result with the same inputs (although the differences are kind of "symmetric" which makes me think that they are kind of equivalent at least in some way ?) Also rotate3Dbis() has a tendency to produce NaN numbers, especially when i'm not moving the mouse (x & y = 0).
But most importantly, in the end it doesn't work. Instead of rotating, the drawing just zooms out progressively when I'm using rotate3D(), and rotate3Dbis() doesn't render correctly because of the NaNs.
The overall question :
I'm trying to get guidance from people who understand transformations Matrices and trying to narrow down where the issue is. Are my processing/java implementations of rotate3D() flawed ? Or would the issue come from somewhere else ? And are my rotate3D() and rotate3Dbis functions equivalent ?
You might get away with simply rotating on X and Y axis, as you already mentioned, using the previous and current mouse coordinates:
PVector cameraRotation = new PVector(0, 0);
void setup(){
size(900, 900, P3D);
rectMode(CENTER);
strokeWeight(9);
strokeJoin(MITER);
}
void draw(){
//update "camera" rotation
if (mousePressed){
cameraRotation.x += -float(mouseY-pmouseY);
cameraRotation.y += float(mouseX-pmouseX);
}
background(255);
translate(width * 0.5, height * 0.5, 0);
rotateX(radians(cameraRotation.x));
rotateY(radians(cameraRotation.y));
rect(0, 0, 300, 450);
}
The Document Paris example you've shared also uses easing. You can have a look at this minimal easing Processing example
Here's a version of the above with easing applied:
PVector cameraRotation = new PVector();
PVector cameraTargetRotation = new PVector();
float easing = 0.01;
void setup(){
size(900, 900, P3D);
rectMode(CENTER);
strokeWeight(9);
strokeJoin(MITER);
}
void draw(){
//update "camera" rotation
if (mousePressed){
cameraTargetRotation.x += -float(mouseY-pmouseY);
cameraTargetRotation.y += float(mouseX-pmouseX);
}
background(255);
translate(width * 0.5, height * 0.5, 0);
// ease rotation
rotateX(radians(cameraRotation.x -= (cameraRotation.x - cameraTargetRotation.x) * easing));
rotateY(radians(cameraRotation.y -= (cameraRotation.y - cameraTargetRotation.y) * easing));
fill(255);
rect(0, 0, 300, 450);
fill(0);
translate(0, 0, 3);
rect(0, 0, 300, 450);
}
Additionally there's a library called PeasyCam which can make this much simpler.
If you do want to implement your own version using PMatrix3D here are a couple of tips that could save you time:
When you instantiate PMatrix3D() it's the identity matrix. If you have transformations applied and you want to reset() to identity.
If you want to rotate a PMatrix3D() around and axis the rotate(float angleInRadians, float axisX, float axisY, float axisZ) override should help.
Additionally you could get away without PMatrix3D since resetMatrix() will reset the global transformation matrix and you can call rotate(float angleInRadians, float axisX, float axisY, float axisZ) directly.
Part of the answer is a fix added to the first rotate3D function.
I needed to normalize the x,y,z values to avoid the weird scaling.
I'm posting the current state of the code (i'm skipping a few parts for the sake of simplicity):
// Mouse movement since last fame on X axis
float deltaX() {
return (float)(mouseX-pmouseX);
}
// Mouse movement since last fame on Y axis
float deltaY() {
return (float)(mouseY-pmouseY);
}
// Convert user input into angle and amount to rotate to
void mouseRotate() {
double diag = Math.sqrt(Math.pow(width,2)+Math.pow(height,2));
double x = deltaX()/ diag * 50;
double y = -deltaY()/ diag * 50;
double angle = Math.sqrt( x*x + y*y );
currentMatrix.apply( rotate3D((float)y,(float)x,0,(float)angle) );
}
// Convert those values into a rotation matrix
PMatrix3D rotate3D(float getX, float getY, float getZ, float getA) {
float normalizer = sqrt( getX*getX + getY*getY + getZ*getZ );
float x = 0;
float y = 0;
float z = 0;
if (normalizer != 0) {
x = getX/normalizer;
y = getY/normalizer;
z = getZ/normalizer;
}
float x2 = pow(x,2);
float y2 = pow(y,2);
float z2 = 0;
float sina = sin(getA);
float f1cosa = 1-cos(getA);
PMatrix3D rotationMatrix = new PMatrix3D(
1+f1cosa*(x2-1), z*sina+x*y*f1cosa, -y*sina+x*z*f1cosa, 0,
-z*sina+x*y*f1cosa, 1+f1cosa*(y2-1), x*sina+y*z*f1cosa, 0,
y*sina+x*z*f1cosa, -x*sina+y*z*f1cosa, 1+f1cosa*(z2-1), 0,
0, 0, 0, 1
);
return rotationMatrix;
}
// Draw
draw() {
mouseRotate();
applyMatrix(currentMatrix);
object.render();
}
I thought that using this method would allow me to "stack" cumulative rotations relative to the screen and not relative to the object. But the result seems to always do the rotation relative to the object drawn.
I am not using a camera because I basically only want to rotate the object on itself. I'm actually a bit lost atm on what I should rotate and when to that the newly applied rotations are relative to the user, and the previously applied rotation are conserved.
I have this code that basically reads each pixel of an image and redraws it with different shapes. All shapes will get faded in using a sin() wave.
Now I want to rotate every "Pixelshape" around its own axis (shapeMode(CENTER)) while they are faded in and the translate function gives me a headache in this complex way.
Here is the code so far:
void setup() {
size(1080, 1350);
shapeMode(CENTER);
img = loadImage("loremipsum.png");
…
}
void draw() {
background(123);
for (int gridX = 0; gridX < img.width; gridX++) {
for (int gridY = 0; gridY < img.height; gridY++) {
// grid position + tile size
float tileWidth = width / (float)img.width;
float tileHeight = height / (float)img.height;
float posX = tileWidth*gridX;
float posY = tileHeight*gridY;
// get current color
color c = img.pixels[gridY*img.width+gridX];
// greyscale conversion
int greyscale = round(red(c)*0.222+green(c)*0.707+blue(c)*0.071);
int gradientToIndex = round(map(greyscale, 0, 255, 0, shapeCount-1));
//FADEIN
float wave = map(sin(radians(frameCount*4)), -1, 1, 0, 2);
//translate(HEADACHE);
rotate(radians(wave));
shape(shapes[gradientToIndex], posX, posY, tileWidth * wave, tileHeight * wave);
}
}
I have tried many calculations but it just lets my sketch explode.
One that worked in another sketch where I tried basically the same but just in loop was (equivalent written):
translate(posX + tileWidth/2, posY + tileHeight/2);
I think I just don't get the matrix right? How can I translate them to its meant place?
Thank you very much #Rabbid76 – at first I just pasted in your idea and it went of crazy – then I added pushMatrix(); and popMatrix(); – turned out your translate(); code was in fact right!
Then I had to change the x and y location where every shape is drawn to 0,0,
And this is it! Now it works!
See the code here:
float wave = map(sin(radians(frameCount*4)), -1, 1, 0, 2);
pushMatrix();
translate(posX + tileWidth/2, posY + tileHeight/2);
rotate(radians(wave*180));
shape(shapes[gradientToIndex], 0, 0, tileWidth*wave , tileHeight*wave );
popMatrix();
PERFECT! Thank you so much!
rotate defines a rotation matrix and multiplies the current matrix by the rotation matrix. rotate therefore causes a rotation by (0, 0).
You have to center the rectangle around (0, 0), rotate it and move the rotated rectangle to the desired position with translate.
Since translate and rotate multiplies the current matrix by a new matrix, you must store and restore the matrix by pushMatrix() respectively popMatrix().
The center of a tile is (posX + tileWidth/2, posY + tileHeight/2):
pushMatrix();
translate(posX + tileWidth/2, posY + tileHeight/2);
rotate(radians(wave));
shape(shapes[gradientToIndex],
-tileWidth*wave/2, -tileHeight*wave/2,
tileWidth * wave, tileHeight * wave);
popMatrix();
I've done this a hundred times, but this is my first time with a manually constructed cube made of "sticks", which are 3D lines. It's constructed around the origin, out 5 from the origin in each of the X, Y, and Z directions.
When I rotate it, I'm still "inside it" and it rotates around me (the camera). I'm applying a translation and rotation, so I'm stymied as to what I'm doing wrong.
Here's the basic code to rotate the box, by which I mean generate it's world matrix:
float rotateX = 0.0f, rotateY = 0.0f, rotateZ = 0.0f;
XMFLOAT4 positionBox = XMFLOAT4(0, 0, -50, 1); // Camera at origin looking at this
XMMATRIX matrixCubeWorld;
void CALLBACK OnFrameMove( double fTime, float fElapsedTime, void* pUserContext )
{
auto pCamera = g_GameServices.GetService<CWorldCamera>();
XMMATRIX translation = XMMatrixTranslationFromVector(XMLoadFloat4(&positionBox));
XMMATRIX rotation = XMMatrixRotationRollPitchYaw(rotateX, rotateY, rotateZ);
matrixCubeWorld = rotation * translation;
if (GetKeyState('X') < 0)
rotateX = RotateAround(rotateX, fElapsedTime);
if (GetKeyState('Y') < 0)
rotateY = RotateAround(rotateY, fElapsedTime);
}
And when I set up to draw, I use that matrix:
D3D11_MAPPED_SUBRESOURCE MappedResource;
V(pd3dImmediateContext->Map(_pVertexShaderVariables, 0, D3D11_MAP_WRITE_DISCARD, 0, &MappedResource));
auto pCB = reinterpret_cast<VSCB3DLineChangesEveryFrame *>(MappedResource.pData);
pCB->_gWorldViewProj = matrixCubeWorld * pCamera->GetViewMatrix() * pCamera->GetProjMatrix();
pd3dImmediateContext->Unmap(_pVertexShaderVariables, 0);
return hr;
...and the shader is as simple as can be:
VertexShaderOutput Line3DVertexShaderFunction(float3 position : POSITION, float4 color : COLOR, float2 tex : TEXCOORD0)
{
VertexShaderOutput output;
output.position = mul(float4(position, 1), _gWorldViewProj);
output.color = color;
output.tex = tex;
return output;
}
So do I have a bug or a misunderstanding? I've tried with the inverse of the translation, thinking that would 'bring it back to the origin before rotating' but didn't improve it.
Transformations look good imho.
Maybe it's due to the fact that 'XMMatrixTranslationFromVector'
takes only 3d-vector as the documentation (msdn) says.
Also make sure that RotateAround function and camera view/proj matrices give correct results.
Best regards.
I am using saveFrame to create an image sequence to bring into after effects. At each loop, I'm upping the frameRate - which I'm sure is not the best way to go about thing. At the end of each loop, I'm saving the frame, but saveFrame can't keep up with the progressively higher frameRate I'm trying to save at. Anyone have an idea how to achieve the effect I'm going for without upping the frameRate, so that saveFrame can keep up? Here's my code:
```
int w = 640; // canvas size
int h = 480;
int n = 10; // number of grid cells
int d = w/n; // diameter of a grid cell
float depth = 0.5; // relative cell depth
int fr = 100;
int iterator = 0;
boolean doSaveFrames = false;
void setup() {
size(w, h, P3D);
rectMode(CENTER);
background(0);
fill(51, 255, 0);
noStroke();
frameRate(fr);
}
void draw() {
// get coordinates
int xy = frameCount % (n*n);
// shift image in z-direction
if (xy == 0) {
PImage img = get();
background(0);
pushMatrix();
translate(0, 0, -d * depth);
tint(255, 127);
image(img, 0, 0);
popMatrix();
// fr+=iterator*10;
// frameRate(fr); //MH - really cool but I can't export fast enough
iterator++;
}
// scale and rotate the square
scale(d);
translate(xy%n + .5, xy/n + .5, -depth * .5 );
rotate(QUARTER_PI - HALF_PI *int(random(2)));
rotateX(HALF_PI);
// draw the square
rect(0, 0, sqrt(2), depth);
if (doSaveFrames) {
saveFrame("frames/line-######.tga");
}
}
```
Instead of basing your animation off of the frameCount variable, create your own variable that you increment at your own speed, and then increase that speed over time. Keep your framerate the same, but increase your animation speed.
I wrote a program in Procesisng that renders opaque cubes with random colour and rotation on top of each other, but I'm looking to individually continuously spin each cube while the program is running. Here's my code at the moment,
int boxval = 1;
void setup(){
size (640, 320, P3D);
frameRate(60);
}
void draw(){
for (int i = 0; i < boxval; i++){
translate(random(0,640), random(0,320), 0);
rotateY(random(0,360));
rotateX(random(0,360));
rotateZ(random(0,360));
fill(random(0,255),random(0,255),random(0,255),50);
noStroke();
box(64,64,64);
}
}
Here's a screenshot if it helps at all,
This is a great time to use Object Oriented Programming! If I understand the question correctly, you would like each cube to rotate independently of the other cubes. Let's make a Cube class. Think of each cube as an object that we will handle individually.
class Cube {
float x, y, z; // position of the cube
float size; // size of cube
color c; // color of cube
float xAngle, yAngle, zAngle; // current rotation amount of cube's x, y, z axes
float xSpeed, ySpeed, zSpeed; // how quickly the cube is rotated in the x, y, z axes
// Cube constructor - create the cube and all of its parameters
Cube(float x_, float y_, float z_, float size_, color c_, float xSpeed_, float ySpeed_, float zSpeed_) {
x = x_;
y = y_;
z = z_;
size = size_;
c = c_;
xSpeed = xSpeed_;
ySpeed = ySpeed_;
zSpeed = zSpeed_;
xAngle = yAngle = zAngle = 0; // starting position
}
// update the cube
// all we're doing is rotating each axis
void update() {
xAngle += xSpeed;
yAngle += ySpeed;
zAngle += zSpeed;
}
// draw the cube to the screen
void display() {
pushMatrix(); // need this
translate(x, y, z); // position on screen
rotateX(xAngle); // rotation amounts
rotateY(yAngle);
rotateZ(zAngle);
fill(c);
noStroke();
box(size);
popMatrix(); // and this
// push and pop matrix allows for individual cube rotation
// otherwise you would rotate the whole draw window, which isn't what you're looking for
}
}
If you would like each cube to change color and position on screen but still rotate independently, the display() function could be something like this instead:
void display() {
pushMatrix();
translate(random(0, width), random(0, height), random(-100, 100)); // random position on screen
rotateX(xAngle);
rotateY(yAngle);
rotateZ(zAngle);
fill(random(255), random(255), random(255), 50); // random color
noStroke();
box(size);
popMatrix();
}
Understanding rotation and translation of elements in Processing is really key. I highly recommend this tutorial from the Processing website if you have not read it. I incorporated some concepts into the Cube class.
Since you would like to have more than one Cube drawn on the screen, let's make an array of Cubes. I chose 25 as an arbitrary number.
Cube[] cube = new Cube[25];
Now in setup(), we'll need to actually create each Cube and give it certain parameters, like position on screen, color, etc. Here is how that is accomplished.
for (int i = 0; i < cube.length; i++) {
cube[i] = new Cube(random(0, width), random(0, height), 0, // x, y, z position
random(30, 80), color(random(255), random(255), random(255), 50), // size, color
random(0.001, 0.020), random(0.001, 0.020), random(0.001, 0.020)); // xSpeed, ySpeed, zSpeed
}
Now we just need to draw the Cubes to the screen and update the rotation of each one, which simply happens in the draw() loop.
for (int i = 0; i < cube.length; i++) {
cube[i].update();
cube[i].display()
}
Here is whole program. It's important to call background() each time through the draw() loop so the display window will be cleared each frame. Comment it out to see what will happen, but I noticed that was not in the code snippet you provided above. I guess it can be an effect though!
Cube[] cube = new Cube[25];
void setup() {
size(640, 320, P3D);
smooth();
frameRate(60);
for (int i = 0; i < cube.length; i++) {
cube[i] = new Cube(random(0, width), random(0, height), 0,
random(30, 80), color(random(255), random(255), random(255), 50),
random(0.001, 0.020), random(0.001, 0.020), random(0.001, 0.020));
}
}
void draw() {
camera();
lights();
background(50);
for (int i = 0; i < cube.length; i++) {
cube[i].update();
cube[i].display();
}
}
I'm not sure what your programming background is, but getting a hang of Object Oriented Programming is really helpful in Processing (and other OOP languages), so I'd recommend this OOP tutorial from the Processing website if you need a crash course. My programming life changed when OOP finally made sense.