diff --git a/README.md b/README.md index 27b5336..f3f4344 100644 --- a/README.md +++ b/README.md @@ -1,72 +1,17 @@ # HW 6: Ray marching and SDFs -## Goal -In this assignment, you will be implementing SDF operators on various primitives and use a ray marcher to render them. Ray marching is a technique for rendering implicit surfaces where the ray-primitive intersection equation cannot be solved analytically. +I used ray-marching and sine distance fields to create an animated robot. The final project can be found at https://tabathah.github.io/Project6-RayMarching-Implicit-Surfaces. Here are some pictures of the final product: -**Warning**: this assignment diverges significantly from marching cubes, so switching options midway can be costly for your time and effort. +![](./robot1.PNG) ![](./robot2.PNG) -## Base code framework +For every fragment in the scene, I cast a ray from the camera position to the fragment. I then march down this ray, evaluating how far I should I march by the closest value based on sine distance fields of the objects in my scene, until I reach a sine distance field value less than a certain epsilon value. -We have provided a preview scene, and a toggle for the ray marcher rendering. When you correctly implement the ray marcher, the image should match the preview scene containing the simple geometry. Your ray marching calculation should be performed in the fragment shader. +I implemented the following primitive shapes and operators for sine distance fields, using IQ's SDF notes (http://iquilezles.org/www/articles/distfunctions/distfunctions.htm) as a reference. -### Ray Marcher (25 pts) +I wrote SDF methods for Sphere, Box, Cone, Cylinder, and Torus. I also wrote operators, union, intersection, and subtraction, to combine them. I also wrote a function that took in a point and a matrix that included translation and rotation (scale was dealt with manually in the parameters of the SDFs), and applied the inverse of these transformations on the point to put it in world space, rather than local object space. -The ray marcher should generate a ray direction, and march through the scene using the distances computed from sphere tracing. +I also wrote a function to compute the normal of the point using the SDFs, and computed a simple Lambertian shader. -**Note**: Your scene won't be rendered until you have implemented the SDFs for primitives below. +To animate my robot, I passed time in as a uniform, and translated the neck/head, the arms, and the legs based on the time value. -- Generate Rays (15 pts): for each fragment inside the fragment shader, compute a ray direction for the ray marcher -- Sphere Tracing (10 pts): compute the nearest distance from the scene SDFs and update the ray marching's step size. - -### SDF (50 pts) -##### Implement primitive SDFs (15pts): -These are simple primitives with well-defined SDFs. We encourage trying other SDFs not listed here, they are interesting! - - Sphere (3pts) - - Box (3pts) - - Cone (3pts) - - Torus (3pts) - - Cylinder (3pts) - -##### Useful Operators (15pts) -To create constructive geometry, and interesting shapes (such as holes, bumps, etc.), implement the following operators to combine your primitive SDFs. - - Intersection (2pts) - - Subtraction (3pts) - - Union (2pts) - - Transformation (8pts) - - translation and scaling -##### Compute normals based on gradient (15 pts) - -Compute the normals to use for shading your surface. -- Read Chapter 13 of [Morgan McGuire's notes](http://graphics.cs.williams.edu/courses/cs371/f14/reading/implicit.pdf) -##### Material (5pts) -Implement a simple Lambert material. Additional materials can earn extra points. - -### Custom Scene (25 pts) -##### Create a mechanical device or a scene of your choice using all operators - - intersection, subtraction, union, transformation (20pts) -##### Animate the scene (5pts) -Use time as an input to some of your functions to animate your scene! - -## Extra credits (Up to 30 pts) -- Implement SDF for [Mandelbulb](https://www.shadertoy.com/view/XsXXWS) (10pts) - - You need to implement naive raymarching (not sphere tracing) to get this to work -- Lighting effects - - Soft shadowing using secondary rays (5pts) - - Ambient occlusion (10pts) -- Additional materials besides Lambert. (5pts each) -- Additional SDFs besides the listed primitive. (5pts each) - -## Resources -http://graphics.cs.williams.edu/courses/cs371/f14/reading/implicit.pdf - -## Submission -- Update `README.md` to contain a solid description of your project -- Publish your project to gh-pages. `npm run deploy`. It should now be visible at http://username.github.io/repo-name -- Create a [pull request](https://help.github.com/articles/creating-a-pull-request/) to this repository, and in the comment, include a link to your published project. -- Submit the link to your pull request on Canvas. - -## Deploy -- `npm run build` -- Add and commit all changes -- `npm run deploy` -- If you're having problems with assets not linking correctly, make sure you wrap you're filepaths in `require()`. This will make the bundler package and your static assets as well. So, instead of `loadTexture('./images/thing.bmp')`, do `loadTexture(require('./images/thing.bmp'))`. \ No newline at end of file +The program runs very slow right now. I created bounding volumes to optimize the SDF computing, but this didn't seem to do much. I suspect the problem is in my ray casting, as I was having trouble doing camera computations in the CPU, so I do them in the GPU. I hope to fix this in the near future. \ No newline at end of file diff --git a/robot1.PNG b/robot1.PNG new file mode 100644 index 0000000..c993c19 Binary files /dev/null and b/robot1.PNG differ diff --git a/robot2.PNG b/robot2.PNG new file mode 100644 index 0000000..2763313 Binary files /dev/null and b/robot2.PNG differ diff --git a/src/glsl/pass-vert.glsl b/src/glsl/pass-vert.glsl index 748eb5c..f276de6 100644 --- a/src/glsl/pass-vert.glsl +++ b/src/glsl/pass-vert.glsl @@ -1,5 +1,10 @@ varying vec2 f_uv; +varying mat4 viewMat; +varying mat4 projMat; + void main() { f_uv = uv; + viewMat = modelViewMatrix; + projMat = projectionMatrix; gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0); } \ No newline at end of file diff --git a/src/glsl/rayMarch-frag.glsl b/src/glsl/rayMarch-frag.glsl index 7c01941..c167a78 100644 --- a/src/glsl/rayMarch-frag.glsl +++ b/src/glsl/rayMarch-frag.glsl @@ -1,5 +1,6 @@ #define MAX_GEOMETRY_COUNT 100 +#define MAX_ITER 80 /* This is how I'm packing the data struct geometry_t { @@ -9,16 +10,414 @@ struct geometry_t { */ uniform vec4 u_buffer[MAX_GEOMETRY_COUNT]; uniform int u_count; +uniform vec3 cameraPos; +uniform mat4 cameraTransform; +uniform float tanAlpha; +uniform float aspRatio; + +uniform int time; varying vec2 f_uv; -void main() { - float t; - for (int i = 0; i < MAX_GEOMETRY_COUNT; ++i) { - if (i >= u_count) { - break; - } +//returns direction of ray from camera to this fragment +vec3 createRay() +{ + vec3 F = normalize(vec3(cameraTransform * vec4(0.0, 0.0, -1.0, 0.0))); + vec3 R = normalize(cross(F, vec3(0.0, 1.0, 0.0))); + vec3 U = normalize(cross(R, F)); + vec3 ref = cameraPos + 0.1*F; + float len = length(ref - cameraPos); + vec3 p = ref + ((2.0*f_uv.x-1.0) * (R*len*aspRatio*tanAlpha)) + ((2.0*f_uv.y-1.0) * (U*len*tanAlpha)); + return normalize(p-cameraPos); +} + +//returns transformed point based on rotation and translation matrix of shape +vec3 transform(vec3 point, mat4 trans) +{ + //columns of the rotation matrix transpose + vec3 col1 = vec3(trans[0][0], trans[1][0], trans[2][0]); + vec3 col2 = vec3(trans[0][1], trans[1][1], trans[2][1]); + vec3 col3 = vec3(trans[0][2], trans[1][2], trans[2][2]); + + mat3 rotTranspose = mat3(col1, col2, col3); + + vec3 col4 = -1.0*rotTranspose*vec3(trans[3]); + + mat4 newTrans = mat4(vec4(col1, 0.0), vec4(col2, 0.0), vec4(col3, 0.0), vec4(col4, 1.0)); + + return vec3(newTrans * vec4(point, 1.0)); +} + +//SDFS: + +float sphereSDF(vec3 point, mat4 trans, float radius) { + vec3 p = transform(point, trans); //puts point in local object space + return length(p) - radius; +} + +//diagonal is the vector from the center of the box to the first quadrant corner +float boxSDF(vec3 point, mat4 trans, vec3 diagonal) { + vec3 p = transform(point, trans); //puts point in local object space + vec3 d = abs(p) - diagonal; + return min(max(d.x,max(d.y,d.z)),0.0) + length(max(d,0.0)); +} + +//first value in param is radius, second value is, third value is the height +float coneSDF(vec3 point, mat4 trans, vec3 param) +{ + vec3 p = transform(point, trans); //puts point in local object space + vec2 q = vec2( length(p.xz), p.y ); + vec2 v = vec2( param.z*param.y/param.x, -param.z ); + vec2 w = v - q; + vec2 vv = vec2( dot(v,v), v.x*v.x ); + vec2 qv = vec2( dot(v,w), v.x*w.x ); + vec2 d = max(qv,0.0)*qv/vv; + return sqrt( dot(w,w) - max(d.x,d.y) ) * sign(max(q.y*v.x-q.x*v.y,w.y)); +} + +//first value in param is inner radius, second value is the thickness +float torusSDF(vec3 point, mat4 trans, vec2 param) { + vec3 p = transform(point, trans); //puts point in local object space + vec2 q = vec2(length(p.xz)-param.x,p.y); + return length(q)-param.y; +} + +//first value in param is radius, second value is the height +float cylinderSDF(vec3 point, mat4 trans, vec2 param) { + vec3 p = transform(point, trans); //puts point in local object space + vec2 d = abs(vec2(length(p.xz),p.y)) - param; + return min(max(d.x,d.y),0.0) + length(max(d,0.0)); +} + +//Operators: + +float intersection(float d1, float d2) +{ + return max(d1,d2); +} + +float subtraction( float d1, float d2 ) +{ + return max(-d1,d2); +} + +float un(float d1, float d2) +{ + return min(d1,d2); +} + +float getMod(int num1, int num2) +{ + int div = num1/num2; + return float(num1 - div*num2); +} + +//returns the new step size for the sphere marching, holds the info for the scene +float sphereTrace(vec3 point) +{ + //bounding volume for body + float bbb = boxSDF(point, mat4(1.0), vec3(2.0,2.0,1.5)); + + float fullbody; + if(bbb < .015) + { + //body cube of robot, centered at origin, scaled + float body = boxSDF(point, mat4(1.0), vec3(2.0,2.0,1.0)); + + //sphere buttons on robots chest + mat4 b1Mat = mat4(1.0); b1Mat[3][0] = -1.5; b1Mat[3][1] = 1.5; b1Mat[3][2] = 1.0; + float b1 = sphereSDF(point, b1Mat, 0.25); + + mat4 b2Mat = mat4(1.0); b2Mat[3][0] = -0.75; b2Mat[3][1] = 1.5; b2Mat[3][2] = 1.0; + float b2 = sphereSDF(point, b2Mat, 0.25); + + mat4 b3Mat = mat4(1.0); b3Mat[3][0] = -1.5; b3Mat[3][1] = 0.75; b3Mat[3][2] = 1.0; + float b3 = sphereSDF(point, b3Mat, 0.25); + + mat4 b4Mat = mat4(1.0); b4Mat[3][0] = -0.75; b4Mat[3][1] = 0.75; b4Mat[3][2] = 1.0; + float b4 = sphereSDF(point, b4Mat, 0.25); + + fullbody = un(body, un(b1, un(b2, un(b3, b4)))); + } + else + { + fullbody = bbb; + } + + + + float animHeight; //height change for animation + float mod = getMod(time, 120); + if(mod < 61.0) {animHeight = mod/60.0;} + else {animHeight = (120.0-mod)/60.0;} + + + + //bounding volume for neck + mat4 bbnMat = mat4(1.0); bbnMat[3][1] = 2.0 + animHeight; + float bbn = boxSDF(point, bbnMat, vec3(1.0,1.0,1.25)); + + float fullneck; + if(bbn < 0.015) + { + //neck cylinder, placed at top of box body, scaled so that it goes inside body box for animation purposes + mat4 neckMat = mat4(1.0); neckMat[3][1] = 2.0 + animHeight; + float neck = cylinderSDF(point, neckMat, vec2(0.5, 2.0)); + + //neck attachment torus, will be intersected with box to create interesting shape + mat4 ntMat = mat4(1.0); ntMat[3][1] = 2.0; + float nt = torusSDF(point, ntMat, vec2(0.75, 0.5)); + + //neck attachment box, will be intersected with torus to create interesting shape + mat4 nbMat = mat4(1.0); nbMat[3][1] = 2.0; + float nb = boxSDF(point, ntMat, vec3(0.8, 0.5, 0.8)); + + fullneck = un(neck, intersection(nt, nb)); + } + else + { + fullneck = bbn; + } + + + + //bounding volume for head + mat4 bbhMat = mat4(1.0); bbhMat[3][1] = 4.0 + animHeight; + float bbh = boxSDF(point, bbhMat, vec3(1.0,1.0,1.5)); + + float fullhead; + if(bbh < 0.015) + { + //head box, placed at top of neck cylinder, moves up and down in animation + mat4 headMat = mat4(1.0); headMat[3][1] = 4.0 + animHeight; + float head = boxSDF(point, headMat, vec3(1.0)); + + //outer mouth box + mat4 omMat = mat4(1.0); omMat[3][1] = 3.5 + animHeight; omMat[3][2] = 1.0; + float oMouth = boxSDF(point, omMat, vec3(0.75, 0.2, 0.5)); + + //inner mouth box, to be subtracted + mat4 imMat = mat4(1.0); imMat[3][1] = 3.5 + animHeight; imMat[3][2] = 1.2; + float iMouth = boxSDF(point, imMat, vec3(0.5, 0.1, 0.5)); + + //outer left eye + mat4 oe1Mat = mat4(1.0); oe1Mat[3][0] = -0.5; oe1Mat[3][1] = 4.5 + animHeight; oe1Mat[3][2] = 1.0; + float oe1 = sphereSDF(point, oe1Mat, 0.4); + + //inner left eye + mat4 ie1Mat = mat4(1.0); ie1Mat[3][0] = -0.5; ie1Mat[3][1] = 4.5 + animHeight; ie1Mat[3][2] = 1.25; + ie1Mat[1][1] = 0.0; ie1Mat[1][2] = 1.0; ie1Mat[2][1] = -1.0; ie1Mat[2][2] = 0.0; //rotating by 90 degrees about x axis + float ie1 = cylinderSDF(point, ie1Mat, vec2(0.2, 0.4)); + + //outer right eye + mat4 oe2Mat = mat4(1.0); oe2Mat[3][0] = 0.5; oe2Mat[3][1] = 4.5 + animHeight; oe2Mat[3][2] = 1.0; + float oe2 = sphereSDF(point, oe2Mat, 0.4); + + //inner right eye + mat4 ie2Mat = mat4(1.0); ie2Mat[3][0] = 0.5; ie2Mat[3][1] = 4.5 + animHeight; ie2Mat[3][2] = 1.25; + ie2Mat[1][1] = 0.0; ie2Mat[1][2] = 1.0; ie2Mat[2][1] = -1.0; ie2Mat[2][2] = 0.0; //rotating by 90 degrees about x axis + float ie2 = cylinderSDF(point, ie2Mat, vec2(0.2, 0.4)); + + fullhead = un(head, un(subtraction(iMouth, oMouth), un(subtraction(ie1, oe1), subtraction(ie2, oe2)))); + } + else + { + fullhead = bbh; + } + + + + //bounding volume for antenna + mat4 bbaMat = mat4(1.0); bbaMat[3][1] = 5.5 + animHeight; + float bba = boxSDF(point, bbaMat, vec3(0.2 + 0.2*animHeight,0.8 + 0.2*animHeight,0.2 + 0.2*animHeight)); + + float antenna; + if(bba < 0.015) + { + //antenna cone piece, will be intersected with box for interesting shape + mat4 acMat = mat4(1.0); acMat[3][1] = 5.5 + animHeight; + float ac = coneSDF(point, acMat, vec3(0.5, 0.5, 0.5)); + + //antenna box piece, will be intersected with cone for interesting shape + mat4 abMat = mat4(1.0); abMat[3][1] = 5.5 + animHeight; + float ab = boxSDF(point, abMat, vec3(0.15, 0.5, 0.15)); + + //antenna sphere, will animate in scale + mat4 asMat = mat4(1.0); asMat[3][1] = 5.75 + animHeight; + float as = sphereSDF(point, asMat, 0.2 + 0.2*animHeight); + + antenna = un(as, intersection(ac, ab)); + } + else + { + antenna = bba; + } + + + + //bounding volume for left arm + mat4 bba1Mat = mat4(1.0); bba1Mat[3][0] = 4.0 - 2.0*animHeight; bba1Mat[3][1] = 0.75; + float bba1 = boxSDF(point, bba1Mat, vec3(3.0, 1.0, 1.0)); + + float leftArm; + if(bba1 < 0.015) + { + //left arm cylinder, moves in and out in animation + mat4 arm1Mat = mat4(1.0); arm1Mat[3][0] = 4.0 - 2.0*animHeight; arm1Mat[3][1] = 0.75; + arm1Mat[0][0] = 0.0; arm1Mat[0][1] = 1.0; arm1Mat[1][0] = -1.0; arm1Mat[1][1] = 0.0; //rotating by 90 degrees about z axis + float arm1 = cylinderSDF(point, arm1Mat, vec2(0.5, 2.0)); + + //hand sphere + mat4 hand1Mat = mat4(1.0); hand1Mat[3][0] = 6.25 - 2.0*animHeight; hand1Mat[3][1] = 0.75; + float hand1 = sphereSDF(point, hand1Mat, 0.75); + + //inner hand box, to be subtracted in order to create claw + mat4 ihand1Mat = mat4(1.0); ihand1Mat[3][0] = 6.75 - 2.0*animHeight; ihand1Mat[3][1] = 0.75; + float ihand1 = boxSDF(point, ihand1Mat, vec3(0.5, 0.3, 1.0)); + + leftArm = un(subtraction(ihand1, hand1), arm1); } + else + { + leftArm = bba1; + } + + + + //bounding volume for left arm + mat4 bba2Mat = mat4(1.0); bba2Mat[3][0] = -2.0 - 2.0*animHeight; bba2Mat[3][1] = 0.75; + float bba2 = boxSDF(point, bba2Mat, vec3(3.0, 1.0, 1.0)); + + float rightArm; + if(bba2 < 0.015) + { + //left arm cylinder, moves in and out in animation + mat4 arm2Mat = mat4(1.0); arm2Mat[3][0] = -2.0 - 2.0*animHeight; arm2Mat[3][1] = 0.75; + arm2Mat[0][0] = 0.0; arm2Mat[0][1] = 1.0; arm2Mat[1][0] = -1.0; arm2Mat[1][1] = 0.0; //rotating by 90 degrees about z axis + float arm2 = cylinderSDF(point, arm2Mat, vec2(0.5, 2.0)); + + //hand sphere + mat4 hand2Mat = mat4(1.0); hand2Mat[3][0] = -4.25 - 2.0*animHeight; hand2Mat[3][1] = 0.75; + float hand2 = sphereSDF(point, hand2Mat, 0.75); + + //inner hand box, to be subtracted in order to create claw + mat4 ihand2Mat = mat4(1.0); ihand2Mat[3][0] = -4.75 - 2.0*animHeight; ihand2Mat[3][1] = 0.75; + float ihand2 = boxSDF(point, ihand2Mat, vec3(0.5, 0.3, 1.0)); + + rightArm = un(subtraction(ihand2, hand2), arm2); + } + else + { + rightArm = bba2; + } + + + + //bounding volume for left leg + mat4 bbl1Mat = mat4(1.0); bbl1Mat[3][0] = 1.0; bbl1Mat[3][1] = -2.0 - 2.0*animHeight; + float bbl1 = boxSDF(point, bbl1Mat, vec3(1.0, 2.0, 1.0)); + + float leftLeg; + if(bbl1 < 0.015) + { + //left leg cylinder, placed at bottom of body box, moves up and down in animation + mat4 leg1Mat = mat4(1.0); leg1Mat[3][0] = 1.0; leg1Mat[3][1] = -2.0 - 2.0*animHeight; + float leg1 = cylinderSDF(point, leg1Mat, vec2(0.5, 2.0)); + + //left leg top torus, placed a third of the way down left leg, subtracted to create indentation + mat4 ll1Mat = mat4(1.0); ll1Mat[3][0] = 1.0; ll1Mat[3][1] = -1.0 - 2.0*animHeight; + float ll1 = torusSDF(point, ll1Mat, vec2(0.75, 0.5)); + + //left leg top torus, placed a third of the way down left leg, subtracted to create indentation + mat4 ll2Mat = mat4(1.0); ll2Mat[3][0] = 1.0; ll2Mat[3][1] = -3.0 - 2.0*animHeight; + float ll2 = torusSDF(point, ll2Mat, vec2(0.75, 0.5)); + + //left foot cone, placed under leg such that point is inside the cylinder and hidden + mat4 foot1Mat = mat4(1.0); foot1Mat[3][0] = 1.0; foot1Mat[3][1] = -3.0 - 2.0*animHeight; + float foot1 = coneSDF(point, foot1Mat, vec3(1.0, 1.0, 1.0)); + + leftLeg = un(foot1, subtraction(ll1, subtraction(ll2, leg1))); + } + else + { + leftLeg = bbl1; + } + + + + //bounding volume for right leg + mat4 bbl2Mat = mat4(1.0); bbl2Mat[3][0] = -1.0; bbl2Mat[3][1] = -4.0 + 2.0*animHeight; + float bbl2 = boxSDF(point, bbl2Mat, vec3(1.0, 2.0, 1.0)); + + float rightLeg; + if(bbl2 < 0.015) + { + //right leg cylinder, placed at bottom of body box, moves up and down in animation + mat4 leg2Mat = mat4(1.0); leg2Mat[3][0] = -1.0; leg2Mat[3][1] = -4.0 + 2.0*animHeight; + float leg2 = cylinderSDF(point, leg2Mat, vec2(0.5, 2.0)); + + //left leg top torus, placed a third of the way down left leg, subtracted to create indentation + mat4 rl1Mat = mat4(1.0); rl1Mat[3][0] = -1.0; rl1Mat[3][1] = -3.0 + 2.0*animHeight; + float rl1 = torusSDF(point, rl1Mat, vec2(0.75, 0.5)); + + //left leg top torus, placed a third of the way down left leg, subtracted to create indentation + mat4 rl2Mat = mat4(1.0); rl2Mat[3][0] = -1.0; rl2Mat[3][1] = -5.0 + 2.0*animHeight; + float rl2 = torusSDF(point, rl2Mat, vec2(0.75, 0.5)); + + //right foot cone, placed under leg such that point is inside the cylinder and hidden + mat4 foot2Mat = mat4(1.0); foot2Mat[3][0] = -1.0; foot2Mat[3][1] = -5.0 + 2.0*animHeight; + float foot2 = coneSDF(point, foot2Mat, vec3(1.0, 1.0, 1.0)); + + rightLeg = un(foot2, subtraction(rl1, subtraction(rl2, leg2))); + } + else + { + rightLeg = bbl2; + } + + return un(fullbody, un(fullneck, un(fullhead, un(antenna, un(leftArm, un(rightArm, un(leftLeg, rightLeg))))))); +} + +vec3 getNormal(vec3 point) +{ + float epsilon = 0.1; + float x = sphereTrace(vec3(point.x+epsilon, point.y, point.z)) - sphereTrace(vec3(point.x-epsilon, point.y, point.z)); + float y = sphereTrace(vec3(point.x, point.y+epsilon, point.z)) - sphereTrace(vec3(point.x, point.y-epsilon, point.z)); + float z = sphereTrace(vec3(point.x, point.y, point.z+epsilon)) - sphereTrace(vec3(point.x, point.y, point.z-epsilon)); + return normalize(vec3(x, y, z)); +} + +vec3 lambert(vec3 norm) +{ + vec3 light = -1.0 * normalize(vec3(2.0, -3.0, -6.0)); + return clamp(dot(light, norm), 0.0, 1.0)*vec3(0.5, 0.5, 0.7); +} + +vec4 traceRay() +{ + vec3 ray = createRay(); + vec3 currPt = cameraPos; + float t = 0.0; + int count = 0; + for(int i = 0; i < MAX_ITER; i++) + { + currPt = cameraPos + ray * t; + float offset = sphereTrace(currPt); + + if (abs(offset) < 0.01) { + break; + } + t += offset; + ++count; + } + + //return vec4(vec3(float(count)/float(MAX_ITER)), 1.0); + return vec4(lambert(getNormal(currPt)), 1.0); +} + +void main() { + + vec4 color = traceRay(); - gl_FragColor = vec4(f_uv, 0, 1); + gl_FragColor = color; } \ No newline at end of file diff --git a/src/main.js b/src/main.js index ade21ee..2ebd674 100644 --- a/src/main.js +++ b/src/main.js @@ -44,7 +44,7 @@ window.addEventListener('load', function() { var gui = new DAT.GUI(); var options = { - strategy: 'Proxy Geometry' + strategy: 'Ray Marching' } gui.add(options, 'strategy', ['Proxy Geometry', 'Ray Marching']); diff --git a/src/rayMarching.js b/src/rayMarching.js index 03c3680..2e3d293 100644 --- a/src/rayMarching.js +++ b/src/rayMarching.js @@ -3,6 +3,10 @@ const EffectComposer = require('three-effectcomposer')(THREE) import {PROXY_BUFFER_SIZE} from './proxy_geometry' +var options = { + time: 0 +} + export default function RayMarcher(renderer, scene, camera) { var composer = new EffectComposer(renderer); var shaderPass = new EffectComposer.ShaderPass({ @@ -15,6 +19,30 @@ export default function RayMarcher(renderer, scene, camera) { type: 'i', value: 0 }, + cameraPos: { + type: '3fv', + value: camera.position + }, + cameraTransform: + { + type: 'm4', + value: camera.matrix + }, + tanAlpha: + { + type: 'f', + value: Math.tan(camera.fov/2.0 * Math.PI/180.0) + }, + aspRatio: + { + type: 'f', + value: window.innerWidth/window.innerHeight + }, + time: + { + type: 'i', + value: options.time + }, }, vertexShader: require('./glsl/pass-vert.glsl'), fragmentShader: require('./glsl/rayMarch-frag.glsl') @@ -27,7 +55,28 @@ export default function RayMarcher(renderer, scene, camera) { shaderPass.material.uniforms.u_buffer.value = buffer; shaderPass.material.uniforms.u_count.value = buffer.length / PROXY_BUFFER_SIZE; + camera.updateMatrixWorld(); + + // var tempF = new THREE.Vector4(0.0, 0.0, -1.0, 0.0); + // var temp = tempF.applyMatrix4(camera.matrix); + // var F = new THREE.Vector3(temp[0], temp[1], temp[2]); console.log(F);F.normalize(); + // var R = (F.cross(THREE.Vector3(0.0, 1.0, 0.0))).normalize(); + // var U = R.cross(F).normalize(); + // var ref = camera.position + 0.1*F; + // var len = THREE.Vector3(ref - cameraPos).length(); + // var tanAlpha = Math.tan(camera.fov/2.0 * Math.PI/180.0); + // var p = ref + ((2.0*f_uv.x-1.0) * (R*len*camera.aspect*tanAlpha)) + ((2.0*f_uv.y-1.0) * (U*len*tanAlpha)); + + shaderPass.material.uniforms.cameraTransform.value = camera.matrix; + shaderPass.material.uniforms.cameraPos.value = camera.position; + options.time++; + shaderPass.material.uniforms.time.value = options.time; + composer.render(); + }, + + update: function() { + } } } \ No newline at end of file