我试图渲染简单的形状(圆形,矩形和三角形,但是,当WebGL渲染它们时,它们变得非常像素化。
着色器代码:
<!-- vertex shader -->
<script id="2d-vertex-shader" type="x-shader/x-vertex">
attribute vec2 a_position;
uniform vec2 u_resolution;
void main() {
// convert the rectangle points from pixels to 0.0 to 1.0
vec2 zeroToOne = a_position / u_resolution;
// convert from 0->1 to 0->2
vec2 zeroToTwo = zeroToOne * 2.0;
// convert from 0->2 to -1->+1 (clipspace)
vec2 clipSpace = zeroToTwo - 1.0;
gl_Position = vec4(clipSpace * vec2(1, -1), 0, 1);
}
</script>
<!-- fragment shader -->
<script id="2d-fragment-shader" type="x-shader/x-fragment">
precision mediump float;
uniform vec4 u_color;
void main() {
gl_FragColor = u_color;
}
</script>
这是我渲染圆圈的代码:
var WebGLRenderer = (function () {
function WebGLRenderer() {
this.canvas = document.getElementById('canvas')
this.gl = this.canvas.getContext('webgl') || this.canvas.getContext('experimental-webgl')
if (!this.gl) {
throw Error('Your browser does not support WebGL')
return
}
// Programs
this.rectangleProgram = webglUtils.createProgramFromScripts(this.gl, ['2d-vertex-shader', '2d-fragment-shader'])
// Locations
this.rectanglePoisitionLocation = this.gl.getAttribLocation(this.rectangleProgram, 'a_position')
// Uniforms
this.rectangleResolutionLocation = this.gl.getUniformLocation(this.rectangleProgram, 'u_resolution')
this.rectangleColorLocation = this.gl.getUniformLocation(this.rectangleProgram, 'u_color')
// this.positionBuffer = this.gl.createBuffer()
this.rectanglePositionBuffer = this.gl.createBuffer()
// this.gl.bindBuffer(this.gl.ARRAY_BUFFER, this.positionBuffer)
requestAnimationFrame(this.render.bind(this))
}
WebGLRenderer.prototype.clearCanvas = function (color) {
var rgba = color.getColor()
this.gl.clearColor(...rgba)
this.gl.clear(this.gl.COLOR_BUFFER_BIT)
}
WebGLRenderer.prototype.drawCircle = function (x, y, radius, color) {
// Render circle
// For now user rectangleProgram
this.gl.useProgram(this.rectangleProgram)
this.gl.enableVertexAttribArray(this.rectanglePoisitionLocation)
// this.gl.bindBuffer(this.gl.ARRAY_BUFFER, this.positionBuffer)
this.circleBuffer = this.gl.createBuffer()
// this.gl.bindBuffer(this.gl.ARRAY_BUFFER, this.rectanglePositionBuffer)
this.gl.bindBuffer(this.gl.ARRAY_BUFFER, this.circleBuffer)
// Setup circle
var circleVertices = [x, y]
var numFans = 360
var anglePerFan = (2 * Math.PI) / numFans
for (var i = 0; i <= numFans; i++) {
var angle = anglePerFan * (i + 1)
var angledX = x + Math.cos(angle) * radius
var angledY = y + Math.sin(angle) * radius
circleVertices.push(angledX, angledY)
// circleVertices.push()
}
this.gl.bufferData(this.gl.ARRAY_BUFFER, new Float32Array(circleVertices), this.gl.DYNAMIC_DRAW)
// this.gl.bufferData(this.gl.ARRAY_BUFFER, new Float32Array(positions), this.gl.STATIC_DRAW)
var size = 2
var type = this.gl.FLOAT
var normalize = false
var stride = 0
var offset = 0
this.gl.vertexAttribPointer(this.rectanglePoisitionLocation, size, type, normalize, stride, offset)
this.gl.uniform2f(this.rectangleResolutionLocation, this.gl.canvas.width, this.gl.canvas.height)
// Color
var colorArray = color.getColor()
this.gl.uniform4fv(this.rectangleColorLocation, colorArray)
// Draw rectangle
var primitiveType = this.gl.TRIANGLE_FAN
// var primitiveType = this.gl.POINTS
var offset = 0
var count = circleVertices.length / size
// var count = positions.length / size
this.gl.drawArrays(primitiveType, offset, count)
}
WebGLRenderer.prototype.render = function (time) {
this.gl.viewport(0, 0, this.gl.canvas.width, this.gl.canvas.height)
var delta = Math.sin(time / 1000) * 10
this.clearCanvas(new Color(0, 0, 0, 255))
var rectangleColor = new Color(0, 65, 255, 255)
var width = 50
var height = 50
var circleColor = new Color(0, 167, 255, 255)
this.drawCircle(10, 10, 10, circleColor)
requestAnimationFrame(this.render.bind(this))
}
return WebGLRenderer
})()
function Color(r, g, b, a) {
this.r = r
this.g = g
this.b = b
this.a = a
this.getColor = function () {
return [r / 255, g / 255, b / 255, a / 255]
}
}
var renderer = new WebGLRenderer()
结果:模糊的圆圈(我用WebGL渲染的一切都很模糊)
请看结果小提琴:https://jsfiddle.net/xLwmngav/1/
预期结果:圆滑圆
任何帮助表示赞赏。先感谢您。
正如在this article指出的那样,画布有2种尺寸,它们的分辨率(它们中有多少像素)和它们显示的尺寸。
通常,您希望分辨率匹配或超过画布显示的大小。最好的方法是在渲染之前检查画布的分辨率是否与显示的大小相匹配,以及是否不使用像这样的函数调整大小
function resize(canvas) {
// Lookup the size the browser is displaying the canvas.
const desiredWidth = canvas.clientWidth;
const desiredHeight = canvas.clientHeight;
// Check if the canvas is not the same size.
if (canvas.width !== desiredWidth ||
canvas.height !== desiredHeight) {
// Make the canvas the same size
canvas.width = desiredWidth;
canvas.height = desiredHeight;
}
}
并像这样使用它
function render() {
resize(canvas);
gl.viewport(0, 0, gl.canvas.width, gl.canvas.height);
... draw here ...
...
例:
function resize(canvas) {
// Lookup the size the browser is displaying the canvas.
const desiredWidth = canvas.clientWidth;
const desiredHeight = canvas.clientHeight;
// Check if the canvas is not the same size.
if (canvas.width !== desiredWidth ||
canvas.height !== desiredHeight) {
// Make the canvas the same size
canvas.width = desiredWidth;
canvas.height = desiredHeight;
}
}
var WebGLRenderer = (function () {
function WebGLRenderer() {
this.canvas = document.getElementById('canvas')
this.gl = this.canvas.getContext('webgl') || this.canvas.getContext('experimental-webgl')
if (!this.gl) {
throw Error('Your browser does not support WebGL')
return
}
// Programs
this.rectangleProgram = webglUtils.createProgramFromScripts(this.gl, ['2d-vertex-shader', '2d-fragment-shader'])
// Locations
this.rectanglePoisitionLocation = this.gl.getAttribLocation(this.rectangleProgram, 'a_position')
// Uniforms
this.rectangleResolutionLocation = this.gl.getUniformLocation(this.rectangleProgram, 'u_resolution')
this.rectangleColorLocation = this.gl.getUniformLocation(this.rectangleProgram, 'u_color')
// this.positionBuffer = this.gl.createBuffer()
this.rectanglePositionBuffer = this.gl.createBuffer()
// this.gl.bindBuffer(this.gl.ARRAY_BUFFER, this.positionBuffer)
requestAnimationFrame(this.render.bind(this))
}
WebGLRenderer.prototype.clearCanvas = function (color) {
var rgba = color.getColor()
this.gl.clearColor(...rgba)
this.gl.clear(this.gl.COLOR_BUFFER_BIT)
}
WebGLRenderer.prototype.drawCircle = function (x, y, radius, color) {
// Render circle
// For now user rectangleProgram
this.gl.useProgram(this.rectangleProgram)
this.gl.enableVertexAttribArray(this.rectanglePoisitionLocation)
// this.gl.bindBuffer(this.gl.ARRAY_BUFFER, this.positionBuffer)
this.circleBuffer = this.gl.createBuffer()
// this.gl.bindBuffer(this.gl.ARRAY_BUFFER, this.rectanglePositionBuffer)
this.gl.bindBuffer(this.gl.ARRAY_BUFFER, this.circleBuffer)
// Setup circle
var circleVertices = [x, y]
var numFans = 360
var anglePerFan = (2 * Math.PI) / numFans
for (var i = 0; i <= numFans; i++) {
var angle = anglePerFan * (i + 1)
var angledX = x + Math.cos(angle) * radius
var angledY = y + Math.sin(angle) * radius
circleVertices.push(angledX, angledY)
// circleVertices.push()
}
/*var circleVertices = [
x, y,
15, 18,
5, 18,
0, 10,
4, 1,
14, 1,
20, 9,
15, 18
]*/
// three 2d points
// TODO: Research static draw
this.gl.bufferData(this.gl.ARRAY_BUFFER, new Float32Array(circleVertices), this.gl.DYNAMIC_DRAW)
// this.gl.bufferData(this.gl.ARRAY_BUFFER, new Float32Array(positions), this.gl.STATIC_DRAW)
var size = 2
var type = this.gl.FLOAT
var normalize = false
var stride = 0
var offset = 0
this.gl.vertexAttribPointer(this.rectanglePoisitionLocation, size, type, normalize, stride, offset)
this.gl.uniform2f(this.rectangleResolutionLocation, this.gl.canvas.width, this.gl.canvas.height)
// Color
var colorArray = color.getColor()
this.gl.uniform4fv(this.rectangleColorLocation, colorArray)
// Draw rectangle
var primitiveType = this.gl.TRIANGLE_FAN
// var primitiveType = this.gl.POINTS
var offset = 0
var count = circleVertices.length / size
// var count = positions.length / size
this.gl.drawArrays(primitiveType, offset, count)
}
WebGLRenderer.prototype.render = function (time) {
resize(this.gl.canvas);
this.gl.viewport(0, 0, this.gl.canvas.width, this.gl.canvas.height)
var delta = Math.sin(time / 1000) * 10
this.clearCanvas(new Color(0, 0, 0, 255))
var rectangleColor = new Color(0, 65, 255, 255)
var width = 50
var height = 50
var circleColor = new Color(0, 167, 255, 255)
this.drawCircle(10, 10, 10, circleColor)
requestAnimationFrame(this.render.bind(this))
}
return WebGLRenderer
})()
function Color(r, g, b, a) {
this.r = r
this.g = g
this.b = b
this.a = a
this.getColor = function () {
return [r / 255, g / 255, b / 255, a / 255]
}
}
var renderer = new WebGLRenderer()
window.WebGLRenderer = WebGLRenderer
body {
margin: 0;
}
#canvas {
display: block; /* prevents scrollbar */
width: 100vw;
height: 100vh;
}
<canvas id="canvas"></canvas>
<!-- vertex shader -->
<script id="2d-vertex-shader" type="x-shader/x-vertex">
attribute vec2 a_position;
uniform vec2 u_resolution;
void main() {
// convert the rectangle points from pixels to 0.0 to 1.0
vec2 zeroToOne = a_position / u_resolution;
// convert from 0->1 to 0->2
vec2 zeroToTwo = zeroToOne * 2.0;
// convert from 0->2 to -1->+1 (clipspace)
vec2 clipSpace = zeroToTwo - 1.0;
gl_Position = vec4(clipSpace * vec2(1, -1), 0, 1);
}
</script>
<!-- fragment shader -->
<script id="2d-fragment-shader" type="x-shader/x-fragment">
precision mediump float;
uniform vec4 u_color;
void main() {
gl_FragColor = u_color;
}
</script>
<script src="https://webglfundamentals.org/webgl/resources/webgl-utils.js"></script>
<script src="https://webglfundamentals.org/webgl/resources/m3.js"></script>
画布默认宽度和高度为300x150像素。这些是<canvas>
元素的属性,而不是CSS属性。通过100vw
缩放到100vh
,你只是将那些300x150像素拉伸到屏幕上。
要实际获得从画布像素到屏幕像素的1:1映射,您需要将画布的宽度和高度设置为窗口的大小:
this.canvas.width = window.innerWidth
this.canvas.height = window.innerHeight
您可能还想在resize
上收听window
事件并相应地更新画布大小。