We are going to talk about projective math and the relation to homogeneous coordinates and transforms. We will take a look with what was under the hood to those visualizations, and look at the graphics rendering (GPU) pipeline. The specialization comes solely from custom programs.
The intersection between a line and a projection plane will leave an input, and the planes are represented as (Xp, Yp, Zp).
This operation with a z showing up in the denominator is compatible with what linear transformations are like and act like.
If you had a Geometric location (x, y, z) and have agreed to represent this with a quadruple of numbers (x, y, z, 1) where the fourth number is an ace. which allows me to fit the entire affine transformation into a single matrix. Our convention back in the days is that if we play our cards right, all geometic coordinates are converted by appending an ace in the final entry.
This is just a special case of the full-fledge potential of heterogeneous transform.
A homogeneous representation is a quadruple of numbers with the following properties:
1. The 4-vector (x, y, z, 1) is an equivalent homogeneous representation of the 3D vector (x, y, z)
2. 2 homogeneous 4-vectors that are scaled are treated as equal. (x y z w) = (αx αy αz αw). This does not always need to be an ace. Ultimately they represent the point in the 3 dimensional space.
We can subsequently naturally say the following. We can use this division in order to create what certain homogeneous vectors look like.
We are trying to engineer a result of a projection.
Now we want to perform a perspective transformation as a homogeneous transform .
We are going to divide all of these entries by z/d.
We will divide and get the result:
(dx/z dy/z -d 1).
(xp = dx/z, yp = dy/z, zp = -d)
We bring in to the side door that division in order to bring in this expression because this is all we need on order to do this prospective operation.
You actually will have, at some point, wherever you get the final projective result, will have to do that perspective division, and you are getting the last answer in that pipeline division. Before you use that result, you have to divide all the way through with an ace.
If the last number is not an ace you divide everything and you return the result of that division with the first three entries. Matrices in this representation still get combined together by plain matrix multiplication, but if you created a composite transformation with a nonstandard pattern the final result that you are computing might have the property in which the last entry is not an ace.
The next topic to discuss is the shading, rasterization, the graphics pipeline and GLSL.
The following is a 2D way in how we perceive 3D reality.
Modern 3D graphics are represented by meshes, which live in the 3 dimensional world and is represented by meshes.
The vertexes have enumerations and are represented by coordinates.
We then connect the vertices as a triangle/4d objects
Vertices carries information on where an object lies in 3D space, and we can have a color, etc. Triangles identify the verticies they connect(specifying topology) rather than reiterating properties.
Texturing allows the glue to the surface of an object, and take and image and wallpaper it on top of an object.
There are many properties that you can define with an individual vertex. Typically, they should have at least position.
There is a catalog of vertices that have properties given and for each one of them there is an array that indicates the individual property.
The graphics pipeline has a very long control flow for the program.
shdr.bkcore.com
At the top level you are going to have an application program.
It can tap into some features labelled inside of the graphics driver, with an API. We haven't seen this yet.
At some point, somebody needs to "call " some functions from the graphics driver.
At this point, you cross the CPU/GPU barrier, and you have a mesh. Tell the graphics card to do an illumination pattern, specular/diffuse reflection, etc.
A triangle queue is subsequently a collection of triangles for the algorithms to preprocess. All of these things are requests that renders all of the vertices. Then the GPU
Wprocesses requests.
When we then communicated the Geometry/Render, we perform vertex processing and triangle processing. Everything is broken up into their constituent vertices and fed into a queue.
We break every triangle into 3 pieces of work, and take these 3 vertices and feed them into a queue.
Then there are some vertices that need to be performed work on.
Once again, the vertex processor executes a set computation on each such vertex, including transformations into NDC).
For every point, we will give an opportunity for a program to run on it at minimium should figure out where the point projects onto in image space.
We should provide the output of the vertex transformation into normalized device coordinates.
These coordinates get re-scaled with the viewport into the actual drawing window.
The vertex shader has the opportunity to do extra work. When talking about diffuse shading, there is a question. Maybe a property of a vertex can be a temperature and we can essentially change the temperature to a color.
The GPU asks for every vertex, specify what to compute on vertices and give exactly the same program to run on every vertex.
The computation is inside a "vertex-shader" that is user-customizable.
After we have computed these results, we can take these converted locations and reassemble them into triangle, and construct a converted triangle normalizing certain coordinates.
There's another property called a triangle processor that can do stuff prior to the visualizations.
Every triangle is converted into pixels that straddles its spatial extent.
How does rasterization look like? The GPU looks like a triangle and tries to figure out an enclosing rectangle of pixels would have a change of being touched by that triangle. I want to just create a rectangle that straddles the highest X/Y value and the lowest X/Y value.
There is always a process where every point can be written as a percentile combination of the 3 vertices of the triangle.
A pixel is inside a triangle if all three weights are positive and negative. For every pixel, compute a triple of weights ("barycentric coordinates") that would reconstruct the point if used as averageing weights from triangle vertices.
After this operation, we have associated a bunch of fragments with every triangle. Every triangle has been associated with a collection of fragments/pixels that draw into the screen. Then the fragment is fed into another processing unit called a pixel processor.
The pixel processor runs a program to determine what color that each of the pixels should be.
The GPU will calculat what pixels are touched, call fragments, and then give them to a pixel shader, and finally execute all of the programs.
The fragment shader computes the color of the pixel.
The determination of how to paint every pixels can be determine by all the pixel locations in itself. Some pixels are rejected, and the remaining ones are written to the screen.
Some pixels are rejected/hidden, for reasons of occlusion because they have been hidden away by something else.
After these tests have been run, essentially what happens is that the pixels that do survive intuitively get painted on the screen.
The graphics card has a memory embedded in it that is a mirror copy of what you see on the screen. It is a binary representation memory that illustrates to what to show on the screen.
Render to teccture we will talk about when talking about fancy invokations of texture.
With this, I want to make a real vertex shader and fragment shader.
In shdr.bkcore.com you are given the opportunity to write the vertex program, running on every vertex in every triangle that is included in the meshes.
This is what runs on every vertex.
precision highp float;
attribute vec3 position;
attribute vec3 normal;
uniform mat3 normalMatrix;
uniform mat4 modelViewMatrix;
uniform mat4 projectionMatrix;
varying vec3 fNormal;
varying vec3 fPosition;
void main()
{
fNormal = normalize(normalMatrix * normal);
vec4 pos = modelViewMatrix * vec4(position, 1.0);
fPosition = pos.xyz;
gl_Position = projectionMatrix * pos;
}
This is what runs on every fragment.
precision highp float;
uniform float time;
uniform vec2 resolution;
varying vec3 fPosition;
varying vec3 fNormal;
void main()
{
gl_FragColor = vec4(fNormal, 1.0);
}
The command vec4(fposition, 1.0) treats everything as red Green blue values, and taking the depth value involves fPosition.x, or fPosition.y, or z as follows:
gl_FragColor = vec4(0.5 * fPosition.xxx, 0.0, fPosition.z, 1.0);
or something like the following, in order to retract the depth of this 3D model. The easiest thing to do is to take the X position and normalize the vice coordinates that determines the locations that are projected on each pixel, and so I can say that those objects on the right side of the screen, will have 100% black, 100% white, etc. We can shift the vertex as desired vs the xxx (lol ;) depth position.
Now I get all of the negative values to esentially participate in all of the action, to scale from 0 to 1. Something that is all the way to the left is black, and all the way to the right is white
These programs are edited, compiled and loaded onto the GPU card in real time, and then the program runs and the visualization is created. The compiler is embedded onto the graphics driver.
There are very brief walkthroughs of Vertex and fragment shaders and the GLSL basics, look at them later and look into the tutorial.
Comments
Post a Comment