husker-dev / openglfx

OpenGL implementation for JavaFX
Apache License 2.0
80 stars 10 forks source link

Shader not working #25

Closed dmitrykolesnikovich closed 1 year ago

dmitrykolesnikovich commented 1 year ago

Hope you are doing well. Could I ask you please try following example that gives me nothing as graphics output

import com.huskerdev.openglfx.GLCanvasAnimator
import com.huskerdev.openglfx.OpenGLCanvas
import com.huskerdev.openglfx.events.GLInitializeEvent
import com.huskerdev.openglfx.events.GLRenderEvent
import com.huskerdev.openglfx.events.GLReshapeEvent
import com.huskerdev.openglfx.lwjgl.LWJGLExecutor
import javafx.application.Application
import javafx.scene.Scene
import javafx.scene.layout.Region
import javafx.stage.Stage
import org.lwjgl.opengl.GL11
import org.lwjgl.opengl.GL11.GL_FALSE
import org.lwjgl.opengl.GL11.GL_TRIANGLES
import org.lwjgl.opengl.GL15
import org.lwjgl.opengl.GL15.GL_ARRAY_BUFFER
import org.lwjgl.opengl.GL15.GL_STATIC_DRAW
import org.lwjgl.opengl.GL20
import java.io.File
import java.nio.ByteBuffer
import java.nio.ByteOrder
import java.nio.FloatBuffer

fun main() {
    System.setProperty("prism.order", "d3d,sw")
    System.setProperty("prism.vsync", "false")

    Application.launch(HelloTriangleExampleApp::class.java)
}

class HelloTriangleExampleApp : Application() {

    override fun start(stage: Stage) {
        stage.title = "Learn Opengl - Hello Triangle"
        stage.width = 400.0
        stage.height = 400.0
        stage.scene = Scene(createGL())
        stage.show()
    }

    private fun createGL(): Region {
        val canvas = OpenGLCanvas.create(LWJGLExecutor.LWJGL_MODULE)
        canvas.animator = GLCanvasAnimator(60.0)
        canvas.addOnInitEvent(::init)
        canvas.addOnReshapeEvent(::reshape)
        canvas.addOnRenderEvent(::render)
        return canvas
    }

    var bufferId: Int = 0
    var programId: Int = 0
    val bufferData: FloatBuffer = ByteBuffer.allocateDirect(100 shl 2).order(ByteOrder.nativeOrder()).asFloatBuffer()

    fun init(event: GLInitializeEvent) {
        val vertexShaderSource: String = """
            attribute vec3 position;

            void main() {
                gl_Position = vec4(position, 1);
            }
        """.trimIndent()
        val pixelShaderSource: String = """            
            |void main() {
            |    gl_Color = vec4(1.0, 0.5, 0.2, 1.0);
            |}
        """.trimMargin("|")

        programId = GL20.glCreateProgram()

        val vertexShaderId: Int = GL20.glCreateShader(GL20.GL_VERTEX_SHADER)
        GL20.glShaderSource(vertexShaderId, vertexShaderSource)
        GL20.glCompileShader(vertexShaderId)
        if (GL20.glGetShaderi(vertexShaderId, GL20.GL_COMPILE_STATUS) == GL_FALSE) {
            error("vertex shader not compiled")
        }

        val pixelShaderId: Int = GL20.glCreateShader(GL20.GL_FRAGMENT_SHADER)
        GL20.glShaderSource(pixelShaderId, pixelShaderSource)
        GL20.glCompileShader(pixelShaderId)
        if (GL20.glGetShaderi(pixelShaderId, GL20.GL_COMPILE_STATUS) == GL_FALSE) {
            error("pixel shader not compiled")
        }

        GL20.glAttachShader(programId, vertexShaderId)
        GL20.glAttachShader(programId, pixelShaderId)
        GL20.glLinkProgram(programId)

        if (GL20.glGetProgrami(programId, GL20.GL_LINK_STATUS) == GL_FALSE) {
            error("program not linked")
        }

        GL20.glDeleteShader(vertexShaderId)
        GL20.glDeleteShader(pixelShaderId)

        bufferData.put(floatArrayOf(0f, 0f, 0f, 0f, 10f, 0f, 10f, 0f, 0f))
        bufferId = GL15.glGenBuffers()
    }

    fun reshape(event: GLReshapeEvent) {
        val width: Int = event.width
        val height: Int = event.height
        GL11.glViewport(0, 0, width, height)
    }

    fun render(event: GLRenderEvent) {
        GL20.glUseProgram(programId)
        GL15.glBindBuffer(GL_ARRAY_BUFFER, bufferId)
        GL15.glBufferData(GL_ARRAY_BUFFER, bufferData, GL_STATIC_DRAW)
        GL11.glDrawArrays(GL_TRIANGLES, 0, 3)
    }

}

I run the example on Windows:

OS Name Microsoft Windows 10 Pro
Version 10.0.19045 Build 19045
System Type x64-based PC
dmitrykolesnikovich commented 1 year ago

I found out that on Windows you just do not support GLSL shaders:

com.sun.prism.GraphicsPipeline.getPipeline().supportsShaderType(GraphicsPipeline.ShaderType.GLSL) = false
com.sun.prism.GraphicsPipeline.getPipeline().supportsShaderType(GraphicsPipeline.ShaderType.HLSL) = true

So if this is a reason why example fails to work maybe you can suggest something smart about it?

dmitrykolesnikovich commented 1 year ago

Seems like it was a stupid mistake, I have to write System.setProperty("prism.order", "es2,d3d,sw") on the app start. So support of GLSL is working now. But example still not doing much of the output

image

husker-dev commented 1 year ago

About hlsl/glsl checking

The reason why hlsl shaders are not supported when you checking com.sun.prism.GraphicsPipeline.getPipeline().supportsShaderType(GraphicsPipeline.ShaderType.GLSL) is the using of DX9 inside of the JavaFX engine. Openglfx creates separated opengl context, so it is not correct to check hlsl support using JavaFX tools.

Suggestion

I can’t definitely say if it’s a openglfx problem. Are you getting any error messages, shader compilation errors or etc?

Also you can try to play with OpenGL profile using:

OpenGLCanvas.create(LWJGL_MODULE, CORE_PROFILE)
dmitrykolesnikovich commented 1 year ago

I finally found the bug, it's in my example code where I missed glVertexAttribPointer api calls https://learnopengl.com/code_viewer_gh.php?code=src/1.getting_started/2.2.hello_triangle_indexed/hello_triangle_indexed.cpp#22

dmitrykolesnikovich commented 1 year ago

I have a question for you: where is your interest to implement javafx in native comes from? maybe that's because you are aware that SwingNode not working on Windows 10 https://bugs.openjdk.org/browse/JDK-8222317?

dmitrykolesnikovich commented 1 year ago

funnily now I get the rectangle but in the upside-down

image

dmitrykolesnikovich commented 1 year ago

I expect the rectangle to be exactly like in tutorial though

image

dmitrykolesnikovich commented 1 year ago

here is an example that works and gives upside-down triangle (I bet there is something in openglfx internals that causes this bug)

// https://learnopengl.com/Getting-started/Hello-Triangle

import com.huskerdev.openglfx.GLCanvasAnimator
import com.huskerdev.openglfx.OpenGLCanvas
import com.huskerdev.openglfx.events.GLInitializeEvent
import com.huskerdev.openglfx.events.GLRenderEvent
import com.huskerdev.openglfx.events.GLReshapeEvent
import com.huskerdev.openglfx.lwjgl.LWJGLExecutor
import javafx.application.Application
import javafx.scene.Scene
import javafx.scene.layout.Region
import javafx.stage.Stage
import org.lwjgl.opengl.GL11
import org.lwjgl.opengl.GL11.GL_FALSE
import org.lwjgl.opengl.GL11.GL_TRIANGLES
import org.lwjgl.opengl.GL15
import org.lwjgl.opengl.GL15.GL_ARRAY_BUFFER
import org.lwjgl.opengl.GL15.GL_STATIC_DRAW
import org.lwjgl.opengl.GL20
import java.nio.ByteBuffer
import java.nio.ByteOrder
import java.nio.FloatBuffer

fun main() {
    System.setProperty("prism.order", "es2,d3d,sw")
    Application.launch(HelloTriangleExampleApp::class.java)
}

class HelloTriangleExampleApp : Application() {

    override fun start(stage: Stage) {
        stage.title = "Learn Opengl - Hello Triangle"
        stage.width = 400.0
        stage.height = 400.0
        stage.scene = Scene(createGL())
        stage.show()
    }

    private fun createGL(): Region {
        val canvas = OpenGLCanvas.create(LWJGLExecutor.LWJGL_MODULE)
        canvas.animator = GLCanvasAnimator(60.0)
        canvas.addOnInitEvent(::init)
        canvas.addOnReshapeEvent(::reshape)
        canvas.addOnRenderEvent(::render)
        return canvas
    }

    var bufferId: Int = 0
    var programId: Int = 0
    val bufferData: FloatBuffer = ByteBuffer.allocateDirect(100 shl 2).order(ByteOrder.nativeOrder()).asFloatBuffer()
    var isDirty: Boolean = true

    fun init(event: GLInitializeEvent) {
        val vertexShaderSource: String = """
            |#version 330 core
            |
            |layout (location = 0) in vec3 aPos;
            |
            |void main()
            |{
            |    gl_Position = vec4(aPos.x, aPos.y, aPos.z, 1.0);
            |}
            |""".trimMargin("|")
        val pixelShaderSource: String = """  
            |#version 330 core
            | 
            |out vec4 FragColor;
            |       
            |void main() 
            |{
            |    FragColor = vec4(1.0, 0.5, 0.2, 1.0);
            |}
        """.trimMargin("|")

        programId = GL20.glCreateProgram()

        val vertexShaderId: Int = GL20.glCreateShader(GL20.GL_VERTEX_SHADER)
        GL20.glShaderSource(vertexShaderId, vertexShaderSource)
        GL20.glCompileShader(vertexShaderId)
        if (GL20.glGetShaderi(vertexShaderId, GL20.GL_COMPILE_STATUS) == GL_FALSE) {
            error("vertex shader not compiled")
        }

        val pixelShaderId: Int = GL20.glCreateShader(GL20.GL_FRAGMENT_SHADER)
        GL20.glShaderSource(pixelShaderId, pixelShaderSource)
        GL20.glCompileShader(pixelShaderId)
        if (GL20.glGetShaderi(pixelShaderId, GL20.GL_COMPILE_STATUS) == GL_FALSE) {
            error("pixel shader not compiled")
        }

        GL20.glAttachShader(programId, vertexShaderId)
        GL20.glAttachShader(programId, pixelShaderId)
        GL20.glLinkProgram(programId)

        if (GL20.glGetProgrami(programId, GL20.GL_LINK_STATUS) == GL_FALSE) {
            error("program not linked")
        }

        GL20.glDeleteShader(vertexShaderId)
        GL20.glDeleteShader(pixelShaderId)

        bufferData.put(
            floatArrayOf(
                -0.5f, -0.5f, 0.0f,
                0.5f, -0.5f, 0.0f,
                0.0f, 0.5f, 0.0f
            )
        )
        bufferData.rewind()
        bufferId = GL15.glGenBuffers()
    }

    fun reshape(event: GLReshapeEvent) {
        val width: Int = event.width
        val height: Int = event.height
        GL11.glViewport(0, 0, width, height)
    }

    fun render(event: GLRenderEvent) {
        GL11.glClearColor(0.2f, 0.3f, 0.3f, 1.0f)
        GL11.glClear(GL11.GL_COLOR_BUFFER_BIT)
        GL20.glUseProgram(programId)
        GL15.glBindBuffer(GL_ARRAY_BUFFER, bufferId)
        GL20.glEnableVertexAttribArray(0)
        GL20.glVertexAttribPointer(0, 3, GL11.GL_FLOAT, false, 3 * 4, 0)
        if (isDirty) {
            GL15.glBufferData(GL_ARRAY_BUFFER, bufferData, GL_STATIC_DRAW)
            isDirty = false
        }
        GL11.glDrawArrays(GL_TRIANGLES, 0, 3)
    }

}
dmitrykolesnikovich commented 1 year ago

so I fixed the bug by flipping sy1 and sy2 here https://github.com/husker-dev/openglfx/pull/26/files#diff-0541126a600110b3f3fbb4b058b6ba3cf523a859a209fd1425b1d98e83d3225dR172