如何使用多个对象创建球体

时间:2015-10-11 12:57:03

标签: javascript webgl

我必须使用多个方块绘制球体(我也允许使用三角形,但我发现一些现有的代码用于方形帮助,所以我用它)。我已成功绘制了多个正方形(5000)。但我不必使用任何内置函数来创建球体。我的代码如下:

<!DOCTYPE html>

<html lang="en" xmlns="http://www.w3.org/1999/xhtml">
<head>
    <script class="WebGL">
        var gl;
        function createProgram(gl, vertexShader, fragmentShader)
        {
            var vs = gl.createShader(gl.VERTEX_SHADER);
            gl.shaderSource(vs, vertexShader);
            gl.compileShader(vs);

            if (!gl.getShaderParameter(vs, gl.COMPILE_STATUS))
                alert(gl.getShaderInfoLog(vs));
            //////
            var fs = gl.createShader(gl.FRAGMENT_SHADER);
            gl.shaderSource(fs, fragmentShader);
            gl.compileShader(fs);

            if (!gl.getShaderParameter(fs, gl.COMPILE_STATUS))
                alert(gl.getShaderInfoLog(fs));
            program = gl.createProgram();
            gl.attachShader(program, vs);
            gl.attachShader(program, fs);
            gl.linkProgram(program);
            if (!gl.getProgramParameter(program, gl.LINK_STATUS))
                alert(gl.getProgramInfoLog(program));
            return program;
        }
        function createShaderFromScriptElement(gl , shaderName)
        {
            var Shader = document.getElementById(shaderName).firstChild.nodeValue;
            return Shader;
        }
        function start()
        {
            var canvas = document.getElementById("canvas");
            gl = canvas.getContext("experimental-webgl");
            if (!gl) { alert("error while GL load"); }

              var vertexShader = createShaderFromScriptElement(gl, "2d-vertex-shader");
              var fragmentShader = createShaderFromScriptElement(gl, "2d-fragment-shader");

              var program = createProgram(gl, vertexShader, fragmentShader);

            gl.useProgram(program);
            var positionLocation = gl.getAttribLocation(program, "a_position");
            var colorLocation = gl.getUniformLocation(program, "u_color");
            var resolutionLocation = gl.getUniformLocation(program, "u_resolution");

            var buffer = gl.createBuffer();
            gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
            gl.uniform2f(resolutionLocation, 200, 200);

            gl.enableVertexAttribArray(positionLocation);
            gl.vertexAttribPointer(positionLocation, 2, gl.FLOAT, false, 0, 0);
            for (var ii = 0; ii < 5000; ++ii)
            {
                // Setup a random rectangle
                setRectangle(gl, randomInt(300), randomInt(300), 10, 10);
                // Set a random color.
                gl.uniform4f(colorLocation, Math.random(), Math.random(), Math.random(), 1);
                // Draw the rectangle.
                gl.drawArrays(gl.TRIANGLES, 0, 6);
            }
            function randomInt(range)
            {
                return Math.floor(Math.random() * range);
            }

            // Fills the buffer with the values that define a rectangle.
            function setRectangle(gl, x, y, width, height)
            {
                var x1 = x;
                var x2 = x + width;
                var y1 = y;
                var y2 = y + height;
                gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([
                   x1, y1,
                   x2, y1,
                   x1, y2,
                   x1, y2,
                   x2, y1,
                   x2, y2]), gl.STATIC_DRAW);
            }
        }
    </script>
    <script id="2d-vertex-shader" type="x-shader/x-vertex">
        attribute vec2 a_position;
        uniform vec2 u_resolution;

        void main() {
        // convert the rectangle from pixels to 0.0 to 1.0
        vec2 zeroToOne = a_position / u_resolution;

        // convert from 0->1 to 0->2
        vec2 zeroToTwo = zeroToOne * 2.0;

        // convert from 0->2 to -1->+1 (clipspace)
        vec2 clipSpace = zeroToTwo - 1.0;

        gl_Position = vec4(clipSpace* vec2(1, -1), 0, 1);
        }
    </script>

    <script id="2d-fragment-shader" type="x-shader/x-fragment">
        precision mediump float;
        uniform vec4 u_color;

        void main()
        {
        gl_FragColor = u_color;  // green
        }
    </script>
</head>
<body onload="start()">
    <div style="text-align: center">
        <canvas id="canvas" width="1000" height="800"></canvas>
    </div>
</body>
</html>

我所要求的是使用多个对象来绘制球体,我不知道该怎么做。我的尝试首先绘制多个对象(在我的情况下为5000),然后尝试使用它绘制球体(我的意思是使用这5000个方格,我的下一步是创建球体)。

但我不知道如何使用这些方块进一步绘制球体?

我无法理解该怎么做。有人可以帮助我吗?

1 个答案:

答案 0 :(得分:2)

其中一种方法是在顶点着色器中使用矩形切片构造球体。

通常情况下,用瓦片覆盖 [0,2 * M_PI] x [0,M_PI] 区域。比如,你有 N 瓦片,其中 N = m * k m 是一行中的瓦片数量, k 是列中的瓷砖数量。

您可以创建 N 单位正方形,并为每个正方形分配 m * k 矩阵中的唯一位置。然后将这些位置和平铺的宽度/高度( 2 * M_PI / m M_PI / k )作为制服传递给顶点着色器(或作为属性)。

在顶点着色器中知道贴片的位置及其宽度/高度计算 [0,2 * M_PI] x [0,M_PI] 上的顶点坐标(它们将 phi ksi )。然后计算球体上的实际顶点位置:

coord.x = sin(ksi) * cos(phi);
coord.y = sin(ksi) * sin(phi);
coord.z = cos(ksi);

另请注意,您应为此设置透视投影。

选择 m k 取决于您(毕竟有素数)。我建议从方形瓷砖开始。以下是我得到的结果图片:

enter image description here