Package future

Source Code of future.ShadowMapping

/*
* Copyright (c) 2013, Oskar Veerhoek
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
*    list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
*    this list of conditions and the following disclaimer in the documentation
*    and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* The views and conclusions contained in the software and documentation are those
* of the authors and should not be interpreted as representing official policies,
* either expressed or implied, of the FreeBSD Project.
*/

package future;

import org.lwjgl.BufferUtils;
import org.lwjgl.LWJGLException;
import org.lwjgl.input.Keyboard;
import org.lwjgl.opengl.Display;
import org.lwjgl.opengl.DisplayMode;
import org.lwjgl.opengl.GLContext;
import org.lwjgl.util.glu.Sphere;
import org.lwjgl.util.vector.Matrix4f;
import org.lwjgl.util.vector.Vector3f;

import java.nio.FloatBuffer;

import static org.lwjgl.opengl.ARBShadowAmbient.GL_TEXTURE_COMPARE_FAIL_VALUE_ARB;
import static org.lwjgl.opengl.EXTFramebufferObject.*;
import static org.lwjgl.opengl.GL11.*;
import static org.lwjgl.opengl.GL12.GL_CLAMP_TO_EDGE;
import static org.lwjgl.opengl.GL14.*;
import static org.lwjgl.util.glu.GLU.gluLookAt;
import static org.lwjgl.util.glu.GLU.gluPerspective;

/**
* Shows how to get shadows working in OpenGL. Ported from the OpenGLSuperBible. Some code was modified by Oskar
* Veerhoek.
*
* @author Sam K.
* @author Daniel W.
*/
public class ShadowMapping {

    // This represents if the clients computer has the ambient shadow extention
    private static boolean ambientShadowsAvailable;
    // Enable this if you want to see the depth texture for debugging purposes.
    private static final boolean showShadowMap = false;
    // Disable this if your computer doesn't support the FBO extension
    private static final boolean useFBO = true;

    // The amount of polygon offset to use
    private static float factor = 4.0F;

    private static int maxTextureSize;

    private static int shadowWidth = 640;
    private static int shadowHeight = 480;

    private static int frameBuffer;
    private static int renderBuffer;

    private static final FloatBuffer ambientLight = BufferUtils.createFloatBuffer(4);
    private static final FloatBuffer diffuseLight = BufferUtils.createFloatBuffer(4);
    private static final FloatBuffer lightPosition = BufferUtils.createFloatBuffer(4);
    private static final FloatBuffer cameraPosition = BufferUtils.createFloatBuffer(4);
    private static final FloatBuffer tempBuffer = BufferUtils.createFloatBuffer(4);

    private static final Matrix4f textureMatrix = new Matrix4f();
    private static final Sphere sphere = new Sphere();

    public static void main(String[] args) {
        setUpDisplay();
        setUpBufferValues();
        setUpOpenGL();
        while (!Display.isCloseRequested()) {
            render();
            input();
            Display.update();
            Display.sync(60);
        }
        cleanUp();
        System.exit(0);
    }

    /** Sets up a display. */
    private static void setUpDisplay() {
        try {
            Display.setDisplayMode(new DisplayMode(640, 480));
            Display.setTitle("Shadow Mapping Demo");
            Display.create();
        } catch (LWJGLException e) {
            System.err.println("Couldn't set up the display");
            Display.destroy();
            System.exit(1);
        }
    }

    /**
     * This is where anything you want rendered into your world should go.
     *
     * @param drawGround whether to draw the ground
     */
    private static void renderObjects(boolean drawGround) {
        if (drawGround) {
            glColor3f(0.0F, 0.0F, 0.9F);
            glNormal3f(0.0F, 1.0F, 0.0F);
            glBegin(GL_QUADS);
            glVertex3f(-100.0F, -25.0F, -100.0F);
            glVertex3f(-100.0F, -25.0F, 100.0F);
            glVertex3f(100.0F, -25.0F, 100.0F);
            glVertex3f(100.0F, -25.0F, -100.0F);
            glEnd();
        }

        glColor3f(1.0F, 0.0F / 10, 0.0F);
        sphere.draw(12.0F, 50, 50);

        glColor3f(0.0F, 1.0F, 0.0F);
        glPushMatrix();
        glTranslatef(-60.0F, 0.0F, 0.0F);
        sphere.draw(14.0F, 50, 50);
        glPopMatrix();

        glColor3f(1.0F, 1.0F, 0.0F);
        glPushMatrix();
        glTranslatef(-60.0F, 0.0F, -24.0F);
        sphere.draw(15.0F, 50, 50);
        glPopMatrix();

        glColor3f(1.0F, 0.0F, 1.0F);
        glPushMatrix();
        glTranslatef(0.0F, 0.0F, 60.0F);
        sphere.draw(16.0F, 50, 50);
        glPopMatrix();

        glColor3f(0.0F, 1.0F, 1.0F);
        glPushMatrix();
        glTranslatef(0.0F, 0.0F, -60.0F);
        sphere.draw(22.0F, 50, 50);
        glPopMatrix();
    }

    /** Generate the shadow map. */
    private static void generateShadowMap() {
        float lightToSceneDistance, nearPlane, fieldOfView;
        FloatBuffer lightModelView = BufferUtils.createFloatBuffer(16);
        FloatBuffer lightProjection = BufferUtils.createFloatBuffer(16);
        Matrix4f lightProjectionTemp = new Matrix4f();
        Matrix4f lightModelViewTemp = new Matrix4f();

        float sceneBoundingRadius = 95.0F;

        lightToSceneDistance = (float) Math.sqrt(lightPosition.get(0) * lightPosition.get(0) + lightPosition.get(1) *
                lightPosition.get(1) + lightPosition.get(2) * lightPosition.get(2));

        nearPlane = lightToSceneDistance - sceneBoundingRadius;

        fieldOfView = (float) Math.toDegrees(2.0F * Math.atan(sceneBoundingRadius / lightToSceneDistance));

        glMatrixMode(GL_PROJECTION);
        glLoadIdentity();
        gluPerspective(fieldOfView, 1.0F, nearPlane, nearPlane + (2.0F * sceneBoundingRadius));
        glGetFloat(GL_PROJECTION_MATRIX, lightProjection);
        glMatrixMode(GL_MODELVIEW);
        glLoadIdentity();
        gluLookAt(lightPosition.get(0), lightPosition.get(1), lightPosition.get(2), 0.0F, 0.0F, 0.0F, 0.0F, 1.0F, 0.0F);
        glGetFloat(GL_MODELVIEW_MATRIX, lightModelView);
        glViewport(0, 0, shadowWidth, shadowHeight);

        if (useFBO) {
            glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, frameBuffer);
        }

        glClear(GL_DEPTH_BUFFER_BIT);

        // Set rendering states to the minimum required, for speed.
        glShadeModel(GL_FLAT);
        glDisable(GL_LIGHTING);
        glDisable(GL_COLOR_MATERIAL);
        glDisable(GL_NORMALIZE);
        glColorMask(false, false, false, false);

        glEnable(GL_POLYGON_OFFSET_FILL);

        renderObjects(false);

        glCopyTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT, 0, 0, shadowWidth, shadowHeight, 0);

        // Unbind the framebuffer if we are using them.
        if (useFBO) {
            glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
        }

        // Setup the rendering states.
        glShadeModel(GL_SMOOTH);
        glEnable(GL_LIGHTING);
        glEnable(GL_COLOR_MATERIAL);
        glEnable(GL_NORMALIZE);
        glColorMask(true, true, true, true);
        glDisable(GL_POLYGON_OFFSET_FILL);

        lightProjectionTemp.load(lightProjection);
        lightModelViewTemp.load(lightModelView);
        lightProjection.flip();
        lightModelView.flip();

        Matrix4f tempMatrix = new Matrix4f();
        tempMatrix.setIdentity();
        tempMatrix.translate(new Vector3f(0.5F, 0.5F, 0.5F));
        tempMatrix.scale(new Vector3f(0.5F, 0.5F, 0.5F));
        Matrix4f.mul(tempMatrix, lightProjectionTemp, textureMatrix);
        Matrix4f.mul(textureMatrix, lightModelViewTemp, tempMatrix);
        Matrix4f.transpose(tempMatrix, textureMatrix);
    }

    /** Render the scene, and then update. */
    private static void render() {
        glMatrixMode(GL_PROJECTION);
        glLoadIdentity();
        gluPerspective(40, (float) Display.getWidth() / (float) Display.getHeight(), 1.0F, 1000.0F);
        glMatrixMode(GL_MODELVIEW);
        glLoadIdentity();
        gluLookAt(cameraPosition.get(0), cameraPosition.get(1), cameraPosition.get(2), 0.0F, 0.0F, 0.0F, 0.0F, 1.0F,
                0.0F);
        // TODO Add cam.applyModelViewMatrix(true) here and remove the 2
        // lines above

        glViewport(0, 0, Display.getWidth(), Display.getHeight());

        glLight(GL_LIGHT0, GL_POSITION, lightPosition);
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

        if (showShadowMap) {
            glMatrixMode(GL_PROJECTION);
            glLoadIdentity();
            glMatrixMode(GL_MODELVIEW);
            glLoadIdentity();
            glMatrixMode(GL_TEXTURE);
            glPushMatrix();
            glLoadIdentity();
            glEnable(GL_TEXTURE_2D);
            glDisable(GL_LIGHTING);
            glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
            glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE, GL_NONE);

            glBegin(GL_QUADS);
            glTexCoord2f(0.0F, 0.0F);
            glVertex2f(-1.0F, -1.0F);
            glTexCoord2f(1.0F, 0.0F);
            glVertex2f(1.0F, -1.0F);
            glTexCoord2f(1.0F, 1.0F);
            glVertex2f(1.0F, 1.0F);
            glTexCoord2f(0.0F, 1.0F);
            glVertex2f(-1.0F, 1.0F);
            glEnd();

            glDisable(GL_TEXTURE_2D);
            glEnable(GL_LIGHTING);
            glPopMatrix();
            glMatrixMode(GL_PROJECTION);
            gluPerspective(45.0F, 1.0F, 1.0F, 1000.0F);
            glMatrixMode(GL_MODELVIEW);
        } else {
            /*
                    * If we dont have the ambient shadow extention, we will need to
                    * add an extra rendering pass.
                    */
            if (!ambientShadowsAvailable) {
                FloatBuffer lowAmbient = BufferUtils.createFloatBuffer(4);
                lowAmbient.put(new float[]{0.1F, 0.1F, 0.1F, 1.0F});
                lowAmbient.flip();

                FloatBuffer lowDiffuse = BufferUtils.createFloatBuffer(4);
                lowDiffuse.put(new float[]{0.35F, 0.35F, 0.35F, 1.0F});
                lowDiffuse.flip();

                glLight(GL_LIGHT0, GL_AMBIENT, lowAmbient);
                glLight(GL_LIGHT0, GL_DIFFUSE, lowDiffuse);

                renderObjects(true);

                glAlphaFunc(GL_GREATER, 0.9F);
                glEnable(GL_ALPHA_TEST);
            }

            glLight(GL_LIGHT0, GL_AMBIENT, ambientLight);
            glLight(GL_LIGHT0, GL_DIFFUSE, diffuseLight);

            glEnable(GL_TEXTURE_2D);
            glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
            glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE, GL_COMPARE_R_TO_TEXTURE);

            glEnable(GL_TEXTURE_GEN_S);
            glEnable(GL_TEXTURE_GEN_T);
            glEnable(GL_TEXTURE_GEN_R);
            glEnable(GL_TEXTURE_GEN_Q);

            tempBuffer.put(0, textureMatrix.m00);
            tempBuffer.put(1, textureMatrix.m01);
            tempBuffer.put(2, textureMatrix.m02);
            tempBuffer.put(3, textureMatrix.m03);

            glTexGen(GL_S, GL_EYE_PLANE, tempBuffer);

            tempBuffer.put(0, textureMatrix.m10);
            tempBuffer.put(1, textureMatrix.m11);
            tempBuffer.put(2, textureMatrix.m12);
            tempBuffer.put(3, textureMatrix.m13);

            glTexGen(GL_T, GL_EYE_PLANE, tempBuffer);

            tempBuffer.put(0, textureMatrix.m20);
            tempBuffer.put(1, textureMatrix.m21);
            tempBuffer.put(2, textureMatrix.m22);
            tempBuffer.put(3, textureMatrix.m23);

            glTexGen(GL_R, GL_EYE_PLANE, tempBuffer);

            tempBuffer.put(0, textureMatrix.m30);
            tempBuffer.put(1, textureMatrix.m31);
            tempBuffer.put(2, textureMatrix.m32);
            tempBuffer.put(3, textureMatrix.m33);

            glTexGen(GL_Q, GL_EYE_PLANE, tempBuffer);

            renderObjects(true);

            glDisable(GL_ALPHA_TEST);
            glDisable(GL_TEXTURE_2D);
            glDisable(GL_TEXTURE_GEN_S);
            glDisable(GL_TEXTURE_GEN_T);
            glDisable(GL_TEXTURE_GEN_R);
            glDisable(GL_TEXTURE_GEN_Q);
        }

        if (glGetError() != GL_NO_ERROR) {
            System.out.println("An OpenGL error occurred");
        }
    }

    /** Sets up the OpenGL states. */
    private static void setUpOpenGL() {
        int maxRenderbufferSize = glGetInteger(GL_MAX_RENDERBUFFER_SIZE_EXT);

        if (!GLContext.getCapabilities().OpenGL14 && GLContext.getCapabilities().GL_ARB_shadow) {
            System.out.println("Can't create shadows at all. Requires OpenGL 1.4 or the GL_ARB_shadow extension");
            System.exit(0);
        }

        if (GLContext.getCapabilities().GL_ARB_shadow_ambient) {
            ambientShadowsAvailable = true;
        } else {
            System.out.println("GL_ARB_shadow_ambient extension not availible.\n An extra rendering pass will be " +
                    "required.");
        }

        if (GLContext.getCapabilities().OpenGL20 || GLContext.getCapabilities().GL_EXT_framebuffer_object) {
            System.out.println("Higher quality shadows are availible.");
        }

        maxTextureSize = glGetInteger(GL_MAX_TEXTURE_SIZE);

        System.out.println("Maximum texture size: " + maxTextureSize);
        System.out.println("Maximum renderbuffer size: " + maxRenderbufferSize);

        /*
           * Check to see if the maximum texture size is bigger than 2048.
           * Performance drops too much if it much bigger than that.
           */
        if (maxTextureSize > 2048) {
            maxTextureSize = 2048;
            if (maxRenderbufferSize < maxTextureSize) {
                maxTextureSize = maxRenderbufferSize;
            }
        }

        if (useFBO) {
            shadowWidth = maxTextureSize;
            shadowHeight = maxTextureSize;
        }

        glClearColor(0.0F, 0.0F, 0.0F, 1.0F);

        glEnable(GL_DEPTH_TEST);
        glDepthFunc(GL_LEQUAL);
        glPolygonOffset(factor, 0.0F);

        glShadeModel(GL_SMOOTH);
        glEnable(GL_LIGHTING);
        glEnable(GL_COLOR_MATERIAL);
        glEnable(GL_NORMALIZE);
        glEnable(GL_LIGHT0);

        // Setup some texture states
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
        glTexParameteri(GL_TEXTURE_2D, GL_DEPTH_TEXTURE_MODE, GL_INTENSITY);

        // If ambient shadows are availible then we can skip a rendering pass.
        if (ambientShadowsAvailable) {
            glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_FAIL_VALUE_ARB, 0.5F);
        }

        glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR);
        glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR);
        glTexGeni(GL_R, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR);
        glTexGeni(GL_Q, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR);

        // If we are using a FBO, we need to setup the framebuffer.
        if (useFBO) {
            frameBuffer = glGenFramebuffersEXT();
            glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, frameBuffer);

            renderBuffer = glGenRenderbuffersEXT();
            glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, renderBuffer);

            glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, GL_DEPTH_COMPONENT32, maxTextureSize, maxTextureSize);

            glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT,
                    renderBuffer);

            glDrawBuffer(GL_NONE);
            glReadBuffer(GL_NONE);

            int FBOStatus = glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);
            if (FBOStatus != GL_FRAMEBUFFER_COMPLETE_EXT) {
                System.out.println("Framebuffer error!");
            }

            glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
        }
        generateShadowMap();
    }

    /** Handles the keyboard and mouse input. */
    private static void input() {
        if (Keyboard.isKeyDown(Keyboard.KEY_F) && Keyboard.isKeyDown(Keyboard.KEY_LSHIFT)) {
            factor--;
            glPolygonOffset(factor, 0.0F);
            generateShadowMap();
        } else if (Keyboard.isKeyDown(Keyboard.KEY_F)) {
            factor++;
            glPolygonOffset(factor, 10);
            generateShadowMap();
        }

        // TODO Add cam.handleMouse()
        // TODO Add cam.handleKeyboard()
    }

    /** Cleanup after the program. */
    private static void cleanUp() {
        glDeleteFramebuffersEXT(frameBuffer);
        glDeleteRenderbuffersEXT(renderBuffer);
        Display.destroy();
    }

    /** Sets up the FloatBuffers to be used later on. */
    private static void setUpBufferValues() {
        ambientLight.put(new float[]{0.2F, 0.2F, 0.2F, 1.0F});
        ambientLight.flip();

        diffuseLight.put(new float[]{0.7F, 0.7F, 0.7F, 1.0F});
        diffuseLight.flip();

        cameraPosition.put(new float[]{100.0F, 50.0F, 200.0F, 1.0F});
        cameraPosition.flip();

        lightPosition.put(new float[]{100.0F, 300.0F, 100.0F, 1.0F});
        lightPosition.flip();
    }
}
TOP

Related Classes of future.ShadowMapping

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.