feat: fin de séance 1
This commit is contained in:
commit
60f9b0e464
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
|
@ -0,0 +1 @@
|
||||||
|
*.class
|
11
.vscode/settings.json
vendored
Normal file
11
.vscode/settings.json
vendored
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
{
|
||||||
|
"files.exclude": {
|
||||||
|
"**/.git": true,
|
||||||
|
"**/.svn": true,
|
||||||
|
"**/.hg": true,
|
||||||
|
"**/CVS": true,
|
||||||
|
"**/.DS_Store": true,
|
||||||
|
"**/Thumbs.db": true,
|
||||||
|
"**/*.class": true
|
||||||
|
}
|
||||||
|
}
|
65
DepthBuffer.java
Normal file
65
DepthBuffer.java
Normal file
|
@ -0,0 +1,65 @@
|
||||||
|
|
||||||
|
|
||||||
|
import java.lang.Double;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The DepthBuffer class implements a DepthBuffer and its pass test.
|
||||||
|
*/
|
||||||
|
public class DepthBuffer {
|
||||||
|
private double[] buffer;
|
||||||
|
int width;
|
||||||
|
int height;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs a DepthBuffer of size width x height.
|
||||||
|
* The buffer is initially cleared.
|
||||||
|
*/
|
||||||
|
public DepthBuffer (int width, int height) {
|
||||||
|
buffer = new double[width * height];
|
||||||
|
this.width = width;
|
||||||
|
this.height = height;
|
||||||
|
clear ();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Clears the buffer to infinite depth for all fragments.
|
||||||
|
*/
|
||||||
|
public void clear () {
|
||||||
|
for (int i = 0; i < height; i++) {
|
||||||
|
for (int j = 0; j < width; j++) {
|
||||||
|
buffer[i * width + j] = Double.POSITIVE_INFINITY;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test if a fragment passes the DepthBuffer test, i.e. is the fragment the
|
||||||
|
* closest at its position.
|
||||||
|
*/
|
||||||
|
public boolean testFragment (Fragment fragment) {
|
||||||
|
if ((fragment.getX () >= 0) && (fragment.getX () < width) && (fragment.getY () >= 0) && (fragment.getY () < height)) {
|
||||||
|
|
||||||
|
/* COMPLETER */
|
||||||
|
|
||||||
|
return false;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Writes the fragment depth to the buffer
|
||||||
|
*/
|
||||||
|
public void writeFragment (Fragment fragment) {
|
||||||
|
if ((fragment.getX () >= 0) && (fragment.getX () < width) && (fragment.getY () >= 0) && (fragment.getY () < height)) {
|
||||||
|
|
||||||
|
/* COMPLETER */
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
136
Fragment.java
Normal file
136
Fragment.java
Normal file
|
@ -0,0 +1,136 @@
|
||||||
|
|
||||||
|
import java.awt.*;
|
||||||
|
import algebra.*;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The Fragment class represents an attributed 'pixel' as generated
|
||||||
|
* by a Rasterizer.
|
||||||
|
* @author cdehais
|
||||||
|
*/
|
||||||
|
|
||||||
|
public class Fragment {
|
||||||
|
private int x;
|
||||||
|
private int y;
|
||||||
|
private int numAttributes;
|
||||||
|
|
||||||
|
/* attributes placement:
|
||||||
|
* 0: depth
|
||||||
|
* 1-3: color
|
||||||
|
* 4-6: normal
|
||||||
|
* 7-8: (u,v) texture coordinates
|
||||||
|
*/
|
||||||
|
double[] attributes;
|
||||||
|
|
||||||
|
public Fragment (int x, int y) { // int numAdditionalAttributes) {
|
||||||
|
this.x = x;
|
||||||
|
this.y = y;
|
||||||
|
numAttributes = 9;
|
||||||
|
attributes = new double[numAttributes];
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getNumAttributes () {
|
||||||
|
return numAttributes;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets a scalar attribute at index.
|
||||||
|
*/
|
||||||
|
public double getAttribute (int index) {
|
||||||
|
return attributes[index];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets a vector attribute at the given starting location and with the given dimension.
|
||||||
|
*/
|
||||||
|
public double[] getAttribute (int index, int dimension) {
|
||||||
|
double[] attr = new double[dimension];
|
||||||
|
|
||||||
|
for (int i = 0; i < dimension; i++) {
|
||||||
|
attr[i] = attributes[index+i];
|
||||||
|
}
|
||||||
|
|
||||||
|
return attr;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setAttribute (int index, double value) {
|
||||||
|
attributes[index] = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the x pixel coordinate of the Fragment
|
||||||
|
*/
|
||||||
|
public int getX () {
|
||||||
|
return x;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Gets the y pixel coordinate of the Fragment
|
||||||
|
*/
|
||||||
|
public int getY () {
|
||||||
|
return y;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the pixel coordinates (x, y) of the Fragment as a size 2 array
|
||||||
|
*/
|
||||||
|
public int[] getPosition () {
|
||||||
|
int[] position = new int[2];
|
||||||
|
|
||||||
|
position[0] = x;
|
||||||
|
position[1] = y;
|
||||||
|
|
||||||
|
return position;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setPosition (int x, int y) {
|
||||||
|
this.x = x;
|
||||||
|
this.y = y;
|
||||||
|
}
|
||||||
|
|
||||||
|
public double getDepth () {
|
||||||
|
return attributes[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setDepth (double z) {
|
||||||
|
attributes[0] = z;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Vector3 getNormal () {
|
||||||
|
return new Vector3 (attributes[0], attributes[1], attributes[2]);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setNormal (Vector normal) {
|
||||||
|
attributes[4] = normal.get (0);
|
||||||
|
attributes[5] = normal.get (1);
|
||||||
|
attributes[6] = normal.get (2);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setNormal (double nx, double ny, double nz) {
|
||||||
|
attributes[4] = nx;
|
||||||
|
attributes[5] = ny;
|
||||||
|
attributes[6] = nz;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Color getColor () {
|
||||||
|
int r = (int) Math.min (255, Math.max (255 * attributes[1], 0));
|
||||||
|
int g = (int) Math.min (255, Math.max (255 * attributes[2], 0));
|
||||||
|
int b = (int) Math.min (255, Math.max (255 * attributes[3], 0));
|
||||||
|
return new Color (r, g, b);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setColor (Color color) {
|
||||||
|
attributes[1] = color.getRed ();
|
||||||
|
attributes[2] = color.getGreen ();
|
||||||
|
attributes[3] = color.getBlue ();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setColor (double r, double g, double b) {
|
||||||
|
attributes[1] = r;
|
||||||
|
attributes[2] = g;
|
||||||
|
attributes[3] = b;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public String toString () {
|
||||||
|
return "(" + x + "," + y + ")";
|
||||||
|
}
|
||||||
|
}
|
217
GraphicsWrapper.java
Normal file
217
GraphicsWrapper.java
Normal file
|
@ -0,0 +1,217 @@
|
||||||
|
/**
|
||||||
|
* A "virtual" screen, where only "setPixel" is available
|
||||||
|
* (It is a JFrame, and JFrame.EXIT_ON_CLOSE is set)
|
||||||
|
* @author smondet
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
import java.awt.*;
|
||||||
|
import java.awt.geom.*;
|
||||||
|
import java.awt.image.*;
|
||||||
|
import javax.swing.*;
|
||||||
|
import java.lang.Math;
|
||||||
|
|
||||||
|
|
||||||
|
class ImageComponent extends Component {
|
||||||
|
|
||||||
|
BufferedImage renderedImage = null;
|
||||||
|
|
||||||
|
public ImageComponent (BufferedImage init) {
|
||||||
|
renderedImage = init;
|
||||||
|
}
|
||||||
|
|
||||||
|
public BufferedImage swapImage (BufferedImage bi) {
|
||||||
|
BufferedImage ret = renderedImage ;
|
||||||
|
renderedImage = bi ;
|
||||||
|
return ret ;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void paint(Graphics g) {
|
||||||
|
|
||||||
|
if (renderedImage != null) {
|
||||||
|
((Graphics2D)g).drawImage(renderedImage, new AffineTransform(1f,0f,0f,1f,0,0), null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
public class GraphicsWrapper {
|
||||||
|
|
||||||
|
private int height = 0;
|
||||||
|
private int width = 0;
|
||||||
|
private int pixelSize = 0;
|
||||||
|
|
||||||
|
private JFrame myFrame ;
|
||||||
|
|
||||||
|
private ImageComponent drawComp = null;
|
||||||
|
|
||||||
|
private BufferedImage backBuffer = null ;
|
||||||
|
private BufferedImage frontBuffer = null ;
|
||||||
|
|
||||||
|
private void init() {
|
||||||
|
backBuffer = new BufferedImage (width * pixelSize, height * pixelSize, BufferedImage.TYPE_INT_ARGB) ;
|
||||||
|
|
||||||
|
frontBuffer = new BufferedImage (width * pixelSize, height * pixelSize, BufferedImage.TYPE_3BYTE_BGR) ;
|
||||||
|
|
||||||
|
/*
|
||||||
|
Graphics2D gd = initial.createGraphics ();
|
||||||
|
gd.setColor (Color.BLACK) ;
|
||||||
|
gd.fillRect (0,0, width * pixelSize, height * pixelSize) ;
|
||||||
|
gd = drawingImage.createGraphics ();
|
||||||
|
gd.setColor (Color.BLACK) ;
|
||||||
|
gd.fillRect (0,0, width * pixelSize, height * pixelSize) ;
|
||||||
|
*/
|
||||||
|
|
||||||
|
drawComp = new ImageComponent (frontBuffer);
|
||||||
|
drawComp.setPreferredSize (new Dimension (width * pixelSize, height * pixelSize)) ;
|
||||||
|
drawComp.setVisible (true);
|
||||||
|
|
||||||
|
myFrame = new JFrame("Simple Inverse Rasterization Renderer (TSI)");
|
||||||
|
myFrame.setDefaultCloseOperation (JFrame.EXIT_ON_CLOSE) ;
|
||||||
|
myFrame.add("Center", drawComp );
|
||||||
|
myFrame.pack();
|
||||||
|
myFrame.setVisible(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Build a virtual screen of size width x height
|
||||||
|
* And set its window visible.
|
||||||
|
*/
|
||||||
|
public GraphicsWrapper(int width, int height) {
|
||||||
|
this.height = height;
|
||||||
|
this.width = width;
|
||||||
|
this.pixelSize = 1;
|
||||||
|
init();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Build a virtual screen of size width x height, where one virtual pixel is represented by
|
||||||
|
* a pixelSize x pixelSize square.
|
||||||
|
* And set its window visible.
|
||||||
|
*/
|
||||||
|
public GraphicsWrapper(int width, int height, int pixelSize) {
|
||||||
|
this.height = height;
|
||||||
|
this.width = width;
|
||||||
|
this.pixelSize = pixelSize ;
|
||||||
|
init();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Lights the pixel (x,y) with color (r, g, b) (values clamped to [0,1])
|
||||||
|
* on the current draw buffer.
|
||||||
|
* Does nothing for pixels out of the screen.
|
||||||
|
*/
|
||||||
|
public void setPixel (int x, int y, double r, double g, double b) {
|
||||||
|
|
||||||
|
r = Math.min (1.0, Math.max (0.0, r));
|
||||||
|
g = Math.min (1.0, Math.max (0.0, g));
|
||||||
|
b = Math.min (1.0, Math.max (0.0, b));
|
||||||
|
|
||||||
|
setPixel(x, y, (char) (r * 255), (char) (g * 255), (char) (b * 255));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Lights the pixel (x,y) with color (r, g, b) (values clamped to [0, 255])
|
||||||
|
* on the current draw buffer.
|
||||||
|
* Does nothing for pixels out of the screen.
|
||||||
|
*/
|
||||||
|
public void setPixel(int x, int y, char r, char g, char b) {
|
||||||
|
|
||||||
|
if ((x >= 0) && (x < width) && (y >= 0) && (y < height)) {
|
||||||
|
int argb = 0xFF000000 ;
|
||||||
|
argb += ((int)r) << (8 * 2) ;
|
||||||
|
argb += ((int)g) << (8 * 1) ;
|
||||||
|
argb += ((int)b);
|
||||||
|
|
||||||
|
for (int i = 0 ; i < pixelSize ; i++ ) {
|
||||||
|
for (int j = 0 ; j < pixelSize ; j++ ) {
|
||||||
|
backBuffer.setRGB(i + (x * pixelSize) , j + (y * pixelSize), argb) ;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Lights the pixel (x,y) with the given color.
|
||||||
|
* Does nothing for pixels out of the screen.
|
||||||
|
*/
|
||||||
|
public void setPixel(int x, int y, Color color) {
|
||||||
|
|
||||||
|
if ((x >= 0) && (x < width) && (y >= 0) && (y < height)) {
|
||||||
|
int rgb = color.getRGB ();
|
||||||
|
for (int i = 0 ; i < pixelSize ; i++ ) {
|
||||||
|
for (int j = 0 ; j < pixelSize ; j++ ) {
|
||||||
|
backBuffer.setRGB(i + (x * pixelSize) , j + (y * pixelSize), rgb);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the pixel in the back buffer
|
||||||
|
*/
|
||||||
|
public Color getPixel (int x, int y) {
|
||||||
|
Color color;
|
||||||
|
|
||||||
|
if ((x >= 0) && (x < width) && (y >= 0) && (y < height)) {
|
||||||
|
color = new Color (backBuffer.getRGB (x, y), false);
|
||||||
|
} else {
|
||||||
|
color = Color.BLACK;
|
||||||
|
}
|
||||||
|
|
||||||
|
return color;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Color getFrontPixel (int x, int y) {
|
||||||
|
Color color;
|
||||||
|
|
||||||
|
if ((x >= 0) && (x < width) && (y >= 0) && (y < height)) {
|
||||||
|
color = new Color (frontBuffer.getRGB (x, y), false);
|
||||||
|
} else {
|
||||||
|
color = Color.BLACK;
|
||||||
|
}
|
||||||
|
|
||||||
|
return color;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
int getWidth () {
|
||||||
|
return width;
|
||||||
|
}
|
||||||
|
|
||||||
|
int getHeight () {
|
||||||
|
return height;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Clear current draw-buffer (ie Paint it black)
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public void clearBuffer() {
|
||||||
|
Graphics2D gd = backBuffer.createGraphics ();
|
||||||
|
gd.setColor (Color.BLACK) ;
|
||||||
|
gd.fillRect (0,0, width * pixelSize, height * pixelSize) ;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Draw current draw-buffer on the window.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public void swapBuffers() {
|
||||||
|
frontBuffer = drawComp.swapImage (backBuffer) ;
|
||||||
|
myFrame.repaint ();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Destroy window.
|
||||||
|
*/
|
||||||
|
public void destroy() {
|
||||||
|
myFrame.dispose();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
76
Lighting.java
Normal file
76
Lighting.java
Normal file
|
@ -0,0 +1,76 @@
|
||||||
|
import java.lang.*; import java.util.*; import algebra.*;
|
||||||
|
/* * The Lighting class describes a scene lighting environment
|
||||||
|
* @author: gmorin, smondet */
|
||||||
|
public class Lighting {
|
||||||
|
static final int NONE = 0 ; static final int AMBIENT = 1 ;
|
||||||
|
static final int POINT = 2 ;
|
||||||
|
List lights ;
|
||||||
|
/* Internal Class describing a light source */
|
||||||
|
private class Light {
|
||||||
|
public int type = NONE;
|
||||||
|
public double[] params;
|
||||||
|
public Light (int type, double []params) {
|
||||||
|
this.type = type; this.params = params;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public Lighting() {
|
||||||
|
lights = new LinkedList(); }
|
||||||
|
/* Adds a new ambient light source of intensity @ia to the environment. */
|
||||||
|
public void addAmbientLight (double ia) {
|
||||||
|
double [] v = new double[1];
|
||||||
|
v[0] = ia; lights.add (new Light (AMBIENT, v)); }
|
||||||
|
/** Addsa */
|
||||||
|
public void addPointLight (double x, double y, double z, double id)
|
||||||
|
{
|
||||||
|
double[] v = new double[5];
|
||||||
|
v[0] = x; v[1] = y; v[2] = z; v[3] = id;
|
||||||
|
lights.add (new Light (POINT, v)); }
|
||||||
|
/* Computes the illuminated color of a 3D points of given position, normal and color,
|
||||||
|
* and given the camera position and material parameters.
|
||||||
|
* Returns an array of size 3. */
|
||||||
|
public double[] applyLights (Vector3 position, Vector3 normal, double[] color,
|
||||||
|
Vector3 cameraPosition,
|
||||||
|
double ka, double kd, double ks, double s)
|
||||||
|
{
|
||||||
|
double[] litColor = new double[3];
|
||||||
|
/* total light intensity */
|
||||||
|
double I = 0.0;
|
||||||
|
Iterator it = lights.iterator ();
|
||||||
|
while (it.hasNext ()){
|
||||||
|
Light light = (Light) it.next ();
|
||||||
|
switch (light.type) {
|
||||||
|
case AMBIENT:
|
||||||
|
/* Ambient light : A COMPLETER */
|
||||||
|
/* I += ... */
|
||||||
|
break;
|
||||||
|
case POINT:
|
||||||
|
try {
|
||||||
|
/* vector from point to camera center */
|
||||||
|
Vector3 e = new Vector3 (cameraPosition);
|
||||||
|
e.subtract (position);
|
||||||
|
e.normalize ();
|
||||||
|
/* vector from point to light*/
|
||||||
|
Vector3 l = new Vector3 (light.params[0], light.params[1], light.params[2]);
|
||||||
|
l.subtract (position);
|
||||||
|
l.normalize ();
|
||||||
|
/* half-vector between e and l*/
|
||||||
|
Vector3 h = new Vector3 (e);
|
||||||
|
h.add (l);
|
||||||
|
h.normalize ();
|
||||||
|
/* diffuse contribution : A COMPLETER */
|
||||||
|
/* double Id = ... */
|
||||||
|
/* specular contribution : A COMPLETER */
|
||||||
|
/* double Is = ... */
|
||||||
|
/* I += Id + Is;*/
|
||||||
|
} catch (InstantiationException ex) { /* should not reach*/ }
|
||||||
|
catch (SizeMismatchException ex) { /* should not reach*/ }
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
/* ignore unknow lights */
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
litColor[0] = I * color[0]; litColor[1] = I * color[1]; litColor[2] = I * color[2];
|
||||||
|
return litColor;
|
||||||
|
}
|
||||||
|
}
|
196
Mesh.java
Normal file
196
Mesh.java
Normal file
|
@ -0,0 +1,196 @@
|
||||||
|
|
||||||
|
import java.io.* ;
|
||||||
|
import algebra.*;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Defines a triangle based mesh.
|
||||||
|
* A mesh is constructed by interpretting the data given in an OFF file.
|
||||||
|
* @author smondet gg cdehais
|
||||||
|
*/
|
||||||
|
public class Mesh {
|
||||||
|
|
||||||
|
private Vector[] vertices;
|
||||||
|
private int[] faces;
|
||||||
|
private double[] colors;
|
||||||
|
private Vector3[] normals;
|
||||||
|
private double[] texCoords;
|
||||||
|
|
||||||
|
private static String nextLine (BufferedReader in) throws Exception {
|
||||||
|
String r = in.readLine ();
|
||||||
|
|
||||||
|
while (r.matches ("\\s*#.*")) {
|
||||||
|
r = in.readLine ();
|
||||||
|
}
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Builds a Mesh object by reading in an OFF file.
|
||||||
|
* Does not support non triangular meshes.
|
||||||
|
* @filename path to OFF file.
|
||||||
|
*/
|
||||||
|
public Mesh (String filename) throws Exception {
|
||||||
|
BufferedReader in = new BufferedReader (new FileReader (filename));
|
||||||
|
|
||||||
|
String r = nextLine (in);
|
||||||
|
if (!r.equals ("OFF")) {
|
||||||
|
throw new IOException ("Invalid OFF file !");
|
||||||
|
}
|
||||||
|
|
||||||
|
r = nextLine(in);
|
||||||
|
|
||||||
|
String [] sar = r.split("\\s+");
|
||||||
|
|
||||||
|
/* Parse object properties */
|
||||||
|
int verts_nb = new Integer (sar[0]).intValue();
|
||||||
|
int faces_nb = new Integer (sar[1]).intValue();
|
||||||
|
int edges_nb = new Integer (sar[2]).intValue();
|
||||||
|
|
||||||
|
/* Parse vertices and attributes */
|
||||||
|
vertices = new Vector[verts_nb];
|
||||||
|
faces = new int[3*faces_nb];
|
||||||
|
colors = new double[3*verts_nb];
|
||||||
|
for (int i = 0; i < verts_nb; i++ ){
|
||||||
|
|
||||||
|
r = nextLine(in);
|
||||||
|
sar = r.split ("\\s+");
|
||||||
|
|
||||||
|
vertices[i] = new Vector ("v" + i, 4);
|
||||||
|
vertices[i].set (0, new Double (sar[0]).doubleValue());
|
||||||
|
vertices[i].set (1, new Double (sar[1]).doubleValue());
|
||||||
|
vertices[i].set (2, new Double (sar[2]).doubleValue());
|
||||||
|
vertices[i].set (3, 1.0);
|
||||||
|
colors[3 * i + 0] = new Double(sar[3]).doubleValue();
|
||||||
|
colors[3 * i + 1] = new Double(sar[4]).doubleValue();
|
||||||
|
colors[3 * i + 2] = new Double(sar[5]).doubleValue();
|
||||||
|
/* optionnal texture coordinates */
|
||||||
|
if (sar.length >= 8) {
|
||||||
|
if (texCoords == null) {
|
||||||
|
texCoords = new double[2*verts_nb];
|
||||||
|
}
|
||||||
|
texCoords[2*i] = new Double(sar[6]).doubleValue();
|
||||||
|
texCoords[2*i+1] = new Double(sar[7]).doubleValue();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Parse faces */
|
||||||
|
for (int i = 0; i < faces_nb; i++) {
|
||||||
|
|
||||||
|
r = nextLine(in);
|
||||||
|
sar = r.split("\\s+");
|
||||||
|
|
||||||
|
int en = new Integer(sar[0]).intValue();
|
||||||
|
if (en != 3) {
|
||||||
|
throw new IOException("Non-triangular meshes not supported.");
|
||||||
|
}
|
||||||
|
faces[3 * i + 0] = new Integer(sar[1]).intValue();
|
||||||
|
faces[3 * i + 1] = new Integer(sar[2]).intValue();
|
||||||
|
faces[3 * i + 2] = new Integer(sar[3]).intValue();
|
||||||
|
|
||||||
|
}
|
||||||
|
in.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the number of vertices in the mesh
|
||||||
|
*/
|
||||||
|
public int getNumVertices () {
|
||||||
|
return vertices.length;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the number of faces in the mesh
|
||||||
|
*/
|
||||||
|
public int getNumFaces () {
|
||||||
|
return faces.length / 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs a normal for each vertex of the mesh
|
||||||
|
*/
|
||||||
|
private Vector3[] computeNormals () {
|
||||||
|
|
||||||
|
normals = new Vector3[vertices.length];
|
||||||
|
|
||||||
|
// Compute per face normals and set the vertex normal to the average normals across faces
|
||||||
|
// to the vertex.
|
||||||
|
try {
|
||||||
|
for (int i = 0; i < 3 * getNumFaces(); i += 3) {
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/* A COMPLETER */
|
||||||
|
|
||||||
|
|
||||||
|
Vector3 n = new Vector3(); //?
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// ajoute la normale calculee a chq sommet de la face
|
||||||
|
for (int j = 0; j < 3; j++) {
|
||||||
|
Vector nj = normals[faces[i+j]];
|
||||||
|
|
||||||
|
if (nj == null) {
|
||||||
|
normals[faces[i+j]] = new Vector3 (n);
|
||||||
|
normals[faces[i+j]].setName ("n" + faces[i+j]);
|
||||||
|
} else {
|
||||||
|
nj.add (n);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (InstantiationException e) { System.out.println ("Should not reach 1"); }
|
||||||
|
catch (SizeMismatchException e) { System.out.println ("Should not reach 2"); }
|
||||||
|
|
||||||
|
// final round of normalization
|
||||||
|
for (int i = 0; i < normals.length; i++) {
|
||||||
|
if (normals[i] == null) { /* deals with orphans vertices */
|
||||||
|
normals[i] = new Vector3 ("n_orphan");
|
||||||
|
} else {
|
||||||
|
normals[i].normalize();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return normals;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the vertices of the mesh
|
||||||
|
*/
|
||||||
|
public Vector[] getVertices () {
|
||||||
|
return vertices;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the normals associated to the vertices.
|
||||||
|
*/
|
||||||
|
public Vector3[] getNormals () {
|
||||||
|
if (normals == null) {
|
||||||
|
normals = computeNormals ();
|
||||||
|
}
|
||||||
|
|
||||||
|
return normals;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the faces of the mesh. The returned array contains 3*n integers, with n the number of faces.
|
||||||
|
* Each integer is an index into the array of Vector.
|
||||||
|
*/
|
||||||
|
public int[] getFaces () {
|
||||||
|
return faces;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the colors of each vertex in the mesh.
|
||||||
|
*/
|
||||||
|
public double[] getColors () {
|
||||||
|
return colors;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the texture coordinates of each vertex in the mesh.
|
||||||
|
*/
|
||||||
|
public double[] getTextureCoordinates () {
|
||||||
|
return texCoords;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
30
PainterShader.java
Normal file
30
PainterShader.java
Normal file
|
@ -0,0 +1,30 @@
|
||||||
|
|
||||||
|
import algebra.*;
|
||||||
|
import java.awt.*;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Simple shader that just copy the interpolated color to the screen,
|
||||||
|
* taking the depth of the fragment into acount.
|
||||||
|
* @author: cdehais
|
||||||
|
*/
|
||||||
|
public class PainterShader extends Shader {
|
||||||
|
|
||||||
|
DepthBuffer depth;
|
||||||
|
|
||||||
|
public PainterShader (GraphicsWrapper screen) {
|
||||||
|
super (screen);
|
||||||
|
depth = new DepthBuffer (screen.getWidth (), screen.getHeight ());
|
||||||
|
}
|
||||||
|
|
||||||
|
public void shade (Fragment fragment) {
|
||||||
|
if (depth.testFragment (fragment)) {
|
||||||
|
screen.setPixel (fragment.getX (), fragment.getY (), fragment.getColor ());
|
||||||
|
depth.writeFragment (fragment);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void reset () {
|
||||||
|
depth.clear ();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
62
PerspectiveCorrectRasterizer.java
Normal file
62
PerspectiveCorrectRasterizer.java
Normal file
|
@ -0,0 +1,62 @@
|
||||||
|
|
||||||
|
import algebra.*;
|
||||||
|
import java.lang.Math.*;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The PerspectiveCorrectRasterizer class extends Rasterizer to perform Persepctive Correct interpolation
|
||||||
|
* of attributes.
|
||||||
|
*
|
||||||
|
* @author cdehais
|
||||||
|
*/
|
||||||
|
public class PerspectiveCorrectRasterizer extends Rasterizer {
|
||||||
|
|
||||||
|
public PerspectiveCorrectRasterizer (Shader shader) {
|
||||||
|
super(shader);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Rasterizes the triangular face made of the Fragment v1, v2 and v3
|
||||||
|
*/
|
||||||
|
public void rasterizeFace (Fragment v1, Fragment v2, Fragment v3) {
|
||||||
|
Matrix C = makeBarycentricCoordsMatrix (v1, v2, v3);
|
||||||
|
|
||||||
|
/* iterate over the triangle's bounding box */
|
||||||
|
int xmin = Math.min (v1.getX (), Math.min (v2.getX (), v3.getX ()));
|
||||||
|
int ymin = Math.min (v1.getY (), Math.min (v2.getY (), v3.getY ()));
|
||||||
|
int xmax = Math.max (v1.getX (), Math.max (v2.getX (), v3.getX ()));
|
||||||
|
int ymax = Math.max (v1.getY (), Math.max (v2.getY (), v3.getY ()));
|
||||||
|
|
||||||
|
Fragment fragment = new Fragment (0, 0);
|
||||||
|
int numAttributes = fragment.getNumAttributes ();
|
||||||
|
try {
|
||||||
|
for (int x = xmin; x <= xmax; x++) {
|
||||||
|
for (int y = ymin; y <= ymax; y++) {
|
||||||
|
|
||||||
|
/* setup position now to allow early clipping */
|
||||||
|
fragment.setPosition (x, y);
|
||||||
|
if (!shader.isClipped (fragment)) {
|
||||||
|
|
||||||
|
Vector3 v = new Vector3 (1.0, (double)x, (double)y);
|
||||||
|
Vector bar = C.multiply (v);
|
||||||
|
if ((bar.get (0) >= 0.0) && (bar.get (1) >= 0.0) && (bar.get (2) >= 0.0)) {
|
||||||
|
double oneOverZ = bar.get (0) / v1.getDepth () +
|
||||||
|
bar.get (1) / v2.getDepth () +
|
||||||
|
bar.get (2) / v3.getDepth ();
|
||||||
|
for (int i = 0; i < numAttributes; i++) {
|
||||||
|
double aOverZ = bar.get (0) * v1.getAttribute (i) / v1.getDepth () +
|
||||||
|
bar.get (1) * v2.getAttribute (i) / v2.getDepth () +
|
||||||
|
bar.get (2) * v3.getAttribute (i) / v3.getDepth ();
|
||||||
|
|
||||||
|
fragment.setAttribute (i, aOverZ / oneOverZ);
|
||||||
|
}
|
||||||
|
shader.shade (fragment);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (SizeMismatchException e) {
|
||||||
|
/* should not reach */
|
||||||
|
e.printStackTrace ();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
194
Rasterizer.java
Normal file
194
Rasterizer.java
Normal file
|
@ -0,0 +1,194 @@
|
||||||
|
|
||||||
|
import algebra.*;
|
||||||
|
import java.lang.Math.*;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The Rasterizer class is responsible for the discretization of geometric
|
||||||
|
* primitives
|
||||||
|
* (edges and faces) over the screen pixel grid and generates Fragment (pixels
|
||||||
|
* with
|
||||||
|
* interpolated attributes). Those Fragment are then passed to a Shader object,
|
||||||
|
* which will produce the final color of the fragment.
|
||||||
|
*
|
||||||
|
* @author morin, chambon, cdehais
|
||||||
|
*/
|
||||||
|
public class Rasterizer {
|
||||||
|
|
||||||
|
Shader shader;
|
||||||
|
|
||||||
|
public Rasterizer(Shader shader) {
|
||||||
|
this.shader = shader;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setShader(Shader shader) {
|
||||||
|
this.shader = shader;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Linear interpolation of a Fragment f on the edge defined by Fragment's v1 and
|
||||||
|
* v2
|
||||||
|
*/
|
||||||
|
private void interpolate2(Fragment v1, Fragment v2, Fragment f) {
|
||||||
|
int x1 = v1.getX();
|
||||||
|
int y1 = v1.getY();
|
||||||
|
int x2 = v2.getX();
|
||||||
|
int y2 = v2.getY();
|
||||||
|
int x = f.getX();
|
||||||
|
int y = f.getX();
|
||||||
|
|
||||||
|
double alpha;
|
||||||
|
if (Math.abs(x2 - x1) > Math.abs(y2 - y1)) {
|
||||||
|
alpha = (double) (x - x1) / (double) (x2 - x1);
|
||||||
|
} else {
|
||||||
|
if (y2 != y1) {
|
||||||
|
alpha = (double) (y - y1) / (double) (y2 - y1);
|
||||||
|
} else {
|
||||||
|
alpha = 0.5;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
int numAttributes = f.getNumAttributes();
|
||||||
|
for (int i = 0; i < numAttributes; i++) {
|
||||||
|
f.setAttribute(i, (1.0 - alpha) * v1.getAttribute(i) + alpha * v2.getAttribute(i));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Swaps x and y coordinates of the fragment. Used by the Bresenham algorithm.
|
||||||
|
*/
|
||||||
|
private static void swapXAndY(Fragment f) {
|
||||||
|
f.setPosition(f.getY(), f.getX());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Rasterizes the edge between the projected vectors v1 and v2.
|
||||||
|
* Generates Fragment's and calls the Shader::shade() metho on each of them.
|
||||||
|
*/
|
||||||
|
public void rasterizeEdge(Fragment v1, Fragment v2) {
|
||||||
|
|
||||||
|
/* Coordinates of V1 and V2 */
|
||||||
|
int x1 = v1.getX();
|
||||||
|
int y1 = v1.getY();
|
||||||
|
int x2 = v2.getX();
|
||||||
|
int y2 = v2.getY();
|
||||||
|
|
||||||
|
/* For now : just display the vertices */
|
||||||
|
Fragment f = new Fragment(0, 0);
|
||||||
|
int size = 2;
|
||||||
|
for (int i = 0; i < v1.getNumAttributes(); i++) {
|
||||||
|
f.setAttribute(i, v1.getAttribute(i));
|
||||||
|
}
|
||||||
|
for (int i = -size; i <= size; i++) {
|
||||||
|
for (int j = -size; j <= size; j++) {
|
||||||
|
f.setPosition(x1 + i, y1 + j);
|
||||||
|
shader.shade(f);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* tracé d'un segment avec l'algo de Bresenham
|
||||||
|
* int numAttributes = v1.getNumAttributes ();
|
||||||
|
* Fragment fragment = new Fragment (0, 0); //, numAttributes);
|
||||||
|
*
|
||||||
|
* boolean sym = (Math.abs (y2 - y1) > Math.abs (x2 - x1));
|
||||||
|
* if (sym) {
|
||||||
|
* int temp;
|
||||||
|
* temp = x1; x1 = y1 ; y1 = temp;
|
||||||
|
* temp = x2; x2 = y2 ; y2 = temp;
|
||||||
|
* }
|
||||||
|
* if (x1 > x2) {
|
||||||
|
* Fragment ftemp;
|
||||||
|
* int temp;
|
||||||
|
* temp = x1; x1 = x2; x2 = temp;
|
||||||
|
* temp = y1; y1 = y2; y2 = temp;
|
||||||
|
* ftemp = v1; v1 = v2; v2 = ftemp;
|
||||||
|
* }
|
||||||
|
*
|
||||||
|
* int ystep;
|
||||||
|
* if (y1 < y2) {
|
||||||
|
* ystep = 1;
|
||||||
|
* } else {
|
||||||
|
* ystep = -1;
|
||||||
|
* }
|
||||||
|
*
|
||||||
|
* int x = x1;
|
||||||
|
* float y_courant = y1;
|
||||||
|
* int y=y1;
|
||||||
|
* float delta_y = y2-y1;
|
||||||
|
* float delta_x = x2-x1;
|
||||||
|
* float m = delta_y/delta_x;
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* for (int i=1;i<=delta_x;i++) {
|
||||||
|
* x = x+1;
|
||||||
|
* y_courant = y_courant + m;
|
||||||
|
* if ((ystep == 1)&&(y_courant < y+0.5)||((ystep == -1) && (y_courant > y
|
||||||
|
* -0.5))) {
|
||||||
|
* y = y;
|
||||||
|
* } else {
|
||||||
|
* y = y + ystep;
|
||||||
|
* }
|
||||||
|
*
|
||||||
|
* //envoi du fragment au shader
|
||||||
|
* fragment.setPosition (x, y);
|
||||||
|
*
|
||||||
|
* if (!shader.isClipped (fragment)) {
|
||||||
|
*
|
||||||
|
* //interpolation des attributs
|
||||||
|
* interpolate2 (v1, v2, fragment);
|
||||||
|
* if (sym) {
|
||||||
|
* swapXAndY (fragment);
|
||||||
|
* }
|
||||||
|
* shader.shade (fragment);
|
||||||
|
* }
|
||||||
|
* }
|
||||||
|
*/
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
static double triangleArea(Fragment v1, Fragment v2, Fragment v3) {
|
||||||
|
return (double) v2.getX() * v3.getY() - v2.getY() * v3.getX()
|
||||||
|
+ v3.getX() * v1.getY() - v1.getX() * v3.getY()
|
||||||
|
+ v1.getX() * v2.getY() - v2.getX() * v1.getY();
|
||||||
|
}
|
||||||
|
|
||||||
|
static protected Matrix makeBarycentricCoordsMatrix(Fragment v1, Fragment v2, Fragment v3) {
|
||||||
|
Matrix C = null;
|
||||||
|
try {
|
||||||
|
C = new Matrix(3, 3);
|
||||||
|
} catch (InstantiationException e) {
|
||||||
|
/* unreached */
|
||||||
|
}
|
||||||
|
|
||||||
|
double area = triangleArea(v1, v2, v3);
|
||||||
|
int x1 = v1.getX();
|
||||||
|
int y1 = v1.getY();
|
||||||
|
int x2 = v2.getX();
|
||||||
|
int y2 = v2.getY();
|
||||||
|
int x3 = v3.getX();
|
||||||
|
int y3 = v3.getY();
|
||||||
|
C.set(0, 0, (x2 * y3 - x3 * y2) / area);
|
||||||
|
C.set(0, 1, (y2 - y3) / area);
|
||||||
|
C.set(0, 2, (x3 - x2) / area);
|
||||||
|
C.set(1, 0, (x3 * y1 - x1 * y3) / area);
|
||||||
|
C.set(1, 1, (y3 - y1) / area);
|
||||||
|
C.set(1, 2, (x1 - x3) / area);
|
||||||
|
C.set(2, 0, (x1 * y2 - x2 * y1) / area);
|
||||||
|
C.set(2, 1, (y1 - y2) / area);
|
||||||
|
C.set(2, 2, (x2 - x1) / area);
|
||||||
|
|
||||||
|
return C;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Rasterizes the triangular face made of the Fragment v1, v2 and v3
|
||||||
|
*/
|
||||||
|
public void rasterizeFace(Fragment v1, Fragment v2, Fragment v3) {
|
||||||
|
|
||||||
|
Matrix C = makeBarycentricCoordsMatrix(v1, v2, v3);
|
||||||
|
|
||||||
|
/* iterate over the triangle's bounding box */
|
||||||
|
|
||||||
|
/* A COMPLETER */
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
186
Renderer.java
Normal file
186
Renderer.java
Normal file
|
@ -0,0 +1,186 @@
|
||||||
|
|
||||||
|
import algebra.*;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The Renderer class drives the rendering pipeline: read in a scene, projects
|
||||||
|
* the vertices and rasterizes every faces / edges.
|
||||||
|
*
|
||||||
|
* @author: cdehais
|
||||||
|
*/
|
||||||
|
public class Renderer {
|
||||||
|
|
||||||
|
static Scene scene;
|
||||||
|
static Mesh mesh;
|
||||||
|
static Rasterizer rasterizer;
|
||||||
|
static GraphicsWrapper screen;
|
||||||
|
static Shader shader;
|
||||||
|
static Transformation xform;
|
||||||
|
static Lighting lighting;
|
||||||
|
static boolean lightingEnabled;
|
||||||
|
|
||||||
|
static void init(String sceneFilename) throws Exception {
|
||||||
|
scene = new Scene(sceneFilename);
|
||||||
|
mesh = new Mesh(scene.getMeshFileName());
|
||||||
|
screen = new GraphicsWrapper(scene.getScreenW(), scene.getScreenH());
|
||||||
|
screen.clearBuffer();
|
||||||
|
shader = new SimpleShader(screen);
|
||||||
|
// shader = new PainterShader (screen);
|
||||||
|
// rasterizer = new PerspectiveCorrectRasterizer (shader);
|
||||||
|
rasterizer = new Rasterizer(shader);
|
||||||
|
|
||||||
|
xform = new Transformation();
|
||||||
|
xform.setLookAt(scene.getCameraPosition(),
|
||||||
|
scene.getCameraLookAt(),
|
||||||
|
scene.getCameraUp());
|
||||||
|
xform.setProjection();
|
||||||
|
xform.setCalibration(scene.getCameraFocal(), scene.getScreenW(), scene.getScreenH());
|
||||||
|
|
||||||
|
lighting = new Lighting();
|
||||||
|
lighting.addAmbientLight(scene.getAmbientI());
|
||||||
|
double[] lightCoord = scene.getSourceCoord();
|
||||||
|
lighting.addPointLight(lightCoord[0], lightCoord[1], lightCoord[2], scene.getSourceI());
|
||||||
|
}
|
||||||
|
|
||||||
|
static Fragment[] projectVertices() {
|
||||||
|
Vector[] vertices = mesh.getVertices();
|
||||||
|
Vector3[] normals = mesh.getNormals();
|
||||||
|
double[] colors = mesh.getColors();
|
||||||
|
|
||||||
|
Fragment[] fragments = new Fragment[vertices.length];
|
||||||
|
|
||||||
|
try {
|
||||||
|
for (int i = 0; i < vertices.length; i++) {
|
||||||
|
Vector pVertex = xform.projectPoint(vertices[i]);
|
||||||
|
// Vector pNormal = xform.transformVector (normals[i]);
|
||||||
|
Vector3 pNormal = normals[i];
|
||||||
|
|
||||||
|
int x = (int) Math.round(pVertex.get(0));
|
||||||
|
int y = (int) Math.round(pVertex.get(1));
|
||||||
|
fragments[i] = new Fragment(x, y);
|
||||||
|
fragments[i].setDepth(pVertex.get(2));
|
||||||
|
fragments[i].setNormal(pNormal);
|
||||||
|
|
||||||
|
double[] texCoords = mesh.getTextureCoordinates();
|
||||||
|
if (texCoords != null) {
|
||||||
|
fragments[i].setAttribute(7, texCoords[2 * i]);
|
||||||
|
fragments[i].setAttribute(8, texCoords[2 * i + 1]);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!lightingEnabled) {
|
||||||
|
fragments[i].setColor(colors[3 * i], colors[3 * i + 1], colors[3 * i + 2]);
|
||||||
|
} else {
|
||||||
|
double[] color = new double[3];
|
||||||
|
color[0] = colors[3 * i];
|
||||||
|
color[1] = colors[3 * i + 1];
|
||||||
|
color[2] = colors[3 * i + 2];
|
||||||
|
double material[] = scene.getMaterial();
|
||||||
|
double[] litColor = lighting.applyLights(new Vector3(vertices[i]), pNormal, color,
|
||||||
|
scene.getCameraPosition(),
|
||||||
|
material[0], material[1], material[2], material[3]);
|
||||||
|
fragments[i].setColor(litColor[0], litColor[1], litColor[2]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (SizeMismatchException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
/* should not reach */
|
||||||
|
} catch (InstantiationException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
/* should not reach */
|
||||||
|
}
|
||||||
|
|
||||||
|
return fragments;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void renderWireframe() {
|
||||||
|
Fragment[] fragment = projectVertices();
|
||||||
|
int[] faces = mesh.getFaces();
|
||||||
|
|
||||||
|
for (int i = 0; i < 3 * mesh.getNumFaces(); i += 3) {
|
||||||
|
for (int j = 0; j < 3; j++) {
|
||||||
|
Fragment v1 = fragment[faces[i + j]];
|
||||||
|
Fragment v2 = fragment[faces[i + ((j + 1) % 3)]];
|
||||||
|
rasterizer.rasterizeEdge(v1, v2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void renderSolid() {
|
||||||
|
Fragment[] fragments = projectVertices();
|
||||||
|
int[] faces = mesh.getFaces();
|
||||||
|
|
||||||
|
for (int i = 0; i < 3 * mesh.getNumFaces(); i += 3) {
|
||||||
|
Fragment v1 = fragments[faces[i]];
|
||||||
|
Fragment v2 = fragments[faces[i + 1]];
|
||||||
|
Fragment v3 = fragments[faces[i + 2]];
|
||||||
|
|
||||||
|
rasterizer.rasterizeFace(v1, v2, v3);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void setLightingEnabled(boolean enabled) {
|
||||||
|
lightingEnabled = enabled;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void wait(int sec) {
|
||||||
|
try {
|
||||||
|
Thread.sleep(sec * 1000);
|
||||||
|
} catch (Exception e) {
|
||||||
|
/* nothing */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void main(String[] args) {
|
||||||
|
|
||||||
|
if (args.length == 0) {
|
||||||
|
System.out.println("usage: java Renderer <scene_file>");
|
||||||
|
} else {
|
||||||
|
try {
|
||||||
|
init(args[0]);
|
||||||
|
} catch (Exception e) {
|
||||||
|
System.out.println("Problem initializing Renderer: " + e);
|
||||||
|
e.printStackTrace();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* wireframe rendering */
|
||||||
|
renderWireframe();
|
||||||
|
screen.swapBuffers();
|
||||||
|
wait(10);
|
||||||
|
|
||||||
|
/* solid rendering, no lighting */
|
||||||
|
/*
|
||||||
|
* screen.clearBuffer ();
|
||||||
|
* shader.reset ();
|
||||||
|
* renderSolid ();
|
||||||
|
* screen.swapBuffers ();
|
||||||
|
* wait (3);
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* solid rendering, with lighting */
|
||||||
|
/*
|
||||||
|
* screen.clearBuffer ();
|
||||||
|
* shader.reset ();
|
||||||
|
* setLightingEnabled (true);
|
||||||
|
* renderSolid ();
|
||||||
|
* screen.swapBuffers ();
|
||||||
|
* wait (3);
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* solid rendering, with texture */
|
||||||
|
/*
|
||||||
|
* screen.clearBuffer ();
|
||||||
|
* TextureShader texShader = new TextureShader (screen);
|
||||||
|
* texShader.setTexture ("data/brick.jpg");
|
||||||
|
* shader = texShader;
|
||||||
|
* rasterizer.setShader (texShader);
|
||||||
|
* setLightingEnabled (true);
|
||||||
|
* renderSolid ();
|
||||||
|
* screen.swapBuffers ();
|
||||||
|
* wait (3);
|
||||||
|
*/
|
||||||
|
|
||||||
|
screen.destroy();
|
||||||
|
System.exit(0);
|
||||||
|
}
|
||||||
|
}
|
95
Scene.java
Normal file
95
Scene.java
Normal file
|
@ -0,0 +1,95 @@
|
||||||
|
|
||||||
|
import java.io.*;
|
||||||
|
import algebra.*;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class that describes a simple 3D Scene:
|
||||||
|
* This description is meant to be read form a scene description file (.scene extension)
|
||||||
|
*
|
||||||
|
* @author: cdehais based on smondet, gmorin
|
||||||
|
*/
|
||||||
|
|
||||||
|
public class Scene {
|
||||||
|
|
||||||
|
private static String nextLine (BufferedReader in) throws Exception {
|
||||||
|
String r = in.readLine();
|
||||||
|
|
||||||
|
while (r.matches("(\\s*#.*)|(\\s*$)")) {
|
||||||
|
r = in.readLine() ;
|
||||||
|
}
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
String meshFilename;
|
||||||
|
Vector3 cameraPosition = new Vector3 ("cam_pos");
|
||||||
|
Vector3 cameraLookAt = new Vector3 ("cam_lookat");
|
||||||
|
Vector3 cameraUp = new Vector3 ("cam_up");
|
||||||
|
double cameraFocal;
|
||||||
|
int screenW;
|
||||||
|
int screenH;
|
||||||
|
double ambientI;
|
||||||
|
double sourceI;
|
||||||
|
double[] sourceCoord = new double[3] ;
|
||||||
|
double[] material = new double[4] ;
|
||||||
|
|
||||||
|
public Scene (String filename) throws Exception {
|
||||||
|
|
||||||
|
BufferedReader in = new BufferedReader(new FileReader(filename));
|
||||||
|
|
||||||
|
meshFilename = nextLine(in);
|
||||||
|
|
||||||
|
String r = nextLine(in);
|
||||||
|
String [] sar = r.split("\\s+");
|
||||||
|
cameraPosition.set (new Double(sar[0]).doubleValue(),
|
||||||
|
new Double(sar[1]).doubleValue(),
|
||||||
|
new Double(sar[2]).doubleValue());
|
||||||
|
|
||||||
|
r = nextLine(in);
|
||||||
|
sar = r.split("\\s+");
|
||||||
|
cameraLookAt.set (new Double(sar[0]).doubleValue(),
|
||||||
|
new Double(sar[1]).doubleValue(),
|
||||||
|
new Double(sar[2]).doubleValue());
|
||||||
|
|
||||||
|
r = nextLine(in);
|
||||||
|
sar = r.split("\\s+");
|
||||||
|
cameraUp.set (new Double(sar[0]).doubleValue(),
|
||||||
|
new Double(sar[1]).doubleValue(),
|
||||||
|
new Double(sar[2]).doubleValue());
|
||||||
|
|
||||||
|
r = nextLine(in);
|
||||||
|
cameraFocal = new Double(r).doubleValue();
|
||||||
|
|
||||||
|
r = nextLine(in);
|
||||||
|
sar = r.split("\\s+");
|
||||||
|
screenW = new Integer(sar[0]).intValue();
|
||||||
|
screenH = new Integer(sar[1]).intValue();
|
||||||
|
|
||||||
|
r = nextLine(in);
|
||||||
|
ambientI = new Double(r).doubleValue();
|
||||||
|
|
||||||
|
r = nextLine(in);
|
||||||
|
sar = r.split ("\\s+");
|
||||||
|
for (int i = 0; i < sourceCoord.length; i++) {
|
||||||
|
sourceCoord[i] = new Double(sar[i]).doubleValue();
|
||||||
|
}
|
||||||
|
sourceI = new Double(sar[3]).doubleValue();
|
||||||
|
|
||||||
|
r = nextLine(in);
|
||||||
|
sar = r.split ("\\s+");
|
||||||
|
for (int i = 0; i < material.length; i++) {
|
||||||
|
material[i] = new Double(sar[i]).doubleValue();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getMeshFileName () { return meshFilename ; }
|
||||||
|
public Vector3 getCameraPosition () { return cameraPosition ; }
|
||||||
|
public Vector3 getCameraLookAt () { return cameraLookAt ; }
|
||||||
|
public Vector3 getCameraUp () { return cameraUp ; }
|
||||||
|
public double getCameraFocal () { return cameraFocal ; }
|
||||||
|
public int getScreenW () { return screenW ; }
|
||||||
|
public int getScreenH () { return screenH ; }
|
||||||
|
public double getAmbientI () { return ambientI ; }
|
||||||
|
public double getSourceI () { return sourceI ; }
|
||||||
|
public double[] getSourceCoord () { return sourceCoord ; }
|
||||||
|
public double[] getMaterial () { return material ; }
|
||||||
|
}
|
35
Shader.java
Normal file
35
Shader.java
Normal file
|
@ -0,0 +1,35 @@
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The Shader class is responsible for writing final pixel color
|
||||||
|
* to the screen (GraphicWrapper), from a Fragment.
|
||||||
|
* Subclass this base class and implement the ::shade() method.
|
||||||
|
* @author cdehais
|
||||||
|
*/
|
||||||
|
|
||||||
|
public abstract class Shader {
|
||||||
|
|
||||||
|
protected GraphicsWrapper screen;
|
||||||
|
|
||||||
|
public Shader (GraphicsWrapper screen) {
|
||||||
|
this.screen = screen;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Common entry point to ree-initialize the shader
|
||||||
|
*/
|
||||||
|
public void reset () { }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Computes the fragment color and write the result to the screen.
|
||||||
|
*/
|
||||||
|
public abstract void shade (Fragment fragment);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test whether the fragment falls onto the screen.
|
||||||
|
*/
|
||||||
|
public boolean isClipped (Fragment fragment) {
|
||||||
|
return ((fragment.getX () < 0) || (fragment.getX () >= screen.getWidth ()) ||
|
||||||
|
(fragment.getY () < 0) || (fragment.getY () >= screen.getHeight ()));
|
||||||
|
}
|
||||||
|
}
|
21
SimpleShader.java
Normal file
21
SimpleShader.java
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
|
||||||
|
import algebra.*;
|
||||||
|
import java.awt.*;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Simple shader that just copy the interpolated color to the screen.
|
||||||
|
* @author: cdehais
|
||||||
|
*/
|
||||||
|
public class SimpleShader extends Shader {
|
||||||
|
|
||||||
|
public SimpleShader (GraphicsWrapper screen) {
|
||||||
|
super (screen);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void shade (Fragment fragment) {
|
||||||
|
//System.out.println (fragment.getX () + "," + fragment.getY ());
|
||||||
|
//System.out.println ("color " + fragment.getColor ());
|
||||||
|
screen.setPixel (fragment.getX (), fragment.getY (), fragment.getColor ());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
130
TestAlgebra.java
Normal file
130
TestAlgebra.java
Normal file
|
@ -0,0 +1,130 @@
|
||||||
|
|
||||||
|
import algebra.*;
|
||||||
|
|
||||||
|
public class TestAlgebra {
|
||||||
|
|
||||||
|
public static void test() throws Exception {
|
||||||
|
|
||||||
|
System.out.println ("Algebra\n# Test Start");
|
||||||
|
|
||||||
|
Vector v = new Vector (3);
|
||||||
|
Vector v1 = new Vector (1);
|
||||||
|
v1.setName ("up");
|
||||||
|
try {
|
||||||
|
Vector v0 = new Vector (0);
|
||||||
|
} catch (Exception e) {
|
||||||
|
System.out.println ("Wrong size exception caught OK");
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
Vector v0 = new Vector ("named", 0);
|
||||||
|
} catch (Exception e) {
|
||||||
|
System.out.println ("Wrong size exception caught OK");
|
||||||
|
}
|
||||||
|
|
||||||
|
System.out.println (v);
|
||||||
|
System.out.println (v1);
|
||||||
|
|
||||||
|
Vector u1 = new Vector ("u1", 3);
|
||||||
|
u1.set(0, 1.0);
|
||||||
|
u1.set(1, 2.0);
|
||||||
|
u1.set(2, 3.0);
|
||||||
|
Vector u2 = new Vector (3);
|
||||||
|
u2.set (new double[3]);
|
||||||
|
u2.set(1, 2.0);
|
||||||
|
|
||||||
|
System.out.println (u1);
|
||||||
|
System.out.println ("norm(u1) = " + u1.norm());
|
||||||
|
System.out.println (u2);
|
||||||
|
System.out.println ("u1.u2 = " + u1.dot (u2));
|
||||||
|
|
||||||
|
try {
|
||||||
|
u1 = new Vector ("u1", 3);
|
||||||
|
u2 = new Vector ("u2", 4);
|
||||||
|
u1.dot (u2);
|
||||||
|
} catch (SizeMismatchException e) {
|
||||||
|
System.out.println ("Caught exception: " + e);
|
||||||
|
}
|
||||||
|
|
||||||
|
Vector3 r1 = new Vector3 ("u1", 1.0, 2.0, 3.0);
|
||||||
|
Vector3 r2 = new Vector3 ("u2", 1.0, 3.0, 0.0);
|
||||||
|
|
||||||
|
Vector3 r = r1.cross (r2);
|
||||||
|
|
||||||
|
System.out.println (r1);
|
||||||
|
System.out.println (r2);
|
||||||
|
System.out.println ("r1.r2 = " + r1.dot (r2));
|
||||||
|
System.out.println ("r1.r2 = " + r1.dot ((Vector) r2) + " (as Vector)");
|
||||||
|
System.out.println ("r1 x r2 = " + r);
|
||||||
|
System.out.println ("norm(" + r.getName() + ") = " + r.norm());
|
||||||
|
r.normalize ();
|
||||||
|
System.out.println ("norm(" + r.getName() + ") (after ::normalize()) = " + r.norm());
|
||||||
|
|
||||||
|
|
||||||
|
//-------------------------------------
|
||||||
|
System.out.println ("--\n-- Matrix tests\n--");
|
||||||
|
|
||||||
|
Matrix M = new Matrix (3,5);
|
||||||
|
System.out.println (M);
|
||||||
|
Matrix M1 = new Matrix ("M1", 2, 5);
|
||||||
|
M1.set (0, 0, 2.0);
|
||||||
|
M1.set (1, 4, -8.0);
|
||||||
|
M1.set (1, 2, 5.0);
|
||||||
|
|
||||||
|
try {
|
||||||
|
Matrix M2 = new Matrix ("M2", 0, 2);
|
||||||
|
} catch (Exception e) {
|
||||||
|
System.out.println ("Wrong size exception caught OK");
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
M.multiply (M1);
|
||||||
|
} catch (SizeMismatchException e) {
|
||||||
|
System.out.println ("Caught exception: " + e);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Matrix M2 = Matrix.createIdentity (5);
|
||||||
|
System.out.println (M2);
|
||||||
|
|
||||||
|
M = M1.multiply (M2);
|
||||||
|
System.out.println (M1);
|
||||||
|
System.out.println (M2);
|
||||||
|
System.out.println (M);
|
||||||
|
|
||||||
|
M1 = M1.transpose();
|
||||||
|
M1.name = "M1'";
|
||||||
|
System.out.println (M1);
|
||||||
|
|
||||||
|
Vector u = new Vector ("u", 5);
|
||||||
|
u.ones();
|
||||||
|
v = M.multiply (u);
|
||||||
|
System.out.println (M);
|
||||||
|
System.out.println (u);
|
||||||
|
System.out.println ("M.u = " + v);
|
||||||
|
|
||||||
|
try {
|
||||||
|
u = new Vector ("u", 3);
|
||||||
|
v = M.multiply (u);
|
||||||
|
} catch (SizeMismatchException e) {
|
||||||
|
System.out.println ("Caught exception: " + e);
|
||||||
|
}
|
||||||
|
|
||||||
|
Matrix I = Matrix.createIdentity (5);
|
||||||
|
Matrix S = I.getSubMatrix (0, 2, 3, 3);
|
||||||
|
System.out.println (I);
|
||||||
|
System.out.println ("submatrix:\n" + S);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void main(String[] args) {
|
||||||
|
|
||||||
|
try {
|
||||||
|
test() ;
|
||||||
|
System.out.println ("SUCCESS.") ;
|
||||||
|
} catch (Exception e) {
|
||||||
|
System.out.println ("FAIL: " + e) ;
|
||||||
|
e.printStackTrace () ;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
141
TestGraphicWrapper.java
Normal file
141
TestGraphicWrapper.java
Normal file
|
@ -0,0 +1,141 @@
|
||||||
|
|
||||||
|
import java.util.*;
|
||||||
|
import java.awt.*;
|
||||||
|
import java.lang.Math.*;
|
||||||
|
|
||||||
|
public class TestGraphicWrapper {
|
||||||
|
|
||||||
|
static int width = 128;
|
||||||
|
static int height = 128;
|
||||||
|
static GraphicsWrapper screen;
|
||||||
|
|
||||||
|
private static void checker (int polarity, double r, double g, double b) {
|
||||||
|
screen.clearBuffer();
|
||||||
|
|
||||||
|
for (int i = 0; i < height; i++) {
|
||||||
|
for (int j = 0; j < width; j++) {
|
||||||
|
|
||||||
|
if (((i / 8) % 2 == 1) == ((j / 8) % 2 == polarity)) {
|
||||||
|
screen.setPixel (j, i, r, g, b);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void init () {
|
||||||
|
screen = new GraphicsWrapper (width, height, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int countNeighbours (int x0, int y0) {
|
||||||
|
int count = 0;
|
||||||
|
|
||||||
|
for (int y = y0 - 1; y <= y0 + 1; y++) {
|
||||||
|
for (int x = x0 - 1; x <= x0 + 1; x++) {
|
||||||
|
if ((x != x0) || (y != y0)) {
|
||||||
|
int _x = x % width;
|
||||||
|
int _y = y % height;
|
||||||
|
Color pix = screen.getFrontPixel (_x, _y);
|
||||||
|
if (pix.getRed () != 0) {
|
||||||
|
count++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void evolve () {
|
||||||
|
|
||||||
|
for (int y = 0; y < height; y++) {
|
||||||
|
for (int x = 0; x < width; x++) {
|
||||||
|
int c = countNeighbours (x, y);
|
||||||
|
Color pix = screen.getFrontPixel (x, y);
|
||||||
|
Color bpix = screen.getPixel (x, y);
|
||||||
|
if (pix.getRed () == 0) {
|
||||||
|
//System.out.println (x + " " + y + " : dead (" + c + " nbrs) "
|
||||||
|
// + ((bpix.getRed () == 0) ? "dead" : "alive")
|
||||||
|
// );
|
||||||
|
if (c == 3) {
|
||||||
|
/* born */
|
||||||
|
screen.setPixel (x, y, 255, 255, 255);
|
||||||
|
} else {
|
||||||
|
screen.setPixel (x, y, 0, 0, 0);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
//System.out.println (x + " " + y + " : alive (" + c + " nbrs) "
|
||||||
|
// + ((bpix.getRed() == 0) ? "dead" : "alive"));
|
||||||
|
if ((c >= 2) && (c <= 3)) {
|
||||||
|
/* survive */
|
||||||
|
screen.setPixel (x, y, 255, 255, 255);
|
||||||
|
} else {
|
||||||
|
/* die */
|
||||||
|
screen.setPixel (x, y, 0, 0, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void testChecker () throws Exception {
|
||||||
|
|
||||||
|
for (int k = 0; k < 10; k++) {
|
||||||
|
|
||||||
|
checker (1, 1.0, 1.0, 1.0);
|
||||||
|
screen.swapBuffers ();
|
||||||
|
Thread.sleep (100);
|
||||||
|
|
||||||
|
checker (0, 1.0, 1.0, 1.0);
|
||||||
|
screen.swapBuffers ();
|
||||||
|
Thread.sleep (100);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void testConway () throws Exception {
|
||||||
|
|
||||||
|
screen.clearBuffer ();
|
||||||
|
//screen.swapBuffers ();
|
||||||
|
//screen.clearBuffer ();
|
||||||
|
//screen.swapBuffers ();
|
||||||
|
/*
|
||||||
|
for (int y = 0; y < height; y++) {
|
||||||
|
for (int x = 0; x < width; x++) {
|
||||||
|
if (Math.random() < 0.3) {
|
||||||
|
screen.setPixel (x, y, 255, 255, 255);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
screen.setPixel (20, 10, 255, 255, 255);
|
||||||
|
screen.setPixel (21, 11, 255, 255, 255);
|
||||||
|
screen.setPixel (19, 12, 255, 255, 255);
|
||||||
|
screen.setPixel (20, 12, 255, 255, 255);
|
||||||
|
screen.setPixel (21, 12, 255, 255, 255);
|
||||||
|
|
||||||
|
screen.swapBuffers ();
|
||||||
|
Thread.sleep (1000);
|
||||||
|
|
||||||
|
for (int k = 0; k < 100; k++) {
|
||||||
|
evolve ();
|
||||||
|
screen.swapBuffers ();
|
||||||
|
Thread.sleep (30);
|
||||||
|
}
|
||||||
|
|
||||||
|
screen.destroy() ;
|
||||||
|
System.exit(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void main(String[] args) {
|
||||||
|
|
||||||
|
try {
|
||||||
|
init ();
|
||||||
|
//testChecker () ;
|
||||||
|
testConway () ;
|
||||||
|
} catch (Exception e) {
|
||||||
|
System.out.println("EXCEPTION: " + e) ;
|
||||||
|
e.printStackTrace() ;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
64
TestMesh.java
Normal file
64
TestMesh.java
Normal file
|
@ -0,0 +1,64 @@
|
||||||
|
|
||||||
|
import algebra.*;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test class for the Mesh class
|
||||||
|
* @author: cdehais based on gmorin, smondet
|
||||||
|
*/
|
||||||
|
public class TestMesh {
|
||||||
|
|
||||||
|
public static void test() throws Exception {
|
||||||
|
|
||||||
|
System.out.println("OFF\n# Test Start");
|
||||||
|
|
||||||
|
Mesh mesh = new Mesh ("data/cube_multi_color.off") ;
|
||||||
|
// Transform rend = new Transform();
|
||||||
|
|
||||||
|
Vector[] vertices = mesh.getVertices ();
|
||||||
|
int[] faces = mesh.getFaces ();
|
||||||
|
double[] colors = mesh.getColors ();
|
||||||
|
Vector[] normals = mesh.getNormals();
|
||||||
|
|
||||||
|
System.out.println("** vertices + colors: ") ;
|
||||||
|
for (int i = 0 ; i < vertices.length; i++) {
|
||||||
|
System.out.println (vertices[i] + " - (" + colors[3 * i + 0] + ","
|
||||||
|
+ colors[3 * i + 1] + ","
|
||||||
|
+ colors[3 * i + 2] + ")");
|
||||||
|
}
|
||||||
|
|
||||||
|
System.out.println ("** faces: ") ;
|
||||||
|
for (int i = 0 ; i < mesh.getNumFaces (); i++) {
|
||||||
|
System.out.println (faces[3 * i] + " " + faces[3 * i + 1] + " " + faces[3 * i + 2]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* A decommenter lorsque les normales seront calculees */
|
||||||
|
/* System.out.println("** computed per vertex normals: ");
|
||||||
|
for (int i = 0 ; i < vertices.length; i++) {
|
||||||
|
System.out.println (normals[i]);
|
||||||
|
}*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
System.out.println("vertices after change of basis: ") ;
|
||||||
|
|
||||||
|
for (int i = 0 ; i < vertices.length / 3 ; i++ ){
|
||||||
|
System.out.println(
|
||||||
|
vertices[ 3 * i + 0 ] + " " +
|
||||||
|
vertices[ 3 * i + 1 ] + " " +
|
||||||
|
vertices[ 3 * i + 2 ] + " " +
|
||||||
|
colors [ 3 * i + 0 ] + " " +
|
||||||
|
colors [ 3 * i + 1 ] + " " +
|
||||||
|
colors [ 3 * i + 2 ]);
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void main (String[] args) {
|
||||||
|
try {
|
||||||
|
test() ;
|
||||||
|
} catch (Exception e) {
|
||||||
|
System.out.println("EXCEPTION: " + e) ;
|
||||||
|
e.printStackTrace() ;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
47
TestRasterizer.java
Normal file
47
TestRasterizer.java
Normal file
|
@ -0,0 +1,47 @@
|
||||||
|
|
||||||
|
import algebra.*;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test class for the Rasterizer class
|
||||||
|
* @author: cdehais
|
||||||
|
*/
|
||||||
|
public class TestRasterizer {
|
||||||
|
|
||||||
|
static class TestShader extends Shader {
|
||||||
|
|
||||||
|
public TestShader (GraphicsWrapper screen) {
|
||||||
|
super (screen);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void shade (Fragment fragment) {
|
||||||
|
System.out.println (" fragment: (" + fragment.getX () + ", " + fragment.getY () + ")"
|
||||||
|
+ " - color = (" + fragment.getColor() + ")");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void test() throws Exception {
|
||||||
|
|
||||||
|
System.out.println("OFF\n# Test Start");
|
||||||
|
|
||||||
|
TestShader shader = new TestShader (new GraphicsWrapper (256, 256));
|
||||||
|
Rasterizer rasterizer = new Rasterizer (shader);
|
||||||
|
|
||||||
|
System.out.println ("Rasterizing edge");
|
||||||
|
Fragment v1 = new Fragment (0, 20);
|
||||||
|
v1.setColor (0, 0, 0);
|
||||||
|
Fragment v2 = new Fragment (5, -35);
|
||||||
|
v2.setColor (50, 100, 0);
|
||||||
|
|
||||||
|
rasterizer.rasterizeEdge (v1, v2);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void main (String[] args) {
|
||||||
|
try {
|
||||||
|
test() ;
|
||||||
|
} catch (Exception e) {
|
||||||
|
System.out.println("EXCEPTION: " + e) ;
|
||||||
|
e.printStackTrace() ;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
36
Texture.java
Normal file
36
Texture.java
Normal file
|
@ -0,0 +1,36 @@
|
||||||
|
|
||||||
|
import java.awt.*;
|
||||||
|
import java.awt.image.*;
|
||||||
|
import java.io.*;
|
||||||
|
import javax.imageio.ImageIO;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 2D Texture class.
|
||||||
|
*/
|
||||||
|
public class Texture {
|
||||||
|
int width;
|
||||||
|
int height;
|
||||||
|
BufferedImage image;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs a new Texture with the content of the image at @path.
|
||||||
|
*/
|
||||||
|
public Texture (String path) throws Exception {
|
||||||
|
image = ImageIO.read (new File (path));
|
||||||
|
width = image.getWidth ();
|
||||||
|
height = image.getHeight ();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Samples the texture at texture coordinates (u,v), using nearest neighboor interpolation
|
||||||
|
* u and v and wrapped around to [0,1].
|
||||||
|
*/
|
||||||
|
public Color sample (double u, double v) {
|
||||||
|
|
||||||
|
|
||||||
|
/* A COMPLETER */
|
||||||
|
|
||||||
|
|
||||||
|
return new Color (0,0,0);
|
||||||
|
}
|
||||||
|
}
|
58
TextureShader.java
Normal file
58
TextureShader.java
Normal file
|
@ -0,0 +1,58 @@
|
||||||
|
|
||||||
|
import algebra.*;
|
||||||
|
import java.awt.*;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Simple shader that just copy the interpolated color to the screen,
|
||||||
|
* taking the depth of the fragment into acount.
|
||||||
|
* @author: cdehais
|
||||||
|
*/
|
||||||
|
public class TextureShader extends Shader {
|
||||||
|
|
||||||
|
DepthBuffer depth;
|
||||||
|
Texture texture;
|
||||||
|
boolean combineWithBaseColor;
|
||||||
|
|
||||||
|
public TextureShader (GraphicsWrapper screen) {
|
||||||
|
super (screen);
|
||||||
|
depth = new DepthBuffer (screen.getWidth (), screen.getHeight ());
|
||||||
|
texture = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setTexture (String path) {
|
||||||
|
try {
|
||||||
|
texture = new Texture (path);
|
||||||
|
} catch (Exception e) {
|
||||||
|
System.out.println ("Could not load texture " + path);
|
||||||
|
e.printStackTrace ();
|
||||||
|
texture = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setCombineWithBaseColor (boolean combineWithBaseColor) {
|
||||||
|
this.combineWithBaseColor = combineWithBaseColor;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void shade (Fragment fragment) {
|
||||||
|
if (depth.testFragment (fragment)) {
|
||||||
|
/* The Fragment may not have texture coordinates */
|
||||||
|
try {
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/* à compléter */
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
} catch (ArrayIndexOutOfBoundsException e) {
|
||||||
|
screen.setPixel (fragment.getX (), fragment.getY (), fragment.getColor ());
|
||||||
|
}
|
||||||
|
depth.writeFragment (fragment);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void reset () {
|
||||||
|
depth.clear ();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
133
Transformation.java
Normal file
133
Transformation.java
Normal file
|
@ -0,0 +1,133 @@
|
||||||
|
|
||||||
|
import algebra.*;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* author: cdehais
|
||||||
|
*/
|
||||||
|
public class Transformation {
|
||||||
|
|
||||||
|
Matrix worldToCamera;
|
||||||
|
Matrix projection;
|
||||||
|
Matrix calibration;
|
||||||
|
|
||||||
|
public Transformation() {
|
||||||
|
try {
|
||||||
|
worldToCamera = new Matrix("W2C", 4, 4);
|
||||||
|
projection = new Matrix("P", 3, 4);
|
||||||
|
calibration = Matrix.createIdentity(3);
|
||||||
|
calibration.setName("K");
|
||||||
|
} catch (InstantiationException e) {
|
||||||
|
/* should not be reached */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setLookAt(Vector3 cam, Vector3 lookAt, Vector3 up) {
|
||||||
|
try {
|
||||||
|
// compute rotation
|
||||||
|
|
||||||
|
Vector3 e3c = new Vector3(lookAt);
|
||||||
|
e3c.subtract(cam);
|
||||||
|
e3c.normalize();
|
||||||
|
|
||||||
|
Vector3 e1c = up.cross(e3c);
|
||||||
|
e1c.normalize();
|
||||||
|
|
||||||
|
Vector3 e2c = e3c.cross(e1c);
|
||||||
|
|
||||||
|
// insertion de la matrice de rotation (transposée), dans worldToCamera
|
||||||
|
|
||||||
|
worldToCamera.set(0, 0, e1c.get(0));
|
||||||
|
worldToCamera.set(0, 1, e1c.get(1));
|
||||||
|
worldToCamera.set(0, 2, e1c.get(2));
|
||||||
|
|
||||||
|
worldToCamera.set(1, 0, e2c.get(0));
|
||||||
|
worldToCamera.set(1, 1, e2c.get(1));
|
||||||
|
worldToCamera.set(1, 2, e2c.get(2));
|
||||||
|
|
||||||
|
worldToCamera.set(2, 0, e3c.get(0));
|
||||||
|
worldToCamera.set(2, 1, e3c.get(1));
|
||||||
|
worldToCamera.set(2, 2, e3c.get(2));
|
||||||
|
|
||||||
|
// le vecteur de zeros sous la rotation, dans worldToCamera
|
||||||
|
|
||||||
|
worldToCamera.set(3, 0, 0);
|
||||||
|
worldToCamera.set(3, 1, 0);
|
||||||
|
worldToCamera.set(3, 2, 0);
|
||||||
|
|
||||||
|
// le 1 en bas à droite, dans worldToCamera
|
||||||
|
|
||||||
|
worldToCamera.set(3, 3, 1);
|
||||||
|
|
||||||
|
// compute translation
|
||||||
|
|
||||||
|
Matrix M = worldToCamera.getSubMatrix(0, 0, 3, 3);
|
||||||
|
|
||||||
|
Vector t = M.multiply(cam);
|
||||||
|
|
||||||
|
// insertion du vecteur translation, dans worldToCamera
|
||||||
|
|
||||||
|
worldToCamera.set(0, 3, -t.get(0));
|
||||||
|
worldToCamera.set(1, 3, -t.get(1));
|
||||||
|
worldToCamera.set(2, 3, -t.get(2));
|
||||||
|
|
||||||
|
} catch (Exception e) {
|
||||||
|
/* unreached */
|
||||||
|
}
|
||||||
|
|
||||||
|
System.out.println("Modelview matrix:\n" + worldToCamera);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setProjection() {
|
||||||
|
// matrice "identitée" 3x4
|
||||||
|
projection.set(0, 0, 1);
|
||||||
|
projection.set(1, 1, 1);
|
||||||
|
projection.set(2, 2, 1);
|
||||||
|
|
||||||
|
System.out.println("Projection matrix:\n" + projection);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setCalibration(double focal, double width, double height) {
|
||||||
|
// focal sur la diagonale, sauf en bas à droite
|
||||||
|
calibration.set(0, 0, focal);
|
||||||
|
calibration.set(1, 1, focal);
|
||||||
|
|
||||||
|
// translation de w/2 et h/2
|
||||||
|
calibration.set(0, 2, width / 2);
|
||||||
|
calibration.set(1, 2, height / 2);
|
||||||
|
|
||||||
|
System.out.println("Calibration matrix:\n" + calibration);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Projects the given homogeneous, 4 dimensional point onto the screen.
|
||||||
|
* The resulting Vector as its (x,y) coordinates in pixel, and its z coordinate
|
||||||
|
* is the depth of the point in the camera coordinate system.
|
||||||
|
*/
|
||||||
|
public Vector3 projectPoint(Vector p) throws SizeMismatchException, InstantiationException {
|
||||||
|
|
||||||
|
Vector ps = new Vector(3);
|
||||||
|
|
||||||
|
// projection du point dans le plan
|
||||||
|
ps = calibration.multiply(projection.multiply(worldToCamera.multiply(p)));
|
||||||
|
|
||||||
|
double depth = ps.get(2);
|
||||||
|
|
||||||
|
// "normalisation" des coordonnées du point
|
||||||
|
ps.set(0, ps.get(0) / depth);
|
||||||
|
ps.set(1, ps.get(1) / depth);
|
||||||
|
// ps.scale(1 / depth);
|
||||||
|
|
||||||
|
return new Vector3(ps);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Transform a vector from world to camera coordinates.
|
||||||
|
*/
|
||||||
|
public Vector3 transformVector(Vector3 v) throws SizeMismatchException, InstantiationException {
|
||||||
|
/* Doing nothing special here because there is no scaling */
|
||||||
|
Matrix R = worldToCamera.getSubMatrix(0, 0, 3, 3);
|
||||||
|
Vector tv = R.multiply(v);
|
||||||
|
return new Vector3(tv);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
211
algebra/Matrix.java
Normal file
211
algebra/Matrix.java
Normal file
|
@ -0,0 +1,211 @@
|
||||||
|
/*
|
||||||
|
* @author: cdehais
|
||||||
|
*/
|
||||||
|
|
||||||
|
package algebra;
|
||||||
|
|
||||||
|
import java.lang.Math;
|
||||||
|
|
||||||
|
public class Matrix {
|
||||||
|
|
||||||
|
protected Matrix() {
|
||||||
|
}
|
||||||
|
|
||||||
|
protected Matrix(String name) {
|
||||||
|
this.name = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a named Matrix of size nRows x nCols.
|
||||||
|
*/
|
||||||
|
public Matrix(String name, int nRows, int nCols) throws java.lang.InstantiationException {
|
||||||
|
this(nRows, nCols);
|
||||||
|
this.name = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a Matrix of size nRows x nCols.
|
||||||
|
*/
|
||||||
|
public Matrix(int nRows, int nCols) throws java.lang.InstantiationException {
|
||||||
|
allocValues(nRows, nCols);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates an identity matrix of size @size
|
||||||
|
*/
|
||||||
|
public static Matrix createIdentity(int size) throws java.lang.InstantiationException {
|
||||||
|
Matrix id = new Matrix(size, size);
|
||||||
|
|
||||||
|
for (int i = 0; i < size; i++) {
|
||||||
|
id.values[size * i + i] = 1.0;
|
||||||
|
}
|
||||||
|
id.name = "I" + size;
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Extracts a submatrix of size nRows x nCols with top left corner at
|
||||||
|
* (offsetRow, offsetCol)
|
||||||
|
*/
|
||||||
|
public Matrix getSubMatrix(int offsetRow, int offsetCol, int nRows, int nCols)
|
||||||
|
throws InstantiationException {
|
||||||
|
if ((offsetRow < 0) || (offsetCol < 0) || (nRows < 1) || (nCols < 1) ||
|
||||||
|
(offsetRow + nRows > this.nRows) || (offsetCol + nCols > this.nCols)) {
|
||||||
|
throw new InstantiationException("Invalid submatrix");
|
||||||
|
}
|
||||||
|
|
||||||
|
Matrix sub = new Matrix(nRows, nCols);
|
||||||
|
|
||||||
|
for (int i = 0; i < nRows; i++) {
|
||||||
|
for (int j = 0; j < nCols; j++) {
|
||||||
|
sub.set(i, j, this.get(offsetRow + i, offsetCol + j));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return sub;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Transposes the square Matrix.
|
||||||
|
*/
|
||||||
|
public Matrix transpose() {
|
||||||
|
Matrix trans;
|
||||||
|
try {
|
||||||
|
trans = new Matrix(this.nCols, this.nRows);
|
||||||
|
} catch (java.lang.InstantiationException e) {
|
||||||
|
/* unreached */
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
for (int i = 0; i < nCols; i++) {
|
||||||
|
for (int j = i + 1; j < nRows; j++) {
|
||||||
|
trans.values[i * nCols + j] = this.values[j * nCols + i];
|
||||||
|
trans.values[j * nCols + i] = this.values[i * nCols + j];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return trans;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Matrix/Matrix multiplication
|
||||||
|
*/
|
||||||
|
public Matrix multiply(Matrix M) throws SizeMismatchException {
|
||||||
|
if (nCols != M.nRows) {
|
||||||
|
throw new SizeMismatchException(this, M);
|
||||||
|
}
|
||||||
|
|
||||||
|
Matrix R;
|
||||||
|
try {
|
||||||
|
R = new Matrix(this.nRows, M.nCols);
|
||||||
|
} catch (java.lang.InstantiationException e) {
|
||||||
|
/* unreached */
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < R.nRows; i++) {
|
||||||
|
for (int j = 0; j < R.nCols; j++) {
|
||||||
|
for (int k = 0; k < this.nCols; k++) {
|
||||||
|
R.values[i * R.nCols + j] += this.values[i * nCols + k] * M.values[k * nRows + j];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return R;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Matrix/vector multiplication
|
||||||
|
*/
|
||||||
|
public Vector multiply(Vector v) throws SizeMismatchException {
|
||||||
|
if (nCols != v.size()) {
|
||||||
|
throw new SizeMismatchException(this, v);
|
||||||
|
}
|
||||||
|
|
||||||
|
Vector u = null;
|
||||||
|
try {
|
||||||
|
u = new Vector(nRows);
|
||||||
|
} catch (java.lang.InstantiationException e) {
|
||||||
|
/* unreached */
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < u.size(); i++) {
|
||||||
|
double e = 0.0;
|
||||||
|
for (int k = 0; k < this.nCols; k++) {
|
||||||
|
e += values[i * nCols + k] * v.get(k);
|
||||||
|
}
|
||||||
|
u.set(i, e);
|
||||||
|
}
|
||||||
|
|
||||||
|
return u;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the element on row @i and column @j to the given value @value.
|
||||||
|
*/
|
||||||
|
public void set(int i, int j, double value) {
|
||||||
|
values[i * nCols + j] = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the element on row @i and column @j.
|
||||||
|
*/
|
||||||
|
public double get(int i, int j) {
|
||||||
|
return values[i * nCols + j];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the matrix name
|
||||||
|
*/
|
||||||
|
public void setName(String name) {
|
||||||
|
this.name = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a Matlab compatible representation of the Matrix.
|
||||||
|
*/
|
||||||
|
public String toString() {
|
||||||
|
String repr = name + " = [";
|
||||||
|
int spacing = repr.length();
|
||||||
|
for (int i = 0; i < nRows; i++) {
|
||||||
|
if (i > 0) {
|
||||||
|
for (int j = 0; j < spacing; j++) {
|
||||||
|
repr += " ";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (int j = 0; j < nCols; j++) {
|
||||||
|
repr += values[nCols * i + j] + " ";
|
||||||
|
}
|
||||||
|
repr += ";\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
repr += "];";
|
||||||
|
|
||||||
|
return repr;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void allocValues(int nRows, int nCols) throws java.lang.InstantiationException {
|
||||||
|
int size = nRows * nCols;
|
||||||
|
if (size < 1) {
|
||||||
|
throw new java.lang.InstantiationException("Both matrix dimensions must be strictly positive");
|
||||||
|
}
|
||||||
|
this.values = new double[size];
|
||||||
|
this.nRows = nRows;
|
||||||
|
this.nCols = nCols;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getName() {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int nRows() {
|
||||||
|
return nRows;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int nCols() {
|
||||||
|
return nCols;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String name = "M";
|
||||||
|
protected double values[];
|
||||||
|
private int nRows;
|
||||||
|
private int nCols;
|
||||||
|
}
|
29
algebra/SizeMismatchException.java
Normal file
29
algebra/SizeMismatchException.java
Normal file
|
@ -0,0 +1,29 @@
|
||||||
|
|
||||||
|
package algebra;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Exception class for incorrect dimensions in arithmetic operations on Matrix and Vector
|
||||||
|
*/
|
||||||
|
public class SizeMismatchException extends Exception {
|
||||||
|
|
||||||
|
public SizeMismatchException () {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public SizeMismatchException (Vector v1, Vector v2) {
|
||||||
|
super (v1.name + "[" + v1.size () + "] != " + v2.name + "[" + v2.size () + "]");
|
||||||
|
}
|
||||||
|
|
||||||
|
public SizeMismatchException (Matrix M1, Matrix M2) {
|
||||||
|
super (M1.name + "[*," + M1.nCols () + "] != " + M2.name + "[" + M2.nRows () + ",*]");
|
||||||
|
}
|
||||||
|
|
||||||
|
public SizeMismatchException (Matrix M, Vector v) {
|
||||||
|
super (M.name + "[*," + M.nCols () + "] != " + v.name + "[" + v.size () + ",*]");
|
||||||
|
}
|
||||||
|
|
||||||
|
public SizeMismatchException (String msg) {
|
||||||
|
super (msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
198
algebra/Vector.java
Normal file
198
algebra/Vector.java
Normal file
|
@ -0,0 +1,198 @@
|
||||||
|
/**
|
||||||
|
* @author: cdehais
|
||||||
|
*
|
||||||
|
* Basic linear algebra methods
|
||||||
|
*/
|
||||||
|
|
||||||
|
package algebra;
|
||||||
|
|
||||||
|
import java.lang.Math;
|
||||||
|
|
||||||
|
public class Vector implements Cloneable {
|
||||||
|
|
||||||
|
protected int size;
|
||||||
|
protected double values[];
|
||||||
|
public String name = "v";
|
||||||
|
|
||||||
|
protected Vector() {
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a named vector of size @size
|
||||||
|
*/
|
||||||
|
public Vector(String name, int size) throws java.lang.InstantiationException {
|
||||||
|
this(size);
|
||||||
|
this.name = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a vector of size @size
|
||||||
|
*/
|
||||||
|
public Vector(int size) throws java.lang.InstantiationException {
|
||||||
|
allocValues(size);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Compute the norm of the vector
|
||||||
|
*/
|
||||||
|
public double norm() {
|
||||||
|
double r = 0.0;
|
||||||
|
|
||||||
|
for (int i = 0; i < this.size; i++) {
|
||||||
|
r += this.values[i] * this.values[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
return Math.sqrt(r);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Makes the Vector unitary.
|
||||||
|
*/
|
||||||
|
public void normalize() {
|
||||||
|
double norm = norm();
|
||||||
|
|
||||||
|
for (int i = 0; i < size; i++) {
|
||||||
|
values[i] /= norm;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Multiplies the Vector by the given constant.
|
||||||
|
*/
|
||||||
|
public void scale(double f) {
|
||||||
|
for (int i = 0; i < size; i++) {
|
||||||
|
values[i] *= f;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Computes the vector dot product between the Vector and another Vector.
|
||||||
|
* Both must be the same size.
|
||||||
|
*/
|
||||||
|
public double dot(Vector v) throws SizeMismatchException {
|
||||||
|
if (size != v.size) {
|
||||||
|
throw new SizeMismatchException(this, v);
|
||||||
|
}
|
||||||
|
|
||||||
|
double d = 0.0;
|
||||||
|
|
||||||
|
for (int i = 0; i < size; i++) {
|
||||||
|
d += this.values[i] * v.values[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
return d;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds the given Vector to the Vector
|
||||||
|
*/
|
||||||
|
public void add(Vector v) throws SizeMismatchException {
|
||||||
|
if (size != v.size) {
|
||||||
|
throw new SizeMismatchException(this, v);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < size; i++) {
|
||||||
|
values[i] += v.values[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Subtracts the given Vector to the Vector
|
||||||
|
*/
|
||||||
|
public void subtract(Vector v) throws SizeMismatchException {
|
||||||
|
if (size != v.size) {
|
||||||
|
throw new SizeMismatchException(this, v);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < size; i++) {
|
||||||
|
values[i] -= v.values[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a string representation of the Vector.
|
||||||
|
* Using Matlab compatible output for easy debugging.
|
||||||
|
*/
|
||||||
|
public String toString() {
|
||||||
|
String repr = name + " = [";
|
||||||
|
|
||||||
|
for (int i = 0; i < size - 1; i++) {
|
||||||
|
repr += values[i] + ", ";
|
||||||
|
}
|
||||||
|
|
||||||
|
repr += values[size - 1] + "]';";
|
||||||
|
|
||||||
|
return repr;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the name of the Vector
|
||||||
|
*/
|
||||||
|
public void setName(String name) {
|
||||||
|
this.name = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the Vector's name
|
||||||
|
*/
|
||||||
|
public String getName() {
|
||||||
|
return this.name;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the @i-th coordinate to the given value @value.
|
||||||
|
*/
|
||||||
|
public void set(int i, double value) {
|
||||||
|
this.values[i] = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the values of the vector to the values contained in the given array
|
||||||
|
*/
|
||||||
|
public void set(double values[]) throws Exception {
|
||||||
|
if (values.length != this.size) {
|
||||||
|
throw new Exception("Bad size");
|
||||||
|
}
|
||||||
|
this.values = values;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets all elements of the vector to 0
|
||||||
|
*/
|
||||||
|
public void zeros() {
|
||||||
|
for (int i = 0; i < size; i++) {
|
||||||
|
values[i] = 0.0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets all elements of the vector to 1
|
||||||
|
*/
|
||||||
|
public void ones() {
|
||||||
|
for (int i = 0; i < size; i++) {
|
||||||
|
values[i] = 1.0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the @i-th coordinate of the Vector.
|
||||||
|
*/
|
||||||
|
public double get(int i) {
|
||||||
|
return this.values[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the Vector size
|
||||||
|
*/
|
||||||
|
public int size() {
|
||||||
|
return this.size;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void allocValues(int size) throws java.lang.InstantiationException {
|
||||||
|
if (size < 1) {
|
||||||
|
throw new java.lang.InstantiationException("Vector size must be strictly positive");
|
||||||
|
}
|
||||||
|
this.values = new double[size];
|
||||||
|
this.size = size;
|
||||||
|
}
|
||||||
|
}
|
125
algebra/Vector3.java
Normal file
125
algebra/Vector3.java
Normal file
|
@ -0,0 +1,125 @@
|
||||||
|
/**
|
||||||
|
* @author: cdehais
|
||||||
|
*/
|
||||||
|
|
||||||
|
package algebra;
|
||||||
|
|
||||||
|
import java.lang.Math;
|
||||||
|
|
||||||
|
public class Vector3 extends Vector {
|
||||||
|
|
||||||
|
public Vector3(double x, double y, double z) {
|
||||||
|
super();
|
||||||
|
try {
|
||||||
|
allocValues(3);
|
||||||
|
} catch (java.lang.InstantiationException e) {
|
||||||
|
/* unreached */
|
||||||
|
}
|
||||||
|
this.values[0] = x;
|
||||||
|
this.values[1] = y;
|
||||||
|
this.values[2] = z;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Vector3() {
|
||||||
|
this(0.0, 0.0, 0.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Vector3(String name) {
|
||||||
|
this(0.0, 0.0, 0.0);
|
||||||
|
this.setName(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new named 3D vector with coordinates (x, y, z).
|
||||||
|
*/
|
||||||
|
public Vector3(String name, double x, double y, double z) {
|
||||||
|
super();
|
||||||
|
try {
|
||||||
|
allocValues(4);
|
||||||
|
} catch (java.lang.InstantiationException e) {
|
||||||
|
/* unreached */
|
||||||
|
}
|
||||||
|
|
||||||
|
this.values[0] = x;
|
||||||
|
this.values[1] = y;
|
||||||
|
this.values[2] = z;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Copy constructor from a Vector of size 3 or 4.
|
||||||
|
* For a vector of size 4, divide the 3 first coordinates by the fourth.
|
||||||
|
*/
|
||||||
|
public Vector3(Vector v) throws InstantiationException {
|
||||||
|
this();
|
||||||
|
if ((v.size != 3) && (v.size != 4)) {
|
||||||
|
throw new InstantiationException("Can only build 3D vector from vector of size 3 or 4");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (v.size == 3) {
|
||||||
|
set(v.get(0), v.get(1), v.get(2));
|
||||||
|
} else {
|
||||||
|
double w = v.get(3);
|
||||||
|
set(v.get(0) / w, v.get(1) / w, v.get(2) / w);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Makes the x, y, and z coordinates of the Vector3 cartesian, by dividing them
|
||||||
|
* by
|
||||||
|
* the homogeneous coordinate w.
|
||||||
|
*/
|
||||||
|
public void makeCartesian() throws java.lang.ArithmeticException {
|
||||||
|
this.values[0] /= this.values[3];
|
||||||
|
this.values[1] /= this.values[3];
|
||||||
|
this.values[2] /= this.values[3];
|
||||||
|
this.values[3] = 1.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void set(double x, double y, double z) {
|
||||||
|
this.values[0] = x;
|
||||||
|
this.values[1] = y;
|
||||||
|
this.values[2] = z;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Computes the cross product between the Vector3 and the given vector.
|
||||||
|
*/
|
||||||
|
public Vector3 cross(Vector3 v) {
|
||||||
|
double rx = this.getY() * v.getZ() - this.getZ() * v.getY();
|
||||||
|
double ry = this.getZ() * v.getX() - this.getX() * v.getZ();
|
||||||
|
double rz = this.getX() * v.getY() - this.getY() * v.getX();
|
||||||
|
|
||||||
|
return new Vector3(rx, ry, rz);
|
||||||
|
}
|
||||||
|
|
||||||
|
public double dot(Vector3 v) {
|
||||||
|
double r = 0.0;
|
||||||
|
return (values[0] * v.values[0] + values[1] * v.values[1] + values[2] * v.values[2]);
|
||||||
|
}
|
||||||
|
|
||||||
|
public double norm() {
|
||||||
|
double r = (values[0] * values[0] + values[1] * values[1] + values[2] * values[2]);
|
||||||
|
return Math.sqrt(r);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the x coordinates of the Vector3
|
||||||
|
*/
|
||||||
|
public double getX() {
|
||||||
|
return this.values[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the w coordinates of the Vector3
|
||||||
|
*/
|
||||||
|
public double getY() {
|
||||||
|
return this.values[1];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the w coordinates of the Vector3
|
||||||
|
*/
|
||||||
|
public double getZ() {
|
||||||
|
return this.values[2];
|
||||||
|
}
|
||||||
|
}
|
BIN
data/brick.jpg
Normal file
BIN
data/brick.jpg
Normal file
Binary file not shown.
After Width: | Height: | Size: 150 KiB |
1330
data/colored_stfdbunny.off
Normal file
1330
data/colored_stfdbunny.off
Normal file
File diff suppressed because it is too large
Load diff
23
data/cube_multi_color.off
Normal file
23
data/cube_multi_color.off
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
OFF
|
||||||
|
8 12 0
|
||||||
|
# fichier OFF non standard pour ajouter les couleurs (RGB):
|
||||||
|
0 0 0 0.9 0.9 0.9
|
||||||
|
1 0 0 0.8 0. 0
|
||||||
|
1 1 0 0.8 0.8 0
|
||||||
|
0 1 0 0. 0.8 0.
|
||||||
|
0 0 1 0 0 0.8
|
||||||
|
1 0 1 0.8 0. 0.8
|
||||||
|
1 1 1 0.8 0.8 0.8
|
||||||
|
0 1 1 0 0.8 0.8
|
||||||
|
3 0 1 4
|
||||||
|
3 1 5 4
|
||||||
|
3 1 2 5
|
||||||
|
3 2 6 5
|
||||||
|
3 2 3 6
|
||||||
|
3 3 7 6
|
||||||
|
3 3 0 7
|
||||||
|
3 0 4 7
|
||||||
|
3 4 5 7
|
||||||
|
3 5 6 7
|
||||||
|
3 3 2 0
|
||||||
|
3 2 1 0
|
23
data/cube_trigs_color.off
Normal file
23
data/cube_trigs_color.off
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
OFF
|
||||||
|
8 12 0
|
||||||
|
# fichier OFF non standard pour ajouter les couleurs (RGB):
|
||||||
|
0 0 0 0.8 0 0
|
||||||
|
1 0 0 0.8 0 0
|
||||||
|
1 1 0 0.8 0 0
|
||||||
|
0 1 0 0.8 0 0
|
||||||
|
0 0 1 0.8 0 0
|
||||||
|
1 0 1 0.8 0 0
|
||||||
|
1 1 1 0.8 0 0
|
||||||
|
0 1 1 0.8 0 0
|
||||||
|
3 0 1 4
|
||||||
|
3 1 5 4
|
||||||
|
3 1 2 5
|
||||||
|
3 2 6 5
|
||||||
|
3 2 3 6
|
||||||
|
3 3 7 6
|
||||||
|
3 3 0 7
|
||||||
|
3 0 4 7
|
||||||
|
3 4 5 7
|
||||||
|
3 5 6 7
|
||||||
|
3 3 2 0
|
||||||
|
3 2 1 0
|
19
data/example0.scene
Normal file
19
data/example0.scene
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
|
||||||
|
# object filename:
|
||||||
|
data/cube_multi_color.off
|
||||||
|
# camera position:
|
||||||
|
3.0 5.0 5.0
|
||||||
|
# camera looks at:
|
||||||
|
0.0 0.0 0.0
|
||||||
|
# camera's y vector:
|
||||||
|
0.0 -1.0 0.0
|
||||||
|
# focal length:
|
||||||
|
512
|
||||||
|
# w and h (pixels):
|
||||||
|
512 512
|
||||||
|
# ambient light intensity Ia
|
||||||
|
1.8
|
||||||
|
# point light : 3D coordinates and ligth intensity (x, y, z, Id)
|
||||||
|
0.0 0.0 8.0 9.0
|
||||||
|
# object material parameters (Ka, Kd, Ks, s)
|
||||||
|
0.5 0.5 0.5 1.0
|
21
data/example1.scene
Normal file
21
data/example1.scene
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
|
||||||
|
# object filename:
|
||||||
|
data/colored_stfdbunny.off
|
||||||
|
# camera position:
|
||||||
|
2.0 2.0 3.0
|
||||||
|
# camera looks at:
|
||||||
|
0.0 0.1 0.0
|
||||||
|
# camera's y vector:
|
||||||
|
0.0 -1.0 0.0
|
||||||
|
# focal length:
|
||||||
|
3500
|
||||||
|
# w and h (pixels):
|
||||||
|
640 480
|
||||||
|
# ambient light intensity Ia
|
||||||
|
0.5
|
||||||
|
# point light : 3D coordinates and ligth intensity (x, y, z, Id)
|
||||||
|
5.0 8.0 8.0 4.0
|
||||||
|
# object material parameters (Ka, Kd, Ks, s)
|
||||||
|
0.5 0.5 0.5 1.0
|
||||||
|
|
||||||
|
|
19
data/example2.scene
Normal file
19
data/example2.scene
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
|
||||||
|
# object filename:
|
||||||
|
data/monkey2.off
|
||||||
|
# camera position:
|
||||||
|
-1.0 3.0 4.0
|
||||||
|
# camera looks at:
|
||||||
|
0.0 0.0 0.0
|
||||||
|
# camera's y vector:
|
||||||
|
0.0 -1.0 0.0
|
||||||
|
# focal length (pixels):
|
||||||
|
2000
|
||||||
|
# w and h (pixels):
|
||||||
|
800 600
|
||||||
|
# ambient (white) light intensity Ia
|
||||||
|
1.0
|
||||||
|
# point light : 3D coordinates and ligth intensity (x, y, z, Id)
|
||||||
|
0.0 0.0 8.0 0.8
|
||||||
|
# object material parameters (Ka, Kd, Ks, s)
|
||||||
|
0.5 0.5 0.5 3.0
|
19
data/example_textured.scene
Normal file
19
data/example_textured.scene
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
|
||||||
|
# object filename:
|
||||||
|
data/textured_facet.off
|
||||||
|
# camera position:
|
||||||
|
0.75 1.25 0.5
|
||||||
|
# camera looks at:
|
||||||
|
0.5 0.5 0.0
|
||||||
|
# camera's y vector:
|
||||||
|
0.0 0.0 1.0
|
||||||
|
# focal length (pixels):
|
||||||
|
256
|
||||||
|
# w and h (pixels):
|
||||||
|
512 512
|
||||||
|
# ambient light intensity Ia
|
||||||
|
0.1
|
||||||
|
# point light : 3D coordinates and ligth intensity (x, y, z, Id)
|
||||||
|
0.0 0.0 8.0 0.9
|
||||||
|
# object material parameters (Ka, Kd, Ks, s)
|
||||||
|
0.5 0.5 0.5 10.0
|
8757
data/monkey2.off
Normal file
8757
data/monkey2.off
Normal file
File diff suppressed because it is too large
Load diff
9
data/textured_facet.off
Normal file
9
data/textured_facet.off
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
OFF
|
||||||
|
4 2 0
|
||||||
|
# fichier OFF non standard pour ajouter les couleurs (RGB) et les uv
|
||||||
|
0 0 0 1.0 0.0 0.0 0.0 0.0
|
||||||
|
1 0 0 0.0 1.0 0.0 2.0 0.0
|
||||||
|
1 1 0 0.0 0.0 1.0 2.0 4.0
|
||||||
|
0 1 0 0.8 0.1 0.1 0.0 4.0
|
||||||
|
3 0 1 3
|
||||||
|
3 1 2 3
|
BIN
data/world_map.jpg
Normal file
BIN
data/world_map.jpg
Normal file
Binary file not shown.
After Width: | Height: | Size: 80 KiB |
Loading…
Reference in a new issue