Commit db6f3775 authored by Sofus Rose's avatar Sofus Rose

Added work so far.

parents
This diff is collapsed.
MRGB 1 1 1
EYEP 50 50 180
VDIR 0 0 -1
UVEC 0 1 0
FOVY 45
ENDS
# Step Size, Background, Resolution.
STEP 1 #Step Size
BRGB 1 1 1 #Background Color of Alpha is OFF.
ALPH true #Turn on alpha background.
RESO 512 512 #Resolution
# Start frame, stop frame, prefix for config files.
STAR 7
STOP 15
PREF /home/sofus/subhome/src/linemarch/blender_addon/configs/out #Prefix for config files (overwrite this one). Uses START/STOP.
VOXN /home/sofus/subhome/src/linemarch/blender_addon/vox.txt #Prefix for Voxel density file. Uses START/STOP.
FILE ren/output #Output file prefix.
# Voxel Data
DIMS 100 100 100 #Size of loaded density file.
LOFR 0 #0: Load file. 1: Generate Perlin Noise.
PNOI 4 0.03 2.4 216 #Perlin Noise Attributes: Octaves, Frequency, Amplitude, Seed
CENT 0 0 0
# Selected Render Pass: 0, RGBAZ. 1, SPEC.
#~ PASS 0
# Static Lights.
#~ LPOS 100 0 0
#~ LCOL 2 0 0
#~ LPOS 0 0 0
#~ LCOL 0 2 0
#~ LPOS 50 0 0
#~ LCOL 0 0 2
# Material Attributes
MRGB 1 1 1
KATT 1 #Attenuation.
DENS 5 #Density divisor.
# Camera Data. Really want to do these in the individual configs, unless this is the only config.
EYEP 0 0 200
VDIR 0 0 -1
UVEC 0 1 0
FOVY 45
import math, sys
def fSphere(dims, f, inRad=10, outRad=50) : center = (dims[0]/2,dims[1]/2,dims[2]/2) for z in range(dims[2]): for y in range(dims[1]): for x in range(dims[0]): dx = abs(center[0] - x) dy = abs(center[1] - y) dz = abs(center[2] - z) cenDist = math.sqrt(dx*dx + dy*dy + dz*dz) if cenDist <= inRad: print(1, file=f) elif cenDist < outRad: print(1 - ( (cenDist-inRad) / (outRad-inRad) ), file=f) else: print(0, file=f)
def sphere(dims, f, rad=50) : center = (dims[0]/2,dims[1]/2,dims[2]/2) for z in range(dims[2]): for y in range(dims[1]): for x in range(dims[0]): dx = abs(center[0] - x) dy = abs(center[1] - y) dz = abs(center[2] - z) cenDist = math.sqrt(dx*dx + dy*dy + dz*dz) if cenDist < rad: print(1, file=f) else: print(0, file=f) def ripple(dims, f) : center = (dims[0]/2,dims[1]/2,dims[2]/2) for z in range(dims[2]): for y in range(dims[1]): for x in range(dims[0]): dx = abs(center[0] - x) dy = abs(center[1] - y) dz = abs(center[2] - z) val = sin(10(dx**2+dy^2))/10 if dz < val : print(1, f) else : print(0, f) if __name__ == "__main__" : if not sys.argv[1:] : inner = 10 outer = 35 else : inner=float(sys.argv[1]) outer=float(sys.argv[2]) dims = (100, 100, 100) with open('vox.txt', mode='w') as f: fSphere(dims, f, inRad=inner, outRad=outer) #~ print(inner, outer) #~ sphere(dims, f, rad=outer)
\ No newline at end of file
[editor]
line_wrapping=false
line_break_column=120
auto_continue_multiline=true
[file_prefs]
final_new_line=true
ensure_convert_new_lines=false
strip_trailing_spaces=false
replace_tabs=false
[indentation]
indent_width=4
indent_type=1
indent_hard_tab_width=8
detect_indent=false
detect_indent_width=false
indent_mode=2
[project]
name=linemarch
base_path=/home/sofus/subhome/src/linemarch
description=
file_patterns=*.cpp;*.h;*.txt;
[long line marker]
long_line_behaviour=1
long_line_column=72
[files]
current_page=0
[VTE]
last_dir=/home/sofus/subhome/src/linemarch
[prjorg]
source_patterns=*.c;*.C;*.cpp;*.cxx;*.c++;*.cc;*.m;
header_patterns=*.h;*.H;*.hpp;*.hxx;*.h++;*.hh;
ignored_dirs_patterns=.*;CVS;
ignored_file_patterns=*.o;*.obj;*.a;*.lib;*.so;*.dll;*.lo;*.la;*.class;*.jar;*.pyc;*.mo;*.gmo;
generate_tag_prefs=0
external_dirs=
[build-menu]
JavaFT_00_LB=_Compile
JavaFT_00_CM=ant jar-unsigned -f ../build.xml
JavaFT_00_WD=
JavaFT_01_LB=Build Docs
JavaFT_01_CM=ant doc -f ../build.xml
JavaFT_01_WD=
filetypes=Java;
#include "OpenImageIO/imageio.h"
OIIO_NAMESPACE_USING
#include <omp.h>
#include "march.h"
#include "reader.h"
#include <iostream>
#include <string>
#include <chrono>
#include <unistd.h>
#include <sys/resource.h>
using namespace std;
int main(int argc, char* argv[]) {
// TODO: Output All Passes simultaneously. HINT: enumeration is just a fancy list of int states.
// TODO: Blender addon, using named empty properties.
// Enable to debug segfaults.
struct rlimit core_limits;
core_limits.rlim_cur = core_limits.rlim_max = RLIM_INFINITY;
setrlimit(RLIMIT_CORE, &core_limits);
//Read constants file.
string conf = "";
if (argc > 1) conf = (string)argv[1];
else conf = "constants.txt";
// Setup basic variables.
March marcher = March();
Reader reader = Reader(&marcher);
cout << "Reading Constants File: " + conf << endl;
reader.read(conf);
vector<Vec4> defLPos = marcher.lightPos;
vector<Vec3> defLCol = marcher.lightCol;
//~ if (marcher.pref.empty()) marcher.startFrame = 0; marcher.stopFrame = 0;
if (marcher.voxName.empty()) marcher.voxName = "vox.txt";
//~ cout << marcher.stopFrame << endl;
for(int frame = marcher.startFrame; frame <= marcher.stopFrame; frame++) {
marcher.lightPos = defLPos;
marcher.lightCol = defLCol;
if (!marcher.pref.empty()) reader.read(marcher.pref + to_string(frame) + ".txt"); //Read config sequence.
//~ March::testVals(marcher);
//~ return 0; //Test the reader.
//Setup image specs.
string filename;
if (!marcher.pref.empty()) filename = marcher.outFile + to_string(frame) + ".exr";
else filename = marcher.outFile + ".exr";
const int xres = marcher.resolution[0];
const int yres = marcher.resolution[1];
const int channels = 5; // RGB for Rendering
struct Pixel { //Struct where values will go.
float r, g, b, a, z;
};
Pixel* pixels = new Pixel[xres*yres];
//Render itself.
marcher.pass = (Passes)0;//DEPTH;
marcher.setupCamera();
marcher.setupVoxels();
unsigned long progress = 0;
if (!marcher.pref.empty()) cout << "Rendering with config: " + marcher.pref + to_string(frame) + ".txt" + "..." << endl;
else cout << "Rendering..." << endl;
//Wee bit of benchmarking :)
unsigned long start_ms = chrono::system_clock::now().time_since_epoch() / chrono::milliseconds(1);
//The "magic".
//~ #pragma omp parallel for //We're NOT THREAD SAFE!!! (But that's OK)
for(int i=0; i < xres*yres; i++) {
// Determine x and y for raycasting.
int y = i / xres;
int x = i % xres;
// Update progress
if (progress % 500 == 0 && progress != 0) {
cout << "\r" << ((double)progress / (double)(xres*yres)) * 100 << "% " << flush; //Percent Finished.
}
//"Magic" Calculations
Vec4 ray = marcher.rayCast(x, y); //Returns a ray.
Image vals = marcher.march(ray); //Marches along the ray, taking lighting into account. Uses alpha.
pixels[i].r = vals.rgb.x;
pixels[i].g = vals.rgb.y;
pixels[i].b = vals.rgb.z;
pixels[i].a = vals.alpha;
pixels[i].z = vals.depth;
progress++;
}
//Finishing the benchmark and printing it (with correct OOMs!)
unsigned long end_ms = chrono::system_clock::now().time_since_epoch() / chrono::milliseconds(1);
float time_sec = (float)(end_ms - start_ms) / 1000;
cout << "Render completed in " << time_sec << " seconds." << endl;
//Create output image.
ImageOutput *out = ImageOutput::create ("tmpOut.exr");
if (! out) {
cout << "Image Creation Failed." << endl;
delete out;
return 1;
}
if (! out->supports("channelformats")) {
delete out;
return 1;
}
ImageSpec spec (xres, yres, channels, TypeDesc::FLOAT);
//Per Channel
spec.channelformats.push_back (TypeDesc::FLOAT);
spec.channelformats.push_back (TypeDesc::FLOAT);
spec.channelformats.push_back (TypeDesc::FLOAT);
spec.channelformats.push_back (TypeDesc::FLOAT);
spec.channelformats.push_back (TypeDesc::FLOAT);
spec.channelnames.clear ();
spec.channelnames.push_back ("R");
spec.channelnames.push_back ("G");
spec.channelnames.push_back ("B");
spec.channelnames.push_back ("A");
spec.channelnames.push_back ("Z");
//Write image.
out->open ("tmpOut.exr", spec);
out->write_image (TypeDesc::UNKNOWN, pixels, sizeof(Pixel));
out->close();
delete out;
//Copy over file. Overwrite if exists.
remove(filename.c_str());
link("tmpOut.exr", filename.c_str());
unlink("tmpOut.exr");
cout << filename << " written!\n" << std::endl;
}
return 0;
}
#Macros
SHELL = /bin/sh
OBJS = main.o reader.o march.o math.o perlin.o
CXXFLAGS = -Wall -fopenmp -std=gnu++11 -O3
CXX = gcc
LIBS = -lOpenImageIO
DATE = $(shell date)
#Main Rules
all: march
clean:
-rm -f *.o march
install:
@echo "Not Yet Implemented"
debug:
#Executables
march: ${OBJS}
${CXX} ${CXXFLAGS} ${OBJS} ${LIBS} -g -o $@
@echo "Successfully compiled at" ${DATE}
#Dependencies
#.cpp.o:
%.o: %.cpp
${CXX} ${CXXFLAGS} -c $<
#include <cmath>
#include <iostream>
#include <fstream>
#include "march.h"
#include "perlin.h"
using namespace std;
March::March() {
}
March::~March() {}
void March::testVals(March marcher) {
cout << "stepSize " << marcher.stepSize << endl;
cout << "dimensions " << marcher.dimensions[0] << endl;
cout << "dimensions " << marcher.dimensions[1] << endl;
cout << "dimensions " << marcher.dimensions[2] << endl;
cout << "backColor " << marcher.backColor.x << endl;
cout << "backColor " << marcher.backColor.y << endl;
cout << "backColor " << marcher.backColor.z << endl;
cout << "volColor " << marcher.volColor.x << endl;
cout << "volColor " << marcher.volColor.y << endl;
cout << "volColor " << marcher.volColor.z << endl;
cout << "outFile " << marcher.outFile << endl;
cout << "resolution " << marcher.resolution[0] << endl;
cout << "resolution " << marcher.resolution[1] << endl;
cout << "eyePos " << marcher.eyePos.x << endl;
cout << "eyePos " << marcher.eyePos.y << endl;
cout << "eyePos " << marcher.eyePos.z << endl;
cout << "camUp " << marcher.camUp.x << endl;
cout << "camUp " << marcher.camUp.y << endl;
cout << "camUp " << marcher.camUp.z << endl;
cout << "camDir " << marcher.camDir.x << endl;
cout << "camDir " << marcher.camDir.y << endl;
cout << "camDir " << marcher.camDir.z << endl;
for (uint i=0; i < marcher.lightPos.size(); i++) {
cout << "Light Pos " << i << ' ' << marcher.lightPos[i].x << endl;
cout << "Light Pos " << i << ' ' << marcher.lightPos[i].y << endl;
cout << "Light Pos " << i << ' ' << marcher.lightPos[i].z << endl;
cout << "Light Pos " << i << ' ' << marcher.lightPos[i].w << endl;
}
cout << "fov " << marcher.fov << endl;
for (uint i=0; i < marcher.lightCol.size(); i++) {
cout << "lightCol " << i << ' ' << marcher.lightCol[i].x << endl;
cout << "lightCol " << i << ' ' << marcher.lightCol[i].y << endl;
cout << "lightCol " << i << ' ' << marcher.lightCol[i].z << endl;
}
cout << "useAlpha " << marcher.useAlpha << endl;
cout << "voxName " << marcher.voxName << endl;
cout << "loadFrom " << marcher.loadFrom << endl;
cout << "noiseAttr " << marcher.noiseAttr[0] << endl;
cout << "noiseAttr " << marcher.noiseAttr[1] << endl;
cout << "noiseAttr " << marcher.noiseAttr[2] << endl;
cout << "noiseAttr " << marcher.noiseAttr[3] << endl;
cout << "denDiv " << marcher.denDiv << endl;
cout << "k " << marcher.k << endl;
cout << "Center " << marcher.vCent << endl;
cout << "voxDetail " << marcher.voxDetail << endl;
}
void March::setupCamera() {
//E = Eye world coordinates = eyePos
//C = viewing direction vector (normalized) = camDir
//U = up
//fov = horizontal 1/2 angle
//fovv = vertical 1/2 angle
//W in Vec4: 1 means position, 0 means direction (essentially a toggle for whether translations apply).
//^^^ Homogenous Coordinates: Using 4 value vector for 3D space.
//~ eyePos = Vec4(-100, 0, 360, 1); //180 is location in relation to origin.
//~ camDir = Vec4(0, 0, -1, 0); //Pointing along -z direction.
//~ camUp = Vec4(0, 1, 0, 0); //Pointing along +y direction; up.
//~ fov = 45.0;
//~ lightPos = Vec4(-100, 0, 0, 1);
//~ lightCol = Vec3(1, 0, 0);
perlin = new Perlin((int)noiseAttr[0], noiseAttr[1], noiseAttr[2], (int)noiseAttr[3]); //Setup noise object.
k = 1;
A = camDir.normalized().cross(camUp); //Parallel to x axis, and also view plane.
B = A.cross(camDir.normalized()); //In our case, up and b are the same.
midpoint = eyePos + camDir.normalized(); //Midpoint of the screen, in WORLD SPACE.
float aspectRatio = (float)resolution[1] / (float)resolution[0]; //Switch 1 and 0?
float vAspectRatio = (float)resolution[0] / (float)resolution[1]; //Switch 1 and 0?
halfHori = ( A * camDir.normalized().length() * tan((fov * aspectRatio) * PI/180.0) ) / A.length();
halfVert = ( B * camDir.normalized().length() * tan((fov * aspectRatio / vAspectRatio) * PI/180.0) ) / B.length(); //Or just square the aspect ratio.
}
Vec4 March::rayCast(int x, int y) {
// x and y are non-normalized pixels on the output.
//(x / xRes) - .5 = Sx in NDC. B/C origin is at midpoint, shift
// .5 to the left and down.
float Sx = ((float)x / (float)(resolution[0]));
float Sy = ((float)y / (float)(resolution[1])); //From 0 to 1, left edge to right edge.
Vec4 P = midpoint + ( halfHori * (2 * Sx - 1) ) + ( halfVert * (2 * Sy - 1) );
Vec4 ray = (P - eyePos);
//~ Vec4 ray = eyePos + (P - eyePos).normalized();
//~ cout << "Ray: " << ray << " Vec " << (float)resolution[1] / (float)resolution[0] << " NDC x: " << (2 * Sx - 1) << " NDC y: " << (2 * Sy - 1) << " x: " << x << " y: " << y << endl;
return ray.normalized();
}
void March::setupVoxels() { //Expand later.
maxDist = eyePos.length() + sqrt(pow(dimensions[0], 2) + pow(dimensions[1], 2) + pow(dimensions[2], 2));
float ***tmp = new float**[dimensions[0]]; //density.txt: x, y, then z.
for(int i=0; i<dimensions[0]; i++){
tmp[i] = new float*[dimensions[1]];
for(int j =0; j<dimensions[1]; j++){
tmp[i][j] = new float[dimensions[2]];
for(int k = 0; k<dimensions[2]; k++){
tmp[i][j][k] = 0;
}
}
}
voxels = tmp;
string line;
ifstream myfile;
myfile.open(voxName);
if (myfile.is_open()) {
int x = 0; int y = 0; int z = 0;
while (getline(myfile,line)) {
voxels[x][y][z] = atof(line.c_str());
if(x == dimensions[0] - 1) {
x = 0;
if(y == dimensions[1] - 1) {
y = 0;
if(z == dimensions[2] - 1) {
break;
} else {
z++;
}
} else {
y++;
}
} else {
x++;
}
}
}
}
Image March::march(Vec4 ray) {
struct Image out;
out.rgb = Vec3(0, 0, 0);
if(useAlpha) out.alpha = 0;
else out.alpha = 1;
out.depth = 0;
//~ Vec3 color = Vec3(0, 0, 0); //Starting color is black.
Vec4 position = eyePos;
float transmit = 1; //This is the inverted alpha.
float dTransmit = 0;
float tTerm = 0; //For later optimization.
bool firstDepth = true;
bool firstSpec = true; //Only run specular and depth calculations on the first non-zero density point.
while((position - eyePos).length() < maxDist && transmit > 0.0001) {
position = position + (ray * stepSize);
float density = sample(position);
if(density == 0) continue; //Cool optimization - avoid all that lighting bullshit :).
if(pass == SPEC && firstSpec) {
float sum = 0;
for (uint i=0; i < lightPos.size(); i++) { //For each light
Vec4 lDir = (lightPos[i] - position).normalized();
float d2 = sample(position + lDir);
if(d2 == 0) {
float f = lDir.dot(ray);
sum += f;
}
}
firstSpec = false;
out.rgb = Vec3(sum);
}
if(firstDepth) {
if(transmit < .3) {
out.depth = (position-eyePos).length();
firstDepth = false; //Only get the depth once.
}
}
if(pass == RGBAZ) {
dTransmit = exp(-k * stepSize * density);
transmit *= dTransmit;
tTerm = ((1 - dTransmit) / k) * transmit; //This calculation happens once, only.
for (uint i=0; i < lightPos.size(); i++) {
float lTrans = lightTransmit(position, lightPos[i]);
out.rgb = out.rgb + volColor.colMult(lightCol[i]) * tTerm * lTrans;
//Color contribution from the light at the current voxel. Do for each loop and accumulate for all lights.
}
}
}
if(transmit < 0.00015) transmit = 0; //Make sure it flattens out.
if(useAlpha) out.alpha = 1 - transmit; //Set alpha channel.
if(!useAlpha) out.rgb = out.rgb + (backColor * transmit);
return out;
}
float March::getDensity(Vec4 pos) {
//Voxel Density Lookup.
Vec3 oldCent = Vec3((dimensions[0] / 2), (dimensions[1] / 2), (dimensions[2] / 2));
if(
(((int)(pos.x * voxDetail) < ((int)vCent.x + oldCent.x)) && ((int)(pos.x * voxDetail) >= ((int)vCent.x - oldCent.x)))
&& ((int)(pos.y * voxDetail) < ((int)vCent.y + oldCent.y) && (int)(pos.y * voxDetail) >= ((int)vCent.y - oldCent.y))
&& ((int)(pos.z * voxDetail) < ((int)vCent.z + oldCent.z) && (int)(pos.z * voxDetail) >= ((int)vCent.z - oldCent.z)) // Centered at vCent.
) {
return voxels[(int)(pos.x * voxDetail) + ((int)oldCent.x - (int)vCent.x)][(int)(pos.y * voxDetail) + ((int)oldCent.y - (int)vCent.y)][(int)(pos.z * voxDetail) + ((int)oldCent.z - (int)vCent.z)] / denDiv;
} else {
return 0;
}
}
float March::sample(Vec4 pos) {
if(loadFrom == 1) {
Vec4 center = vCent;
float radius = 35;
float dist = (1 - ((pos - center) * (1 / radius)).length() ) + perlin->Get(pos.x, pos.y, pos.z);
if (dist > 0) return dist;
return 0;
} else if (loadFrom == 0) {
return getDensity(pos);
}
return 0;
}
float March::lightTransmit(Vec4 pos, Vec4 lightP) {
//Returns the transmittence between starting pos and light.
Vec4 position = pos; //Starts at pos.
float transmit = 1;
Vec4 ray = (lightP - pos).normalized();
float lightLength = (lightP - pos).length();
float dTransmit = 0;
while(((position - pos).length() < lightLength)) {
position = position + (ray * stepSize);
float density = sample(position);
if(density == 0) continue; //Cool optimization, though only for faraway light - no use updating transmit if it's just gonna be transmit *= exp(0)...
dTransmit = exp(-k * stepSize * density);
transmit *= dTransmit;
}
return transmit;
}
//Good casting test: Feed in x and y, get generated ray R, use its x/y/z as r/g/b.
#ifndef MARCH
#define MARCH
#include <iostream>
#include <string>
#include <vector>
#include "math.h"
#include "perlin.h"
using namespace std;
enum Passes {RGBAZ, SPEC,};
struct Image {
Vec3 rgb;
float alpha; //0..1 range
float depth; //Will go > 1.
float spec; //Direct bw reflection.
};
class March {
public:
March();
~March();
static void testVals(March);
Vec4 A;
Vec4 B;
Vec4 H;
Vec4 V;
Vec4 halfHori;
Vec4 halfVert;
Vec4 midpoint;
float stepSize; //Step size
int dimensions[3]; //Dimensions of voxelbuffer.
float voxDetail;
Vec3 backColor; //Background color.
Vec3 volColor; //Color of Volume
string outFile; //Destination filename.
int resolution[2]; //Final resolution of image.
Vec4 eyePos; //Position of the vcamera in space.
Vec4 camDir; //Direction of camera in space.
Vec4 camUp; //Up vector for camera.
float fov; //Field of view
vector<Vec4> lightPos; //Light positions.
vector<Vec3> lightCol; //Light colors.
//~ Vec4 lightPos; //Light position.
//~ Vec3 lightCol; //Light color.
float k; //Attenuation.
void setupCamera();
Vec4 rayCast(int, int);
float maxDist;
//Noise Stuff
Perlin* perlin;
float ***voxels;
void setupVoxels();
Image march(Vec4);
float getDensity(Vec4);
float sample(Vec4 pos); //0: File, 1: Perlin
float lightTransmit(Vec4, Vec4);
Passes pass;
int startFrame; //First frame
int stopFrame; //Last frame
string pref; //Prefix for config.
bool useAlpha; //Whether or not to use config.
string voxName; //Name of voxel file to load.
int loadFrom; //Int of what to load from. 0: File, 1: Perlin
float noiseAttr[4]; //Array of noise attributes.
float denDiv; //Density divisor. Weird that I need this...
Vec4 vCent; //Center of whichever mechanism we're using.
};
#endif
#include "math.h"
#include <cmath>
#include <algorithm>
using namespace std;
//Vec3 convention: Provide statistics, make new copy.
//Homogenous coordinates: 0 is directional, 1 is coordinate.
Vec3::Vec3() {
x = 0;
y = 0;
z = 0;
}
Vec3::Vec3(float xIn, float yIn, float zIn) {
x = xIn;
y = yIn;
z = zIn;
}
Vec3::Vec3(float in) {
x = in;
y = in;
z = in;
}
Vec3::Vec3(Vec4 in, int drop) {
switch (drop) {
case 1 :
x = in.y;
y = in.z;
z = in.w;
case 2 :
x = in.x;
y = in.z;
z = in.w;
case 3 :
x = in.x;
y = in.y;
z = in.w;
case 4 :
x = in.x;
y = in.y;
z = in.z;
}
}
/*Vec3::Vec3(Vec3 vecIn) {
x = vecIn.x;
y = vecIn.y;
z = vecIn.z;
}*/
Vec3::~Vec3() {}
float Vec3::length() {
return sqrt( x*x + y*y + z*z );
}
Vec3 Vec3::normalized() {
float len = length();
Vec3 tempVec;