Interaction Example▲
Sélectionnez
/**
**************************************************************************
**
** Copyright (C) 2016 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the QtCanvas3D module of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:BSD$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** BSD License Usage
** Alternatively, you may use this file under the terms of the BSD license
** as follows:
**
** "Redistribution and use in source and binary forms, with or without
** modification, are permitted provided that the following conditions are
** met:
** * Redistributions of source code must retain the above copyright
** notice, this list of conditions and the following disclaimer.
** * 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.
** * Neither the name of The Qt Company Ltd nor the names of its
** contributors may be used to endorse or promote products derived
** from this software without specific prior written permission.
**
**
** 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."
**
** $QT_END_LICENSE$
**
***************************************************************************
*/
Qt.include("gl-matrix.js"
)
Qt.include("ThreeJSLoader.js"
)
var gl;
var texturedShaderProgram =
0
;
var vertexShader =
0
;
var fragmentShader =
0
;
var vertexPositionAttribute;
var textureCoordAttribute;
var vertexNormalAttribute;
var pMatrixUniform;
var mvMatrixUniform;
var nMatrixUniform;
var textureSamplerUniform;
var barrelTexture =
0
;
var mvMatrix =
mat4.create();
var pMatrix =
mat4.create();
var nMatrix =
mat4.create();
var startTime;
var canvas3d;
var isLogEnabled =
false
;
function log(message) {
if
(isLogEnabled)
console.log(message)
}
function Model() {
this
.verticesVBO =
0
;
this
.normalsVBO =
0
;
this
.texCoordVBO =
0
;
this
.indexVBO =
0
;
this
.count =
0
;
}
var theModel =
new
Model();
function initializeGL(canvas) {
canvas3d =
canvas
log("*******************************************************************************************"
)
log("initializeGL ENTER..."
)
try
{
startTime =
Date.now();
// Get the OpenGL context jsonObj that represents the API we call
log("Getting Context"
);
gl =
canvas.getContext("canvas3d"
, {
depth:true
, antialias:true
, alpha:false
}
);
log("Context received "
+
gl);
var contextConfig =
gl.getContextAttributes();
log("Depth: "
+
contextConfig.alpha);
log("Stencil: "
+
contextConfig.stencil);
log("Antialiasing: "
+
contextConfig.antialias);
log("Premultiplied alpha: "
+
contextConfig.premultipliedAlpha);
log("Preserve drawingbuffer: "
+
contextConfig.preserveDrawingBuffer);
log("Prefer Low Power To High Performance: "
+
contextConfig.preferLowPowerToHighPerformance);
log("Fail If Major Performance Caveat: "
+
contextConfig.failIfMajorPerformanceCaveat);
// Setup the OpenGL state
gl.enable(gl.DEPTH_TEST);
gl.enable(gl.CULL_FACE);
gl.frontFace(gl.CCW);
gl.cullFace(gl.BACK);
gl.disable(gl.BLEND);
gl.clearColor(0.98
, 0.98
, 0.98
, 1.0
);
gl.clearDepth(1.0
);
// Set viewport
gl.viewport(0
, 0
,
canvas.width *
canvas.devicePixelRatio,
canvas.height *
canvas.devicePixelRatio);
// Initialize the shader program
initShaders();
// Initialize buffers
theModel.verticesVBO =
gl.createBuffer();
theModel.verticesVBO.name =
"BarrelModel.verticesVBO"
;
theModel.normalsVBO =
gl.createBuffer();
theModel.normalsVBO.name =
"BarrelModel.normalsVBO"
;
theModel.texCoordVBO =
gl.createBuffer();
theModel.texCoordVBO.name =
"BarrelModel.texCoordVBO"
;
theModel.indexVBO =
gl.createBuffer();
theModel.indexVBO.name =
"BarrelModel.indexVBO"
;
// Load the barrel texture
gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, true
);
// Load the Qt logo as texture
var barrelImage =
TextureImageFactory.newTexImage();
barrelImage.imageLoaded.connect(function() {
barrelTexture =
gl.createTexture();
barrelTexture.name =
"barrelTexture"
gl.bindTexture(gl.TEXTURE_2D, barrelTexture);
gl.texImage2D(gl.TEXTURE_2D, // target
0
, // level
gl.RGBA, // internalformat
gl.RGBA, // format
gl.UNSIGNED_BYTE, // type
barrelImage); // pixels
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR_MIPMAP_NEAREST);
gl.generateMipmap(gl.TEXTURE_2D);
}
);
barrelImage.imageLoadingFailed.connect(function() {
console.log("Texture load FAILED, "
+
barrelImage.errorString);
}
);
// Aliasing doesn't work correctly with QtQuick compiler for some reason,
// so use full names for barrel.jpg and barrel.json
barrelImage.src =
"qrc:/qml/interaction/barrel.jpg"
;
// Load the model
log(" Create XMLHttpRequest"
)
var request =
new
XMLHttpRequest();
log(" XMLHttpRequest.open"
)
request.open("GET"
, "qrc:/qml/interaction/barrel.json"
);
log(" XMLHttpRequest.onreadystatechange"
)
request.onreadystatechange =
function () {
if
(request.readyState ===
XMLHttpRequest.DONE) {
handleLoadedModel(JSON.parse(request.responseText));
}
}
log(" XMLHttpRequest.send"
)
request.send();
log("...initializeGL EXIT"
);
}
catch
(e) {
console.log("...initializeGL FAILURE!"
);
console.log(""
+
e);
console.log(""
+
e.message);
}
log("*******************************************************************************************"
);
}
function resizeGL(canvas)
{
var pixelRatio =
canvas.devicePixelRatio;
canvas.pixelSize =
Qt.size(canvas.width *
pixelRatio,
canvas.height *
pixelRatio);
if
(gl)
gl.viewport(0
, 0
,
canvas.width *
canvas.devicePixelRatio,
canvas.height *
canvas.devicePixelRatio);
}
function paintGL(canvas) {
// draw
gl.clear(gl.COLOR_BUFFER_BIT |
gl.DEPTH_BUFFER_BIT);
// draw only when we have the mesh and texture
if
(theModel.count &
lt;=
0
||
barrelTexture ==
0
) return
;
gl.useProgram(texturedShaderProgram);
// Calculate the perspective projection
mat4.perspective(pMatrix, degToRad(45
), canvas.width /
canvas.height, 0.1
, 10000.0
);
gl.uniformMatrix4fv(pMatrixUniform, false
, pMatrix);
// Bind the correct buffers
gl.bindBuffer(gl.ARRAY_BUFFER, theModel.verticesVBO);
gl.enableVertexAttribArray(vertexPositionAttribute);
gl.vertexAttribPointer(vertexPositionAttribute, 3
, gl.FLOAT, false
, 0
, 0
);
gl.bindBuffer(gl.ARRAY_BUFFER, theModel.normalsVBO);
gl.enableVertexAttribArray(vertexNormalAttribute);
gl.vertexAttribPointer(vertexNormalAttribute, 3
, gl.FLOAT, false
, 0
, 0
);
gl.bindBuffer(gl.ARRAY_BUFFER, theModel.texCoordVBO);
gl.enableVertexAttribArray(textureCoordAttribute);
gl.vertexAttribPointer(textureCoordAttribute, 2
, gl.FLOAT, false
, 0
, 0
);
gl.activeTexture(gl.TEXTURE0);
gl.bindTexture(gl.TEXTURE_2D, barrelTexture);
gl.uniform1i(textureSamplerUniform, 0
);
// Calculate and apply the modelview matrix
mvMatrix =
mat4.identity(mvMatrix);
mvMatrix =
mat4.translate(mvMatrix, mvMatrix, [0
, -
40
, -
700
]);
mvMatrix =
mat4.rotate(mvMatrix, mvMatrix, degToRad(canvas.xRotSlider), [1
, 0
, 0
]);
mvMatrix =
mat4.rotate(mvMatrix, mvMatrix, degToRad(canvas.yRotSlider), [0
, 1
, 0
]);
mvMatrix =
mat4.rotate(mvMatrix, mvMatrix, degToRad(canvas.zRotSlider), [0
, 0
, 1
]);
gl.uniformMatrix4fv(mvMatrixUniform, false
, mvMatrix);
// Calculate normal matrix
nMatrix =
mat4.invert(nMatrix, mvMatrix);
nMatrix =
mat4.transpose(nMatrix, nMatrix);
gl.uniformMatrix4fv(nMatrixUniform, false
, nMatrix);
// Draw the barrel
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, theModel.indexVBO);
gl.drawElements(gl.TRIANGLES, theModel.count, gl.UNSIGNED_SHORT, 0
);
// Calculate and apply the modelview matrix
mvMatrix =
mat4.identity(mvMatrix);
mvMatrix =
mat4.translate(mvMatrix, mvMatrix, [-
250
, -
50
, -
700
]);
mvMatrix =
mat4.rotate(mvMatrix, mvMatrix, degToRad(canvas.xRotSlider), [0
, 1
, 0
]);
gl.uniformMatrix4fv(mvMatrixUniform, false
, mvMatrix);
// Calculate normal matrix
nMatrix =
mat4.invert(nMatrix, mvMatrix);
nMatrix =
mat4.transpose(nMatrix, nMatrix);
gl.uniformMatrix4fv(nMatrixUniform, false
, nMatrix);
// Draw the barrel
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, theModel.indexVBO);
gl.drawElements(gl.POINTS, theModel.count, gl.UNSIGNED_SHORT, 0
);
// Calculate and apply the modelview matrix
mvMatrix =
mat4.identity(mvMatrix);
mvMatrix =
mat4.translate(mvMatrix, mvMatrix, [250
, -
50
, -
700
]);
mvMatrix =
mat4.rotate(mvMatrix, mvMatrix, degToRad(canvas.zRotSlider), [0
, 1
, 0
]);
gl.uniformMatrix4fv(mvMatrixUniform, false
, mvMatrix);
// Calculate normal matrix
nMatrix =
mat4.invert(nMatrix, mvMatrix);
nMatrix =
mat4.transpose(nMatrix, nMatrix);
gl.uniformMatrix4fv(nMatrixUniform, false
, nMatrix);
// Draw the barrel
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, theModel.indexVBO);
gl.drawElements(gl.LINES, theModel.count, gl.UNSIGNED_SHORT, 0
);
}
function handleLoadedModel(jsonObj) {
log("*******************************************************************************************"
);
log("handleLoadedModel ENTER..."
)
var modelData =
parseJSON3DModel(jsonObj, ""
);
log(" "
+
theModel.verticesVBO);
gl.bindBuffer(gl.ARRAY_BUFFER, theModel.verticesVBO);
gl.bufferData(gl.ARRAY_BUFFER,
new
Float32Array(modelData.vertices),
gl.STATIC_DRAW);
log(" "
+
theModel.normalsVBO);
gl.bindBuffer(gl.ARRAY_BUFFER, theModel.normalsVBO);
gl.bufferData(gl.ARRAY_BUFFER,
new
Float32Array(modelData.normals),
gl.STATIC_DRAW);
log(" "
+
theModel.texCoordVBO);
gl.bindBuffer(gl.ARRAY_BUFFER, theModel.texCoordVBO);
gl.bufferData(gl.ARRAY_BUFFER,
new
Float32Array(modelData.texCoords[0
]),
gl.STATIC_DRAW);
log(" "
+
theModel.indexVBO);
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, theModel.indexVBO);
gl.bufferData(gl.ELEMENT_ARRAY_BUFFER,
new
Uint16Array(modelData.indices),
gl.STATIC_DRAW);
theModel.count =
modelData.indices.length;
log("...handleLoadedModel EXIT"
);
log("*******************************************************************************************"
);
}
function degToRad(degrees) {
return
degrees *
Math.PI /
180
;
}
function initShaders()
{
log(" initShaders ENTER..."
)
vertexShader =
getShader(gl,
"attribute highp vec3 aVertexNormal; \
attribute highp vec3 aVertexPosition; \
attribute highp vec2 aTextureCoord; \
\
uniform highp mat4 uNormalMatrix; \
uniform mat4 uMVMatrix; \
uniform mat4 uPMatrix; \
\
varying highp vec2 vTextureCoord; \
varying highp vec3 vLighting; \
\
void main(void) { \
gl_Position = uPMatrix * uMVMatrix * vec4(aVertexPosition, 1.0); \
vTextureCoord = aTextureCoord; \
highp vec3 ambientLight = vec3(0.5, 0.5, 0.5); \
highp vec3 directionalLightColor = vec3(0.75, 0.75, 0.75); \
highp vec3 directionalVector = vec3(0.85, 0.8, 0.75); \
highp vec4 transformedNormal = uNormalMatrix * vec4(aVertexNormal, 1.0); \
\
highp float directional = max(dot(transformedNormal.xyz, directionalVector), 0.0); \
vLighting = ambientLight + (directionalLightColor * directional); \
gl_PointSize = 1.0; \
}"
, gl.VERTEX_SHADER);
fragmentShader =
getShader(gl,
"varying highp vec2 vTextureCoord; \
varying highp vec3 vLighting; \
\
uniform sampler2D uSampler; \
\
void main(void) { \
mediump vec4 texelColor = texture2D(uSampler, vec2(vTextureCoord.s, vTextureCoord.t)); \
gl_FragColor = vec4(texelColor.rgb * vLighting, 1.0); \
}"
, gl.FRAGMENT_SHADER);
texturedShaderProgram =
gl.createProgram();
texturedShaderProgram.name =
"TexturedShaderProgram"
;
gl.attachShader(texturedShaderProgram, vertexShader);
gl.attachShader(texturedShaderProgram, fragmentShader);
gl.linkProgram(texturedShaderProgram);
if
(!
gl.getProgramParameter(texturedShaderProgram, gl.LINK_STATUS)) {
console.log("Could not initialize shaders"
);
console.log(gl.getProgramInfoLog(texturedShaderProgram));
}
gl.useProgram(texturedShaderProgram);
// look up where the vertex data needs to go.
vertexPositionAttribute =
gl.getAttribLocation(texturedShaderProgram, "aVertexPosition"
);
vertexPositionAttribute.name =
"aVertexPosition_AttribLocation"
;
gl.enableVertexAttribArray(vertexPositionAttribute);
vertexNormalAttribute =
gl.getAttribLocation(texturedShaderProgram, "aVertexNormal"
);
vertexPositionAttribute.name =
"aVertexNormal_AttribLocation"
;
gl.enableVertexAttribArray(vertexNormalAttribute);
textureCoordAttribute =
gl.getAttribLocation(texturedShaderProgram, "aTextureCoord"
);
vertexPositionAttribute.name =
"aTextureCoord_AttribLocation"
;
gl.enableVertexAttribArray(textureCoordAttribute);
pMatrixUniform =
gl.getUniformLocation(texturedShaderProgram, "uPMatrix"
);
pMatrixUniform.name =
"uPMatrix_UniformLocation"
;
mvMatrixUniform =
gl.getUniformLocation(texturedShaderProgram, "uMVMatrix"
);
mvMatrixUniform.name =
"uMVMatrix_UniformLocation"
;
textureSamplerUniform =
gl.getUniformLocation(texturedShaderProgram, "uSampler"
)
textureSamplerUniform.name =
"uSampler_UniformLocation"
;
nMatrixUniform =
gl.getUniformLocation(texturedShaderProgram, "uNormalMatrix"
);
nMatrixUniform.name =
"uNormalMatrix_UniformLocation"
;
log(" ... initShaders EXIT"
);
}
function getShader(gl, str, type) {
var shader =
gl.createShader(type);
gl.shaderSource(shader, str);
gl.compileShader(shader);
if
(!
gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {
console.log("JS:Shader compile failed"
);
console.log(gl.getShaderInfoLog(shader));
return
null;
}
return
shader;
}