예제 #1
0
        private void RenderSphere(SphereElement sphere, float rotationSin, float rotationCos, float colorLerpProgress, Vector3 lightDir)
        {
            float fX = sphere.x * rotationSin - sphere.z * rotationCos;
            float fY = sphere.y;
            float fZ = sphere.screenZ;

            fZ += 1.5f;

            //Skip the sphere that's too close to camera frustum
            if (fZ < 0.001f)
            {
                return;
            }

            //Weak perspective projection
            float screenX      = fX / fZ;
            float screenY      = fY / fZ;
            float screenZ      = fZ;
            float screenRadius = sphere.r / fZ;

            Vector3Byte sphereColor = Vector3Byte.Lerp(sphere.colorA, sphere.colorB, colorLerpProgress);

            int centerY = (int)(screenY * _width / 2 + _width / 2);
            int centerX = (int)(screenX * _width / 2 + _width / 2);

            //For square 1024x1024 buffer - Rx == Ry
            int R = (int)(screenRadius * _width / 2);

            int Rsquared = R * R;
            int minX     = Math.Max(centerX - R * 2, 0);
            int maxX     = Math.Min(centerX + R * 2, _width - 1);
            int minY     = Math.Max(centerY - R * 2, 0);
            int maxY     = Math.Min(centerY + R * 2, _height - 1);

            for (int x = minX; x <= maxX; ++x)
            {
                for (int y = minY; y <= maxY; ++y)
                {
                    int dx  = x - centerX;
                    int dy  = y - centerY;
                    int dx2 = dx * dx;
                    int dy2 = dy * dy;

                    //Skip pixels which are not part of a circle
                    if (dx2 + dy2 > Rsquared)
                    {
                        continue;
                    }

                    if (screenZ < _zBuffer[x + y * _width])
                    {
                        //lock (_zBuffer)
                        {
                            //Writing a float to _zBuffer array is atomic, no danger of corruption
                            _zBuffer[x + y * _width] = screenZ;
                        }

                        // Phong shading
                        {
                            Vector3 vec_normal = new Vector3();
                            vec_normal.x = dx;
                            vec_normal.y = dy;
                            vec_normal.z = (float)Math.Sqrt(Rsquared - (dx2 + dy2));
                            vec_normal.Normalize();

                            float NdotL = lightDir.Dot(vec_normal);
                            if (NdotL > 0)
                            {
                                Vector3 vec_eye = new Vector3();
                                vec_eye.x = lightDir.x + screenX;
                                vec_eye.y = lightDir.y + screenY;
                                vec_eye.z = lightDir.z + 1.0f;
                                vec_eye.Normalize();

                                float NdotHV   = vec_eye.Dot(vec_normal);
                                float specular = NdotHV * NdotHV * NdotHV * NdotHV * NdotHV * NdotHV * NdotHV * NdotHV * NdotHV; // shininess=9
                                float alpha    = NdotL + specular;
                                alpha = Math.Min(alpha, 1.0f);

                                byte r = (byte)(sphereColor.x * alpha);
                                byte g = (byte)(sphereColor.y * alpha);
                                byte b = (byte)(sphereColor.z * alpha);

                                SetPixel(x, y, b, g, r);
                            }
                            else
                            {
                                //Unlit pixel
                                SetPixel(x, y, 0, 0, 0);
                            }
                        }
                    }
                }
            }
        }
예제 #2
0
 private int CompareSpheres(SphereElement s1, SphereElement s2)
 {
     return(Math.Sign(s2.screenZ - s1.screenZ));
 }