diff options
Diffstat (limited to 'src')
3 files changed, 1227 insertions, 0 deletions
diff --git a/src/test/com/jogamp/opengl/test/junit/jogl/demos/es2/ElektronenMultiplizierer.java b/src/test/com/jogamp/opengl/test/junit/jogl/demos/es2/ElektronenMultiplizierer.java new file mode 100644 index 000000000..f484dbf72 --- /dev/null +++ b/src/test/com/jogamp/opengl/test/junit/jogl/demos/es2/ElektronenMultiplizierer.java @@ -0,0 +1,515 @@ +/** + * Copyright 2011 JogAmp Community. 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 JogAmp Community ``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 JogAmp Community 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 JogAmp Community. + */ + + +package com.jogamp.opengl.test.junit.jogl.demos.es2; + +import java.nio.*; + +import javax.media.opengl.*; +import javax.media.opengl.glu.*; + +import com.jogamp.common.nio.*; +import com.jogamp.newt.opengl.*; +import com.jogamp.opengl.util.*; +import com.jogamp.opengl.util.glsl.ShaderCode; +import com.jogamp.opengl.util.glsl.ShaderProgram; +import com.jogamp.opengl.util.glsl.ShaderState; + +import static javax.media.opengl.GL2ES2.*; + +/** + ** __ __|_ ___________________________________________________________________________ ___|__ __ + ** // /\ _ /\ \\ + ** //____/ \__ __ _____ _____ _____ _____ _____ | | __ _____ _____ __ __/ \____\\ + ** \ \ / / __| | | __| _ | | _ | | | __| | | __| | /\ \ / / + ** \____\/_/ | | | | | | | | | | | __| | | | | | | | | | |__ " \_\/____/ + ** /\ \ |_____|_____|_____|__|__|_|_|_|__| | | |_____|_____|_____|_____| _ / /\ + ** / \____\ http://jogamp.org |_| /____/ \ + ** \ / "' _________________________________________________________________________ `" \ / + ** \/____. .____\/ + ** + ** JOGL2 port of my PC 4k intro competition entry for Revision 2011. Sure it got a little bigger + ** while porting but the shader and control code remained more or less untouched. The intro renders + ** a fullscreen billboard using a single fragment shader. The shader encapsulates basically two + ** different routines: A sphere-tracing based raymarcher for a single fractal formula and a bitmap + ** orbit trap julia+mandelbrot fractal renderer. Additionally an inline-processing analog-distortion + ** filter is applied to all rendered fragments to make the overall look more interesting. + ** + ** The different intro parts are all parameter variations of the two routines in the fragment shader + ** synched to the music: Parts 3+5 are obviously the mandelbrot and julia bitmap orbit traps, and parts + ** 1,2,4 and 6 are pure fractal sphere tracing. + ** + ** During the development of the intro it turned out that perfectly raymarching every pixel of the orbit + ** trapped julia+mandelbrot fractal was way to slow even on highend hardware. So I inserted a lowres + ** intermediate FBO to be used by the bitmap based orbit trap routine wich was ofcourse way faster, but + ** had the obvious upscaling artefacts. Maybe I'll produce a perfect quality version for very patient + ** people with insane hardware :) + ** + ** Papers and articles you should be familiar with before trying to understand the code: + ** + ** Distance rendering for fractals: http://www.iquilezles.org/www/articles/distancefractals/distancefractals.htm + ** Geometric orbit traps: http://www.iquilezles.org/www/articles/ftrapsgeometric/ftrapsgeometric.htm + ** Bitmap orbit traps: http://www.iquilezles.org/www/articles/ftrapsbitmap/ftrapsbitmap.htm + ** Ambient occlusion techniques: http://www.iquilezles.org/www/articles/ao/ao.htm + ** Sphere tracing: A geometric method for the antialiased ray tracing of implicit surfaces: http://graphics.cs.uiuc.edu/~jch/papers/zeno.pdf + ** Rendering fractals with distance estimation function: http://www.iquilezles.org/www/articles/mandelbulb/mandelbulb.htm + ** + ** For an impression how this routine looks like see here: http://www.youtube.com/watch?v=lvC8maVHh8Q + ** Original release from the Revision can be found here: http://www.pouet.net/prod.php?which=56860 + **/ +public class ElektronenMultiplizierer implements GLEventListener { + +//BEGIN --- BaseGlobalEnvironment replacement --- + + private final GLCapabilities mCaps; + private final GLU mGlu; + + private String mCommandLineParameter_BaseRoutineClassName; + private boolean mCommandLineParameter_MultiSampling; + private int mCommandLineParameter_NumberOfSampleBuffers; + private boolean mCommandLineParameter_AnisotropicFiltering; + private float mCommandLineParameter_AnisotropyLevel; + private boolean mCommandLineParameter_FrameCapture; + private boolean mCommandLineParameter_FrameSkip; + private boolean mUsesFullScreenMode; + private int mFrameCounter; + private int mCommandLineParameter_FrameRate; + private long mFrameSkipAverageFramerateTimeStart; + private boolean mFrameSkipAverageFrameStartTimeInitialized; + private long mFrameSkipAverageFramerateTimeEnd; + private double mFrameCounterDifference; + private double mFrameCounterTargetValue; + private int mSkippedFramesCounter; +// private BaseMusic mBaseMusic; + boolean mMusicSyncStartTimeInitialized = false; + + private ShaderState st; + private PMVMatrix pmvMatrix; + private GLUniformData pmvMatrixUniform; + private GLUniformData mScreenDimensionUniform; + private GLArrayDataServer vertices0; + private GLArrayDataServer texCoords0; + + public String getBaseRoutineClassName() { return mCommandLineParameter_BaseRoutineClassName; } + public boolean preferMultiSampling() { return mCommandLineParameter_MultiSampling; } + public int getNumberOfSamplingBuffers() { return mCommandLineParameter_NumberOfSampleBuffers; } + public boolean preferAnisotropicFiltering() { return mCommandLineParameter_AnisotropicFiltering; } + public float getAnisotropyLevel() { return mCommandLineParameter_AnisotropyLevel; } + public boolean wantsFrameCapture() { return mCommandLineParameter_FrameCapture; } + public int getDesiredFramerate() { return mCommandLineParameter_FrameRate; } + public boolean wantsFrameSkip() { return mCommandLineParameter_FrameSkip; } + public boolean usesFullScreenMode() { return mUsesFullScreenMode; } + + public ElektronenMultiplizierer ( + String inBaseRoutineClassName, + boolean inMultiSampling, + int inNumberOfSampleBuffers, + boolean inAnisotropicFiltering, + float inAnisotropyLevel, + boolean inFrameCapture, + boolean inFrameSkip, int desiredFrameRate + ) { + mGlu = new GLU(); + mCommandLineParameter_BaseRoutineClassName = inBaseRoutineClassName; + mCommandLineParameter_MultiSampling = inMultiSampling; + mCommandLineParameter_NumberOfSampleBuffers = (inNumberOfSampleBuffers==-1) ? 2 : inNumberOfSampleBuffers; + mCommandLineParameter_AnisotropicFiltering = inAnisotropicFiltering; + mCommandLineParameter_AnisotropyLevel = (inAnisotropyLevel==-1.0f) ? 2.0f : inAnisotropyLevel; + mCommandLineParameter_FrameCapture = inFrameCapture; + mCommandLineParameter_FrameSkip = inFrameSkip; + mCommandLineParameter_FrameRate = desiredFrameRate; + mCaps = new GLCapabilities(GLProfile.get(GLProfile.GL2ES2)); + if (preferMultiSampling()) { + // enable/configure multisampling support ... + mCaps.setSampleBuffers(true); + mCaps.setNumSamples(getNumberOfSamplingBuffers()); + mCaps.setAccumAlphaBits(1); + mCaps.setAccumBlueBits(1); + mCaps.setAccumGreenBits(1); + mCaps.setAccumRedBits(1); + // turns out we need to have alpha, otherwise no AA will be visible + mCaps.setAlphaBits(1); + } + } + + public GLCapabilitiesImmutable getGLCapabilities() { + return mCaps; + } + + public void init(GLAutoDrawable drawable) { + GL2ES2 gl = drawable.getGL().getGL2ES2(); + gl.setSwapInterval(1); + mFrameCounter = 0; + + st = new ShaderState(); + final ShaderCode vp0 = ShaderCode.create(gl, GL2ES2.GL_VERTEX_SHADER, 1, this.getClass(), + "shader", "shader/bin", "default"); + final ShaderCode fp0 = ShaderCode.create(gl, GL2ES2.GL_FRAGMENT_SHADER, 1, this.getClass(), + // "shader", "shader/bin", "elektronenmultiplizierer_development"); + "shader", "shader/bin", "elektronenmultiplizierer_port"); + final ShaderProgram sp0 = new ShaderProgram(); + sp0.add(gl, vp0, System.err); + sp0.add(gl, fp0, System.err); + st.attachShaderProgram(gl, sp0); + st.useProgram(gl, true); + + final float XRESf = (float) drawable.getWidth(); + final float YRESf = (float) drawable.getHeight(); + + mScreenDimensionUniform = new GLUniformData("resolution", 2, Buffers.newDirectFloatBuffer(2)); + final FloatBuffer mScreenDimensionV = (FloatBuffer) mScreenDimensionUniform.getBuffer(); + mScreenDimensionV.put(0, XRESf); + mScreenDimensionV.put(1, YRESf); + st.ownUniform(mScreenDimensionUniform); + st.uniform(gl, mScreenDimensionUniform); + + pmvMatrix = new PMVMatrix(); + pmvMatrixUniform = new GLUniformData("gcu_PMVMatrix", 4, 4, pmvMatrix.glGetPMvMatrixf()); + st.ownUniform(pmvMatrixUniform); + st.uniform(gl, pmvMatrixUniform); + + vertices0 = GLArrayDataServer.createGLSL(st, "gca_Vertices", 2, GL.GL_FLOAT, false, 4, GL.GL_STATIC_DRAW); + vertices0.putf(0); vertices0.putf(YRESf); + vertices0.putf(XRESf); vertices0.putf(YRESf); + vertices0.putf(0); vertices0.putf(0); + vertices0.putf(XRESf); vertices0.putf(0); + vertices0.seal(gl, true); + st.ownAttribute(vertices0, true); + vertices0.enableBuffer(gl, false); + + texCoords0 = GLArrayDataServer.createGLSL(st, "gca_TexCoords", 2, GL.GL_FLOAT, false, 4, GL.GL_STATIC_DRAW); + texCoords0.putf(0f); texCoords0.putf(1f); + texCoords0.putf(1f); texCoords0.putf(1f); + texCoords0.putf(0f); texCoords0.putf(0f); + texCoords0.putf(1f); texCoords0.putf(0f); + texCoords0.seal(gl, true); + st.ownAttribute(texCoords0, true); + texCoords0.enableBuffer(gl, false); + + //generate framebufferobject + int[] result = new int[1]; + gl.glGenTextures(1, result, 0); + mFrameBufferTextureID = result[0]; + gl.glBindTexture(GL_TEXTURE_2D, mFrameBufferTextureID); + gl.glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + gl.glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + gl.glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + gl.glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, 384, 384, 0, GL_RGBA, GL_UNSIGNED_BYTE, null); + + //allocate the framebuffer object ... + gl.glGenFramebuffers(1, result, 0); + mFrameBufferObjectID = result[0]; + gl.glBindFramebuffer(GL_FRAMEBUFFER, mFrameBufferObjectID); + gl.glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, mFrameBufferTextureID, 0); + gl.glClearColor(0.0f, 0.0f, 0.0f, 0.0f); + gl.glBindFramebuffer(GL_FRAMEBUFFER, 0); + st.uniform(gl, new GLUniformData("fb", 0)); + + // will be changed in display(..) + st.uniform(gl, new GLUniformData("en", 0)); + st.uniform(gl, new GLUniformData("tm", 0.0f)); + st.uniform(gl, new GLUniformData("br", 0.0f)); + st.uniform(gl, new GLUniformData("et", 0.0f)); + + gl.glClearColor(0.0f, 0.0f, 0.0f, 0.0f); + +// mBaseMusic = new BaseMusic(BaseGlobalEnvironment.getInstance().getMusicFileName()); +// mBaseMusic.init(); +// mBaseMusic.play(); + } + + public void display(GLAutoDrawable drawable) { + GL2ES2 gl = drawable.getGL().getGL2ES2(); + + final int XRES = drawable.getWidth(); + final int YRES = drawable.getHeight(); + + //if NO music is used sync to mainloop start ... + if (!mFrameSkipAverageFrameStartTimeInitialized) { + mFrameSkipAverageFrameStartTimeInitialized = true; + mFrameSkipAverageFramerateTimeStart = System.nanoTime(); + } +// if (!getBaseMusic().isOffline()) { +// //if music IS used sync to first second of music ... +// if (BaseRoutineRuntime.getInstance().getBaseMusic().getPositionInMilliseconds()>0 && !mMusicSyncStartTimeInitialized) { +// BaseLogging.getInstance().info("Synching to BaseMusic ..."); +// mFrameSkipAverageFramerateTimeStart = (long)(System.nanoTime()-((double)BaseRoutineRuntime.getInstance().getBaseMusic().getPositionInMilliseconds()*1000000.0d)); +// mMusicSyncStartTimeInitialized = true; +// } +// } + //allow music DSP's to synchronize with framerate ... +// mBaseMusic.synchonizeMusic(); + + //use this for offline rendering/capture ... + int MMTime_u_ms = (int)((((double)mFrameCounter)*44100.0f)/60.0f); + //use this for music synched rendering ... + //int MMTime_u_ms = (int)(BaseRoutineRuntime.getInstance().getBaseMusic().getPositionInMilliseconds()*(44100.0f/1000.0f)); + //dedicated sync variable for each event ... kinda lame but who cares X-) + if (MMTime_u_ms>=522240 && !mSyncEvent_01) { mSyncEvent_01 = true; handleSyncEvent(MMTime_u_ms); } + if (MMTime_u_ms>=1305480 && !mSyncEvent_02) { mSyncEvent_02 = true; handleSyncEvent(MMTime_u_ms); } + if (MMTime_u_ms>=1827720 && !mSyncEvent_03) { mSyncEvent_03 = true; handleSyncEvent(MMTime_u_ms); } + if (MMTime_u_ms>=2349960 && !mSyncEvent_04) { mSyncEvent_04 = true; handleSyncEvent(MMTime_u_ms); } + if (MMTime_u_ms>=3394440 && !mSyncEvent_05) { mSyncEvent_05 = true; handleSyncEvent(MMTime_u_ms); } + if (MMTime_u_ms>=3916680 && !mSyncEvent_06) { mSyncEvent_06 = true; handleSyncEvent(MMTime_u_ms); } + if (MMTime_u_ms>=4438408 && !mSyncEvent_07) { mSyncEvent_07 = true; handleSyncEvent(MMTime_u_ms); } + if (MMTime_u_ms>=5482831 && !mSyncEvent_08) { mSyncEvent_08 = true; handleSyncEvent(MMTime_u_ms); } + //calculate current time based on 60fps reference framerate ... + MMTime_u_ms = (int)((((double)mFrameCounter)*44100.0)/60.0); + gl.glDisable(GL_CULL_FACE); + gl.glDisable(GL_DEPTH_TEST); + + st.useProgram(gl, true); + + vertices0.enableBuffer(gl, true); + texCoords0.enableBuffer(gl, true); + + pmvMatrix.glMatrixMode(PMVMatrix.GL_PROJECTION); + pmvMatrix.glLoadIdentity(); + pmvMatrix.glOrthof(0f, XRES, YRES, 0f, -1f, 1f); + pmvMatrix.glMatrixMode(PMVMatrix.GL_MODELVIEW); + pmvMatrix.glLoadIdentity(); + st.uniform(gl, pmvMatrixUniform); + + gl.glActiveTexture(GL_TEXTURE0); + + //gogogo! O-) + float tBrightnessSync = 40.0f-((MMTime_u_ms-mSyncTime)/1000.0f); + if (tBrightnessSync<1) { + tBrightnessSync=1; + } + mEffectTime = (float)((MMTime_u_ms-mEffectSyncTime)/100000.0f); + + if (mSyncEventNumber==0 && mEffectTime<4.0f) { + //fadein and fullscreen rotate + tBrightnessSync = mEffectTime/4.0f; + } else if (mSyncEventNumber==8 && mEffectTime>12.0f) { + //fullscrenn mushroom transform + tBrightnessSync = 1.0f-((mEffectTime-12.0f)/3.5f); + } + + if (mSyncEventNumber==0 || mSyncEventNumber==1) { + //zoomin from fog + mEffectNumber = 3; + mEffectTime *= 1.75; + float tEffectTimeMax = 9.3f; + if (mEffectTime>=tEffectTimeMax) { + mEffectTime=tEffectTimeMax; + } + } else if(mSyncEventNumber==2 || mSyncEventNumber==3) { + //transform big after zoomin + mEffectNumber = 4; + mEffectTime *= 0.25f; + } else if(mSyncEventNumber==4) { + //mandelbrot orbit-trap zoomout + mEffectNumber = 1; + mEffectTime *= 0.0002f; + } else if(mSyncEventNumber==5 || mSyncEventNumber==6) { + //inside fractal + mEffectNumber = 5; + mEffectTime *= 0.02f; + } else if(mSyncEventNumber==7) { + //spiral orbit-trap + mEffectNumber = 0; + mEffectTime *= 0.02f; + } else if(mSyncEventNumber==8) { + //fadeout fractal + mEffectNumber = 6; + mEffectTime *= 0.364f; + } + + gl.glBindFramebuffer(GL_FRAMEBUFFER, mFrameBufferObjectID); + // gl.glViewport(0, 0, drawable.getWidth(), drawable.getHeight()); + GLUniformData en = st.getUniform("en"); + if(mSyncEventNumber==7) { + en.setData(2); + } + if(mSyncEventNumber==4) { + en.setData(7); + } else { + en.setData(0); + } + st.uniform(gl, en); + + GLUniformData et = st.getUniform("et"); + st.uniform(gl, et.setData(9.1f)); + + st.uniform(gl, st.getUniform("tm").setData(MMTime_u_ms/40000.0f)); + st.uniform(gl, st.getUniform("br").setData(tBrightnessSync)); + + if(mSyncEventNumber==4 || mSyncEventNumber==7) { + //render to fbo only when using julia/mandel orbittrap ... + // gl.glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + gl.glDrawArrays(GL.GL_TRIANGLE_STRIP, 0, 4); + } + gl.glBindFramebuffer(GL_FRAMEBUFFER, 0); + st.uniform(gl, en.setData(mEffectNumber)); + st.uniform(gl, et.setData(mEffectTime)); + + gl.glEnable(GL_TEXTURE_2D); + gl.glBindTexture(GL_TEXTURE_2D, mFrameBufferTextureID); + + gl.glClear(GL.GL_COLOR_BUFFER_BIT | GL.GL_DEPTH_BUFFER_BIT); + gl.glDrawArrays(GL.GL_TRIANGLE_STRIP, 0, 4); + + vertices0.enableBuffer(gl, false); + texCoords0.enableBuffer(gl, false); + st.useProgram(gl, false); + + //--- + mFrameCounter++; + if (wantsFrameSkip()) { + mFrameSkipAverageFramerateTimeEnd = System.nanoTime(); + double tDesiredFrameRate = (float)getDesiredFramerate(); + double tSingleFrameTime = 1000000000.0f/tDesiredFrameRate; + double tElapsedTime = mFrameSkipAverageFramerateTimeEnd - mFrameSkipAverageFramerateTimeStart; + mFrameCounterTargetValue = tElapsedTime/tSingleFrameTime; + mFrameCounterDifference = mFrameCounterTargetValue-mFrameCounter; + if (mFrameCounterDifference>2) { + mFrameCounter+=mFrameCounterDifference; + mSkippedFramesCounter+=mFrameCounterDifference; + } else if (mFrameCounterDifference<-2) { + //hold framecounter advance ... + mFrameCounter--; + } + } + + } + + public void reshape(GLAutoDrawable drawable, int x, int y, int width, int height) { + GL2ES2 gl = drawable.getGL().getGL2ES2(); + + st.useProgram(gl, true); + vertices0.seal(false); + vertices0.rewind(); + vertices0.putf(0); vertices0.putf(height); + vertices0.putf(width); vertices0.putf(height); + vertices0.putf(0); vertices0.putf(0); + vertices0.putf(width); vertices0.putf(0); + vertices0.seal(gl, true); + st.ownAttribute(vertices0, true); + vertices0.enableBuffer(gl, false); + + final FloatBuffer mScreenDimensionV = (FloatBuffer) mScreenDimensionUniform.getBuffer(); + mScreenDimensionV.put(0, (float) width); + mScreenDimensionV.put(1, (float) height); + st.uniform(gl, mScreenDimensionUniform); + + st.useProgram(gl, false); + gl.glViewport(0, 0, width, height); + } + + public void dispose(GLAutoDrawable inDrawable) { + GL2ES2 gl = inDrawable.getGL().getGL2ES2(); + gl.glDeleteFramebuffers(1, new int[] { mFrameBufferObjectID }, 0); + gl.glDeleteTextures(1, new int[] { mFrameBufferTextureID }, 0); + st.destroy(gl); + } + +// public BaseMusic getBaseMusic() { +// return mBaseMusic; +// } + + public void resetFrameCounter() { + mFrameCounter = 0; + } + +//END --- BaseRoutineRuntime --- + + protected int mFrameBufferTextureID; + protected int mFrameBufferObjectID; + protected int mSyncTime; + protected int mSyncEventNumber; + protected float mEffectTime; + protected int mEffectNumber; + protected int mEffectSyncTime; + + protected boolean mSyncEvent_01; + protected boolean mSyncEvent_02; + protected boolean mSyncEvent_03; + protected boolean mSyncEvent_04; + protected boolean mSyncEvent_05; + protected boolean mSyncEvent_06; + protected boolean mSyncEvent_07; + protected boolean mSyncEvent_08; + + public void handleSyncEvent(int inMMTime_u_ms) { + mSyncTime = inMMTime_u_ms; + mSyncEventNumber++; + System.out.println("NEW SYNC EVENT! tSyncEventNumber="+mSyncEventNumber+" tSyncTime="+mSyncTime); + if (mSyncEventNumber==0 || mSyncEventNumber==2 || mSyncEventNumber==5 || mSyncEventNumber==8) { + mEffectSyncTime = inMMTime_u_ms; + } + } + + +//BEGIN --- main entry point --- + + static { + //stg dirty I dont wanna think about any further X-) ... + GLProfile.initSingleton(true); + } + + public static void main(String args[]) throws Exception { + String tRoutineClassName = null; + boolean tMultiSampling = false; + int tNumberOfSampleBuffers = -1; + boolean tAnisotropicFiltering = false; + float tAnisotropyLevel = -1.0f; + boolean tFrameCapture = false; + boolean tFrameSkip = true; + int desiredFrameRate = 30; + + final ElektronenMultiplizierer demo = new ElektronenMultiplizierer( + tRoutineClassName, + tMultiSampling,tNumberOfSampleBuffers, + tAnisotropicFiltering,tAnisotropyLevel, + tFrameCapture, + tFrameSkip, desiredFrameRate + ); + GLCapabilitiesImmutable caps = demo.getGLCapabilities(); + + GLWindow glWindow = GLWindow.create(caps); + glWindow.setSize(640, 480); + glWindow.setTitle("Jogamp.org - ElektronenMultiplizierer - GL2ES2/NEWT"); + glWindow.addGLEventListener(demo); + final Animator animator = new Animator(glWindow); + animator.setUpdateFPSFrames(60, System.err); + glWindow.addWindowListener(new com.jogamp.newt.event.WindowAdapter() { + public void windowDestroyNotify(com.jogamp.newt.event.WindowEvent e) { + animator.stop(); + System.exit(0); + } + }); + glWindow.setVisible(true); + animator.start(); + } + +//END --- main entry point --- + +} diff --git a/src/test/com/jogamp/opengl/test/junit/jogl/demos/es2/shader/elektronenmultiplizierer_development.fp b/src/test/com/jogamp/opengl/test/junit/jogl/demos/es2/shader/elektronenmultiplizierer_development.fp new file mode 100644 index 000000000..6b89e6670 --- /dev/null +++ b/src/test/com/jogamp/opengl/test/junit/jogl/demos/es2/shader/elektronenmultiplizierer_development.fp @@ -0,0 +1,432 @@ +/** + * Copyright 2011 JogAmp Community. 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 JogAmp Community ``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 JogAmp Community 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 JogAmp Community. + */ + +/** + ** __ __|_ ___________________________________________________________________________ ___|__ __ + ** // /\ _ /\ \\ + ** //____/ \__ __ _____ _____ _____ _____ _____ | | __ _____ _____ __ __/ \____\\ + ** \ \ / / __| | | __| _ | | _ | | | __| | | __| | /\ \ / / + ** \____\/_/ | | | | | | | | | | | __| | | | | | | | | | |__ " \_\/____/ + ** /\ \ |_____|_____|_____|__|__|_|_|_|__| | | |_____|_____|_____|_____| _ / /\ + ** / \____\ http://jogamp.org |_| /____/ \ + ** \ / "' _________________________________________________________________________ `" \ / + ** \/____. .____\/ + ** + ** JOGL2 port of my PC 4k intro competition entry for Revision 2011. The shader encapsulates basically + ** two different routines: A sphere-tracing based raymarcher for a single fractal formula and a bitmap + ** orbit trap julia+mandelbrot fractal renderer. Additionally an inline-processing analog-distortion + ** filter is applied to all rendered fragments to make the overall look more interesting. + ** + ** Papers and articles you should be familiar with before trying to understand the code: + ** + ** Distance rendering for fractals: http://www.iquilezles.org/www/articles/distancefractals/distancefractals.htm + ** Geometric orbit traps: http://www.iquilezles.org/www/articles/ftrapsgeometric/ftrapsgeometric.htm + ** Bitmap orbit traps: http://www.iquilezles.org/www/articles/ftrapsbitmap/ftrapsbitmap.htm + ** Ambient occlusion techniques: http://www.iquilezles.org/www/articles/ao/ao.htm + ** Sphere tracing: A geometric method for the antialiased ray tracing of implicit surfaces: http://graphics.cs.uiuc.edu/~jch/papers/zeno.pdf + ** Rendering fractals with distance estimation function: http://www.iquilezles.org/www/articles/mandelbulb/mandelbulb.htm + ** + ** For an impression how this routine looks like see here: http://www.youtube.com/watch?v=lvC8maVHh8Q + ** Original release from the Revision can be found here: http://www.pouet.net/prod.php?which=56860 + **/ + +//When I wrote this, only God and I understood what I was doing ... +// ... now only God knows! X-) + +#ifdef GL_ES + #define MEDIUMP mediump + #define HIGHP highp + #define LOWP lowp +#else + #define MEDIUMP + #define HIGHP + #define LOWP +#endif + +uniform HIGHP int en; //effectnumber +uniform HIGHP float et; //effecttime +uniform HIGHP sampler2D fb; //fbotexture +uniform HIGHP float br; //brightness +uniform HIGHP float tm; //time +uniform HIGHP vec2 resolution;//screen resolution/fbo resolution + +float camerafocallengthdode; +vec3 camerapositiondode; +vec2 sizedode; +vec3 backgroundcolor = vec3(0,0.6,0.46); +mat3 worldrotationxyz; +mat3 fractalplanerotationx; +mat3 fractalplanerotationy; +mat3 camerarotationdode; +vec2 oglFragCoord; + +//fractal formula used for sphreretracing/distance-estimation +//dodecahedron serpinski (knighty) +//http://www.fractalforums.com/index.php?topic=3158.msg16982#msg16982 +//normal vectors for the dodecahedra-siepinski folding planes are: +//(phi^2, 1, -phi), (-phi, phi^2, 1), (1, -phi, phi^2), (-phi*(1+phi), phi^2-1, 1+phi), (1+phi, -phi*(1+phi), phi^2-1) and x=0, y=0, z=0 planes. + +//const pre-calc +const float phi = 1.618; +const float _IKVNORM_ = 1.0 / sqrt(pow(phi * (1.0 + phi), 2.0) + pow(phi * phi - 1.0, 2.0) + pow(1.0 + phi, 2.0)); +const float _C1_ = phi * (1.0 + phi) * _IKVNORM_; +const float _C2_ = (phi * phi - 1.0) * _IKVNORM_; +const float _1C_ = (1.0 + phi) * _IKVNORM_; +const vec3 phi3 = vec3(0.5, 0.5 / phi, 0.5 * phi); +const vec3 c3 = vec3(_C1_, _C2_, _1C_); + +vec3 distancefunction(vec3 w) { +//!P center scale offset ... + vec3 offset; + if (en==6) { + offset = vec3(0.61,0.1*et,0.99); + } else { + offset = vec3(0.61,0.0,0.99); + } +//!P center scale \0/ this is awesome for fadeins !!! + float scale = 2.; + w *= worldrotationxyz; + float d, t; + float md = 1000.0, cd = 0.0; +//!P iterations (8) ... 2x see below + for (int i = 0; i < 8; i++) { + w *= fractalplanerotationx; + w = abs(w); + t = w.x * phi3.z + w.y * phi3.y - w.z * phi3.x; + if (t < 0.0) { w += vec3(-2.0, -2.0, 2.0) * t * phi3.zyx; } + t = -w.x * phi3.x + w.y * phi3.z + w.z * phi3.y; + if (t < 0.0) { w += vec3(2.0, -2.0, -2.0) * t * phi3.xzy; } + t = w.x * phi3.y - w.y * phi3.x + w.z * phi3.z; + if (t < 0.0) { w += vec3(-2.0, 2.0, -2.0) * t * phi3.yxz; } + t = -w.x * c3.x + w.y * c3.y + w.z * c3.z; + if (t < 0.0) { w += vec3(2.0, -2.0, -2.0) * t * c3.xyz; } + t = w.x * c3.z - w.y * c3.x + w.z * c3.y; + if (t < 0.0) { w += vec3(-2.0, 2.0, -2.0) * t * c3.zxy; } + w *= fractalplanerotationy; + w *= scale; + w -= offset * (scale - 1.0); + //accumulate minimum orbit for coloring ... + d = dot(w, w); +//!P iterations for coloring (4) + if (i < 4) { + md = min(md, d); + cd = d; + } + } +//!P max iterations (8) + return vec3((length(w) - 2.0) * pow(scale, -8.0), md, cd); +} + +//calculate ray direction fragment coordinates +vec3 raydirection(vec2 pixel) { + vec2 p = (0.5*sizedode-pixel)/vec2(sizedode.x,-sizedode.y); +//!P aspect ratio of dode + p.x *= sizedode.x/sizedode.y; +//!P vec3 w = vec3(0, 0, 1), vec3 v = vec3(0, 1, 0), vec3 u = vec3(1, 0, 0); + vec3 d = (p.x * vec3(1, 0, 0)+p.y * vec3(0, 1, 0)-camerafocallengthdode * vec3(0, 0, 1)); + return normalize(camerarotationdode * d); +} + +//iq's fake ambient occlusion +//http://www.iquilezles.org/www/material/nvscene2008/rwwtt.pdf +//http://www.iquilezles.org/www/articles/ao/ao.htm +float ambientocclusion(vec3 p, vec3 n, float eps) { + float o = 1.0; +//!P ao spread (10.6) +// spreads the output color intensity + eps *= 10.6; +//!P ao intensity (0.16) + float k = 0.16 / eps; + //add little start distance to the surface + float d = 2.0 * eps; +//!P ao iterations (5) ... + for (int i = 0; i < 5; ++i) { + o -= (d - distancefunction(p + n * d).x) * k; + d += eps; + //fade ao when distance to the surface increases + k *= 0.5; + } + return clamp(o, 0.0, 1.0); +} + +vec4 render(vec2 pixel) { + vec3 ray_direction = raydirection(pixel); +//!P minimum ray length (6e-5) + float ray_length = 6e-5; + vec3 ray = camerapositiondode + ray_length * ray_direction; +//!P minimum epsilon (6e-7) ... + float eps = 6e-7; + vec3 dist; + vec3 normal = vec3(0); + int steps = 0; + bool hit = false; + float minmarch = 0.0; +//!P maxmarch = 10000.0; + float maxmarch = 25.0; +//!P field of view scale = (1.0 / sqrt(1.0 + camerafocallengthdode * camerafocallengthdode)) +//!P detail of surface approximation = 1.22 +//!P pixelscale = (1.0 / min(sizedode.x, sizedode.y)) + float epsfactor = 2.0 * (1.0 / sqrt(1.0 + camerafocallengthdode * camerafocallengthdode)) * (1.0 / min(sizedode.x, sizedode.y)) * 1.22; + ray_length = minmarch; + ray = camerapositiondode + ray_length * ray_direction; +//!P max number of raymarching steps (90); + for (int i = 0; i < 90; i++) { + steps = i; + dist = distancefunction(ray); +//!P X-) questionable surface smoothing (0.53) + dist.x *= 0.53; + //backtrack previous step and check if it was only a "fussel" + if (hit && dist.x < eps || ray_length > maxmarch || ray_length < minmarch) { + steps--; + break; + } + hit = false; + ray_length += dist.x; + ray = camerapositiondode + ray_length * ray_direction; + eps = ray_length * epsfactor; + if (dist.x < eps || ray_length < minmarch) { + hit = true; + } + } + //\0/ there is a hit! + vec4 color = vec4(backgroundcolor,0.5); + if (hit) { + float aof = 1.0; + if (steps < 1 || ray_length < minmarch) { + normal = normalize(ray); + } else { + //gradient in x,y and z direction for intersection point + //!P minimum normal (1.5e-7) + float e = max(eps * 0.5, 1.5e-7); + normal = normalize(vec3( + distancefunction(ray + vec3(e, 0, 0)).x - distancefunction(ray - vec3(e, 0, 0)).x, + distancefunction(ray + vec3(0, e, 0)).x - distancefunction(ray - vec3(0, e, 0)).x, + distancefunction(ray + vec3(0, 0, e)).x - distancefunction(ray - vec3(0, 0, e)).x + )); + aof = ambientocclusion(ray, normal, eps); + } +//!P hardcoded light position vec3(-50,150,-25) + float diffuse = max(dot(normal, normalize(vec3(-50,150,-25) - ray)), 0.0); +//blinn/phong specular stuff ... +//!P specular exponent (4) +//!P specularity (0.8) +//!P diffuse color vec3(0.45) 2x in one line ... +//!P ambient color vec2 ambientcolor = vec2(0.5,0.3) + color.rgb = (mix(vec3(0.5), backgroundcolor, 0.3) * vec3(0.45) + vec3(0.45) * diffuse + pow(diffuse, 4.) * 0.8)*aof; + color.a = 1.0; + } +//!P fog factor = 0.01 + color.rgb = mix(backgroundcolor, color.rgb, exp(-pow(ray_length, 2.0) * 0.01)); + return color; +} + +mat3 xmatrixrotation(float angle) { + return mat3( + vec3(1.0, 0.0, 0.0), + vec3(0.0, cos(angle), sin(angle)), + vec3(0.0, -sin(angle), cos(angle)) + ); +} + +mat3 ymatrixrotation(float angle) { + return mat3( + vec3(cos(angle), 0.0, -sin(angle)), + vec3( 0.0, 1.0, 0.0), + vec3(sin(angle), 0.0, cos(angle)) + ); +} + +vec4 raymarch_orbittrap_image(vec2 fragcoord) { + //do the matrix calculations by hand X-) + //as mat4 constructor and arithmetic assignments are + //currently broken (2010-09-21) on ATI cards i found + //a workaround using vec4 constructors wich works on + //both NVIDIA+ATI --- MAGIC. DO NOT TOUCH! -=#:-) + mat3 identitymatrix = mat3(1,0,0,0,1,0,0,0,1); + float sin_phi = sin(0.1*tm); + float cos_phi = cos(0.1*tm); + mat3 zrot = mat3( + vec3( cos_phi, sin_phi, 0.0), + vec3(-sin_phi, cos_phi, 0.0), + vec3( 0.0, 0.0, 1.0) + ); + vec2 position; + float fractalplanex_var; + float fractalplaney_var; + position = oglFragCoord.xy; + camerafocallengthdode = 1.0; + if (en==2) { + sizedode = vec2(384,384); + camerapositiondode = vec3(0.0,0.0,-2.7); + } else if (en==3) { + camerapositiondode = vec3(0.0,0.0,-2.7*(10.-et)); + } else if (en==4) { + camerapositiondode = vec3(0.0,0.0,-2.7*(10.-9.3)); + fractalplanex_var = et; + fractalplaney_var = 0.0; + } else if (en==5) { + //inside effect + camerapositiondode = vec3(0.0,0.0,-0.05); + fractalplanex_var = 1.06; + fractalplaney_var = -1.0-et; + } else if (en==6) { + camerapositiondode = vec3(0.0,0.0,-2.7*(10.-9.5)); + fractalplanex_var = et; + fractalplaney_var = sin(et*0.03)-1.0; + } else if (en==7) { + sizedode = vec2(384,384); + fractalplanex_var = et; + fractalplaney_var = sin(et*0.93)-1.0; + camerapositiondode = vec3(0.0,0.0,-2.7); + } + worldrotationxyz = xmatrixrotation(0.1*tm)*ymatrixrotation(0.1*tm)*zrot*identitymatrix; + fractalplanerotationx = xmatrixrotation(fractalplanex_var)*identitymatrix; + fractalplanerotationy = xmatrixrotation(fractalplaney_var)*identitymatrix; + camerarotationdode = ymatrixrotation(3.14)*identitymatrix; + vec4 color = render(position); + return color; +} + +//---------------------------------------------------------------------------------------------------------- + +vec4 orbitmapping(vec4 c, vec2 w) { +//!P orbit trap scale and offset + vec2 orbittrapoffset = vec2(0.24,-0.24); + float orbittrapscale; + if (en==0) { + //julia set ... + orbittrapscale = 0.625; + } else { + //mandlebrot ... + orbittrapscale = 0.325; + } + vec2 sp = 0.5 + (w / orbittrapscale - orbittrapoffset); + vec4 s = texture2D(fb, sp); + if (s.a > 0.0) { + c = mix(c, s, s.a); + } + return c; +} + +vec4 orbittrap(vec2 z) { + float powerjulia = 2.; + vec3 colorjulia = vec3(1.0); + vec4 color = vec4(colorjulia, 0.0); + float n = 0.0; + vec2 c; + if (en==0) { + //julia mode ... +//!P use offset-julia from 2.25 to 2.5 + c = vec2(sin(et+2.07)*0.05,cos(et+2.07)); + } else { + //mandelbrot mode ... + c = z; + } +//!P max iterations for julia (128) ... 2x parameter - see below! + for (int i = 0; i<128; i++) { + n += 1.0; + float r = pow(length(z), powerjulia); + float a = powerjulia * atan(z.y, z.x); + z = vec2(cos(a) * r, sin(a) * r) +c; +//!P min iterations for julia (1.0) ... + if (n >= 1.0) { + color = orbitmapping(color, z); +//!P orbit trap alpha precision (0.6) ... + if (color.a >= 0.6) { + break; + } + } + } +//!P max iterations for julia (128.0) ... + float blend = clamp(1.0 - (n / 128.0) * 2.0, 0.0, 1.0); + color.rgb = mix(colorjulia, color.rgb, blend); + return color; +} + +void main() { + vec2 sizejulia = resolution; + sizedode = sizejulia; + oglFragCoord = gl_FragCoord.xy; + vec4 color; + if (en==0 || en==1) { + //render 2d julia/mandelbrot +//!P camera position for julia ... + vec3 camerapositionjulia; + if (en==0) { + //julia + camerapositionjulia = vec3(-0.2,-0.515,0.095347+(et*1.75)); + } else { + //mandelbrot + camerapositionjulia = vec3(0.325895,0.049551,0.0005+et); + } +//!P absolute output size of julia orbit trap ... + vec2 z = ((oglFragCoord.xy - (sizejulia * 0.5)) / sizejulia) * + vec2(sizejulia.x/sizejulia.y, 1.0) * //aspect ratio + camerapositionjulia.z + + camerapositionjulia.xy; + color = orbittrap(z); + } else { + color = raymarch_orbittrap_image(oglFragCoord.xy); + } + if (en==2 || en==7) { + gl_FragColor = color; + } else { + //do normal rendering ... + //analog-tv distortion ... + vec2 position = oglFragCoord.xy / sizejulia.xy; + position.y *=-1.0; + vec3 color_tv = color.rgb; + //contrast + color_tv = clamp(color_tv*0.5+0.5*color_tv*color_tv*1.2,0.0,1.0); + //circular vignette fade + color_tv *= 0.5 + 0.5*16.0*position.x*position.y*(1.0-position.x)*(-1.0-position.y); + //color shift + if (en==0 || en==3) { + color_tv *= vec3(0.8,1.0,0.7); //green + } + if (en==1 || en==4) { + color_tv *= vec3(0.95,0.85,1.0); //blue + } + if (en==5) { + color_tv *= vec3(1.0,0.7,1.0); //purple + } + + if (en==6) { + color_tv *= vec3(0.7,1.0,1.0); //cyan + } + if (en==2) { + color_tv *= vec3(1.0,1.0,0.7); //yellow + } + //tvlines effect + color_tv *= 0.9+0.1*sin(1.5*tm+position.y*1000.0); + //tv flicker effect + color_tv *= 0.97+0.13*sin(2.5*tm); + color_tv *= br; + gl_FragColor = vec4(color_tv,1.0); + } +} diff --git a/src/test/com/jogamp/opengl/test/junit/jogl/demos/es2/shader/elektronenmultiplizierer_port.fp b/src/test/com/jogamp/opengl/test/junit/jogl/demos/es2/shader/elektronenmultiplizierer_port.fp new file mode 100644 index 000000000..fdd159616 --- /dev/null +++ b/src/test/com/jogamp/opengl/test/junit/jogl/demos/es2/shader/elektronenmultiplizierer_port.fp @@ -0,0 +1,280 @@ +/** + * Copyright 2011 JogAmp Community. 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 JogAmp Community ``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 JogAmp Community 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 JogAmp Community. + */ + +/** + ** __ __|_ ___________________________________________________________________________ ___|__ __ + ** // /\ _ /\ \\ + ** //____/ \__ __ _____ _____ _____ _____ _____ | | __ _____ _____ __ __/ \____\\ + ** \ \ / / __| | | __| _ | | _ | | | __| | | __| | /\ \ / / + ** \____\/_/ | | | | | | | | | | | __| | | | | | | | | | |__ " \_\/____/ + ** /\ \ |_____|_____|_____|__|__|_|_|_|__| | | |_____|_____|_____|_____| _ / /\ + ** / \____\ http://jogamp.org |_| /____/ \ + ** \ / "' _________________________________________________________________________ `" \ / + ** \/____. .____\/ + ** + ** JOGL2 port of my PC 4k intro competition entry for Revision 2011. The shader encapsulates basically + ** two different routines: A sphere-tracing based raymarcher for a single fractal formula and a bitmap + ** orbit trap julia+mandelbrot fractal renderer. Additionally an inline-processing analog-distortion + ** filter is applied to all rendered fragments to make the overall look more interesting. + ** + ** Papers and articles you should be familiar with before trying to understand the code: + ** + ** Distance rendering for fractals: http://www.iquilezles.org/www/articles/distancefractals/distancefractals.htm + ** Geometric orbit traps: http://www.iquilezles.org/www/articles/ftrapsgeometric/ftrapsgeometric.htm + ** Bitmap orbit traps: http://www.iquilezles.org/www/articles/ftrapsbitmap/ftrapsbitmap.htm + ** Ambient occlusion techniques: http://www.iquilezles.org/www/articles/ao/ao.htm + ** Sphere tracing: A geometric method for the antialiased ray tracing of implicit surfaces: http://graphics.cs.uiuc.edu/~jch/papers/zeno.pdf + ** Rendering fractals with distance estimation function: http://www.iquilezles.org/www/articles/mandelbulb/mandelbulb.htm + ** + ** For an impression how this routine looks like see here: http://www.youtube.com/watch?v=lvC8maVHh8Q + ** Original release from the Revision can be found here: http://www.pouet.net/prod.php?which=56860 + **/ + +//When I wrote this, only God and I understood what I was doing ... +// ... now only God knows! X-) + +uniform int en; +uniform float et; +uniform sampler2D fb; +uniform float br,tm; +uniform vec2 resolution; +float v; +vec3 n; +vec2 e; +vec3 f=vec3(0,.6,.46); +mat3 i,m,r,y; +vec2 c; +const float x=1.618,t=1./sqrt(pow(x*(1.+x),2.)+pow(x*x-1.,2.)+pow(1.+x,2.)),z=x*(1.+x)*t,s=(x*x-1.)*t,w=(1.+x)*t; +const vec3 a=vec3(.5,.5/x,.5*x),p=vec3(z,s,w); +vec3 l(vec3 v) { + vec3 n; + if(en==6) + n=vec3(.61,.1*et,.99); + else + n=vec3(.61,0.,.99); + float e=2.; + v*=i; + float f,x,c=1000.,y=0.; + for(int z=0;z<8;z++) { + v*=m; + v=abs(v); + x=v.x*a.z+v.y*a.y-v.z*a.x; + if(x<0.) + v+=vec3(-2.,-2.,2.)*x*a.zyx; + x=-v.x*a.x+v.y*a.z+v.z*a.y; + if(x<0.) + v+=vec3(2.,-2.,-2.)*x*a.xzy; + x=v.x*a.y-v.y*a.x+v.z*a.z; + if(x<0.) + v+=vec3(-2.,2.,-2.)*x*a.yxz; + x=-v.x*p.x+v.y*p.y+v.z*p.z; + if(x<0.) + v+=vec3(2.,-2.,-2.)*x*p.xyz; + x=v.x*p.z-v.y*p.x+v.z*p.y; + if(x<0.) + v+=vec3(-2.,2.,-2.)*x*p.zxy; + v*=r; + v*=e; + v-=n*(e-1.); + f=dot(v,v); + if(z<4) + c=min(c,f),y=f; + } + return vec3((length(v)-2.)*pow(e,-8.),c,y); +} +vec3 b(vec2 x) { + vec2 n=(.5*e-x)/vec2(e.x,-e.y); + n.x*=e.x/e.y; + vec3 a=n.x*vec3(1,0,0)+n.y*vec3(0,1,0)-v*vec3(0,0,1); + return normalize(y*a); +} +float b(vec3 e,vec3 x,float v) { + float n=1.; + v*=10.6; + float t=.16/v,y=2.*v; + for(int i=0;i<5;++i) + n-=(y-l(e+x*y).x)*t,y+=v,t*=.5; + return clamp(n,0.,1.); +} +vec4 h(vec2 x) { + vec3 a=b(x); + float i=6e-05; + vec3 y=n+i*a; + float c=6e-07; + vec3 m,z=vec3(0); + int r=0; + bool t=false; + float s=0.,w=25.,p=2.*(1./sqrt(1.+v*v))*(1./min(e.x,e.y))*1.22; + i=s; + y=n+i*a; + for(int g=0;g<90;g++) { + r=g; + m=l(y); + m.x*=.53; + if(t&&m.x<c||i>w||i<s) { + r--; + break; + } + t=false; + i+=m.x; + y=n+i*a; + c=i*p; + if(m.x<c||i<s) + t=true; + } + vec4 g=vec4(f,.5); + if(t) { + float d=1.; + if(r<1||i<s) + z=normalize(y); + else { + float h=max(c*.5,1.5e-07); + z=normalize(vec3(l(y+vec3(h,0,0)).x-l(y-vec3(h,0,0)).x,l(y+vec3(0,h,0)).x-l(y-vec3(0,h,0)).x,l(y+vec3(0,0,h)).x-l(y-vec3(0,0,h)).x)); + d=b(y,z,c); + } + float h=max(dot(z,normalize(vec3(-66,162,-30)-y)),0.); + g.xyz=(mix(vec3(.5),f,.3)*vec3(.45)+vec3(.45)*h+pow(h,4.)*.8)*d; + g.w=1.; + } + g.xyz=mix(f,g.xyz,exp(-pow(i,2.)*.01)); + return g; +} +mat3 g(float e) { + return mat3(vec3(1.,0.,0.),vec3(0.,cos(e),sin(e)),vec3(0.,-sin(e),cos(e))); +} +mat3 d(float e) { + return mat3(vec3(cos(e),0.,-sin(e)),vec3(0.,1.,0.),vec3(sin(e),0.,cos(e))); +} +vec4 D(vec2 x) { + mat3 a=mat3(1,0,0,0,1,0,0,0,1); + float t=sin(.1*tm),z=cos(.1*tm); + mat3 p=mat3(vec3(z,t,0.),vec3(-t,z,0.),vec3(0.,0.,1.)); + vec2 f; + float s,w; + f=c.xy; + v=1.; + if(en==2) + e=vec2(384,384),n=vec3(0.,0.,-2.7); + if(en==3) + n=vec3(0.,0.,-2.7*(10.-et)); + if(en==4) + n=vec3(0.,0.,-1.89),s=et,w=0.; + if(en==5) + n=vec3(0.,0.,-.05),s=1.06,w=-1.-et; + if(en==6) + n=vec3(0.,0.,-1.35),s=et,w=sin(et*.03)-1.; + if(en==7) + e=vec2(384,384),s=et,w=sin(et*.93)-1.,n=vec3(0.,0.,-2.7); + i=g(.1*tm)*d(.1*tm)*p*a; + m=g(s)*a; + r=g(w)*a; + y=d(3.14)*a; + vec4 l=h(f); + if(l.w<.00392) { + discard; + } + return l; +} +vec4 D(vec4 e,vec2 x) { + vec2 n=vec2(.24,-.24); + float y; + if(en==0) + y=.625; + else + y=.325; + vec2 v=.5+(x/y-n); + vec4 c=texture2D(fb,v); + if(c.w>0.) + e=mix(e,c,c.w); + return e; +} +vec4 o(vec2 v) { + float n=2.; + vec3 e=vec3(1.); + vec4 i=vec4(e,0.); + float y=0.; + vec2 x; + if(en==0) + x=vec2(sin(et+2.07)*.05,cos(et+2.07)); + else + x=v; + for(int f=0;f<128;f++) { + y+=1.; + float t=pow(length(v),n),c=n*atan(v.y,v.x); + v=vec2(cos(c)*t,sin(c)*t)+x; + if(y>=1.) { + i=D(i,v); + if(i.w>=.6) { + break; + } + } + } + float c=clamp(1.-y/128.*2.,0.,1.); + i.xyz=mix(e,i.xyz,c); + return i; +} +void main() { + //vec2 v=vec2(640.0,480.0); + vec2 v =resolution; + e=v; + c=gl_FragCoord.xy; + vec4 n; + if(en==0||en==1) { + vec3 a; + if(en==0) + a=vec3(-.2,-.515,.095347+et*1.75); + else + a=vec3(.325895,.049551,.0005+et); + vec2 x=(c.xy-v*.5)/v*vec2(v.x/v.y,1.)*a.z+a.xy; + n=o(x); + } else + n=D(c.xy); + if(en==2||en==7) + gl_FragColor=n; + else { + vec2 i=c.xy/v.xy; + i.y*=-1.; + vec3 x=n.xyz; + x=clamp(x*.5+.5*x*x*1.2,0.,1.); + x*=.5+8.*i.x*i.y*(1.-i.x)*(-1.-i.y); + if(en==0||en==3) + x*=vec3(.8,1.,.7); + if(en==1||en==4) + x*=vec3(.95,.85,1.); + if(en==5) + x*=vec3(1.,.7,1.); + if(en==6) + x*=vec3(.7,1.,1.); + if(en==2) + x*=vec3(1.,1.,.7); + x*=.9+.1*sin(1.5*tm+i.y*1000.); + x*=.97+.13*sin(2.5*tm); + x*=br; + gl_FragColor=vec4(x,1.); + } +} |