Welcome toVigges Developer Community-Open, Learning,Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
148 views
in Technique[技术] by (71.8m points)

javascript - Ray Tracing with JS

Good Morning.

I'm doing a small ray tracing example with JS but I've a problem. When I'm trying to calculate the reflected color it always returns [255,255,255] and I don't know why. If object is specular I trace a ray and it return 255,255,255. (Line 114 - 124 js)

In addition the spheres makes the shadows of the lighy ok, but no the shadows of for example (sphere 1 to sphere 2). I think the problem is in the function isLightVisible(line 89-98 js)

Finally I think that they don't respect wich is in front of wich one.

HTML CODE:

<html>
    <head>
        <title>Ray Tracing Example</title>
    </head>

    <body>
        <h1>Ray Tracing</h1>

            <table>
                <th>
                    <canvas id="glcanvas" style="border: solid;" width="400" height="400"></canvas>
                    <button onclick="start()"> Start </button>
                </th>
            </table>

        <p style="text-indent:85px;">Camera Position: [0, 0, 0]</p>

        <script type="text/javascript" src="raytracingV2.js"></script>
        <script src="gl-matrix/common.js"></script>
        <script type="text/javascript" src="gl-matrix/vec3.js"></script>
        <script type="text/javascript" src="gl-matrix/vec2.js"></script>
        <script type="text/javascript" src="gl-matrix/vec4.js"></script>
        <script type="text/javascript" src="gl-matrix/vec4.js"></script>
        <script type="text/javascript" src="gl-matrix/mat4.js"></script>
        <script type="text/javascript" src="gl-matrix/mat3.js"></script>
        <script type="text/javascript" src="gl-matrix/quat.js"></script>

        <script type="text/javascript">

            function start () {
                // Inicialitzem el RayTracing
                inicialitzar(Scene);
            }

            var Screen = {
                width   : 0,
                height  : 0,
                canvas  : null,
                context : null,
                buffer  : null,
            };

            var Scene = {

                Fons: [0, 0, 0],

                Shapes: [
                    {

                        id      : "esfera_blava",
                        tipus   : "esfera",
                        radi    : 0.25,
                        centre  : [-0.3,0,1],
                        point   : [-0.3,0,1],
                    
                        color: [155, 200, 155],
                        specular: 0.2,
                        lambert: 0.7,
                        ambient: 0.1,
                        // Material:
                        // Rd, Rs, Ra (colors)
                        // alpha specular (float)
                        //  Reflexion and/or Transmision (float)

                    },
                    {

                        id      : "esfera_vermella",
                        tipus   : "esfera",
                        radi    : 0.25,
                        centre  : [0.3,0,1.4],
                        point   : [0.3,0,1.4],

                        color: [200, 155, 155],
                        specular: 0.2,
                        lambert: 0.7,
                        ambient: 0.1,
                        // Material:
                        // Rd, Rs, Ra (colors)
                        // alpha specular (float)
                        //  Reflexion and/or Transmision (float)

                        },
                ],
                Camera: {
                    position: [0,0,0],  // posicio camera
                    up      : [0,1,0],      // vector amunt
                    centre  : [0,0,-1],     // centre escena
                    fov     : 60,           // field of view
                    X       : vec3.create(),
                    Z       : vec3.create(),
                    Y       : vec3.create(),
                },
                Lights: [
                    {
                        position: vec3.create(), // S'emplena segons els valors entrats
                        color   : vec3.create(), // S'emplena segons els valors entrats
                    },
                    {
                        position: vec3.create(), // S'emplena segons els valors entrats
                        color   : vec3.create(), // S'emplena segons els valors entrats
                    },
                                        {
                        position: vec3.create(), // S'emplena segons els valors entrats
                        color   : vec3.create(), // S'emplena segons els valors entrats
                    },
                ]
            };
        </script>

    </body>
</html>

RAY TRACING JS CODE


// RAY TRACING - example //

// Inicialitzem el RayTracing
function inicialitzar(Scene) {

    // Parametres de les llums
    // Put it interactively
    Scene.Lights[0].position = [-1, 2, 4];
    Scene.Lights[0].color = [0.4, 0.4, 0.4];
    Scene.Lights[1].position = [1, 4, 4];
    Scene.Lights[1].color = [1, 0, 0];
    Scene.Lights[1].position = [-1, -4, -4];
    Scene.Lights[1].color = [1, 0, 0];

    Screen.canvas = document.getElementById("glcanvas");
    if (Screen.canvas == null)  {
        alert("Invalid element: " + id);
        return;
    }
    Screen.context = Screen.canvas.getContext("2d");
    if(Screen.context == null){
        alert("Could not get context");
        return;
    }
    Screen.width = Screen.canvas.width;
    Screen.height = Screen.canvas.height;
    Screen.buffer = Screen.context.createImageData(Screen.width,Screen.height);

    // Calculem els eixos de la camera
    calcularEixos(Scene);

    // Calculem els increments i P0 (GLOBALS)
    incX = calcularIncrementX(Scene.Camera,Screen);
    incY = calcularIncrementY(Scene.Camera,Screen);
    P0 = calcularP0(incX,incY,Scene.Camera,Screen);

    // Executem RayTracing
    rayTracing(Scene, Screen);
    Screen.context.putImageData(Screen.buffer, 0, 0);
};

function sphereIntersection(sphere, ray, scene){

    var eye_to_center = vec3.subtract(sphere.point, scene.Camera.position);

    var v = vec3.dot(eye_to_center, vec3.clone(ray));

    var eoDot = vec3.dot(eye_to_center,eye_to_center);

    var discriminant = sphere.radi * sphere.radi -eoDot + v * v;

    if (discriminant<0){
        return;
    }else{
        return v - Math.sqrt(discriminant);
    }
}

// Calcular increment de X
function calcularIncrementX(Cam,Scr) {
    var rati = (Scr.height/Scr.width);

    var theta = (Cam.fov * Math.PI / 180);
    var w = 2*Math.tan(theta/2); // Calculem w' = 2*tg(theta/2)
    var h = w*rati; // Calculem h' = w'*rati

    var aux = w/Scr.width; // w'/W
    var incX = vec3.scale(Cam.X,aux); // Calculem increment de X (X * 2*tg(theta/2)/W)

    return incX;
}


// Calcular increment de Y
function calcularIncrementY(Cam,Scr) {
    var rati = (Scr.height/Scr.width);

    var theta = (Cam.fov * Math.PI / 180);
    var w = 2*Math.tan(theta/2); // Calculem w' = 2*tg(theta/2)
    var h = w*rati; // Calculem h' = w'*rati

    var aux = rati*w/Scr.height; // rati*w'/H
    var incY = vec3.scale(Cam.Y,aux); // Calculem increment de Y (Y * 2*tg(theta/2)/W)

    return incY;
}

function isLightVisible(pt, scene, light){
    var distObject = intersectarScene(
        {
            point:pt,
            vector: vec3.unitVector(vec3.sub(pt, light)),
        },
        scene
    );
    return distObject[0] > -0.005;
}

function surface(ray, scene, object, pointAtTime, normal, depth){
    var b = object.color;
    var c = [0,0,0];
    var lambertAmount = 0;

    if (object.lambert){
        for (var i = 0; i<scene.Lights.length; i++){
            var lightPoint = scene.Lights[i].position;
            if (!isLightVisible(pointAtTime, scene, lightPoint)) continue;
            var contribution = vec3.dot(vec3.unitVector(vec3.subtract(lightPoint, pointAtTime)), normal);
            if (contribution > 0) lambertAmount += contribution;
        }
    }

    if (object.specular){
        var reflectedRay = {
            point: pointAtTime,
            vector: vec3.reflectThrough(vec3.clone(ray), normal),
        };
        var reflectedColor = trace(reflectedRay, scene, ++depth);

        if(reflectedColor){
            c = vec3.add(c, vec3.scale(reflectedColor, object.specular));
        }
    }

    lambertAmount = Math.min(1,lambertAmount);
    var a = vec3.scale(b, lambertAmount * object.lambert);
    var d = vec3.scale(b, object.ambient);

    var color = vec3.add3(a, d, c); 

    return color;
}

// Calcular P0
function calcularP0(incX,incY,Cam,Scr) {

    var P = vec3.subtract(Cam.position,Cam.Z); // Calculem P (O - Z)
    var aux = vec3.scale(incX,((Scr.width-1)/2)); // Increment de X * (W-1)/2
    var aux2 = vec3.scale(incY,((Scr.height-1)/2)); // Increment de Y * (H-1)/2
    var aux3 = vec3.subtract(P,aux); // P - Increment de X * (W-1)/2
    var P0 = vec3.add(aux3,aux2); // Calculem P0 (P - Increment de X * (W-1)/2 + Increment de Y * (H-1)/2)

    return P0;
}


// Calcular els eixos de la camera
function calcularEixos(Scene) {
    Scene.Camera.Z = vec3.normalize(vec3.subtract(Scene.Camera.position, Scene.Camera.centre)); // |O - C|
    Scene.Camera.X = vec3.normalize(vec3.cross(Scene.Camera.up, Scene.Camera.Z)); // |up x Z|
    Scene.Camera.Y = vec3.cross(Scene.Camera.Z, Scene.Camera.X); // Z x X

}


function plot(x,y,color){
    var index = (x+y*Screen.buffer.width)*4;
    Screen.buffer.data[index+0] = color[0];
    Screen.buffer.data[index+1] = color[1];
    Screen.buffer.data[index+2] = color[2];
    Screen.buffer.data[index+3] = 255;
    return index;
}

function sphereNormal(sphere, pos) {
    return vec3.unitVector(vec3.subtract(pos, sphere.point));
}

function intersectarScene(ray, scene) {
    var closest = [Infinity, null];

    for (var i = 0; i< scene.Shapes.length; i++){
        var object = scene.Shapes[i];
        var dist = sphereIntersection(object, ray,scene);
        if (dist !== undefined && dist < closest[0]) {
            closest = [dist, object];
        }
    }
    return closest;
}

function trace(ray, scene, depth){

    if (depth > 3) return;

    var distObject = intersectarScene(ray,scene);
    if (distObject[0] === Infinity) {
        return [255,255,255];
      }
      
    var dist = distObject[0];
    var object = distObject[1];
    var pointAtTime = vec3.add(scene.Camera.position, vec3.scale(vec3.clone(ray), dist));
    return surface(ray,scene,object,pointAtTime, sphereNormal(object, pointAtTime), depth);
}

// Pintar cada pixel
function rayTracing(Scene, Screen) {
    console.log(incX);
    for(var x = 0; x < Screen.width; x++){
        for (y = 0; y < Screen.height; y++){
            var rDirection = computeRay(incX,incY,P0,Scene.Camera,x,y);
            var color = trace(rDirection, Scene, 0);
            plot(x,y,color);
        }
    }
}


// Computar el raig
function computeRay(incX,incY,P0,Cam,x,y){

    // Calculem la direccio per a cada pixel
    var aux = vec3.scale(incX,x); // Increment de X * x
    var aux2 = vec3.scale(incY,y); // Increment de Y * y
   

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)
等待大神答复

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to Vigges Developer Community for programmer and developer-Open, Learning and Share
...